aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/dracut
diff options
context:
space:
mode:
authorнаб <[email protected]>2022-04-04 22:45:58 +0200
committerBrian Behlendorf <[email protected]>2022-04-20 16:44:47 -0700
commit245529d85fb807bfc4525b3b1858896d2860995b (patch)
treedaa3d9fbe380d2c85117d5242e24e05838acbd62 /contrib/dracut
parent2c74617bcf76b305937097278b614443d47681a0 (diff)
contrib; dracut: centralise root= parsing, actually support root=s
So far, everything parsed root= manually, which meant that while zfs-parse.sh was updated, and supposedly supported + -> ' ' conversion, it meant nothing Instead, centralise parsing, and allow: root= root=zfs root=zfs: root=zfs:AUTO root=ZFS=data/set root=zfs:data/set root=zfs:ZFS=data/set (as a side-effect; allowed but undocumented) rootfstype=zfs AND root=data/set <=> root=data/set rootfstype=zfs AND root= <=> root=zfs:AUTO So rootfstype=zfs /also/ behaves as expected, and + decoding works Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Ahelenia Ziemiańska <[email protected]> Closes #13291
Diffstat (limited to 'contrib/dracut')
-rwxr-xr-xcontrib/dracut/90zfs/mount-zfs.sh.in33
-rwxr-xr-xcontrib/dracut/90zfs/parse-zfs.sh.in61
-rwxr-xr-xcontrib/dracut/90zfs/zfs-generator.sh.in30
-rwxr-xr-xcontrib/dracut/90zfs/zfs-lib.sh.in61
-rwxr-xr-xcontrib/dracut/90zfs/zfs-load-key.sh.in28
-rw-r--r--contrib/dracut/README.md14
6 files changed, 108 insertions, 119 deletions
diff --git a/contrib/dracut/90zfs/mount-zfs.sh.in b/contrib/dracut/90zfs/mount-zfs.sh.in
index 7e11c9afd..6bb06a7ff 100755
--- a/contrib/dracut/90zfs/mount-zfs.sh.in
+++ b/contrib/dracut/90zfs/mount-zfs.sh.in
@@ -3,34 +3,20 @@
. /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."
@@ -38,6 +24,9 @@ info "ZFS: Mounting root with the traditional mount-zfs.sh instead."
modprobe zfs 2>/dev/null
udevadm settle
+ZFS_DATASET=
+ZFS_POOL=
+
if [ "${root}" = "zfs:AUTO" ] ; then
if ! ZFS_DATASET="$(find_bootfs)" ; then
# shellcheck disable=SC2086
@@ -53,7 +42,7 @@ 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
diff --git a/contrib/dracut/90zfs/parse-zfs.sh.in b/contrib/dracut/90zfs/parse-zfs.sh.in
index 77595bcdb..f7d1f1c5d 100755
--- a/contrib/dracut/90zfs/parse-zfs.sh.in
+++ b/contrib/dracut/90zfs/parse-zfs.sh.in
@@ -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=)
@@ -15,46 +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:*)
- # 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=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="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"
- 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
diff --git a/contrib/dracut/90zfs/zfs-generator.sh.in b/contrib/dracut/90zfs/zfs-generator.sh.in
index e50b9530c..56f7ca978 100755
--- a/contrib/dracut/90zfs/zfs-generator.sh.in
+++ b/contrib/dracut/90zfs/zfs-generator.sh.in
@@ -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
@@ -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
@@ -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]"
diff --git a/contrib/dracut/90zfs/zfs-lib.sh.in b/contrib/dracut/90zfs/zfs-lib.sh.in
index afd872d69..b48c97034 100755
--- a/contrib/dracut/90zfs/zfs-lib.sh.in
+++ b/contrib/dracut/90zfs/zfs-lib.sh.in
@@ -1,6 +1,6 @@
#!/bin/sh
-command -v getarg >/dev/null || . /lib/dracut-lib.sh
+command -v getarg >/dev/null || . /lib/dracut-lib.sh || . /usr/lib/dracut/modules.d/99base/dracut-lib.sh
command -v getargbool >/dev/null || {
# Compatibility with older Dracut versions.
# With apologies to the Dracut developers.
@@ -161,7 +161,9 @@ ask_for_password() {
shift
done
- { flock -s 9;
+ {
+ flock -s 9
+
# Prompt for password with plymouth, if installed and running.
if plymouth --ping 2>/dev/null; then
plymouth ask-for-password \
@@ -191,3 +193,58 @@ ask_for_password() {
[ "$ret" -ne 0 ] && echo "Wrong password" >&2
return "$ret"
}
+
+# Parse root=, rootfstype=, return them decoded and normalised to zfs:AUTO for auto, plain dset for explicit
+#
+# True if ZFS-on-root, false if we shouldn't
+#
+# Supported values:
+# root=
+# root=zfs
+# root=zfs:
+# root=zfs:AUTO
+#
+# root=ZFS=data/set
+# root=zfs:data/set
+# root=zfs:ZFS=data/set (as a side-effect; allowed but undocumented)
+#
+# rootfstype=zfs AND root=data/set <=> root=data/set
+# rootfstype=zfs AND root= <=> root=zfs:AUTO
+#
+# '+'es in explicit dataset decoded to ' 's.
+decode_root_args() {
+ if [ -n "$rootfstype" ]; then
+ [ "$rootfstype" = zfs ]
+ return
+ fi
+
+ root=$(getarg root=)
+ rootfstype=$(getarg rootfstype=)
+
+ # shellcheck disable=SC2249
+ case "$root" in
+ ""|zfs|zfs:|zfs:AUTO)
+ root=zfs:AUTO
+ rootfstype=zfs
+ return 0
+ ;;
+
+ ZFS=*|zfs:*)
+ root="${root#zfs:}"
+ root="${root#ZFS=}"
+ root=$(echo "$root" | tr '+' ' ')
+ rootfstype=zfs
+ return 0
+ ;;
+ esac
+
+ if [ "$rootfstype" = "zfs" ]; then
+ case "$root" in
+ "") root=zfs:AUTO ;;
+ *) root=$(echo "$root" | tr '+' ' ') ;;
+ esac
+ return 0
+ fi
+
+ return 1
+}
diff --git a/contrib/dracut/90zfs/zfs-load-key.sh.in b/contrib/dracut/90zfs/zfs-load-key.sh.in
index c974b3d9e..9fbef8f68 100755
--- a/contrib/dracut/90zfs/zfs-load-key.sh.in
+++ b/contrib/dracut/90zfs/zfs-load-key.sh.in
@@ -4,32 +4,20 @@
# only run this on systemd systems, we handle the decrypt in mount-zfs.sh in the mount hook otherwise
[ -e /bin/systemctl ] || [ -e /usr/bin/systemctl ] || return 0
-# This script only gets executed on systemd systems, see mount-zfs.sh for non-systemd systems
+# shellcheck source=zfs-lib.sh.in
+. /lib/dracut-zfs-lib.sh
-# import the libs now that we know the pool imported
-[ -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
-# shellcheck source=./lib-zfs.sh.in
-. "$dracutlib"
-
-# load the kernel command line vars
-[ -z "$root" ] && root="$(getarg root=)"
-# 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
+decode_root_args || return 0
# There is a race between the zpool import and the pre-mount hooks, so we wait for a pool to be imported
-while [ "$(zpool list -H)" = "" ]; do
- systemctl is-failed --quiet zfs-import-cache.service zfs-import-scan.service && exit 1
+while ! systemctl is-active --quiet zfs-import.target; do
+ systemctl is-failed --quiet zfs-import-cache.service zfs-import-scan.service && return 1
sleep 0.1s
done
-# run this after import as zfs-import-cache/scan service is confirmed good
-# we do not overwrite the ${root} variable, but create a new one, BOOTFS, to hold the dataset
-if [ "${root}" = "zfs:AUTO" ] ; then
- BOOTFS="$(zpool list -H -o bootfs | awk '$1 != "-" {print; exit}')"
-else
- BOOTFS="${root##zfs:}"
- BOOTFS="${BOOTFS##ZFS=}"
+BOOTFS="$root"
+if [ "$BOOTFS" = "zfs:AUTO" ]; then
+ BOOTFS="$(zpool get -Ho value bootfs | grep -m1 -vFx -)"
fi
# if pool encryption is active and the zfs command understands '-o encryption'
diff --git a/contrib/dracut/README.md b/contrib/dracut/README.md
index fc3d504ef..522f2ce3c 100644
--- a/contrib/dracut/README.md
+++ b/contrib/dracut/README.md
@@ -16,18 +16,18 @@ Encrypted datasets have keys loaded automatically or prompted for.
If the root dataset contains children with `mountpoint=`s of `/etc`, `/bin`, `/lib*`, or `/usr`, they're mounted too.
## cmdline
-1. `root=` | Root dataset is… | Pools imported |
- -------------------|----------------------------------------------------------|----------------|
- *(empty)* | the first `bootfs=` after `zpool import -aN` | all |
- `zfs:AUTO` | *(as above, but overriding other autoselection methods)* | all |
- `ZFS=pool/dataset` | `pool/dataset` | `pool` |
- `zfs:pool/dataset` | *(as above)* | `pool` |
+1. `root=` | Root dataset is… |
+ ---------------------------|----------------------------------------------------------|
+ *(empty)* | the first `bootfs=` after `zpool import -aN` |
+ `zfs:AUTO`, `zfs:`, `zfs` | *(as above, but overriding other autoselection methods)* |
+ `ZFS=pool/dataset` | `pool/dataset` |
+ `zfs:pool/dataset` | *(as above)* |
All `+`es are replaced with spaces (i.e. to boot from `root pool/data set`, pass `root=zfs:root+pool/data+set`).
The dataset can be at any depth, including being the pool's root dataset (i.e. `root=zfs:pool`).
- `rootfstype=zfs` is mostly equivalent to `root=zfs:AUTO`.
+ `rootfstype=zfs` is equivalent to `root=zfs:AUTO`, `rootfstype=zfs root=pool/dataset` is equivalent to `root=zfs:pool/dataset`.
2. `spl_hostid`: passed to `zgenhostid -f`, useful to override the `/etc/hostid` file baked into the initrd.