ZFS root on FreeBSD 9.1

Throwing this here mostly for myself. After repeated failures at installing FreeBSD 9.1 straight on ZFS, mostly because of typos, I decided to create a script to do it. It will probably be superfluous soon as FreeBSD 10 should be able to do it from the installer. There might be typos inside the script too.

I copied the script to an USB stick, booted from the FreeBSD cd, dropped into a shell, mounted the USB stick under /tmp/whatever (do NOT mount anywhere under /mnt), removed the exit line at the beginning and executed.

It creates partitions, installs FreeBSD, modifies loader.conf, rc.conf, periodic.conf and fstab and exits. Server should be ready for reboot at this point. Compiled from several HOW-TOs around the Internet.

It was not written to be easily adapted to new systems, needs to be modified. Do NOT just run it as it is. Once started it can only be stopped with CTRL+C.

echo '...'
## change the setting for rc.conf too, later on
## also replace zroot with the name of the pool if needed
exit

DISK0="da0"
DISK1="da1"
echo "will use pool zroot, made up of disks $DISK0 and DISK1"

echo "Creating partitions and writing the proper bootcode..."
echo "  $DISK0"
gpart create -s gpt $DISK0
gpart add -b 34 -s 64k -t freebsd-boot -l g0boot $DISK0
gpart add -s 4G -a 4k -t freebsd-swap -l g0swap $DISK0
gpart add -a 4k -t freebsd-zfs -l g0zfs $DISK0
gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 $DISK0
echo "  $DISK1"
gpart create -s gpt $DISK1
gpart add -b 34 -s 64k -t freebsd-boot -l g1boot $DISK1
gpart add -s 4G -a 4k -t freebsd-swap -l g1swap $DISK1
gpart add -a 4k -t freebsd-zfs -l g1zfs $DISK1
gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 $DISK1
echo "done"

echo "Loading kernel modules..."
# errors that say the module is already loaded are fine here
kldload opensolaris
kldload zfs
kldload geom_mirror
echo "done"

echo 'Setting swap as mirror...'
gmirror label gswap /dev/gpt/g0swap /dev/gpt/g1swap
echo 'done'

echo "Creating zroot and mounting it on /mnt..."
zpool create -o altroot=/mnt -o cachefile=/var/tmp/zpool.cache zroot mirror /dev/gpt/g0zfs /dev/gpt/g1zfs
echo "done"

echo "Creating fielsystems"
zfs create -o setuid=off zroot/tmp
chmod 1777 /mnt/tmp
zfs create zroot/usr
zfs create zroot/usr/home
cd /mnt
ln -s usr/home home
cd -
zfs create zroot/usr/local
zfs create -o compression=on -o exec=off -o setuid=off zroot/usr/src
zfs create zroot/var
zfs create -o exec=off -o setuid=off zroot/var/backups
zfs create -o compression=on -o exec=off -o setuid=off zroot/var/crash
zfs create -o exec=off -o setuid=off zroot/var/db
zfs create -o compression=on -o exec=on -o setuid=off zroot/var/db/pkg
zfs create -o exec=off -o setuid=off zroot/var/empty
zfs create -o compression=on -o exec=off -o setuid=off zroot/var/log
zfs create -o compression=on -o exec=off -o setuid=off zroot/var/mail
zfs create -o exec=off -o setuid=off zroot/var/run
zfs create -o setuid=off zroot/var/tmp
chmod 1777 /mnt/var/tmp
zfs create -o setuid=off zroot/usr/ports
zfs create -o exec=off -o setuid=off zroot/usr/ports/distfiles
zfs create -o exec=off -o setuid=off zroot/usr/ports/packages
echo "done"

echo "Making zfs bootable..."
# Note that 9.1 STILL NEEDS the cache to be copied.
# Apparently the changes that would allow the pool to boot without
# doing that didn't make it into release
zpool set bootfs=zroot zroot
mkdir -p /mnt/boot/zfs
cp -p /var/tmp/zpool.cache /mnt/boot/zfs/zpool.cache
echo "done"

echo 'Installing FreeBSD...'
cd /usr/freebsd-dist
export DESTDIR=/mnt
for file in base.txz lib32.txz kernel.txz doc.txz ports.txz src.txz;
do (cat $file | tar --unlink -xpJf - -C ${DESTDIR:-/}); done
echo 'done'

echo 'Setting up the new system'
echo '  loader.conf'
echo 'zfs_load="YES"' >> /mnt/boot/loader.conf
echo 'geom_mirror_load="YES"' >> /mnt/boot/loader.conf
# I don't think this is needed on 9.1. Doesn't hurt though
echo 'vfs.root.mountfrom="zfs:zroot"' >> /mnt/boot/loader.conf

echo '  rc.conf'
echo 'zfs_enable="YES"' >> /mnt/etc/rc.conf
echo 'hostanme="zfstest.example.org"' >> /mnt/etc/rc.conf
echo 'ifconfig_bce0="inet 10.10.10.10 netmask 255.255.255.0"' >> /mnt/etc/rc.conf
echo 'defaultrouter="10.10.10.1"' >> /mnt/etc/rc.conf
echo 'sshd_enable="YES"' >> /mnt/etc/rc.conf

echo '  periodic.conf'
echo 'daily_status_gmirror="YES"' >> /mnt/etc/periodic.conf

echo '  fstab'
echo '# Device          Mountpoint      FStype  Opts    Dump    Pass#' >> /mnt/etc/fstab
echo '/dev/mirror/gswap none            swap    sw      0       0' >> /mnt/etc/fstab

echo 'done'

echo 'Make sure empty stays empty. (why?)'
zfs set readonly=on zroot/var/empty
echo 'done'

echo 'all done, can reboot: shutdown -r now'