Plugins

As of now plugins for the following bootloaders exist:

  • FreeBSD’s loader - freebsdloader
  • systemd-boot - systemdboot
  • GRUB (alpha) - grub

In order to integrate with a bootloader, an extra flag ‘-b/--bootloader’ must be used to specify a bootloader plugin. The plugin will make the necessary changes to boot from the new Boot Environment.

If you expect you will always be using a certain bootloader, you can set the org.zedenv:bootloader property on your boot environments, and the bootloader plugin will be used without you having to specify.

$ zedenv set org.zedenv:bootloader=<bootloader plugin>

Plugins available for your system can be listed with zedenv --plugins.

freebsdloader

The freebsdloader plugin is quite simple. During activation, it will respect /etc/rc.d/zfsbe if it exists, and set, all datasets to canmount=noauto, otherwise the datasets will be set canmount=on.

It will also change the root dataset to mount from in /boot/loader.conf, and /boot/loader.conf.local.

The current /boot/zfs/zpool.cache will also be copied into the newly activated boot environment.

systemdboot

Multiple kernels can be managed with this plugin and systemd-boot, but it will require changing the mountpoint of the esp (EFI System Partition).

Problem With Regular Mountpoint

Usually the $esp would get mounted at /boot or /boot/efi. The kernels would sit in the root of the $esp, and the configs for systemdboot in $esp/loader/.

$esp
.
├── initramfs-linux-fallback.img
├── initramfs-linux.img
├── intel-ucode.img
├── vmlinuz-linux
│
└── loader/
    ├── entries/
    │   └── arch.conf
    └── loader.conf

The configs would then reference kernels in the root directory.

title           Arch Linux
linux           vmlinuz-linux
initrd          intel-ucode.img
initrd          initramfs-linux.img
options         zfs=bootfs rw

The problem with this method, is multiple kernels cannot be kept at the same time. Therefore this hierarchy is not conducive to boot environments.

Alternate Mountpoint

First, remount the $esp to a new location, the default is /mnt/efi.

If you would like to explicitly specify the mountpoint used, you can set the org.zedenv.systemdboot:esp property on your current boot environment, and the plugin will use the specified location:

zedenv set org.zedenv.systemdboot:esp='/mnt/efi'

Don’t forget to change the mount point in /etc/fstab.

UUID=9F8A-F566            /mnt/efi  vfat    rw,defaults,errors=remount-ro  0 2

Now, make a subdirectory $esp/env, kernels will be kept in a subdirectory of this location.

The bootloader configuration can now use a different path for each boot environment.

So the ‘default’ boot environment config, located at $esp/loader/entries/zedenv-default.conf, would look something like:

title           Arch Linux
linux           /env/zedenv-default/vmlinuz-linux
initrd          /env/zedenv-default/intel-ucode.img
initrd          /env/zedenv-default/initramfs-linux.img
options         zfs=zpool/ROOT/default rw

To make the system happy when it looks for kernels at /boot, this directory should be bindmounted to /boot.

Bindmount /mnt/efi/env/zedenv-default to /boot in /etc/fstab.

/mnt/efi/env/zedenv-default   /boot     none    rw,defaults,errors=remount-ro,bind    0 0

If this directory is not here, the kernels will not be updated when the system rebuilds the kernel.

Once our system is set up in the proper configuration, zedenv will update the bootloader, and fstab - if requested - when a new boot environment is activated.

It will also update the configuration described above, asking you if the modifications that made are correct. You will have a chance to inspect and change them if they are not.

If you are confident and the changes it is making, and do not wish to inspect them, adding the --noconfirm/-y flag will run the command without asking for confirmation.

GRUB

GRUB support is provided via external plugin.

One of two types of setup can be used with grub.

  • Boot on ZFS - separate grub dataset needed.
  • Separate partition for kernels

Separate Partition for Kernels

An example system on Arch Linux with a separate partition for kernels would be the following:

  • Boot partition mounted to /mnt/boot.
  • The directory containing kernels for the active boot environment, /mnt/boot/env/zedenv-${boot_env} bind mounted to /boot.
  • The grub directory /mnt/boot/grub bindmounted to /boot/grub
  • org.zedenv.grub:bootonzfs should be set to no

What this would look like during an arch Linux install would be the following:

zpool import -d /dev/disk/by-id -R /mnt vault

mkdir -p /mnt/mnt/boot /mnt/boot
mount /dev/sda1 /mnt/mnt/boot

mkdir /mnt/mnt/boot/env/zedenv-default /mnt/boot/grub
mount --bind /mnt/mnt/boot/env/zedenv-default /mnt/boot
mount --bind /mnt/mnt/boot/grub /mnt/boot/grub

genfstab -U -p /mnt >> /mnt/etc/fstab

arch-chroot /mnt /bin/bash

In chroot

export ZPOOL_VDEV_NAME_PATH=1

grub-install --target=x86_64-efi --efi-directory=/mnt/boot --bootloader-id=GRUB
grub-mkconfig -o /boot/grub/grub.cfg

Converting Existing System

Create a backup.

cp /boot /boot.bak

Unmount /boot, and remount it at /mnt/boot.

mkdir -p /mnt/boot
mount /dev/sdxY /mnt/boot

Then you want to move your current kernel to /mnt/boot/env/zedenv-${boot_env_name}

mkdir /mnt/boot/env/zedenv-default
mv /mnt/boot/* /mnt/boot/env/zedenv-default

Move the grub directory back if it was also moved (or don’t move it in the first place).

mv /mnt/boot/env/zedenv-default/grub /mnt/boot/grub

Now bindmount the current kernel directory to /boot so that everything is where the system expects it.

mount --bind /mnt/boot/env/zedenv-default /boot

Same thing with the grub directory

mount --bind /mnt/boot/grub /boot/grub

Now everything is back to appearing how it looked originally, but things are actually stored in a different place.

You’re also probably going to want to update your fstab, if you’re using Arch you can use genfstab, which requires arch-install-scripts.

genfstab -U -p /

You’ll need to add the output to /etc/fstab.

This is what an example looks like.

# /dev/sda1
UUID=B11F-0328          /mnt/boot       vfat            rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro       0 2

/mnt/boot/env/zedenv-grub-test-3        /boot           none            rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro,bind   0 0
/mnt/boot/grub          /boot/grub      none            rw,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro,bind   0 0

Post Setup

After install, run zedenv --plugins, you should see grub.

zedenv will do its best to decide whether or not you are booting off of an all ZFS system, but it can also be set explicitly with org.zedenv.grub:bootonzfs=yes.

Any values you have set explicitly will show up with zedenv get.

You may want to disable all of the grub generators in /etc/grub.d/ except for 00_header and the zedenv generator 05_zfs_linux.py by removing the executable bit.