contrib/dracut: 90: mount essential datasets under root

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
This commit is contained in:
наб 2021-04-13 22:41:10 +02:00 committed by Brian Behlendorf
parent 51bc60e582
commit d8ced6613d
2 changed files with 100 additions and 18 deletions

View File

@ -11,12 +11,13 @@ GENERATOR_DIR="$1"
[ -f /lib/dracut-lib.sh ] && dracutlib=/lib/dracut-lib.sh [ -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 [ -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 || { command -v getarg >/dev/null 2>&1 || {
[ -n "$debug" ] && echo "zfs-generator: loading Dracut library from $dracutlib" >> /dev/kmsg [ -n "$debug" ] && echo "zfs-generator: loading Dracut library from $dracutlib" >> /dev/kmsg
. "$dracutlib" . "$dracutlib"
} }
. /lib/dracut-zfs-lib.sh
[ -z "$root" ] && root=$(getarg root=) [ -z "$root" ] && root=$(getarg root=)
[ -z "$rootfstype" ] && rootfstype=$(getarg rootfstype=) [ -z "$rootfstype" ] && rootfstype=$(getarg rootfstype=)
[ -z "$rootflags" ] && rootflags=$(getarg rootflags=) [ -z "$rootflags" ] && rootflags=$(getarg rootflags=)
@ -28,40 +29,84 @@ command -v getarg >/dev/null 2>&1 || {
[ "$rootfstype" != "zfs" ] && [ "$rootfstype" != "zfs" ] &&
exit 0 exit 0
rootfstype=zfs
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
[ -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 "[Unit]"
echo "Before=initrd-root-fs.target" echo "Before=initrd-root-fs.target"
echo "After=zfs-import.target" echo "After=zfs-import.target"
echo
echo "[Mount]" echo "[Mount]"
if [ "${root}" = "zfs:AUTO" ] ; then if [ "${root}" = "zfs:AUTO" ]; then
echo "PassEnvironment=BOOTFS" echo "PassEnvironment=BOOTFS"
echo 'What=${BOOTFS}' echo 'What=${BOOTFS}'
else else
root="${root##zfs:}"
root="${root##ZFS=}"
echo "What=${root}" echo "What=${root}"
fi fi
echo "Type=${rootfstype}" echo "Type=zfs"
echo "Options=${rootflags}" echo "Options=${rootflags}"
} > "$GENERATOR_DIR"/sysroot.mount.d/zfs-enhancement.conf } > "$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
[ -d "$GENERATOR_DIR"/dracut-pre-mount.service.d ] || mkdir "$GENERATOR_DIR"/dracut-pre-mount.service.d 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
{ {
echo "[Unit]" echo "[Unit]"

View File

@ -23,6 +23,7 @@ command -v getargbool >/dev/null || {
OLDIFS="${IFS}" OLDIFS="${IFS}"
NEWLINE=" NEWLINE="
" "
TAB=" "
ZPOOL_IMPORT_OPTS="" ZPOOL_IMPORT_OPTS=""
if getargbool 0 zfs_force -y zfs.force -y zfsforce ; then if getargbool 0 zfs_force -y zfs.force -y zfsforce ; then
@ -58,7 +59,7 @@ find_bootfs() {
# import_pool POOL # import_pool POOL
# imports the given zfs pool if it isn't imported already. # imports the given zfs pool if it isn't imported already.
import_pool() { import_pool() {
pool="${1}" pool="${1}"
if ! zpool list -H "${pool}" > /dev/null 2>&1; then if ! zpool list -H "${pool}" > /dev/null 2>&1; then
info "ZFS: Importing pool ${pool}..." info "ZFS: Importing pool ${pool}..."
@ -71,26 +72,62 @@ import_pool() {
return 0 return 0
} }
_mount_dataset_cb() {
mount -o zfsutil -t zfs "${1}" "${NEWROOT}${2}"
}
# mount_dataset DATASET # mount_dataset DATASET
# mounts the given zfs dataset. # mounts the given zfs dataset.
mount_dataset() { mount_dataset() {
dataset="${1}" dataset="${1}"
mountpoint="$(zfs get -H -o value mountpoint "${dataset}")" mountpoint="$(zfs get -H -o value mountpoint "${dataset}")"
ret=0
# We need zfsutil for non-legacy mounts and not for legacy mounts. # We need zfsutil for non-legacy mounts and not for legacy mounts.
if [ "${mountpoint}" = "legacy" ] ; then if [ "${mountpoint}" = "legacy" ] ; then
mount -t zfs "${dataset}" "${NEWROOT}" mount -t zfs "${dataset}" "${NEWROOT}" || ret=$?
else 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 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 # export_all OPTS
# exports all imported zfs pools. # exports all imported zfs pools.
export_all() { export_all() {
opts="${@}" opts="${@}"
ret=0 ret=0
IFS="${NEWLINE}" IFS="${NEWLINE}"