notes for booting from zfs

notes for myself for when i set up debian to boot from zfs… part of /etc/default/grub

GRUB_CMDLINE_LINUX="boot=zfs rpool=pool0 bootfs=pool0/ROOT/debian"

part of /etc/modules [and also part of /etc/initramfs-tools/modules]

zfs
spl
zavl
zunicode
zcommon
znvpair

/usr/share/initramfs-tools/scripts/zfs [relevant part is the symlink at the end of pre_mountroot]

# ZFS boot stub for initramfs-tools.
#
# In the initramfs environment, the /init script sources this stub to
# override the default functions in the /scripts/local script.
#
# Enable this by passing boot=zfs on the kernel command line.
#


pre_mountroot()
{
	[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-top"
	run_scripts /scripts/local-top
	[ "$quiet" != "y" ] && log_end_msg

	if [ -r '/etc/default/zfs' ]
	then
		. '/etc/default/zfs'
		if [ "$ZFS_INITRD_PRE_MOUNTROOT_SLEEP" -gt '0' ]
		then
			[ "$quiet" != "y" ] && log_begin_msg "Sleeping for $ZFS_INITRD_PRE_MOUNTROOT_SLEEP seconds..."
			sleep "$ZFS_INITRD_PRE_MOUNTROOT_SLEEP"
			[ "$quiet" != "y" ] && log_end_msg
		fi
	fi
	ln -s /proc/mounts /etc/mtab
}

# Duplicates the functionality found under try_failure_hooks in functions
# but invoking that would be inappropriate here.
disable_plymouth()
{
	if [ -x /bin/plymouth ] && /bin/plymouth --ping
	then
		/bin/plymouth hide-splash >/dev/null 2>&1
	fi
}

mountroot()
{
	pre_mountroot

	[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-premount"
	run_scripts /scripts/local-premount
	[ "$quiet" != "y" ] && log_end_msg

	# Wait for all of the /dev/{hd,sd}[a-z] device nodes to appear.
	wait_for_udev

	# Load the module now to get consistent automatic pool import behavior.
	modprobe zfs

	# Check the kernel command line for overrides.
	ZFS_RPOOL="${rpool#rpool=}"
	ZFS_BOOTFS="${bootfs#bootfs=}"

	if [ -z "$ZFS_RPOOL" ]
	then
		# Check for the `-B zfs-bootfs=%s/%u,...` kind of parameter.
		#
		# The ${zfs-bootfs} variable is set at the kernel commmand
		# line, usually by GRUB, but it cannot be referenced here
		# directly because bourne variable names cannot contain a
		# hyphen.
		#
		# Reassign the variable by dumping the environment and
		# stripping the zfs-bootfs= prefix.  Let the shell handle
		# quoting through the eval command.
		eval ZFS_RPOOL=$(set | sed -n -e 's,^zfs-bootfs=,,p')

		# Only the pool name is relevant because the ZFS filesystem on
		# Linux is extrinsic and the userland cannot resolve a ZFS
		# object number.
		#
		# Strip everything after the first slash character.
		ZFS_RPOOL=$(echo "$ZFS_RPOOL" | sed -e 's,/.*,,')
	fi

	# Use "rpool" as the default, like on most Solaris systems.
	[ -z "$ZFS_RPOOL" ] && ZFS_RPOOL='rpool'

	# @FIXME: Forcing the import should not be necessary.
	#
	# Consider inhibiting automatic zpool imports in the initramfs
	# environment and doing a full import in the regular system instead.

	[ "$quiet" != "y" ] && log_begin_msg "Importing ZFS root pool $ZFS_RPOOL"
	if [ -f /etc/zfs/zpool.cache ]
	then
		ZFS_STDERR=$(zpool list "$ZFS_RPOOL" 1>/dev/null 2>&1 \
		  || zpool import -f -N "$ZFS_RPOOL" 2>&1)
		ZFS_ERROR=$?
	else
		ZFS_STDERR=$(zpool import -f -N "$ZFS_RPOOL" 2>&1)
		ZFS_ERROR=$?
	fi
	[ "$quiet" != "y" ] && log_end_msg

	if [ "$ZFS_ERROR" -ne 0 ]
	then
		disable_plymouth
		echo "Command: zpool import -f -N $ZFS_RPOOL"
		echo "Message: $ZFS_STDERR"
		echo "Error: $ZFS_ERROR"
		echo ""
		echo "Manually import the root pool at the command prompt and then exit."
		echo "Hint: Try:  zpool import -f -R / -N $ZFS_RPOOL"
		/bin/sh
	fi

	if [ -z "$ZFS_BOOTFS" ]
	then
		[ "$quiet" != "y" ] && log_begin_msg "Getting ZFS bootfs property"
		ZFS_BOOTFS=$(zpool list -H -o bootfs "$ZFS_RPOOL")
		ZFS_ERROR=$?
		[ "$quiet" != "y" ] && log_end_msg
	fi

	if [ -z "$ZFS_BOOTFS" ]
	then
		disable_plymouth
		echo "Command: zpool list -H -o bootfs $ZFS_RPOOL"
		echo "Error: $ZFS_ERROR, unable to get the bootfs property."
		echo ""
		echo "Manually mount the root filesystem on $rootmnt and then exit."
		echo "Hint: Try:  mount -t zfs -o zfsutil $ZFS_RPOOL/ROOT/system $rootmnt"
		/bin/sh	
	fi

	# Force the mountpoint to the only correct value for a root filesystem.
	[ "$quiet" != "y" ] && log_begin_msg "Setting mountpoint=/ on ZFS filesystem $ZFS_BOOTFS"
	ZFS_STDERR=$(zfs set mountpoint=/ "$ZFS_BOOTFS" 2>&1)
	[ "$quiet" != "y" ] && log_end_msg

	# Ideally, the root filesystem would be mounted like this:
	#
	#   zpool import -R "$rootmnt" -N "$ZFS_RPOOL"
	#   zfs mount -o mountpoint=/ "$ZFS_BOOTFS"
	#
	# but the MOUNTPOINT prefix is preserved on descendent filesystem after
	# the pivot into the regular root, which later breaks things like
	# `zfs mount -a` and the /etc/mtab refresh.

	[ "$quiet" != "y" ] && log_begin_msg "Mounting ZFS filesystem $ZFS_BOOTFS"
	ZFS_STDERR=$(mount -t zfs -o zfsutil "$ZFS_BOOTFS" "$rootmnt" 2>&1)
	ZFS_ERROR=$?
	[ "$quiet" != "y" ] && log_end_msg

	if [ "$ZFS_ERROR" -ne 0 ]
	then
		disable_plymouth
		echo ""
		echo "Command: mount -t zfs -o zfsutil $ZFS_BOOTFS $rootmnt"
		echo "Message: $ZFS_STDERR"
		echo "Error: $ZFS_ERROR"
		echo ""
		echo "Manually mount the root filesystem on $rootmnt and then exit."
		/bin/sh	
	fi

	[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-bottom"
	run_scripts /scripts/local-bottom
	[ "$quiet" != "y" ] && log_end_msg
}

/etc/init.d/mountzfs.sh

#!/bin/bash
### BEGIN INIT INFO
# Provides:		mountzfs
# Required-Start:	udev
# Required-Stop:	
# Default-Start:	S
# Default-Stop:		
# Short-Description:	mount zvols
# Description:		mount zvols
### END INIT INFO


case "$1" in
  start)
    echo "setting up zfs mountpoints..."
    rm -f /var/*
    /sbin/zfs mount -a
    echo "...done."
    ;;
  stop)
    echo
    ;;
  *)
    echo "usage: /etc/init.d/mountzfs.sh {start|stop}"
    exit 1
    ;;
esac

exit 0

had to make a one-liner to fix up /dev so that grub could walk it correctly…grr.

dest=$(echo $(grub-probe / 2>&1 | cut -f3 -d'/' | cut -f1 -d.)) bash -c 'ln -s $(readlink -f /dev/disk/by-id/$dest) /dev/$dest'

i have grub sourcing kernel and initrd from an ext2 /boot, rather than depending on debian repos having a version of grub that understands zfs [and feature flags]. used https://github.com/zfsonlinux/pkg-zfs/wiki/HOWTO-install-Ubuntu-to-a-Native-ZFS-Root-Filesystem in part , but with a few changes:

  • partitioned the drive with one boot volume, one large unused section, and one small partition at the end for the temporary root.
  • performed normal netinstall to temporary root
  • configured temporary root
  • installed and configured debian-zfs packages from llnl
  • set up the pool and volumes per the above link
  • rsync’d the running (!) temporary root to the zfs root
  • fixed up the files that i have noted above
  • crossed fingers and rebooted

note: had to use the ppa https://launchpad.net/~zfs-native/+archive/daily to have linux 3.10 support.  really would have rather not done that.