Skip to content

Commit

Permalink
contrib/dracut: 90: mount essential datasets under root
Browse files Browse the repository at this point in the history
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

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
Closes #11898
  • Loading branch information
nabijaczleweli authored and behlendorf committed Apr 16, 2021
1 parent 51bc60e commit d8ced66
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 19 deletions.
71 changes: 58 additions & 13 deletions contrib/dracut/90zfs/zfs-generator.sh.in
Original file line number Diff line number Diff line change
Expand Up @@ -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=)
Expand All @@ -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]"
Expand Down
49 changes: 43 additions & 6 deletions contrib/dracut/90zfs/zfs-lib.sh.in
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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}..."
Expand All @@ -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}"
Expand Down

0 comments on commit d8ced66

Please sign in to comment.