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 <behlendorf1@llnl.gov> Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz> Closes #13291
This commit is contained in:
parent
2c74617bcf
commit
245529d85f
|
@ -3,34 +3,20 @@
|
||||||
|
|
||||||
. /lib/dracut-zfs-lib.sh
|
. /lib/dracut-zfs-lib.sh
|
||||||
|
|
||||||
ZFS_DATASET=""
|
decode_root_args || return 0
|
||||||
ZFS_POOL=""
|
|
||||||
|
|
||||||
case "${root}" in
|
|
||||||
zfs:*) ;;
|
|
||||||
*) return ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
GENERATOR_FILE=/run/systemd/generator/sysroot.mount
|
GENERATOR_FILE=/run/systemd/generator/sysroot.mount
|
||||||
GENERATOR_EXTENSION=/run/systemd/generator/sysroot.mount.d/zfs-enhancement.conf
|
GENERATOR_EXTENSION=/run/systemd/generator/sysroot.mount.d/zfs-enhancement.conf
|
||||||
|
|
||||||
if [ -e "$GENERATOR_FILE" ] && [ -e "$GENERATOR_EXTENSION" ] ; then
|
if [ -e "$GENERATOR_FILE" ] && [ -e "$GENERATOR_EXTENSION" ]; then
|
||||||
# If the ZFS sysroot.mount flag exists, the initial RAM disk configured
|
# We're under systemd and dracut-zfs-generator ran to completion.
|
||||||
# it to mount ZFS on root. In that case, we bail early. This flag
|
info "ZFS: Delegating root mount to sysroot.mount at al."
|
||||||
# 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.
|
|
||||||
# We now prevent Dracut from running this thing again.
|
# We now prevent Dracut from running this thing again.
|
||||||
for zfsmounthook in "$hookdir"/mount/*zfs* ; do
|
rm -f "$hookdir"/mount/*zfs*
|
||||||
if [ -f "$zfsmounthook" ] ; then
|
|
||||||
rm -f "$zfsmounthook"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
info "ZFS: No sysroot.mount exists or zfs-generator did not extend it."
|
info "ZFS: No sysroot.mount exists or zfs-generator did not extend it."
|
||||||
info "ZFS: Mounting root with the traditional mount-zfs.sh instead."
|
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
|
modprobe zfs 2>/dev/null
|
||||||
udevadm settle
|
udevadm settle
|
||||||
|
|
||||||
|
ZFS_DATASET=
|
||||||
|
ZFS_POOL=
|
||||||
|
|
||||||
if [ "${root}" = "zfs:AUTO" ] ; then
|
if [ "${root}" = "zfs:AUTO" ] ; then
|
||||||
if ! ZFS_DATASET="$(find_bootfs)" ; then
|
if ! ZFS_DATASET="$(find_bootfs)" ; then
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
|
@ -53,7 +42,7 @@ if [ "${root}" = "zfs:AUTO" ] ; then
|
||||||
info "ZFS: Using ${ZFS_DATASET} as root."
|
info "ZFS: Using ${ZFS_DATASET} as root."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ZFS_DATASET="${ZFS_DATASET:-${root#zfs:}}"
|
ZFS_DATASET="${ZFS_DATASET:-${root}}"
|
||||||
ZFS_POOL="${ZFS_DATASET%%/*}"
|
ZFS_POOL="${ZFS_DATASET%%/*}"
|
||||||
|
|
||||||
if import_pool "${ZFS_POOL}" ; then
|
if import_pool "${ZFS_POOL}" ; then
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# shellcheck disable=SC2034,SC2154
|
# 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.
|
# Let the command line override our host id.
|
||||||
spl_hostid=$(getarg spl_hostid=)
|
spl_hostid=$(getarg spl_hostid=)
|
||||||
|
@ -15,46 +16,20 @@ else
|
||||||
warn "ZFS: Pools may not import correctly."
|
warn "ZFS: Pools may not import correctly."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
wait_for_zfs=0
|
if decode_root_args; then
|
||||||
case "${root}" in
|
if [ "$root" = "zfs:AUTO" ]; then
|
||||||
""|zfs|zfs:)
|
info "ZFS: Boot dataset autodetected from bootfs=."
|
||||||
# We'll take root unset, root=zfs, or root=zfs:
|
else
|
||||||
# No root set, so we want to read the bootfs attribute. We
|
info "ZFS: Boot dataset is ${root}."
|
||||||
# can't do that until udev settles so we'll set dummy values
|
fi
|
||||||
# and hope for the best later on.
|
|
||||||
root="zfs:AUTO"
|
|
||||||
rootok=1
|
rootok=1
|
||||||
wait_for_zfs=1
|
# Make sure Dracut is happy that we have a root and will wait for ZFS
|
||||||
|
# modules to settle before mounting.
|
||||||
info "ZFS: Enabling autodetection of bootfs after udev settles."
|
if [ -n "${wait_for_zfs}" ]; then
|
||||||
;;
|
ln -s null /dev/root
|
||||||
|
echo '[ -e /dev/zfs ]' > "${hookdir}/initqueue/finished/zfs.sh"
|
||||||
ZFS=*|zfs:*)
|
fi
|
||||||
# root is explicit ZFS root. Parse it now. We can handle
|
else
|
||||||
# a root=... param in any of the following formats:
|
info "ZFS: no ZFS-on-root."
|
||||||
# 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"
|
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# shellcheck disable=SC2016,SC1004
|
# shellcheck disable=SC2016,SC1004,SC2154
|
||||||
|
|
||||||
grep -wq debug /proc/cmdline && debug=1
|
grep -wq debug /proc/cmdline && debug=1
|
||||||
[ -n "$debug" ] && echo "zfs-generator: starting" >> /dev/kmsg
|
[ -n "$debug" ] && echo "zfs-generator: starting" >> /dev/kmsg
|
||||||
|
@ -10,37 +10,17 @@ GENERATOR_DIR="$1"
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
[ -f /lib/dracut-lib.sh ] && dracutlib=/lib/dracut-lib.sh
|
# shellcheck source=zfs-lib.sh.in
|
||||||
[ -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"
|
|
||||||
}
|
|
||||||
|
|
||||||
. /lib/dracut-zfs-lib.sh
|
. /lib/dracut-zfs-lib.sh
|
||||||
|
decode_root_args || exit 0
|
||||||
|
|
||||||
[ -z "$root" ] && root=$(getarg root=)
|
[ -z "${rootflags}" ] && rootflags=$(getarg rootflags=)
|
||||||
[ -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
|
|
||||||
|
|
||||||
case ",${rootflags}," in
|
case ",${rootflags}," in
|
||||||
*,zfsutil,*) ;;
|
*,zfsutil,*) ;;
|
||||||
,,) rootflags=zfsutil ;;
|
,,) rootflags=zfsutil ;;
|
||||||
*) rootflags="zfsutil,${rootflags}" ;;
|
*) rootflags="zfsutil,${rootflags}" ;;
|
||||||
esac
|
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
|
[ -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() {
|
_zfs_generator_cb() {
|
||||||
dset="${1}"
|
dset="${1}"
|
||||||
mpnt="${2}"
|
mpnt="${2}"
|
||||||
unit="sysroot$(echo "$mpnt" | tr '/' '-').mount"
|
unit="$(systemd-escape --suffix=mount -p "/sysroot${mpnt}")"
|
||||||
|
|
||||||
{
|
{
|
||||||
echo "[Unit]"
|
echo "[Unit]"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/sh
|
#!/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 || {
|
command -v getargbool >/dev/null || {
|
||||||
# Compatibility with older Dracut versions.
|
# Compatibility with older Dracut versions.
|
||||||
# With apologies to the Dracut developers.
|
# With apologies to the Dracut developers.
|
||||||
|
@ -161,7 +161,9 @@ ask_for_password() {
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
{ flock -s 9;
|
{
|
||||||
|
flock -s 9
|
||||||
|
|
||||||
# Prompt for password with plymouth, if installed and running.
|
# Prompt for password with plymouth, if installed and running.
|
||||||
if plymouth --ping 2>/dev/null; then
|
if plymouth --ping 2>/dev/null; then
|
||||||
plymouth ask-for-password \
|
plymouth ask-for-password \
|
||||||
|
@ -191,3 +193,58 @@ ask_for_password() {
|
||||||
[ "$ret" -ne 0 ] && echo "Wrong password" >&2
|
[ "$ret" -ne 0 ] && echo "Wrong password" >&2
|
||||||
return "$ret"
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -4,32 +4,20 @@
|
||||||
# only run this on systemd systems, we handle the decrypt in mount-zfs.sh in the mount hook otherwise
|
# 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
|
[ -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
|
decode_root_args || return 0
|
||||||
[ -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
|
|
||||||
|
|
||||||
# There is a race between the zpool import and the pre-mount hooks, so we wait for a pool to be imported
|
# 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
|
while ! systemctl is-active --quiet zfs-import.target; do
|
||||||
systemctl is-failed --quiet zfs-import-cache.service zfs-import-scan.service && exit 1
|
systemctl is-failed --quiet zfs-import-cache.service zfs-import-scan.service && return 1
|
||||||
sleep 0.1s
|
sleep 0.1s
|
||||||
done
|
done
|
||||||
|
|
||||||
# run this after import as zfs-import-cache/scan service is confirmed good
|
BOOTFS="$root"
|
||||||
# we do not overwrite the ${root} variable, but create a new one, BOOTFS, to hold the dataset
|
if [ "$BOOTFS" = "zfs:AUTO" ]; then
|
||||||
if [ "${root}" = "zfs:AUTO" ] ; then
|
BOOTFS="$(zpool get -Ho value bootfs | grep -m1 -vFx -)"
|
||||||
BOOTFS="$(zpool list -H -o bootfs | awk '$1 != "-" {print; exit}')"
|
|
||||||
else
|
|
||||||
BOOTFS="${root##zfs:}"
|
|
||||||
BOOTFS="${BOOTFS##ZFS=}"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# if pool encryption is active and the zfs command understands '-o encryption'
|
# if pool encryption is active and the zfs command understands '-o encryption'
|
||||||
|
|
|
@ -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.
|
If the root dataset contains children with `mountpoint=`s of `/etc`, `/bin`, `/lib*`, or `/usr`, they're mounted too.
|
||||||
|
|
||||||
## cmdline
|
## cmdline
|
||||||
1. `root=` | Root dataset is… | Pools imported |
|
1. `root=` | Root dataset is… |
|
||||||
-------------------|----------------------------------------------------------|----------------|
|
---------------------------|----------------------------------------------------------|
|
||||||
*(empty)* | the first `bootfs=` after `zpool import -aN` | all |
|
*(empty)* | the first `bootfs=` after `zpool import -aN` |
|
||||||
`zfs:AUTO` | *(as above, but overriding other autoselection methods)* | all |
|
`zfs:AUTO`, `zfs:`, `zfs` | *(as above, but overriding other autoselection methods)* |
|
||||||
`ZFS=pool/dataset` | `pool/dataset` | `pool` |
|
`ZFS=pool/dataset` | `pool/dataset` |
|
||||||
`zfs:pool/dataset` | *(as above)* | `pool` |
|
`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`).
|
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`).
|
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.
|
2. `spl_hostid`: passed to `zgenhostid -f`, useful to override the `/etc/hostid` file baked into the initrd.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue