summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorнаб <[email protected]>2021-04-13 22:41:10 +0200
committerBrian Behlendorf <[email protected]>2021-04-19 15:22:57 -0700
commit692387343f92f2a88c64b72b4c53d584fc7ba26a (patch)
tree26d44ee0abc9a8aac37165a0e94fde306a620b1e
parent8d869cd8404dca6bd668d60a2ea040dbfaa8c147 (diff)
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 <[email protected]> Signed-off-by: Ahelenia Ziemiańska <[email protected]> Closes #11898
-rwxr-xr-xcontrib/dracut/90zfs/zfs-generator.sh.in71
-rwxr-xr-xcontrib/dracut/90zfs/zfs-lib.sh.in49
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 8e97b896c..e3fbf334f 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 c39cc5cff..f3cdd1503 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}"