ZFS mirror ubuntu boot drive
[mirror.sh]
#!/bin/sh
# =========================================================================== #
# Description: ZFS mirror ubuntu boot drive
# Requirements: ZFS mirror ubuntu boot drive
# Version: 0.1
# Make executable: chmod +x mirror.sh
# Execute the script: sudo mirror.sh
#
#
# Assumptions and requirements
# - All drives will be formatted. These instructions are not suitable for dual-boot
# - No hardware or software RAID is to be used, these would keep ZFS from detecting disk errors and correcting them. In UEFI settings, set controller mode to AHCI, not RAID
# - These instructions are specific to UEFI systems and GPT. If you have an older BIOS/MBR system, please use https://openzfs.github.io/openzfs-docs/Getting%20Started/Ubuntu/Ubuntu%2020.04%20Root%20on%20ZFS.html
# change the these disks variables to your disks paths (check with lsblk)
DISK1="/dev/nvme0n1"
DISK2="/dev/nvme1n1"
if [ "$(id -u)" -ne 0 ]; then
echo "Please run this script with sudo:"
echo "sudo $0 $*"
exit 1
fi
echo "Installing dependencies"
apt install -y gdisk mdadm grub-efi-amd64
echo "-- Create partitions on second drive"
echo "Change swap partition type"
sgdisk -t2:FD00 $DISK1
echo "Copy partition table from disk 1 to disk 2"
sgdisk -R $DISK2 $DISK1
echo "Change GUID of second disk"
sgdisk -G $DISK2
# this change seems to take a while to propagate :/
sleep 1
echo "-- Mirror boot pool"
echo "Get GUID of partition 3 on disk 2"
DISK1_PART3_GUID=$(sgdisk -i3 $DISK1 | grep "^Partition unique GUID:" | awk '{print tolower($4)}')
DISK2_PART3_GUID=$(sgdisk -i3 $DISK2 | grep "^Partition unique GUID:" | awk '{print tolower($4)}')
echo "DISK 1 PART 3 GUID"
echo $DISK1_PART3_GUID
echo "DISK 2 PART 3 GUID"
echo $DISK2_PART3_GUID
if [ -z $DISK1_PART3_GUID ]; then
echo "error: failed to get the disk1 part 3 guid"
exit 1
fi
if [ -z $DISK2_PART3_GUID ]; then
echo "error: failed to get the disk2 part 3 guid"
exit 1
fi
echo "attach partition to bpool"
zpool attach bpool $DISK1_PART3_GUID /dev/disk/by-partuuid/$DISK2_PART3_GUID || exit 1
# TODO: check for failure here by the zpool status not showing the mirror
echo "-- Mirror root pool"
DISK1_PART4_GUID=$(sgdisk -i4 $DISK1 | grep "^Partition unique GUID:" | awk '{print tolower($4)}')
DISK2_PART4_GUID=$(sgdisk -i4 $DISK2 | grep "^Partition unique GUID:" | awk '{print tolower($4)}')
if [ -z $DISK1_PART4_GUID ]; then
echo "error: failed to get the disk1 part 4 guid"
exit 1
fi
if [ -z $DISK2_PART4_GUID ]; then
echo "error: failed to get the disk2 part 4 guid"
exit 1
fi
echo "attach partition to rpool"
zpool attach rpool $DISK1_PART4_GUID /dev/disk/by-partuuid/$DISK2_PART4_GUID || exit 1
# TODO: check for failure here by the zpool status not showing the mirror
echo "-- Mirror Swap"
echo "remove existing swap"
swapoff -a || exit 1
echo "remove the swap mount line in /etc/fstab"
sed -i '/swap/d' /etc/fstab
echo "create software mirror drive for swap"
mdadm --create /dev/md0 --metadata=1.2 --level=mirror --raid-devices=2 ${DISK1}p2 ${DISK2}p2 || exit 1
echo "configure mirror drive for swap"
mkswap -f /dev/md0 || exit 1
echo "place mirror swap in fstab"
sh -c "echo UUID=$(sudo blkid -s UUID -o value /dev/md0) none swap discard 0 0 >> /etc/fstab"
# TODO: verify that line is in fstab cat /etc/fstab
echo "use the new swap"
swapon -a || exit 1
echo "-- Move grub menu to ZFS"
# TODO: verify that grub can see the ZFS boot pool grub-probe /boot
echo "create EFI file system on second disk"
mkdosfs -F 32 -s 1 -n EFI ${DISK2}p1
echo "remove /boot/grub from fstab"
sed -i '/grub/d' /etc/fstab
echo "umount /boot/grub"
umount /boot/grub
# TODO: Verify with df -h, /boot should be mounted on bpool/BOOT/ubuntu_UID, /boot/efi on /dev/sda1 or similar depending on device name of your first disk, and no /boot/grub
echo "remove /boot/grub"
rm -rf /boot/grub
echo "create ZFS datatset for grub"
zfs create -o com.ubuntu.zsys:bootfs=no bpool/grub
echo "refresh initrd files"
update-initramfs -c -k all
echo "disable memory zeroing to address a performance regression of ZFS on linux"
sed -i.bak "s/GRUB_CMDLINE_LINUX_DEFAULT=\"quiet splash\"/GRUB_CMDLINE_LINUX_DEFAULT=\"quiet splash init_on_alloc=0\"/g" /etc/default/grub
echo "update grub"
update-grub
echo "reload daemon"
systemctl daemon-reload
echo "install grub to the esp"
grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu --recheck --no-floppy
echo "disable grub-initrd-fallback.service"
systemctl mask grub-initrd-fallback.service
echo "DONE without errors"
dpkg-reconfigure grub-efi-amd64