Skip to content

Commit

Permalink
Initramfs scripts for ZoL.
Browse files Browse the repository at this point in the history
* Put in /usr/share/initramfs-tools/ or /etc/initramfs-tools/.
* With pull request openzfs#1476 (not yet merged) comes a verbose warning
  if /usr/bin/net doesn't exist or isn't executable. Just create
  a dummy...
* If user haven't specified pool, but bootfs then use the first part
  of the bootfs path as pool name.
* Add support for booting of a ZFS snapshot.
  Do this by cloning the snapshot into a dataset. If this the resulting
  dataset already exists, destroy it. Then set mountpoint=/ on that
  dataset and mount it on root.
  + If snapshot does not exist, use base dataset (the part before '@')
    as boot filesystem instead.
* Add support for more kernel command line arguments (ideas taken from
  the Fedora/Redhat dracut script):
  + (zfs_force|zfs.force|zfsforce)=(on|yes|1) (ignore case).
  + root=zfs:AUTO => try to find rootfs automatically.
  + root=zfs:<dataset>
  + root=ZFS=<dataset>
* Remove the existing '-f' option to 'zpool import', instead let
  this be controlled on the kernel command line.
* Do not force-set mountpoint=/ - should (??) not be nessesary.
* Support mounting a rootfs with mountpoint=legacy
* Support both RPM based and DEB based system by removing the logic
  from the dracut script and instead use the logic in scripts/zfs-initramfs/scripts/zfs
  for both Debian GNU/Linux (etc) and RedHat/Fedora (etc).
* Only run the local-* script(s) if/when it/they exists.
* Don't auto import pools when loading module - keep better control of the imports.
* If called with only 'rpool' (or only 'zfs-bootfs'), then fake it by setting 'root=zfs:AUTO'
  (to avoid duplication of code etc) so that it will be auto detected later.
  + If pool is specified and we're auto discovering, don't go through ALL pools, only the one we specified.
* Rewrite the auto detection of bootfs in the auto detector.
* Only try to import pool if it haven't already been imported (in the auto detector).
* Add support for only having 'root=pool/dataset' option.
* Remove the use of setting 'ZFS_RPOOL=rpool'. No longer nessesary.
* Check if /scripts/local-* is either file or directory - should be dir, but just to be safe check both.
* Make wait_for_udev wait for 10 seconds.
* Add a configurable ZFS_INITRD_POST_MODPROBE_SLEEP (set in /etc/default/zfs) after the modprobe.
* Merge openzfs#2196.
  Remove lines that contain only a hyphen (match '^-$' instead of '-').
* Add a 'default' file to go in '/etc/default/zfs'.
* Support mounting additional filesystems (such as /var and /usr etc)
  in the initrd using ZFS_INITRD_ADDITIONAL_DATASETS set in /etc/defaults/zfs.
* Add exceptions to pool imports.
  + Both for init and initrd script.
* Make sure that the zpool.cache file is actually copied onto the initrd!!
* Include /etc/modprobe.d/{zfs,spl}.conf in the initrd if they exist.
* Export all pools found after the modprobe - zfs_autoimport_disable=1'
  don't seem to be working in >= 0.6.3.
  + This snippet will go away as soon as I can figure out why it doesn't,
    it's ugly!!
* Only try /dev/disk/by-* in the initrd if USE_DISK_BY_ID is set.
  + Try this first, then fallback to using the cache file if that exist.
  • Loading branch information
FransUrbo committed Aug 3, 2014
1 parent c0be636 commit 5efb434
Show file tree
Hide file tree
Showing 7 changed files with 776 additions and 66 deletions.
6 changes: 4 additions & 2 deletions dracut/90zfs/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ pkgdracutdir = $(dracutdir)/modules.d/90zfs
pkgdracut_SCRIPTS = \
$(top_srcdir)/dracut/90zfs/module-setup.sh \
$(top_srcdir)/dracut/90zfs/mount-zfs.sh \
$(top_srcdir)/dracut/90zfs/parse-zfs.sh
$(top_srcdir)/dracut/90zfs/parse-zfs.sh \
$(top_srcdir)/scripts/zfs-initramfs/scripts/zfs

EXTRA_DIST = \
$(top_srcdir)/dracut/90zfs/module-setup.sh.in \
$(top_srcdir)/dracut/90zfs/mount-zfs.sh.in \
$(top_srcdir)/dracut/90zfs/parse-zfs.sh.in
$(top_srcdir)/dracut/90zfs/parse-zfs.sh.in \
$(top_srcdir)/scripts/zfs-initramfs/scripts/zfs

$(pkgdracut_SCRIPTS):
-$(SED) -e 's,@bindir\@,$(bindir),g' \
Expand Down
1 change: 1 addition & 0 deletions dracut/90zfs/module-setup.sh.in
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ install() {
dracut_install @udevdir@/zvol_id
dracut_install mount.zfs
dracut_install hostid
dracut_install /usr/lib/dracut/modules.d/90zfs/zfs
inst_hook cmdline 95 "$moddir/parse-zfs.sh"
inst_hook mount 98 "$moddir/mount-zfs.sh"

Expand Down
88 changes: 24 additions & 64 deletions dracut/90zfs/mount-zfs.sh.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,70 +2,30 @@

. /lib/dracut-lib.sh

ZPOOL_FORCE=""

if getargbool 0 zfs_force -y zfs.force -y zfsforce ; then
warn "ZFS: Will force-import pools if necessary."
ZPOOL_FORCE="-f"
# Of course the functions we need is called differently
# on different distributions - it would be way to easy
# otherwise!!
if type log_failure_msg > /dev/null 2>&1 ; then
# LSB functions
log_begin_msg=log_begin_msg
log_failure_msg=log_failure_msg
log_progress_msg=log_progress_msg
elif type success > /dev/null 2>&1 ; then
# Fedora/RedHat functions
log_begin_msg=success
log_failure_msg=failure
log_progress_msg="echo -n"
elif type einfo > /dev/null 2>&1 ; then
# Gentoo functions
log_begin_msg=einfo
log_failure_msg=eerror
log_progress_msg="echo -n"
else
log_begin_msg="echo -n"
log_failure_msg=echo
log_progress_msg="echo -n"
fi

case "$root" in
zfs:*)
# We have ZFS modules loaded, so we're able to import pools now.
if [ "$root" = "zfs:AUTO" ] ; then
# Need to parse bootfs attribute
info "ZFS: Attempting to detect root from imported ZFS pools."

# Might be imported by the kernel module, so try searching before
# we import anything.
zfsbootfs=`zpool list -H -o bootfs | sed -n '/-/ !p' | sed 'q'`
if [ "$?" != "0" ] || [ "$zfsbootfs" = "" ] || \
[ "$zfsbootfs" = "no pools available" ] ; then
# Not there, so we need to import everything.
info "ZFS: Attempting to import additional pools."
zpool import -N -a ${ZPOOL_FORCE}
zfsbootfs=`zpool list -H -o bootfs | sed -n '/-/ !p' | sed 'q'`
if [ "$?" != "0" ] || [ "$zfsbootfs" = "" ] || \
[ "$zfsbootfs" = "no pools available" ] ; then
rootok=0
pool=""

warn "ZFS: No bootfs attribute found in importable pools."

# Re-export everything since we're not prepared to take
# responsibility for them.
zpool list -H | while read fs rest ; do
zpool export "$fs"
done

return 1
fi
fi
info "ZFS: Using ${zfsbootfs} as root."
else
# Should have an explicit pool set, so just import it and we're done.
zfsbootfs="${root#zfs:}"
pool="${zfsbootfs%%/*}"
if ! zpool list -H $pool > /dev/null ; then
# pool wasn't imported automatically by the kernel module, so
# try it manually.
info "ZFS: Importing pool ${pool}..."
if ! zpool import -N ${ZPOOL_FORCE} $pool ; then
warn "ZFS: Unable to import pool ${pool}."
rootok=0

return 1
fi
fi
fi
. /usr/lib/dracut/modules.d/90zfs/zfs

# Above should have left our rpool imported and pool/dataset in $root.
# We need zfsutil for non-legacy mounts and not for legacy mounts.
mountpoint=`zfs get -H -o value mountpoint $zfsbootfs`
if [ "$mountpoint" = "legacy" ] ; then
mount -t zfs "$zfsbootfs" "$NEWROOT" && ROOTFS_MOUNTED=yes
else
mount -o zfsutil -t zfs "$zfsbootfs" "$NEWROOT" && ROOTFS_MOUNTED=yes
fi
;;
esac
mountroot
2 changes: 2 additions & 0 deletions scripts/zfs-initramfs/conf-hooks.d/zfs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Force the inclusion of Busybox in the initramfs.
BUSYBOX=y
66 changes: 66 additions & 0 deletions scripts/zfs-initramfs/default
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# ZoL userland configuration.

# Run `zfs mount -a` during system start?
# This should be 'no' if zfs-mountall or a systemd generator
# is available.
ZFS_MOUNT='yes'

# Run `zfs unmount -a` during system stop?
# This should be 'no' on most systems.
ZFS_UNMOUNT='yes'

# Run `zfs share -a` during system start?
# nb: The shareiscsi, sharenfs, and sharesmb dataset properties.
ZFS_SHARE='yes'

# Run `zfs unshare -a` during system stop?
ZFS_UNSHARE='yes'

# Sould we use '-d /dev/disk/by-*' when importing pool.
# This is recomended, but the default 'no' uses the cache
# file.
# Variable is somewhat missleading. Previously the code
# tried _only_ '/dev/disk/by-id', but will now try any
# '/dev/disk/by-*' directory.
USE_DISK_BY_ID='yes'

# Should the datasets be mounted verbosly (a mount counter
# will be used when mounting if set to 'yes').
VERBOSE_MOUNT='no'

# Should we allow overlay mounts (this is standard in Linux,
# but not ZFS which comes from Solaris where this is not allowed).
DO_OVERLAY_MOUNTS='no'

# Any additional option to the 'zfs mount' command line.
# Include '-o' for each option wanted.
MOUNT_EXTRA_OPTIONS=""

# Build kernel modules with the --enable-debug switch?
ZFS_DKMS_ENABLE_DEBUG='no'

# Build kernel modules with the --enable-debug-dmu-tx switch?
ZFS_DKMS_ENABLE_DEBUG_DMU_TX='no'

# Keep debugging symbols in kernel modules?
ZFS_DKMS_DISABLE_STRIP='no'

# Wait for this many seconds in the initrd pre_mountroot?
# This delays startup and should be '0' on most systems.
ZFS_INITRD_PRE_MOUNTROOT_SLEEP='0'

# Wait for this many seconds in the initrd mountroot?
# This delays startup and should be '0' on most systems.
# This might help on systems which have their ZFS root on
# a USB disk that takes just a little longer to be available
ZFS_INITRD_POST_MODPROBE_SLEEP='0'

# List of additional datasets to mount after the root
# dataset is mounted.
# The init script will use the mountpoint specified in
# the 'mountpoint' property value in the dataset to
# determine where it should be mounted.
#ZFS_INITRD_ADDITIONAL_DATASETS="rpool/ROOT/usr_local"

# Location of the lockfile.
LOCKDIR=/run/lock
101 changes: 101 additions & 0 deletions scripts/zfs-initramfs/hooks/zfs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/bin/sh
#
# Add ZoL filesystem capabilities to an initrd, usually for a native ZFS root.
#

# This hook installs udev rules for ZoL.
PREREQ="zdev"

# These prerequisites are provided by the zfsutils package. The zdb utility is
# not strictly required, but it can be useful at the initramfs recovery prompt.
COPY_EXEC_LIST="/sbin/zdb /sbin/zpool /sbin/zfs /sbin/mount.zfs"

# These prerequisites are provided by the base system.
COPY_EXEC_LIST="$COPY_EXEC_LIST /bin/hostname /sbin/blkid"

# Explicitly specify all kernel modules because automatic dependency resolution
# is unreliable on many systems.
BASE_MODULES="zlib_deflate spl zavl zcommon znvpair zunicode zfs"
CRPT_MODULES="sun-ccm sun-gcm sun-ctr"
MANUAL_ADD_MODULES_LIST="$BASE_MODULES"

# Generic result code.
RC=0

case $1 in
prereqs)
echo "$PREREQ"
exit 0
;;
esac

for ii in $COPY_EXEC_LIST
do
if [ ! -x "$ii" ]
then
echo "Error: $ii is not executable."
RC=2
fi
done

if [ "$RC" -ne 0 ]
then
exit "$RC"
fi

. /usr/share/initramfs-tools/hook-functions

mkdir -p "$DESTDIR/etc/"

# ZDB uses pthreads for some functions, but the library dependency is not
# automatically detected. The `find` utility and extended `cp` options are
# used here because libgcc_s.so could be in a subdirectory of /lib for
# multi-arch installations.
cp --target-directory="$DESTDIR" --parents $(find /lib -type f -name libgcc_s.so.1)

for ii in $COPY_EXEC_LIST
do
copy_exec "$ii"
done

for ii in $MANUAL_ADD_MODULES_LIST
do
manual_add_modules "$ii"
done

if [ -f "/etc/hostname" ]
then
cp -p "/etc/hostname" "$DESTDIR/etc/"
else
hostname >"$DESTDIR/etc/hostname"
fi

for ii in zfs zfs.conf spl spl.conf
do
if [ -f "/etc/modprobe.d/$ii" ]; then
if [ ! -d "$DESTDIR/etc/modprobe.d" ]; then
mkdir -p $DESTDIR/etc/modprobe.d
fi
cp -p "/etc/modprobe.d/$ii" $DESTDIR/etc/modprobe.d/
fi
done

# The spl-dkms package ensures that the /etc/hostid file exists.
# NB: Commentary in the spl-dkms.postinst script.
[ -f "/etc/hostid" ] && cp -p "/etc/hostid" "$DESTDIR/etc/hostid"

# Install the zpool.cache file.
[ -d /boot/zfs ] && cp -r /boot/zfs "$DESTDIR/boot"
[ ! -d "$DESTDIR/boot/zfs" ] && mkdir -p "$DESTDIR/boot/zfs"
[ -f /etc/zfs/zpool.cache ] && cp /etc/zfs/zpool.cache $DESTDIR/boot/zfs/

# With pull request #1476 (not yet merged) comes a verbose warning
# if /usr/bin/net doesn't exist or isn't executable. Just create
# a dummy...
[ ! -d "$DESTDIR/usr/bin" ] && mkdir -p "$DESTDIR/usr/bin"
if [ ! -x "$DESTDIR/usr/bin/net" ]; then
touch "$DESTDIR/usr/bin/net"
chmod +x "$DESTDIR/usr/bin/net"
fi

exit 0
Loading

0 comments on commit 5efb434

Please sign in to comment.