Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix dracut. Document it. #13291

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions contrib/dracut/90zfs/module-setup.sh.in
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,10 @@ check() {
for tool in "zgenhostid" "zpool" "zfs" "mount.zfs"; do
command -v "${tool}" >/dev/null || return 1
done

return 0
}

depends() {
echo udev-rules
return 0
}

installkernel() {
Expand All @@ -39,7 +36,6 @@ install() {
{ dfatal "Failed to install essential binaries"; exit 1; }

# Adapted from https://github.com/zbm-dev/zfsbootmenu

if ! ldd "$(command -v zpool)" | grep -qF 'libgcc_s.so'; then
# On systems with gcc-config (Gentoo, Funtoo, etc.), use it to find libgcc_s
if command -v gcc-config >/dev/null; then
Expand Down Expand Up @@ -79,7 +75,6 @@ install() {
fi

if dracut_module_included "systemd"; then

inst_simple "${systemdsystemunitdir}/zfs-import.target"
systemctl -q --root "${initdir}" add-wants initrd.target zfs-import.target

Expand Down
130 changes: 82 additions & 48 deletions contrib/dracut/90zfs/mount-zfs.sh.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,71 @@

. /lib/dracut-zfs-lib.sh

ZFS_DATASET=""
ZFS_POOL=""

case "${root}" in
zfs:*) ;;
*) return ;;
esac
decode_root_args || return 0

GENERATOR_FILE=/run/systemd/generator/sysroot.mount
GENERATOR_EXTENSION=/run/systemd/generator/sysroot.mount.d/zfs-enhancement.conf

if [ -e "$GENERATOR_FILE" ] && [ -e "$GENERATOR_EXTENSION" ] ; then
# If the ZFS sysroot.mount flag exists, the initial RAM disk configured
# it to mount ZFS on root. In that case, we bail early. This flag
# file gets created by the zfs-generator program upon successful run.
info "ZFS: There is a sysroot.mount and zfs-generator has extended it."
info "ZFS: Delegating root mount to sysroot.mount."
# Let us tell the initrd to run on shutdown.
# We have a shutdown hook to run
# because we imported the pool.
if [ -e "$GENERATOR_FILE" ] && [ -e "$GENERATOR_EXTENSION" ]; then
# We're under systemd and dracut-zfs-generator ran to completion.
info "ZFS: Delegating root mount to sysroot.mount at al."

# We now prevent Dracut from running this thing again.
for zfsmounthook in "$hookdir"/mount/*zfs* ; do
if [ -f "$zfsmounthook" ] ; then
rm -f "$zfsmounthook"
fi
done
rm -f "$hookdir"/mount/*zfs*
return
fi

info "ZFS: No sysroot.mount exists or zfs-generator did not extend it."
info "ZFS: Mounting root with the traditional mount-zfs.sh instead."

# ask_for_password tries prompt cmd
#
# Wraps around plymouth ask-for-password and adds fallback to tty password ask
# if plymouth is not present.
ask_for_password() {
tries="$1"
prompt="$2"
cmd="$3"

{
flock -s 9

# Prompt for password with plymouth, if installed and running.
if plymouth --ping 2>/dev/null; then
plymouth ask-for-password \
--prompt "$prompt" --number-of-tries="$tries" | \
eval "$cmd"
ret=$?
else
i=1
while [ "$i" -le "$tries" ]; do
printf "%s [%i/%i]:" "$prompt" "$i" "$tries" >&2
eval "$cmd" && ret=0 && break
ret=$?
i=$((i+1))
printf '\n' >&2
done
unset i
fi
} 9>/.console_lock

[ "$ret" -ne 0 ] && echo "Wrong password" >&2
return "$ret"
}


# Delay until all required block devices are present.
modprobe zfs 2>/dev/null
udevadm settle

ZFS_DATASET=
ZFS_POOL=

if [ "${root}" = "zfs:AUTO" ] ; then
if ! ZFS_DATASET="$(find_bootfs)" ; then
if ! ZFS_DATASET="$(zpool get -Ho value bootfs | grep -m1 -vFx -)"; then
# shellcheck disable=SC2086
zpool import -N -a ${ZPOOL_IMPORT_OPTS}
if ! ZFS_DATASET="$(find_bootfs)" ; then
if ! ZFS_DATASET="$(zpool get -Ho value bootfs | grep -m1 -vFx -)"; then
warn "ZFS: No bootfs attribute found in importable pools."
zpool export -aF

Expand All @@ -53,34 +78,43 @@ if [ "${root}" = "zfs:AUTO" ] ; then
info "ZFS: Using ${ZFS_DATASET} as root."
fi

ZFS_DATASET="${ZFS_DATASET:-${root#zfs:}}"
ZFS_DATASET="${ZFS_DATASET:-${root}}"
ZFS_POOL="${ZFS_DATASET%%/*}"

if import_pool "${ZFS_POOL}" ; then
# Load keys if we can or if we need to
if [ "$(zpool list -H -o feature@encryption "${ZFS_POOL}")" = 'active' ]; then
# if the root dataset has encryption enabled
ENCRYPTIONROOT="$(zfs get -H -o value encryptionroot "${ZFS_DATASET}")"
if ! [ "${ENCRYPTIONROOT}" = "-" ]; then
KEYSTATUS="$(zfs get -H -o value keystatus "${ENCRYPTIONROOT}")"
# if the key needs to be loaded
if [ "$KEYSTATUS" = "unavailable" ]; then
# decrypt them
ask_for_password \
--tries 5 \
--prompt "Encrypted ZFS password for ${ENCRYPTIONROOT}: " \
--cmd "zfs load-key '${ENCRYPTIONROOT}'"
fi

if ! zpool get -Ho name "${ZFS_POOL}" > /dev/null 2>&1; then
info "ZFS: Importing pool ${ZFS_POOL}..."
# shellcheck disable=SC2086
if ! zpool import -N ${ZPOOL_IMPORT_OPTS} "${ZFS_POOL}"; then
warn "ZFS: Unable to import pool ${ZFS_POOL}"
rootok=0
return 1
fi
fi

# Load keys if we can or if we need to
# TODO: for_relevant_root_children like in zfs-load-key.sh.in
if [ "$(zpool get -Ho value feature@encryption "${ZFS_POOL}")" = 'active' ]; then
# if the root dataset has encryption enabled
ENCRYPTIONROOT="$(zfs get -Ho value encryptionroot "${ZFS_DATASET}")"
if ! [ "${ENCRYPTIONROOT}" = "-" ]; then
KEYSTATUS="$(zfs get -Ho value keystatus "${ENCRYPTIONROOT}")"
# if the key needs to be loaded
if [ "$KEYSTATUS" = "unavailable" ]; then
# decrypt them
ask_for_password \
5 \
"Encrypted ZFS password for ${ENCRYPTIONROOT}: " \
"zfs load-key '${ENCRYPTIONROOT}'"
fi
fi
# Let us tell the initrd to run on shutdown.
# We have a shutdown hook to run
# because we imported the pool.
info "ZFS: Mounting dataset ${ZFS_DATASET}..."
if mount_dataset "${ZFS_DATASET}" ; then
ROOTFS_MOUNTED=yes
return 0
fi
fi

rootok=0
# Let us tell the initrd to run on shutdown.
# We have a shutdown hook to run
# because we imported the pool.
info "ZFS: Mounting dataset ${ZFS_DATASET}..."
if ! mount_dataset "${ZFS_DATASET}"; then
rootok=0
return 1
fi
67 changes: 18 additions & 49 deletions contrib/dracut/90zfs/parse-zfs.sh.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#!/bin/sh
# shellcheck disable=SC2034,SC2154

. /lib/dracut-lib.sh
# shellcheck source=zfs-lib.sh.in
. /lib/dracut-zfs-lib.sh

# Let the command line override our host id.
spl_hostid=$(getarg spl_hostid=)
Expand All @@ -15,52 +16,20 @@ else
warn "ZFS: Pools may not import correctly."
fi

wait_for_zfs=0
case "${root}" in
""|zfs|zfs:)
# We'll take root unset, root=zfs, or root=zfs:
# No root set, so we want to read the bootfs attribute. We
# can't do that until udev settles so we'll set dummy values
# and hope for the best later on.
root="zfs:AUTO"
rootok=1
wait_for_zfs=1

info "ZFS: Enabling autodetection of bootfs after udev settles."
;;

ZFS=*|zfs:*|FILESYSTEM=*)
# root is explicit ZFS root. Parse it now. We can handle
# a root=... param in any of the following formats:
# root=ZFS=rpool/ROOT
# root=zfs:rpool/ROOT
# root=zfs:FILESYSTEM=rpool/ROOT
# root=FILESYSTEM=rpool/ROOT
# root=ZFS=pool+with+space/ROOT+WITH+SPACE (translates to root=ZFS=pool with space/ROOT WITH SPACE)

# Strip down to just the pool/fs
root="${root#zfs:}"
root="${root#FILESYSTEM=}"
root="zfs:${root#ZFS=}"
# switch + with spaces because kernel cmdline does not allow us to quote parameters
root=$(echo "$root" | tr '+' ' ')
rootok=1
wait_for_zfs=1

info "ZFS: Set ${root} as bootfs."
;;

*)
info "ZFS: no ZFS-on-root"
esac

# Make sure Dracut is happy that we have a root and will wait for ZFS
# modules to settle before mounting.
if [ "${wait_for_zfs}" -eq 1 ]; then
ln -s /dev/null /dev/root 2>/dev/null
initqueuedir="${hookdir}/initqueue/finished"
test -d "${initqueuedir}" || {
initqueuedir="${hookdir}/initqueue-finished"
}
echo '[ -e /dev/zfs ]' > "${initqueuedir}/zfs.sh"
if decode_root_args; then
if [ "$root" = "zfs:AUTO" ]; then
info "ZFS: Boot dataset autodetected from bootfs=."
else
info "ZFS: Boot dataset is ${root}."
fi

rootok=1
# Make sure Dracut is happy that we have a root and will wait for ZFS
# modules to settle before mounting.
if [ -n "${wait_for_zfs}" ]; then
ln -s null /dev/root
echo '[ -e /dev/zfs ]' > "${hookdir}/initqueue/finished/zfs.sh"
fi
else
info "ZFS: no ZFS-on-root."
fi
2 changes: 1 addition & 1 deletion contrib/dracut/90zfs/zfs-env-bootfs.service.in
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Before=zfs-import.target

[Service]
Type=oneshot
ExecStart=/bin/sh -c "exec systemctl set-environment BOOTFS=$(@sbindir@/zpool list -H -o bootfs | grep -m1 -v '^-$')"
ExecStart=/bin/sh -c "exec systemctl set-environment BOOTFS=$(@sbindir@/zpool list -H -o bootfs | grep -m1 -vFx -)"

[Install]
WantedBy=zfs-import.target
30 changes: 5 additions & 25 deletions contrib/dracut/90zfs/zfs-generator.sh.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/bin/sh
# shellcheck disable=SC2016,SC1004
# shellcheck disable=SC2016,SC1004,SC2154

grep -wq debug /proc/cmdline && debug=1
[ -n "$debug" ] && echo "zfs-generator: starting" >> /dev/kmsg
Expand All @@ -10,37 +10,17 @@ GENERATOR_DIR="$1"
exit 1
}

[ -f /lib/dracut-lib.sh ] && dracutlib=/lib/dracut-lib.sh
[ -f /usr/lib/dracut/modules.d/99base/dracut-lib.sh ] && dracutlib=/usr/lib/dracut/modules.d/99base/dracut-lib.sh
command -v getarg >/dev/null 2>&1 || {
[ -n "$debug" ] && echo "zfs-generator: loading Dracut library from $dracutlib" >> /dev/kmsg
. "$dracutlib"
}

# shellcheck source=zfs-lib.sh.in
. /lib/dracut-zfs-lib.sh
decode_root_args || exit 0

[ -z "$root" ] && root=$(getarg root=)
[ -z "$rootfstype" ] && rootfstype=$(getarg rootfstype=)
[ -z "$rootflags" ] && rootflags=$(getarg rootflags=)

# If root is not ZFS= or zfs: or rootfstype is not zfs
# then we are not supposed to handle it.
[ "${root##zfs:}" = "${root}" ] &&
[ "${root##ZFS=}" = "${root}" ] &&
[ "$rootfstype" != "zfs" ] &&
exit 0

[ -z "${rootflags}" ] && rootflags=$(getarg rootflags=)
case ",${rootflags}," in
*,zfsutil,*) ;;
,,) rootflags=zfsutil ;;
*) rootflags="zfsutil,${rootflags}" ;;
esac

if [ "${root}" != "zfs:AUTO" ]; then
root="${root##zfs:}"
root="${root##ZFS=}"
fi

[ -n "$debug" ] && echo "zfs-generator: writing extension for sysroot.mount to $GENERATOR_DIR/sysroot.mount.d/zfs-enhancement.conf" >> /dev/kmsg


Expand Down Expand Up @@ -89,7 +69,7 @@ else
_zfs_generator_cb() {
dset="${1}"
mpnt="${2}"
unit="sysroot$(echo "$mpnt" | tr '/' '-').mount"
unit="$(systemd-escape --suffix=mount -p "/sysroot${mpnt}")"

{
echo "[Unit]"
Expand Down
Loading