diff --git a/modules/services/network-filesystems/nfs-kernel.nix b/modules/services/network-filesystems/nfs-kernel.nix index c3974881f0a..e9c42237e0d 100644 --- a/modules/services/network-filesystems/nfs-kernel.nix +++ b/modules/services/network-filesystems/nfs-kernel.nix @@ -162,7 +162,7 @@ in description = "Kernel NFS server - Network Status Monitor"; startOn = "${if cfg.server.enable then "starting nfs-kernel-nfsd and " else ""} started portmap"; - stopOn = if cfg.server.enable then "stopped nfs-kernel-nfsd" else "starting shutdown"; + stopOn = "never"; preStart = '' diff --git a/modules/services/networking/portmap.nix b/modules/services/networking/portmap.nix index eead1c52ff0..9c0d559f867 100644 --- a/modules/services/networking/portmap.nix +++ b/modules/services/networking/portmap.nix @@ -67,6 +67,7 @@ in { description = "ONC RPC portmap"; startOn = "started network-interfaces"; + stopOn = "never"; daemonType = "fork"; diff --git a/modules/system/activation/activation-script.nix b/modules/system/activation/activation-script.nix index 5327740c631..637f2503466 100644 --- a/modules/system/activation/activation-script.nix +++ b/modules/system/activation/activation-script.nix @@ -75,7 +75,6 @@ let var = fullDepEntry '' # Various log/runtime directories. - mkdir -m 0755 -p /var/run touch /var/run/utmp # must exist chgrp ${toString config.ids.gids.utmp} /var/run/utmp @@ -84,16 +83,6 @@ let mkdir -m 0755 -p /var/run/nix/current-load # for distributed builds mkdir -m 0700 -p /var/run/nix/remote-stores - # Use a tmpfs for /var/run/nscd to ensure that / or /var can be - # unmounted or at least remounted read-only during shutdown. - # (Upstart 0.6 apparently uses nscd to do some name lookups, - # resulting in it holding some mmap mapping to deleted files in - # /var/run/nscd.) - if [ ! -e /var/run/nscd ]; then - mkdir -p /var/run/nscd - ${pkgs.utillinux}/bin/mount -t tmpfs -o "mode=755" none /var/run/nscd - fi - mkdir -m 0755 -p /var/log mkdir -m 0755 -p /var/log/upstart diff --git a/modules/system/boot/stage-2-init.sh b/modules/system/boot/stage-2-init.sh index 69c67de6e3a..201c539bb6b 100644 --- a/modules/system/boot/stage-2-init.sh +++ b/modules/system/boot/stage-2-init.sh @@ -109,6 +109,16 @@ rm -rf /var/log/upstart rm -rf /nix/var/nix/chroots # recreated in activate-configuration.sh +# Use a tmpfs for /var/run to ensure that / or /var can be unmounted +# or at least remounted read-only during shutdown. (Upstart 0.6 +# apparently uses nscd to do some name lookups, resulting in it +# holding some mmap mapping to deleted files in /var/run/nscd. +# Similarly, portmap and statd have open files in /var/run and are +# needed during shutdown to unmount NFS volumes.) +mkdir -m 0755 -p /var/run +mount -t tmpfs -o "mode=755" none /var/run + + # Clear the resume device. if test -n "$resumeDevice"; then mkswap "$resumeDevice" || echo 'Failed to clear saved image.' diff --git a/modules/system/upstart-events/shutdown.nix b/modules/system/upstart-events/shutdown.nix index 2aad17cd1ac..1b2b63cd9c0 100644 --- a/modules/system/upstart-events/shutdown.nix +++ b/modules/system/upstart-events/shutdown.nix @@ -37,14 +37,19 @@ with pkgs.lib; sync - # Kill all remaining processes except init and this one. + # Kill all remaining processes except init, this one and any + # Upstart jobs that don't stop on the "starting shutdown" + # event, as these are necessary to complete the shutdown. + omittedPids=$(initctl list | sed -e 's/.*process \([0-9]\+\)/-o \1/;t;d') + #echo "saved PIDs: $omittedPids" + echo "sending the TERM signal to all processes..." - kill -TERM -1 + ${pkgs.sysvtools}/bin/killall5 -15 $job $omittedPids sleep 1 # wait briefly echo "sending the KILL signal to all processes..." - kill -KILL -1 + ${pkgs.sysvtools}/bin/killall5 -9 $job $omittedPids # If maintenance mode is requested, start a root shell, and @@ -71,8 +76,8 @@ with pkgs.lib; # Stop all swap devices. swapoff -a - - + + # Unmount file systems. We repeat this until no more file systems # can be unmounted. This is to handle loopback devices, file # systems mounted on other file systems and so on. @@ -84,7 +89,7 @@ with pkgs.lib; cp /proc/mounts /dev/.mounts # don't read /proc/mounts while it's changing exec 4< /dev/.mounts while read -u 4 device mp fstype options rest; do - if [ "$mp" = /proc -o "$mp" = /sys -o "$mp" = /dev -o "$device" = "rootfs" -o "$mp" = /var/run/nscd ]; then continue; fi + if [ "$mp" = /proc -o "$mp" = /sys -o "$mp" = /dev -o "$device" = "rootfs" -o "$mp" = /var/run ]; then continue; fi echo "unmounting $mp..." diff --git a/tests/nfs.nix b/tests/nfs.nix index 1e021eb10c1..f8d1cf951f3 100644 --- a/tests/nfs.nix +++ b/tests/nfs.nix @@ -71,6 +71,14 @@ in $server->start; $client1->succeed("touch /data/xyzzy"); $client1->fail("time flock -n -s /data/lock true"); + + # Test whether unmounting during shutdown happens quickly. This + # requires portmap and statd to keep running during the + # shutdown. + my $t1 = time; + $client1->shutdown; + my $duration = time - $t1; + die "shutdown took too long ($duration seconds)" if $duration > 30; ''; }