zfs: build a ramdisk on amd64 with enough to mount rpool/ROOT on /

Until we get ZFS integrated into our boot loader, this is the next best
thing. The idea is simple - have a small FFS partition with a kernel,
modules and this ramdisk. Once the ramdisk boots it will mount the FFS
partition read only, copy the needed ZFS modules to the ramdisk and then
unmount the partition. Then we import the ZFS root pool, mount the
ZFS root filesystem and then pivot to it.

Because the initial FFS partition is not mounted at this point, we
can mount it in /altroot so we can replace the kernel and modules with
newer ones so it's easily maintainable.

This ZFS boot strapper currently makes the following assumptions:
 * The device NAME=boot is the FFS with kernel, modules and this ramdisk.
 * The ZFS root pool and root filesystem are called rpool/ROOT.

A boot.cfg menu entry can then be added like so:
menu=Boot ZFS root:fs /ramdisk-zfsroot.fs;boot
This commit is contained in:
roy 2020-02-22 09:53:47 +00:00
parent 11fc230787
commit 5403a7a7c1
5 changed files with 130 additions and 0 deletions

View File

@ -0,0 +1,17 @@
# $NetBSD: Makefile,v 1.1 2020/02/22 09:53:47 roy Exp $
IMAGE= ramdisk-zfsroot.fs
IMAGESIZE= 5000k
IMAGEDEPENDS=
MAKEDEVTARGETS= all
CRUNCHENV= INIT_CHROOT=1
SMALLPROG_INET6= 1
LISTS+= ${DISTRIBDIR}/common/list.zfsroot
.include "${.CURDIR}/../common/Makefile.ramdisk"
.include "${DISTRIBDIR}/common/Makefile.makedev"
LISTS+= ${.CURDIR}/list
MTREECONF+= ${DISTRIBDIR}/common/mtree.zfsroot

View File

@ -0,0 +1,12 @@
# $NetBSD: list,v 1.1 2020/02/22 09:53:47 roy Exp $
PROG bin/sync
PROG sbin/fdisk
PROG sbin/gpt
PROG sbin/mbrlabel
PROG sbin/shutdown
PROG usr/bin/less usr/bin/more
PROG usr/sbin/installboot

View File

@ -0,0 +1,29 @@
# $NetBSD: list.zfsroot,v 1.1 2020/02/22 09:53:47 roy Exp $
#
# list file (c.f. parselist.awk) for ZFS on root.
#
SRCDIRS external/cddl/osnet/sbin
PROG sbin/zfs
PROG sbin/zpool
LINK sbin/zfs sbin/mount_zfs
ARGVLN zfs mount_zfs
# We need sysctl to set init.root=/altroot
PROG sbin/sysctl
LIBS -lnvpair
LIBS -luutil
LIBS -lzfs
LIBS -lavl
LIBS -lm
LIBS -lpthread
LIBS -lumem
#LIBS -lutil # replaced by libhack
LIBS -lz
LIBS -lzfs_core
COPY ${NETBSDSRCDIR}/distrib/common/zfsroot.rc etc/rc
# Make firmware images available.
SYMLINK altroot/libdata libdata

View File

@ -0,0 +1,8 @@
# $NetBSD: mtree.zfsroot,v 1.1 2020/02/22 09:53:47 roy Exp $
.
./altroot
./etc
./etc/zfs
./rpool
./stand

64
distrib/common/zfsroot.rc Normal file
View File

@ -0,0 +1,64 @@
#/bin/sh
#
# $NetBSD: zfsroot.rc,v 1.1 2020/02/22 09:53:47 roy Exp $
# ZFS on Root boot strapper
# Configurable - define the ZFS root pool and ROOT.
# XXX Can these be set in boot.cfg?
# Assumption - the root pool is set to legacy mount.
rpool=rpool
rroot=ROOT
# Assumption - the boot device is named boot.
# Could use dk0, wd0a, etc instead.
# XXX Can be exposed by sysctl kern.boot_device?
bootdev="NAME=boot"
# Setup some stuff incase things go south and we drop to the shell
export HOME=/
export PATH=/sbin:/bin:/usr/sbin:/usr/bin
umask 022
echo
echo "Starting ZFS on root boot strapper"
# Avoid having the solaris and zfs modules in ramdisk directly.
# Means we don't need to update the ramdisk with the kernel modules
# or load them from boot.cfg so it's less pain for the user.
#bootdev="$(/sbin/sysctl -n kern.boot_device)"
modpath="$(/sbin/sysctl -n kern.module.path)"
modmnt=/mnt
echo "Copying needed kernel modules from $bootdev:$modpath"
case "$bootdev" in
*=*|"/"*) ;;
*) bootdev="/dev/$bootdev";;
esac
/sbin/mount -o ro "$bootdev" "$modmnt"
/sbin/mount -t tmpfs none /stand
for m in solaris zfs; do
p="$modpath/$m"
if [ ! -e "$modmnt/$p/$m.kmod" ]; then
echo "$modmnt/$p/$m.kmod not found!" >&2
continue
fi
echo " $m.kmod"
/bin/mkdir -p "$p"
/bin/cp "$modmnt/$p/$m.kmod" "$p"
done
# zpool list will load the needed modules, then we can dispose of the mounts.
/sbin/zpool list >/dev/null 2>&1
/sbin/umount /stand
/sbin/umount "$modmnt"
echo
echo "Importing $rpool, mounting and pivoting"
# If we can mount the ZFS root partition to /altroot
# then chroot to it and start /etc/rc
if /sbin/zpool import -f -N "$rpool" && \
/sbin/mount -t zfs "$rpool/$rroot" /altroot; then
# This ensures that mountall mounts all ZFS mounts set to automount.
if [ ! -e /altroot/etc/zfs/zpool.cache ]; then
echo >/altroot/etc/zfs/zpool.cache
fi
/sbin/sysctl -w init.root=/altroot
fi