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 diff --git a/contrib/dracut/90zfs/zfs-generator.sh.in b/contrib/dracut/90zfs/zfs-generator.sh.in index 12293bd24f78..e3fbf334f7d0 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" ] || { @@ -10,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 || { - echo "zfs-generator: loading Dracut library from $dracutlib" >> /dev/kmsg + [ -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=) @@ -27,44 +29,90 @@ command -v getarg >/dev/null 2>&1 || { [ "$rootfstype" != "zfs" ] && exit 0 -rootfstype=zfs case ",${rootflags}," in *,zfsutil,*) ;; ,,) rootflags=zfsutil ;; *) rootflags="zfsutil,${rootflags}" ;; esac -echo "zfs-generator: writing extension for sysroot.mount to $GENERATOR_DIR"/sysroot.mount.d/zfs-enhancement.conf >> /dev/kmsg +if [ "${root}" != "zfs:AUTO" ]; then + root="${root##zfs:}" + root="${root##ZFS=}" +fi -[ -d "$GENERATOR_DIR" ] || mkdir "$GENERATOR_DIR" -[ -d "$GENERATOR_DIR"/sysroot.mount.d ] || mkdir "$GENERATOR_DIR"/sysroot.mount.d +[ -n "$debug" ] && echo "zfs-generator: writing extension for sysroot.mount to $GENERATOR_DIR/sysroot.mount.d/zfs-enhancement.conf" >> /dev/kmsg + +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 -[ -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 +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"/dracut-pre-mount.service.d ] || mkdir "$GENERATOR_DIR"/dracut-pre-mount.service.d { echo "[Unit]" 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 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}" 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 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