zedenv - ZFS boot environment manager - GRUB plugin
Install zedenv
then zedenv-grub
.
One of two types of setup needs to be used with grub.
- Boot on ZFS - separate
grub
dataset needed. - Separate partition for kernels
To use boot on ZFS:
- A
grub
dataset is needed. It should be mounted at/boot/grub
. org.zedenv.grub:bootonzfs
should be set toyes
- Individual boot environments should contain their kernels in
/boot
, which should be part of the root dataset.
To convert an existing grub install, set up the grub
dataset, and mount it. Then install grub again.
zfs create -o canmount=off zroot/boot
zfs create -o mountpoint=legacy zroot/boot/grub
mount -t zfs zroot/boot/grub /boot/grub
# efi
mount ${esp} /boot/efi
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUB
# or for BIOS
grub-install --target=i386-pc /dev/sdx --recheck
If you get:
/dev/sda
Installing for i386-pc platform.
grub-install: error: failed to get canonical path of `/dev/ata-SAMSUNG_SSD_830_Series_S0VVNEAC702110-part2'.
A workaround is to symlink the expected partition to the id
ln -s /dev/sda2 /dev/ata-SAMSUNG_SSD_830_Series_S0VVNEAC702110-part2
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 tono
withzedenv set org.zedenv.grub:bootonzfs=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
An example generated grub.cfg looks like:
### BEGIN /etc/grub.d/10_linux ###
menuentry 'Arch Linux' --class arch --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-a1b916c0819a1863' {
load_video
set gfxpayload=keep
insmod gzio
insmod part_gpt
insmod fat
set root='hd0,gpt1'
if [ x$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt1 --hint-efi=hd0,gpt1 --hint-baremetal=ahci0,gpt1 B11F-0328
else
search --no-floppy --fs-uuid --set=root B11F-0328
fi
echo 'Loading Linux linux ...'
linux /env/zedenv-default/vmlinuz-linux root=ZFS=vault/sys/zedenv/ROOT/default rw quiet
echo 'Loading initial ramdisk ...'
initrd /env/zedenv-default/initramfs-linux.img
}
Create a backup.
cp -a /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 grab 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
After install, run zedenv --plugins
, you should see grub
.
Set bootloader config, options can be queried with zedenv get --defaults
:
$ zedenv get --defaults
PROPERTY DEFAULT DESCRIPTION
org.zedenv:bootloader Set a bootloader plugin.
org.zedenv.systemdboot:esp /mnt/efi Set location for esp.
org.zedenv.grub:boot /mnt/boot Set location for boot.
org.zedenv.grub:bootonzfs yes
Set the bootloader so it doesn't have to be declared on every usage with the -b
flag.
# zedenv set org.zedenv:bootloader=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
.
Now create a new boot environment:
# zedenv create linux-4.18.12
# zfs list
NAME USED AVAIL REFER MOUNTPOINT
zroot 2.43G 36.1G 29K none
zroot/ROOT 2.42G 36.1G 29K none
zroot/ROOT/default 2.42G 36.1G 2.42G /
zroot/ROOT/linux-4.18.12 1K 36.1G 2.42G /
zroot/data 9.36M 36.1G 29K none
zroot/data/home 9.33M 36.1G 9.33M legacy
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.