- Put the files below in place (replace
_
with/
) - Add
my-shutdown
to/etc/mkinitcpio.conf
'sHOOKS
, afterzfs
and beforefilesystems
. For example,HOOKS=(base udev autodetect keyboard keymap modconf kms block zfs my-shutdown filesystems)
.
Last active
March 1, 2024 14:45
-
-
Save Frederick888/8fdd100ec6233c062f84998a8d1704e3 to your computer and use it in GitHub Desktop.
Arch Linux `initcpio` hook that additionally unloads NVIDIA modules and exports ZFS pools
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/ash | |
# SPDX-License-Identifier: GPL-2.0-only | |
run_cleanuphook() { | |
rm -rf /usr/lib/modules | |
cp -ax /. /run/initramfs | |
} | |
# vim: set ft=sh ts=4 sw=4 et: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# SPDX-License-Identifier: GPL-2.0-only | |
build() { | |
add_binary cp | |
add_binary date | |
add_binary lsblk | |
add_binary findmnt | |
add_binary fuser | |
add_binary umount | |
add_file "/etc/initcpio/my-shutdown" "/shutdown" 755 | |
add_runscript | |
} | |
help() { | |
cat <<HELPEOF | |
This hook copies the contents of the initramfs into /run/initramfs for reuse | |
on shutdown. This is needed when you have /usr mounted on a separate partition. | |
This version additionally unloads NVIDIA modules and exports ZFS pools. | |
HELPEOF | |
} | |
# vim: set ft=sh ts=4 sw=4 et: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/ash | |
# SPDX-License-Identifier: GPL-2.0-only | |
# 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) | |
# dmsetup could be used here, but we don't know that it | |
# exists. | |
read -r devname <"$1/dm/name" | |
cryptsetup remove "$devname" | |
;; | |
lvm | dm) | |
read -r devname <"$1/dm/name" | |
dmsetup --noudevsync remove "$devname" | |
;; | |
raid*) | |
# wait for arrays with external metadata to be marked as | |
# clean. unfortunately, there isn't a whole lot we can do | |
# if this fails, and the array may need a full rebuild on | |
# the next reboot. | |
IFS=: read -r metadata _ <"/sys/class/block/$1/md/metadata_version" | |
if [ "$metadata" = external ]; then | |
mdadm --wait-clean "/dev/$1" | |
fi | |
mdadm --stop "/dev/$1" | |
;; | |
dmraid) | |
read -r devname <"$1/dm/name" | |
dmraid -an "$devname" | |
;; | |
# 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 | |
[ -e "$holder" ] && disassemble "${holder##*/}" | |
stop_device "$1" | |
done | |
} | |
copy_binary_from_host() { | |
local bin="$1" | |
# hardcode a sane PATH | |
for p in '/usr/sbin' '/usr/bin' '/sbin' '/bin'; do | |
if [ -e "/oldroot/$p/$bin" ]; then | |
cp "/oldroot/$p/$bin" "/usr/bin/$1" | |
return 0 | |
fi | |
done | |
return 1 | |
} | |
# XXX: Discourage libdevmapper from thinking that udev | |
# might be in a useful state. FS#30995. | |
rm -rf /run/udev | |
if [ "$1" = kexec ] && ! command -v kexec >/dev/null; then | |
copy_binary_from_host kexec | |
fi | |
# chdir, so that we can avoid a lot of path chopping | |
cd /sys/class/block || exit | |
date | |
printf '%s\n' "Unloading NVIDIA modules." | |
lsmod | grep nvidia | |
# printf 'SKIPPED!\n' | |
rmmod nvidia_drm nvidia_uvm nvidia_modeset nvidia | |
date | |
printf '%s\n' "Unmounting all devices." | |
umount --recursive /oldroot | |
date | |
printf '%s\n' "Exporting ZFS pools." | |
zpool export -a | |
debug_log() { | |
mkdir /debug | |
mount /dev/disk/by-uuid/e0919973-0f0d-4938-b23a-fdf243675a97 /debug | |
date | tee -a /debug/log.txt | |
mount 2>&1 | tee -a /debug/log.txt | |
fuser -vm "$1" 2>&1 | tee -a /debug/log.txt | |
umount /debug | |
} | |
if findmnt /oldroot/sys; then | |
debug_log /oldroot/sys | |
elif findmnt /oldroot; then | |
debug_log /oldroot | |
fi | |
date | |
printf '%s\n' 'Detaching loop devices.' | |
for loop in loop*/loop; do | |
[ -e "$loop" ] && losetup -d "${loop%/loop}" | |
done | |
date | |
printf '%s\n' "Disassembling stacked devices." | |
# iterate over devices with holders | |
for part in */holders/*; do | |
[ -e "$part" ] && disassemble "${part%%/*}" | |
done | |
case "$1" in | |
poweroff | shutdown | halt) | |
"$1" -f | |
;; | |
*) | |
type kexec >/dev/null && kexec -e | |
reboot -f | |
;; | |
esac | |
# vim: ft=sh ts=4 sw=4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment