.. highlight:: sh Create a Boot Environment ========================== This page is tested for Alpine, Arch Linux, Fedora and RHEL guides. Not useful for NixOS since system rollback is already managed by Nix. With Root on ZFS, it is possible to take snapshots of existing root file systems, which is a read-only copy of that file system. A new, full-fledged file system -- clones -- can be then created from this snapshot. This bootable clone of the current system is then called a "Boot Environment". This could be useful if you are performing a major system upgrade and wish to have the option to go back to a previous state if the upgrade fails. #. Identify which dataset is currently mounted as root ``/`` and boot ``/boot``:: findmnt / # output TARGET SOURCE FSTYPE OPTIONS / rpool/archlinux/root zfs rw,relatime,xattr,posixacl findmnt /boot # output TARGET SOURCE FSTYPE OPTIONS /boot bpool/archlinux/root zfs rw,relatime,xattr,posixacl #. Identify your distribution in the dataset (file system) path:: DISTRO=archlinux # or `fedora', `alma', `alpinelinux' #. Choose a name for the new boot environment:: BE_NAME=backup #. Take snapshots of the ``/`` and ``/boot`` datasets:: zfs snapshot rpool/$DISTRO/root@$BE_NAME zfs snapshot bpool/$DISTRO/root@$BE_NAME #. Create clones from read-only snapshots:: zfs clone -o canmount=noauto \ -o mountpoint=/ \ rpool/$DISTRO/root@$BE_NAME \ rpool/$DISTRO/$BE_NAME zfs clone -o canmount=noauto \ -o mountpoint=legacy \ bpool/$DISTRO/root@$BE_NAME \ bpool/$DISTRO/$BE_NAME #. Mount clone and update file system table (fstab) :: mount -t zfs -o zfsutil rpool/$DISTRO/$BE_NAME /mnt mount -t zfs bpool/$DISTRO/$BE_NAME /mnt/boot sed -i "s|rpool/$DISTRO/root|rpool/$DISTRO/$BE_NAME|g" /mnt/etc/fstab sed -i "s|bpool/$DISTRO/root|bpool/$DISTRO/$BE_NAME|g" /mnt/etc/fstab If legacy mountpoint is used, omit ``-o zfsutil`` from mount command. #. Create GRUB menu for new clone:: m='/dev /proc /sys' for i in $m; do mount --rbind $i /mnt/$i; done chroot /mnt /usr/bin/env sh < grub.cfg cp grub.cfg $i fi done rm new_entry #. After reboot, select boot environment entry from GRUB menu to boot from the clone. Press ESC inside submenu to return to the previous menu. #. Steps above can also be used to create a new clone from an existing snapshot. #. To set a boot environment as default, replace existing ``grub.cfg`` inside EFI system partition with the one from the boot environment:: mount -t zfs bpool/$DISTRO/$BE_NAME /mnt # backup existing grub.cfg inside EFI # then replace it with menu from clone mkdir -p /mnt/grub_menu_backup menu_counter=1 find /boot/efis/ -name "grub.cfg" \ | while read i; do if grep -q "${DISTRO}" $i; then cp $i /mnt/grub_menu_backup/grub_${menu_counter}.cfg echo $i > /mnt/grub_menu_backup/grub_${menu_counter}_path.txt cp /mnt/grub.cfg $i menu_counter=$(($menu_counter + 1)) fi done umount -Rl /mnt #. To delete the boot environment, check with ``findmnt`` that the boot environment is not currently used:: findmnt / findmnt /boot Set variables:: DISTRO=archlinux Then check the origin snapshot:: zfs get origin rpool/archlinux/backup # rpool/archlinux/root@backup zfs get origin bpool/archlinux/backup # bpool/archlinux/root@backup RM_BE=backup RM_SNAPSHOT=root@backup Finally, destroy clone (boot environment) and its origin snapshot:: zfs destroy rpool/${DISTRO}/${RM_BE} zfs destroy rpool/${DISTRO}/${RM_SNAPSHOT} zfs destroy bpool/${DISTRO}/${RM_BE} zfs destroy bpool/${DISTRO}/${RM_SNAPSHOT} Remove GRUB entry:: find /boot/efis/ -name "grub.cfg" \ | while read i; do if grep -q "${DISTRO}/${RM_BE}@/grub.cfg" $i; then head -n -1 $i > grub.cfg cp grub.cfg $i fi done