diff options
author | Dave Reisner <dreisner@archlinux.org> | 2012-03-24 23:39:17 +0100 |
---|---|---|
committer | Dave Reisner <dreisner@archlinux.org> | 2012-03-26 03:13:15 +0200 |
commit | ab24f0129f680ecbdd62bca39b101eec03eb6038 (patch) | |
tree | 3be186a0d8eef7698dee0092f587e4559f3c0f88 | |
parent | 78a6fad8f45cc32735b8e17a5df039854a83ed58 (diff) | |
download | mkinitcpio-ab24f0129f680ecbdd62bca39b101eec03eb6038.tar.gz mkinitcpio-ab24f0129f680ecbdd62bca39b101eec03eb6038.tar.xz |
shutdown: disassemble devices on shutdown
sysfs contains enough information about block devices to be able to
determine the order of stacked devices such as lvm, raid, or crypto. By
looking at the device symlinks from the holders/ attributes of a block
device, we can walk down each device chain until we reach the most
descendant device.
For each of these devices at the end of a chain, detect its type and
perform the appropriate action to disassemble it. Then, walk back up the
device chain, disassembling each parent device.
To save ourselves some pain and make sure we're fairly accurate, lsblk
is brought in for detection of device types.
Thanks-To: Florian Pritz <bluewind@xinu.at>
Thanks-To: Tom Gundersen <teg@jklm.no>
Signed-off-by: Dave Reisner <dreisner@archlinux.org>
-rw-r--r-- | install/shutdown | 2 | ||||
-rwxr-xr-x | shutdown | 64 |
2 files changed, 65 insertions, 1 deletions
diff --git a/install/shutdown b/install/shutdown index 5b56f17..600209e 100644 --- a/install/shutdown +++ b/install/shutdown @@ -1,7 +1,7 @@ #!/bin/bash build() { - BINARIES='cp' + BINARIES='cp lsblk' SCRIPT='shutdown' add_file "/usr/lib/initcpio/shutdown" "/shutdown" @@ -1,5 +1,59 @@ #!/usr/bin/ash +# teardown a single device by node name +# $1: device node name, e.g. md0, dm-2 +stop_device() { + local devtype= devname= + + # the device must still be active + [ -e "/sys/class/block/$1" ] || return 1 + + # this can sometimes fail on stopped md devices, when the + # sysfs node doesn't go away as quickly as i'd like it to. + devtype=$(lsblk -drno TYPE "/dev/$1" 2>/dev/null) || return 1 + case $devtype in + crypt) + read devname <"$1/dm/name" + cryptsetup luksClose "$devname" + ;; + dm|lvm) + # disassemble the parent VG + read devname <"$1/dm/name" + lvm lvdisplay -c "/dev/mapper/$devname" | { + IFS=: read _ vgname _ + lvm vgchange -an "$vgname" + } + ;; + raid*) + mdadm --stop "/dev/$1" + ;; + dmraid) + # XXX: i have no idea how dmraid works + dmraid -an + ;; + # silently ignore unstacked devices + esac +} + +# recursively disassemble a device chain +# $1: device node name, e.g. md0, dm-2 +disassemble() { + local holder= + + for holder in "$1"/holders/*; do + if [ ! -e "$holder" ]; then + # end of the chain, recurse back up + stop_device "$1" + return + fi + disassemble "${holder##*/}" + stop_device "$1" + done +} + +printf '%s\n' "Unmounting all devices." + +# unmount everything, but leave the API mounts findmnt -Rruno TARGET /oldroot | awk ' BEGIN { i = 0 } ! /^\/(proc|dev|sys)/ { @@ -15,6 +69,16 @@ END { umount -l "$mount" done +printf '%s\n' "Disassembling stacked devices." + +# chdir, so that we can avoid a lot of path chopping +cd /sys/class/block + +# iterate over devices with holders +for part in */holders/*; do + [ -e "$part" ] && disassemble "${part%%/*}" +done + case $1 in poweroff|shutdown|halt) "$1" -f |