From 57ece7cee6bb420dd9b595b03f00b56eb380dc71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Tue, 13 Apr 2021 22:31:26 +0200 Subject: [PATCH 1/5] contrib/dracut: 02: don't spill device names across multiple lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ahelenia Ziemiańska --- contrib/dracut/02zfsexpandknowledge/module-setup.sh.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in b/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in index 8429bd109411..f4b7b8cdcce3 100755 --- a/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in +++ b/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in @@ -100,7 +100,7 @@ if [[ $hostonly ]]; then mountpoint "$mp" >/dev/null 2>&1 || continue blockdevs=$(find_zfs_block_devices "$mp") if [ -z "$blockdevs" ] ; then continue ; fi - dinfo "zfsexpandknowledge: block devices backing ZFS dataset $mp: $blockdevs" + dinfo "zfsexpandknowledge: block devices backing ZFS dataset $mp: ${blockdevs//$'\n'/ }" for dev in $blockdevs do array_contains "$dev" "${host_devs[@]}" || host_devs+=("$dev") @@ -114,7 +114,7 @@ if [[ $hostonly ]]; then _depdevname=$(udevadm info --query=property --name="$_depdev" | grep "^DEVNAME=" | sed 's|^DEVNAME=||') _depdevtype=$(get_devtype "$_depdevname") _depmajmin=$(get_maj_min "$_depdevname") - dinfo "zfsexpandknowledge: underlying block device backing ZFS dataset $mp: $_depdevname" + dinfo "zfsexpandknowledge: underlying block device backing ZFS dataset $mp: ${_depdevname//$'\n'/ }" array_contains "$_depdevname" "${host_devs[@]}" || host_devs+=("$_depdevname") host_fs_types["$_depdevname"]="$_depdevtype" done From 2336ae9cb7c1cb9f8028f272be653a72c16c65f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Tue, 13 Apr 2021 22:37:59 +0200 Subject: [PATCH 2/5] contrib/dracut: 90: generator: only log to kmsg if debug set on cmdline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "debug" is also used by systemd itself, and there's really no reason for the generator to write this much garbage by default Signed-off-by: Ahelenia Ziemiańska --- contrib/dracut/90zfs/zfs-generator.sh.in | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/contrib/dracut/90zfs/zfs-generator.sh.in b/contrib/dracut/90zfs/zfs-generator.sh.in index 12293bd24f78..8e97b896c23f 100755 --- a/contrib/dracut/90zfs/zfs-generator.sh.in +++ b/contrib/dracut/90zfs/zfs-generator.sh.in @@ -1,6 +1,7 @@ #!/bin/sh -echo "zfs-generator: starting" >> /dev/kmsg +grep -wq debug /proc/cmdline && debug=1 +[ -n "$debug" ] && echo "zfs-generator: starting" >> /dev/kmsg GENERATOR_DIR="$1" [ -n "$GENERATOR_DIR" ] || { @@ -12,7 +13,7 @@ GENERATOR_DIR="$1" [ -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 || { - echo "zfs-generator: loading Dracut library from $dracutlib" >> /dev/kmsg + [ -n "$debug" ] && echo "zfs-generator: loading Dracut library from $dracutlib" >> /dev/kmsg . "$dracutlib" } @@ -34,7 +35,7 @@ case ",${rootflags}," in *) rootflags="zfsutil,${rootflags}" ;; esac -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 [ -d "$GENERATOR_DIR" ] || mkdir "$GENERATOR_DIR" [ -d "$GENERATOR_DIR"/sysroot.mount.d ] || mkdir "$GENERATOR_DIR"/sysroot.mount.d @@ -67,4 +68,6 @@ ln -s ../sysroot.mount "$GENERATOR_DIR"/initrd-root-fs.target.requires/sysroot.m echo "After=zfs-import.target" } > "$GENERATOR_DIR"/dracut-pre-mount.service.d/zfs-enhancement.conf -echo "zfs-generator: finished" >> /dev/kmsg +[ -n "$debug" ] && echo "zfs-generator: finished" >> /dev/kmsg + +exit 0 From 45ab7fe1db18f8a91be051fc8b68049da308b603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Tue, 13 Apr 2021 22:41:10 +0200 Subject: [PATCH 3/5] contrib/dracut: 90: mount essential datasets under root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This partly mirrors what the i-t script does (though that mounts all children, recursively) ‒ /etc, /usr, /lib*, and /bin are all essential, if present, to successfully invoke the real init, which will then mount everything else it might need in the right order The following extreme-case set-up boots w/o issues now: / zoot zfs rw,relatime,xattr,noacl ├─/etc zoot/etc zfs rw,relatime,xattr,noacl ├─/usr zoot/usr zfs rw,relatime,xattr,noacl │ └─/usr/local zoot/usr/local zfs rw,relatime,xattr,noacl ├─/var zoot/var zfs rw,relatime,xattr,noacl │ ├─/var/lib zoot/var/lib zfs rw,relatime,xattr,noacl │ ├─/var/log zoot/var/log zfs rw,relatime,xattr,posixacl │ ├─/var/cache zoot/var/cache zfs rw,relatime,xattr,noacl │ └─/var/tmp zoot/var/tmp zfs rw,relatime,xattr,noacl ├─/home zoot/home zfs rw,relatime,xattr,noacl │ └─/home/nab zoot/home/nab zfs rw,relatime,xattr,noacl ├─/boot zoot/boot zfs rw,relatime,xattr,noacl ├─/root zoot/home/root zfs rw,relatime,xattr,noacl ├─/opt zoot/opt zfs rw,relatime,xattr,noacl └─/srv zoot/srv zfs rw,relatime,xattr,noacl Signed-off-by: Ahelenia Ziemiańska --- contrib/dracut/90zfs/zfs-generator.sh.in | 71 +++++++++++++++++++----- contrib/dracut/90zfs/zfs-lib.sh.in | 49 ++++++++++++++-- 2 files changed, 101 insertions(+), 19 deletions(-) diff --git a/contrib/dracut/90zfs/zfs-generator.sh.in b/contrib/dracut/90zfs/zfs-generator.sh.in index 8e97b896c23f..e3fbf334f7d0 100755 --- a/contrib/dracut/90zfs/zfs-generator.sh.in +++ b/contrib/dracut/90zfs/zfs-generator.sh.in @@ -11,12 +11,13 @@ GENERATOR_DIR="$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" } +. /lib/dracut-zfs-lib.sh + [ -z "$root" ] && root=$(getarg root=) [ -z "$rootfstype" ] && rootfstype=$(getarg rootfstype=) [ -z "$rootflags" ] && rootflags=$(getarg rootflags=) @@ -28,40 +29,84 @@ command -v getarg >/dev/null 2>&1 || { [ "$rootfstype" != "zfs" ] && exit 0 -rootfstype=zfs 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 -[ -d "$GENERATOR_DIR" ] || mkdir "$GENERATOR_DIR" -[ -d "$GENERATOR_DIR"/sysroot.mount.d ] || mkdir "$GENERATOR_DIR"/sysroot.mount.d +mkdir -p "$GENERATOR_DIR"/sysroot.mount.d "$GENERATOR_DIR"/initrd-root-fs.target.requires "$GENERATOR_DIR"/dracut-pre-mount.service.d { echo "[Unit]" echo "Before=initrd-root-fs.target" echo "After=zfs-import.target" + echo echo "[Mount]" - if [ "${root}" = "zfs:AUTO" ] ; then + if [ "${root}" = "zfs:AUTO" ]; then echo "PassEnvironment=BOOTFS" echo 'What=${BOOTFS}' else - root="${root##zfs:}" - root="${root##ZFS=}" echo "What=${root}" fi - echo "Type=${rootfstype}" + echo "Type=zfs" echo "Options=${rootflags}" } > "$GENERATOR_DIR"/sysroot.mount.d/zfs-enhancement.conf +ln -fs ../sysroot.mount "$GENERATOR_DIR"/initrd-root-fs.target.requires/sysroot.mount + + +if [ "${root}" = "zfs:AUTO" ]; then + { + echo "[Unit]" + echo "Before=initrd-root-fs.target" + echo "After=sysroot.mount" + echo "DefaultDependencies=no" + echo + echo "[Service]" + echo "Type=oneshot" + echo "PassEnvironment=BOOTFS" + echo "ExecStart=/bin/sh -c '" ' \ + . /lib/dracut-zfs-lib.sh; \ + _zfs_nonroot_necessities_cb() { \ + zfs mount | grep -m1 -q "^$1 " && return 0; \ + echo "Mounting $1 on /sysroot$2"; \ + mount -o zfsutil -t zfs "$1" "/sysroot$2"; \ + }; \ + for_relevant_root_children "${BOOTFS}" _zfs_nonroot_necessities_cb;' \ + "'" + } > "$GENERATOR_DIR"/zfs-nonroot-necessities.service + ln -fs ../zfs-nonroot-necessities.service "$GENERATOR_DIR"/initrd-root-fs.target.requires/zfs-nonroot-necessities.service +else + # We can solve this statically at generation time, so do! + _zfs_generator_cb() { + dset="${1}" + mpnt="${2}" + unit="sysroot$(echo "$mpnt" | sed 's;/;-;g').mount" + + { + echo "[Unit]" + echo "Before=initrd-root-fs.target" + echo "After=sysroot.mount" + echo + echo "[Mount]" + echo "Where=/sysroot${mpnt}" + echo "What=${dset}" + echo "Type=zfs" + echo "Options=zfsutil" + } > "$GENERATOR_DIR/${unit}" + ln -fs ../"${unit}" "$GENERATOR_DIR"/initrd-root-fs.target.requires/"${unit}" + } + + for_relevant_root_children "${root}" _zfs_generator_cb +fi -[ -d "$GENERATOR_DIR"/initrd-root-fs.target.requires ] || mkdir -p "$GENERATOR_DIR"/initrd-root-fs.target.requires -ln -s ../sysroot.mount "$GENERATOR_DIR"/initrd-root-fs.target.requires/sysroot.mount - - -[ -d "$GENERATOR_DIR"/dracut-pre-mount.service.d ] || mkdir "$GENERATOR_DIR"/dracut-pre-mount.service.d { echo "[Unit]" diff --git a/contrib/dracut/90zfs/zfs-lib.sh.in b/contrib/dracut/90zfs/zfs-lib.sh.in index c39cc5cfff1f..f3cdd1503d34 100755 --- a/contrib/dracut/90zfs/zfs-lib.sh.in +++ b/contrib/dracut/90zfs/zfs-lib.sh.in @@ -23,6 +23,7 @@ command -v getargbool >/dev/null || { OLDIFS="${IFS}" NEWLINE=" " +TAB=" " ZPOOL_IMPORT_OPTS="" if getargbool 0 zfs_force -y zfs.force -y zfsforce ; then @@ -58,7 +59,7 @@ find_bootfs() { # import_pool POOL # imports the given zfs pool if it isn't imported already. import_pool() { - pool="${1}" + pool="${1}" if ! zpool list -H "${pool}" > /dev/null 2>&1; then info "ZFS: Importing pool ${pool}..." @@ -71,26 +72,62 @@ import_pool() { return 0 } +_mount_dataset_cb() { + mount -o zfsutil -t zfs "${1}" "${NEWROOT}${2}" +} + # mount_dataset DATASET # mounts the given zfs dataset. mount_dataset() { - dataset="${1}" + dataset="${1}" mountpoint="$(zfs get -H -o value mountpoint "${dataset}")" + ret=0 # We need zfsutil for non-legacy mounts and not for legacy mounts. if [ "${mountpoint}" = "legacy" ] ; then - mount -t zfs "${dataset}" "${NEWROOT}" + mount -t zfs "${dataset}" "${NEWROOT}" || ret=$? else - mount -o zfsutil -t zfs "${dataset}" "${NEWROOT}" + mount -o zfsutil -t zfs "${dataset}" "${NEWROOT}" || ret=$? + + if [ "$ret" = "0" ]; then + for_relevant_root_children "${dataset}" _mount_dataset_cb || ret=$? + fi fi - return $? + return ${ret} +} + +# for_relevant_root_children DATASET EXEC +# Runs "EXEC dataset mountpoint" for all children of DATASET that are needed for system bringup +# Used by zfs-generator.sh and friends, too! +for_relevant_root_children() { + dataset="${1}" + exec="${2}" + + zfs list -t filesystem -Ho name,mountpoint,canmount -r "${dataset}" | + ( + _ret=0 + while IFS="${TAB}" read -r dataset mountpoint canmount; do + [ "$canmount" != "on" ] && continue + + case "$mountpoint" in + /etc|/bin|/lib|/lib??|/libx32|/usr) + # If these aren't mounted we may not be able to get to the real init at all, or pollute the dataset holding the rootfs + "${exec}" "${dataset}" "${mountpoint}" || _ret=$? + ;; + *) + # Up to the real init to remount everything else it might need + ;; + esac + done + exit ${_ret} + ) } # export_all OPTS # exports all imported zfs pools. export_all() { - opts="${@}" + opts="${@}" ret=0 IFS="${NEWLINE}" From 895540313f72625bdcde1e859839ee409b156e3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Tue, 13 Apr 2021 23:23:15 +0200 Subject: [PATCH 4/5] contrib/i-t: properly mount root's children with spaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ahelenia Ziemiańska --- contrib/initramfs/scripts/zfs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/contrib/initramfs/scripts/zfs b/contrib/initramfs/scripts/zfs index 377f9efca933..b7e9e57035f3 100644 --- a/contrib/initramfs/scripts/zfs +++ b/contrib/initramfs/scripts/zfs @@ -935,9 +935,14 @@ mountroot() # Go through the complete list (recursively) of all filesystems below # the real root dataset - filesystems=$("${ZFS}" list -oname -tfilesystem -H -r "${ZFS_BOOTFS}") - for fs in $filesystems $ZFS_INITRD_ADDITIONAL_DATASETS - do + filesystems="$("${ZFS}" list -oname -tfilesystem -H -r "${ZFS_BOOTFS}")" + OLD_IFS="$IFS" ; IFS=" +" + for fs in $filesystems; do + IFS="$OLD_IFS" mount_fs "$fs" + done + IFS="$OLD_IFS" + for fs in $ZFS_INITRD_ADDITIONAL_DATASETS; do mount_fs "$fs" done From 50ba8a5ba5bc695677294d6d879dec7bd899c1a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Wed, 14 Apr 2021 17:30:59 +0200 Subject: [PATCH 5/5] contrib/dracut: 90: zfs-{rollback,snapshot}-bootfs: use @sbindir@ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ahelenia Ziemiańska --- contrib/dracut/90zfs/zfs-rollback-bootfs.service.in | 2 +- contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in b/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in index 4b058c1b8c9a..0d45f71eadce 100644 --- a/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in +++ b/contrib/dracut/90zfs/zfs-rollback-bootfs.service.in @@ -10,5 +10,5 @@ ConditionKernelCommandLine=bootfs.rollback # ${BOOTFS} should have been set by zfs-env-bootfs.service Type=oneshot ExecStartPre=/bin/sh -c 'test -n "${BOOTFS}"' -ExecStart=/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.rollback)"; /sbin/zfs rollback -Rf "${BOOTFS}@${SNAPNAME:-%v}"' +ExecStart=/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.rollback)"; @sbindir@/zfs rollback -Rf "${BOOTFS}@${SNAPNAME:-%v}"' RemainAfterExit=yes diff --git a/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in b/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in index cfd5f7029f06..11513ba27b01 100644 --- a/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in +++ b/contrib/dracut/90zfs/zfs-snapshot-bootfs.service.in @@ -10,5 +10,5 @@ ConditionKernelCommandLine=bootfs.snapshot # ${BOOTFS} should have been set by zfs-env-bootfs.service Type=oneshot ExecStartPre=/bin/sh -c 'test -n "${BOOTFS}"' -ExecStart=-/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.snapshot)"; /sbin/zfs snapshot "${BOOTFS}@${SNAPNAME:-%v}"' +ExecStart=-/bin/sh -c '. /lib/dracut-lib.sh; SNAPNAME="$(getarg bootfs.snapshot)"; @sbindir@/zfs snapshot "${BOOTFS}@${SNAPNAME:-%v}"' RemainAfterExit=yes