mirror of
				https://git.proxmox.com/git/mirror_zfs
				synced 2025-10-31 22:53:11 +00:00 
			
		
		
		
	 3399a30ee0
			
		
	
	
		3399a30ee0
		
			
		
	
	
	
	
		
			
			This had always worked in my testing, but a user on hardware reported
this to happen 100%, and I reproduced it once with cold VM host caches.
dracut-zfs-generator runs as a systemd generator, i.e. at Some
Relatively Early Time; if root= is a fixed dataset, it tries to
"solve [necessities] statically at generation time".
If by that point zfs-import.target hasn't popped (because the import is
taking a non-negligible amount of time for whatever reason), it'll see
no children for the root datase, and as such generate no mounts.
This has never had any right to work. No-one caught this earlier because
it's just that much more convenient to have root=zfs:AUTO, which orders
itself properly.
To fix this, always run zfs-nonroot-necessities.service;
this additionally simplifies the implementation by:
  * making BOOTFS from zfs-env-bootfs.service be the real, canonical,
    root dataset name, not just "whatever the first bootfs is",
    and only set it if we're ZFS-booting
  * zfs-{rollback,snapshot}-bootfs.service can use this instead of
    re-implementing it
  * having zfs-env-bootfs.service also set BOOTFSFLAGS
  * this means the sysroot.mount drop-in can be fixed text
  * zfs-nonroot-necessities.service can also be constant and always
    enabled, because it's conditioned on BOOTFS being set
There is no longer any code generated at run-time
(the sysroot.mount drop-in is an unavoidable gratuitous cp).
The flow of BOOTFS{,FLAGS} from zfs-env-bootfs.service to sysroot.mount
is not noted explicitly in dracut.zfs(7), because (a) at some point it's
just visual noise and (b) it's already ordered via d-p-m.s from z-i.t.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
Closes #14690
		
	
			
		
			
				
	
	
		
			121 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/bin/sh
 | |
| # shellcheck disable=SC2034
 | |
| 
 | |
| command -v getarg >/dev/null || . /lib/dracut-lib.sh || . /usr/lib/dracut/modules.d/99base/dracut-lib.sh
 | |
| 
 | |
| TAB="	"
 | |
| 
 | |
| ZPOOL_IMPORT_OPTS=
 | |
| if getargbool 0 zfs_force -y zfs.force -y zfsforce; then
 | |
|     warn "ZFS: Will force-import pools if necessary."
 | |
|     ZPOOL_IMPORT_OPTS=-f
 | |
| fi
 | |
| 
 | |
| _mount_dataset_cb() {
 | |
|     # shellcheck disable=SC2154
 | |
|     mount -o zfsutil -t zfs "${1}" "${NEWROOT}${2}"
 | |
| }
 | |
| 
 | |
| # mount_dataset DATASET
 | |
| #   mounts the given zfs dataset.
 | |
| mount_dataset() {
 | |
|     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}" || ret=$?
 | |
|     else
 | |
|         mount -o zfsutil -t zfs "${dataset}" "${NEWROOT}" || ret=$?
 | |
| 
 | |
|         if [ "$ret" = "0" ]; then
 | |
|             for_relevant_root_children "${dataset}" _mount_dataset_cb || ret=$?
 | |
|         fi
 | |
|     fi
 | |
| 
 | |
|     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-nonroot-necessities.service 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}"
 | |
|         )
 | |
| }
 | |
| 
 | |
| # Parse root=, rootfstype=, return them decoded and normalised to zfs:AUTO for auto, plain dset for explicit
 | |
| #
 | |
| # True if ZFS-on-root, false if we shouldn't
 | |
| #
 | |
| # Supported values:
 | |
| #   root=
 | |
| #   root=zfs
 | |
| #   root=zfs:
 | |
| #   root=zfs:AUTO
 | |
| #
 | |
| #   root=ZFS=data/set
 | |
| #   root=zfs:data/set
 | |
| #   root=zfs:ZFS=data/set (as a side-effect; allowed but undocumented)
 | |
| #
 | |
| #   rootfstype=zfs AND root=data/set <=> root=data/set
 | |
| #   rootfstype=zfs AND root=         <=> root=zfs:AUTO
 | |
| #
 | |
| # '+'es in explicit dataset decoded to ' 's.
 | |
| decode_root_args() {
 | |
|     if [ -n "$rootfstype" ]; then
 | |
|         [ "$rootfstype" = zfs ]
 | |
|         return
 | |
|     fi
 | |
| 
 | |
|     xroot=$(getarg root=)
 | |
|     rootfstype=$(getarg rootfstype=)
 | |
| 
 | |
|     # shellcheck disable=SC2249
 | |
|     case "$xroot" in
 | |
|         ""|zfs|zfs:|zfs:AUTO)
 | |
|             root=zfs:AUTO
 | |
|             rootfstype=zfs
 | |
|             return 0
 | |
|             ;;
 | |
| 
 | |
|         ZFS=*|zfs:*)
 | |
|             root="${xroot#zfs:}"
 | |
|             root="${root#ZFS=}"
 | |
|             root=$(echo "$root" | tr '+' ' ')
 | |
|             rootfstype=zfs
 | |
|             return 0
 | |
|             ;;
 | |
|     esac
 | |
| 
 | |
|     if [ "$rootfstype" = "zfs" ]; then
 | |
|         case "$xroot" in
 | |
|             "") root=zfs:AUTO ;;
 | |
|             *)  root=$(echo "$xroot" | tr '+' ' ') ;;
 | |
|         esac
 | |
|         return 0
 | |
|     fi
 | |
| 
 | |
|     return 1
 | |
| }
 |