[arch-general] [PATCH 1/1] Make umounting filesystems much more paranoid.
In addition to just umounting filesystems, we also try to tear down volume groups, crypt mappings, and loopback devices. We skip /, /proc, /sys, and /dev when umounting filesystems. We do all of the above in a loop, escalating how forcible we are in umounting filesystems up to the point where we give up and try to just remount filesystems read-only. We do not escalate how forcible we are until we stop making progress in umounting filesystems. This patch does not print anything when tearing down crypt devices, deactivating volume groups, or tearing down loopback devices. It does this because root on lvm and root on dm_crypt are fairly common cases, and figuring out which of these is the case and avoiding that volume group or dm_crypt mapping is tricky. We also no longer rely on /etc/crypttab at all for shutdown to tear down dm_crypt mappings. --- rc.shutdown | 112 +++++++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 90 insertions(+), 22 deletions(-) diff --git a/rc.shutdown b/rc.shutdown index 2a561e4..d430dce 100755 --- a/rc.shutdown +++ b/rc.shutdown @@ -64,30 +64,98 @@ stat_busy "Deactivating Swap" /sbin/swapoff -a stat_done -stat_busy "Unmounting Filesystems" -/bin/umount -a -r -t noramfs,notmpfs,nosysfs,noproc,nodevtmpfs -O no_netdev -stat_done +# reverse an array +reverse() { + res=() + [[ $1 ]] || return 0 + local i=("$@") j=0 + for ((j=${#i[@]}-1; j>=0; j--)); do + res+=("${i[j]}") + done +} -# Kill non-root encrypted partition mappings -if [[ -f /etc/crypttab && $CS ]]; then - stat_busy "Deactivating encrypted volumes:" - do_lock() { - stat_append "${1}.." - if $CS remove "$1" >/dev/null 2>&1; then - stat_append "ok " - else - stat_append "failed " - fi - } - read_crypttab do_lock - stat_done -fi +# Get mounted filesystems +fs=() +ignore_re='^/(proc|sys|dev)?$' +while read dev mntpt rest; do + [[ $mntpt =~ $ignore_re ]] && continue + fs+=("$mntpt") +done < /proc/self/mounts +# reverse list of filesystems to let us umount them in reverse order +reverse "${fs[@]}" +fs=("${res[@]}") + +# get volume groups +vg=() +which lvm >/dev/null 2>&1 && \ + vg=($(lvm vgs --unbuffered --noheadings -o vg_name)) +# reverse list of volume groups to grab more of them at once. +reverse "${vg[@]}" +vg=("${res[@]}") + +# get crypto devices +crypt=() +[[ $CS ]] && { + for dev in /dev/mapper/*; do + "$CS" status "${dev##*/}" >/dev/null 2>&1 || continue + crypt+=(${dev##*/}) + done +} +# don't bother reversing crypt, it is in no defined order anyways. + +# get loopback devices in use +loops=() +which losetup >/dev/null 2>&1 && { + while read dev rest; do + loops+=("${dev%:}") + done < <(losetup -a) +} +reverse "${loops[@]}" +loops=("${res[@]}") + +do_umount() { + local ret=0 i j pass=$1 umountopts='' last + # do not umount anything that matches this regex + case $pass in + 2) umountopts='-f';; #next try forcing the umount + 3) umountopts='-r'; last=true;; #next try remounting readonly + esac + + # first, try umounting filesystems. + for i in "${!fs[@]}"; do + if status "Unmounting ${fs[i]} (pass $pass)" /bin/umount -d $umountopts \ + "${fs[i]}"; then + unset fs[$i] + else + ((ret++)) + fi + done + + # Second, deactivate any LVM groups that we can free up + for i in "${!vg[@]}"; do + /sbin/lvm vgchange --sysinit -an "${vg[i]}" >/dev/null 2>&1 && \ + unset vg[$i] + done + + # Third, tear down as many cryptsetup devices as we can. + for i in "${!crypt[@]}"; do + $CS remove "${crypt[i]}" >/dev/null 2>&1 && unset crypt[$i] + done + + # Last, tear down as many loop devices as we can + for i in "${!loops[@]}"; do + losetup -d "${loops[i]}" >/dev/null 2>&1 && unset loops[$i] + done + [[ $last = true ]] && return 0 + return $ret +} -if [[ $USELVM =~ yes|YES && -x /sbin/lvm && -d /sys/block ]]; then - stat_busy "Deactivating LVM2 groups" - /sbin/lvm vgchange --ignorelockingfailure -an >/dev/null 2>&1 - stat_done -fi +# Loop and try to umount filesystems +for ((pass=1,fses=${#fs[@]}; ;fses=${#fs[@]})); do + do_umount $pass && break; # if we umounted all the filesystems, break. + # only escalate if we did not make progress unmounting filesystems. + ((fses == ${#fs[@]})) && ((pass++)) +done stat_busy "Remounting Root Filesystem Read-only" /bin/mount -n -o remount,ro / -- 1.7.1.1
fwiw in AIF I do something similar (see http://github.com/Dieterbe/aif/blob/master/src/core/libs/lib-blockdevices-fi...) (but there i use a text file containing all mountpoints) The interesting thing is, to find the order in which you should mount or (or umount) blockdevices can be found by doing a normal alpabetical (reverse) sorting of the mountpoints, so i just use the sort tool. Dieter
On Jul 11, 2010, at 10:34 AM, Dieter Plaetinck <dieter@plaetinck.be> wrote:
fwiw in AIF I do something similar (see http://github.com/Dieterbe/aif/blob/master/src/core/libs/lib-blockdevices-fi... ) (but there i use a text file containing all mountpoints)
The interesting thing is, to find the order in which you should mount or (or umount) blockdevices can be found by doing a normal alpabetical (reverse) sorting of the mountpoints, so i just use the sort tool.
How so? Filesystems are not mounted in any particular order, and /proc/ self/mounts lists the filesystems in the order they were mounted. Using the sort command would screw up the mount ordering, which means I would have to do more passes to properly umount things.
Dieter
On Sun, 11 Jul 2010 12:20:39 -0500 Victor Lowther <victor.lowther@gmail.com> wrote:
On Jul 11, 2010, at 10:34 AM, Dieter Plaetinck <dieter@plaetinck.be> wrote:
fwiw in AIF I do something similar (see http://github.com/Dieterbe/aif/blob/master/src/core/libs/lib-blockdevices-fi... ) (but there i use a text file containing all mountpoints)
The interesting thing is, to find the order in which you should mount or (or umount) blockdevices can be found by doing a normal alpabetical (reverse) sorting of the mountpoints, so i just use the sort tool.
How so? Filesystems are not mounted in any particular order, and /proc/ self/mounts lists the filesystems in the order they were mounted. Using the sort command would screw up the mount ordering, which means I would have to do more passes to properly umount things.
ah, nevermind. with aif, the user specifies no specific order, so i mount all filesystems in the order that makes most sense (ie, first /home, then /home/someuser, then /home/someuser/blah). in your case, you want to use the "real order", even if it may seem weird. Dieter
participants (2)
-
Dieter Plaetinck
-
Victor Lowther