[arch-general] [PATCH 1/1] Make umounting filesystems much more paranoid.

Victor Lowther victor.lowther at gmail.com
Sun Jul 11 11:22:36 EDT 2010


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



More information about the arch-general mailing list