From a5c433696cabd9e1f75e03b1de2df4de8b51acf2 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 9 Jun 2010 22:29:06 +0000 Subject: [PATCH] * Put all of /var/run (not just /var/run/nscd) on a tmpfs to simplify shutdown. (Portmap and statd are needed during shutdown to unmount NFS volumes but have open files in /var/run.) * In the shutdown job, don't kill PIDs belonging to Upstart jobs that are still running. If they don't stop on the "starting shutdown" event, then they're needed during shutdown (such as portmap and statd). * NFS test: test whether the shutdown quickly unmounts NFS volumes (i.e. whether portmap and statd are still running). svn path=/nixos/branches/boot-order/; revision=22204 --- .../services/network-filesystems/nfs-kernel.nix | 2 +- modules/services/networking/portmap.nix | 1 + modules/system/activation/activation-script.nix | 11 ----------- modules/system/boot/stage-2-init.sh | 10 ++++++++++ modules/system/upstart-events/shutdown.nix | 17 +++++++++++------ tests/nfs.nix | 8 ++++++++ 6 files changed, 31 insertions(+), 18 deletions(-) diff --git a/modules/services/network-filesystems/nfs-kernel.nix b/modules/services/network-filesystems/nfs-kernel.nix index c3974881f0a2..e9c42237e0d4 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 eead1c52ff01..9c0d559f867e 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 5327740c6315..637f2503466d 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 69c67de6e3a4..201c539bb6ba 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 2aad17cd1ac0..1b2b63cd9c0b 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 1e021eb10c1d..f8d1cf951f31 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; ''; }