From b825169404ecc9c38bcd4ca9a5ad72fc93d04d7b Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 16 Sep 2013 17:15:42 +0200 Subject: [PATCH] Add kexec support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit You can now do a fast reboot (bypassing the BIOS, which may take several minutes on servers) by running ‘systemctl kexec’. Unfortunately the QEMU test for this is unreliable due to a QEMU bug (it randomly crashes with a message like ‘Guest moved used index from 8 to 0’), so it's commented out. --- doc/manual/running.xml | 22 +++++++++++++++++++--- lib/test-driver/Machine.pm | 4 ++-- modules/module-list.nix | 1 + modules/system/boot/kexec.nix | 21 +++++++++++++++++++++ modules/system/boot/systemd.nix | 1 + tests/default.nix | 1 + tests/kexec.nix | 18 ++++++++++++++++++ 7 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 modules/system/boot/kexec.nix create mode 100644 tests/kexec.nix diff --git a/doc/manual/running.xml b/doc/manual/running.xml index 858372c1acac..e50099707cc5 100644 --- a/doc/manual/running.xml +++ b/doc/manual/running.xml @@ -101,9 +101,25 @@ doing: $ shutdown -This is equivalent to running systemctl poweroff. -Likewise, reboot (a.k.a. systemctl -reboot) will reboot the system. +This is equivalent to running systemctl +poweroff. + +To reboot the system, run + + +$ reboot + + +which is equivalent to systemctl reboot. +Alternatively, you can quickly reboot the system using +kexec, which bypasses the BIOS by directly loading +the new kernel into memory: + + +$ systemctl kexec + + + The machine can be suspended to RAM (if supported) using systemctl suspend, and suspended to disk using diff --git a/lib/test-driver/Machine.pm b/lib/test-driver/Machine.pm index c56e650ed361..a28214ea934f 100644 --- a/lib/test-driver/Machine.pm +++ b/lib/test-driver/Machine.pm @@ -232,9 +232,9 @@ sub connect { $self->start; - local $SIG{ALRM} = sub { die "timed out waiting for the guest to connect\n"; }; + local $SIG{ALRM} = sub { die "timed out waiting for the VM to connect\n"; }; alarm 300; - readline $self->{socket} or die; + readline $self->{socket} or die "the VM quit before connecting\n"; alarm 0; $self->log("connected to guest root shell"); diff --git a/modules/module-list.nix b/modules/module-list.nix index 717828fbd70d..08acd213355e 100644 --- a/modules/module-list.nix +++ b/modules/module-list.nix @@ -235,6 +235,7 @@ ./system/activation/activation-script.nix ./system/activation/top-level.nix ./system/boot/kernel.nix + ./system/boot/kexec.nix ./system/boot/loader/efi-boot-stub/efi-boot-stub.nix ./system/boot/loader/efi.nix ./system/boot/loader/generations-dir/generations-dir.nix diff --git a/modules/system/boot/kexec.nix b/modules/system/boot/kexec.nix new file mode 100644 index 000000000000..b7821f9509f1 --- /dev/null +++ b/modules/system/boot/kexec.nix @@ -0,0 +1,21 @@ +{ config, pkgs, ... }: + +{ + environment.systemPackages = [ pkgs.kexectools ]; + + systemd.services."prepare-kexec" = + { description = "Preparation for kexec"; + wantedBy = [ "kexec.target" ]; + before = [ "systemd-kexec.service" ]; + unitConfig.DefaultDependencies = false; + serviceConfig.Type = "oneshot"; + path = [ pkgs.kexectools ]; + script = + '' + p=$(readlink -f /nix/var/nix/profiles/system) + if ! [ -d $p ]; then exit 1; fi + exec kexec --load $p/kernel --initrd=$p/initrd --append="$(cat $p/kernel-params) init=$p/init" + ''; + }; + +} \ No newline at end of file diff --git a/modules/system/boot/systemd.nix b/modules/system/boot/systemd.nix index 900cbfd0cd51..5ad8cdbcb18b 100644 --- a/modules/system/boot/systemd.nix +++ b/modules/system/boot/systemd.nix @@ -129,6 +129,7 @@ let "umount.target" "final.target" "kexec.target" + "systemd-kexec.service" # Password entry. "systemd-ask-password-console.path" diff --git a/tests/default.nix b/tests/default.nix index a94ad0695106..36a2a2d608b8 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -10,6 +10,7 @@ with import ../lib/testing.nix { inherit system minimal; }; installer = makeTests (import ./installer.nix); ipv6 = makeTest (import ./ipv6.nix); kde4 = makeTest (import ./kde4.nix); + #kexec = makeTest (import ./kexec.nix); login = makeTest (import ./login.nix {}); latestKernel.login = makeTest (import ./login.nix ({ config, pkgs, ... }: { boot.kernelPackages = pkgs.linuxPackages_latest; })); misc = makeTest (import ./misc.nix); diff --git a/tests/kexec.nix b/tests/kexec.nix new file mode 100644 index 000000000000..b8da332b919b --- /dev/null +++ b/tests/kexec.nix @@ -0,0 +1,18 @@ +# Test whether fast reboots via kexec work. + +{ pkgs, ... }: + +{ + + machine = { config, pkgs, ... }: + { virtualisation.vlans = [ ]; }; + + testScript = + '' + $machine->waitForUnit("multi-user.target"); + $machine->execute("systemctl kexec &"); + $machine->{connected} = 0; + $machine->waitForUnit("multi-user.target"); + ''; + +}