WARNING:
YOU WILL LOSE ALL YOUR DATA. Following this guide will destroy all data on your disks. Make sure you have backups. This will not work on 2 TB or larger boot drives, of course. That's the MBR partition limit.
2 The MBR root on ZFS wiki page insists that the ZFS partition go first. The bsdinstall zfsboot script always creates a separate boot pool when BIOS booting from an MBR partition. I found the latter unnecessary, and am unsure that the former is strictly needed.
* After reading this I decided to trim and enable TRIM on these root pools because they are on SSDs
YOU WILL LOSE ALL YOUR DATA. Following this guide will destroy all data on your disks. Make sure you have backups. This will not work on 2 TB or larger boot drives, of course. That's the MBR partition limit.
Rationale
I have two machines that duel boot Freebsd; one duels with Linux, the other duels with Windows 10. These were 12.4 machines I set up with UFS root filesystems back before 13.x was released, and when I did not have much experience with ZFS. I wanted to update them to 13.2. This seemed like a good time to rebuild them with ZFS root filesystems. I want that for snapshots, boot environments, better poudriere(8) performance, etc. I want BIOS booting from MBR partitions because I know I can make the simpleboot0
boot loader work in such a setup. Also, GRUB needs a not-so-special 1 MB partition at the beginning of the disk to BIOS boot from a GPT partition. I'm not a fan of small "special" partitions.Setup
Each system has a 1TB NVMe drive as the boot drive, and some large spinning rust formatted with NTFS mainly to store my Steam library. The latter is irrelevant for this guide and won't be mentioned again. We'll split each boot drive in half for Freebsd, with the alternative operating system installed on the other half. A one-terabyte drive has 932 gibibytes in it. This works out to a 466 gibibyte Freebsd slice inside of which we'll create a 434 gibibyte ZFS partition. The remaining 32 gibibytes will be allocated to a swap partition.Problem
The Freebsd installer only allows one to use the whole disk for ZFS on root, or to drop to a shell and do manual partitioning. There's no guided fractional partitioning option like there is for UFS. I found a guide on the wiki for doing ZFS Root on BIOS/MBR systems, and a similar one for GPT partitioning. Neither exactly suited what I wanted to achieve so I pieced together an approach using those wiki pages and the bsdinstall(8) zfsboot script. It was complicated and took some time. I'm sharing it here in case anyone else finds it useful, and so I can find it when I need to do this again.Steps
- Boot into the Freebsd installer
- Choose "Shell" at the "Partitioning" dialog
- Find your installation disk
gpart show
- Destroy any existing partitions on it
gpart destroy -F foo0
- Create MBR partitioning scheme
gpart create -s mbr foo0
- Create a freebsd slice on the new partitioning scheme
Code:# gpart add -s 466G -t freebsd foo0 foo0s1 added
- Destroy any old ZFS labels that may linger on the disk1
Code:# zpool labelclear -f foo0 # zpool labelclear -f foo0s1
- Destroy any old BSD labels that may linger1
gpart destroy -F foo0s1
- Create the slice
Code:# gpart create -s BSD foo0s1 foo0s1 created
- Set the first slice active
gpart set -a active -i 1 foo0
- Add the ZFS partition first2
Code:# gpart add -s 434G -t freebsd-zfs foo0s1 foo0s1a added
- Then add the swap partition
Code:# gpart add -t freebsd-swap foo0s1 foo0s1b added
- Install the boot manager
Code:# gpart bootcode -b /boot/boot0 foo0 bootcode written to foo0
- Mount a tmpfs to /mnt
mount -t tmpfs tmpfs /mnt
- Create the ZFS root pool
Code:# zpool create -o altroot=/mnt -O compress=lz4 -O atime=off zroot foo0s1a
- Export zroot before installing boot code
zpool export zroot
- Install the boot1 stage
Code:# dd if=/boot/zfsboot of=/tmp/zfsboot1 count=1 # gpart bootcode -b /tmp/zfsboot1 /dev/foo0s1 bootcode written to foo0s1
- Install the boot2 ZFS stage into the convenient hole in the ZFS filesystem on-disk format which is located just after the ZFS metadata (this is the seek=1024)
Code:# dd if=/boot/zfsboot of=/dev/foo0s1a skip=1 seek=1024
- Import zroot to continue the install
zpool import -o altroot=/mnt zroot
- Create the ZFS datasets
Code:zfs create -o mountpoint=none zroot/ROOT zfs create -o mountpoint=/ zroot/ROOT/default zfs create -o mountpoint=/tmp -o exec=on -o setuid=off zroot/tmp zfs create -o mountpoint=/usr -o canmount=off zroot/usr zfs create zroot/usr/home zfs create -o setuid=off zroot/usr/ports zfs create -o mountpoint=/var -o canmount=off zroot/var zfs create -o exec=off -o setuid=off zroot/var/audit zfs create -o exec=off -o setuid=off zroot/var/crash zfs create -o exec=off -o setuid=off zroot/var/log zfs create -o atime=on zroot/var/mail zfs create -o setuid=off zroot/var/tmp
- Create /home link and adjust permissions
Code:# ln -s /usr/home /mnt/home # chmod 1777 /mnt/var/tmp # chmod 1777 /mnt/tmp
- Configure boot environment
Code:# zpool set bootfs=zroot/ROOT/default zroot # zfs set canmount=noauto zroot/ROOT/default
- Edit fstab (vi /tmp/bsdinstall_etc/fstab) and add
Code:# Device Mountpoint FStype Options Dump Pass /dev/foo0s1b none swap sw 0 0
- Exit shell partitioning mode, bsdinstall will continue and complete the installation
- In the post installation step, when asked if you would like to drop into the installed system, choose yes and run
Code:# sysrc zfs_enable="YES"
Notes
1 I'm not sure these steps are necessary. The bsdinstall zfsboot script performs these cleanups, but calls them "pedantic." I had weird problems that may have been caused by stale ZFS labels.2 The MBR root on ZFS wiki page insists that the ZFS partition go first. The bsdinstall zfsboot script always creates a separate boot pool when BIOS booting from an MBR partition. I found the latter unnecessary, and am unsure that the former is strictly needed.
* After reading this I decided to trim and enable TRIM on these root pools because they are on SSDs
Code:
# zpool trim zroot
# zpool set autotrim=on
Last edited: