aboutsummaryrefslogtreecommitdiff
path: root/docs/research-sandreas-zarch.org
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-01-22 23:21:18 -0600
committerCraig Jennings <c@cjennings.net>2026-01-22 23:21:18 -0600
commit3e70ba84c15d69f48f436239e7f0ac9628464c55 (patch)
tree7850e50ac618a661a9c9d0b09b531a89d0696071 /docs/research-sandreas-zarch.org
parent8c5f6c19dbcf744dd239f23146b0a6d4cb8070d9 (diff)
downloadarchangel-3e70ba84c15d69f48f436239e7f0ac9628464c55.tar.gz
archangel-3e70ba84c15d69f48f436239e7f0ac9628464c55.zip
Replace GRUB with ZFSBootMenu bootloader
This is a major change that replaces the GRUB bootloader with ZFSBootMenu, providing native ZFS boot environment support. Key changes: - EFI partition reduced from 1GB to 512MB (only holds ZFSBootMenu) - EFI now mounts at /efi instead of /boot - Kernel and initramfs live on ZFS root (enables snapshot boot with matching kernel) - Downloads pre-built ZFSBootMenu EFI binary from get.zfsbootmenu.org - Creates EFI boot entries for all disks in multi-disk configurations - Syncs ZFSBootMenu to all EFI partitions for redundancy - Sets org.zfsbootmenu:commandline on zroot/ROOT for kernel cmdline inheritance - Sets bootfs pool property for default boot environment - AMD GPU workarounds (pg_mask, cwsr_enable) added to kernel cmdline when AMD detected Deleted GRUB snapshot tooling (no longer needed): - custom/grub-zfs-snap - custom/40_zfs_snapshots - custom/zz-grub-zfs-snap.hook - custom/zfs-snap-prune Updated helper scripts: - zfssnapshot: removed grub-zfs-snap call, shows ZFSBootMenu tip - zfsrollback: removed grub-zfs-snap call, notes auto-detection Tested configurations: - Single disk installation - 2-disk mirror (mirror-0) - 3-disk RAIDZ1 (raidz1-0) - All boot correctly with ZFSBootMenu
Diffstat (limited to 'docs/research-sandreas-zarch.org')
-rw-r--r--docs/research-sandreas-zarch.org365
1 files changed, 365 insertions, 0 deletions
diff --git a/docs/research-sandreas-zarch.org b/docs/research-sandreas-zarch.org
new file mode 100644
index 0000000..55bc77b
--- /dev/null
+++ b/docs/research-sandreas-zarch.org
@@ -0,0 +1,365 @@
+#+TITLE: Research: sandreas/zarch ZFSBootMenu Installation
+#+DATE: 2026-01-22
+#+AUTHOR: Research Notes
+
+* Overview
+
+This document summarizes research on the [[https://github.com/sandreas/zarch][sandreas/zarch]] GitHub repository for
+Arch Linux ZFS installation. The project uses ZFSBootMenu, native encryption,
+and automatic snapshots via zrepl.
+
+* Project Philosophy
+
+sandreas/zarch is described as a "single, non-modular file with some minor
+config profiles" - the author explicitly avoids a "modular multi-script beast."
+This contrasts with our more modular approach but offers useful patterns.
+
+** Key Features
+- ZFSBootMenu as bootloader (not GRUB)
+- Native ZFS encryption (AES-256-GCM)
+- Automatic snapshots via zrepl
+- EFI-only (no BIOS support)
+- Profile-based configuration
+
+* ZFSBootMenu Installation
+
+** Download and Install
+#+begin_src bash
+# Create EFI directory
+mkdir -p /efi/EFI/ZBM
+
+# Download latest ZFSBootMenu EFI binary
+wget -c https://get.zfsbootmenu.org/latest.EFI -O /efi/EFI/ZBM/ZFSBOOTMENU.EFI
+
+# Or use curl variant
+curl -o /boot/efi/EFI/ZBM/VMLINUZ.EFI -L https://get.zfsbootmenu.org/efi
+#+end_src
+
+** EFI Boot Entry Registration
+#+begin_src bash
+efibootmgr --disk $DISK --part 1 \
+ --create \
+ --label "ZFSBootMenu" \
+ --loader '\EFI\ZBM\ZFSBOOTMENU.EFI' \
+ --unicode "spl_hostid=$(hostid) zbm.timeout=3 zbm.prefer=zroot zbm.import_policy=hostid" \
+ --verbose
+#+end_src
+
+** Key ZFSBootMenu Parameters
+| Parameter | Purpose |
+|------------------------+------------------------------------------------|
+| zbm.timeout=N | Seconds to wait before auto-booting default |
+| zbm.prefer=POOL | Preferred pool for default boot environment |
+| zbm.import_policy | Pool import strategy (hostid recommended) |
+| zbm.skip | Skip menu and boot default immediately |
+| zbm.show | Force menu display |
+| spl_hostid=0xXXXXXXXX | Host ID for pool import validation |
+
+** Kernel Command Line for Boot Environments
+#+begin_src bash
+# Set inherited command line on ROOT dataset
+zfs set org.zfsbootmenu:commandline="quiet loglevel=0" zroot/ROOT
+
+# Set pool bootfs property
+zpool set bootfs=zroot/ROOT/arch zroot
+#+end_src
+
+* Dataset Layout
+
+** zarch Dataset Structure
+#+begin_example
+$POOL mountpoint=none
+$POOL/ROOT mountpoint=none (container for boot environments)
+$POOL/ROOT/arch mountpoint=/, canmount=noauto (active root)
+$POOL/home mountpoint=/home (shared across boot environments)
+#+end_example
+
+** Comparison: Our archzfs Dataset Structure
+#+begin_example
+zroot mountpoint=none, canmount=off
+zroot/ROOT mountpoint=none, canmount=off
+zroot/ROOT/default mountpoint=/, canmount=noauto, reservation=5-20G
+zroot/home mountpoint=/home
+zroot/home/root mountpoint=/root
+zroot/media mountpoint=/media, compression=off
+zroot/vms mountpoint=/vms, recordsize=64K
+zroot/var mountpoint=/var, canmount=off
+zroot/var/log mountpoint=/var/log
+zroot/var/cache mountpoint=/var/cache
+zroot/var/lib mountpoint=/var/lib, canmount=off
+zroot/var/lib/pacman mountpoint=/var/lib/pacman
+zroot/var/lib/docker mountpoint=/var/lib/docker
+zroot/var/tmp mountpoint=/var/tmp, auto-snapshot=false
+zroot/tmp mountpoint=/tmp, auto-snapshot=false
+#+end_example
+
+** Key Differences
+- zarch: Minimal dataset layout (ROOT, home)
+- archzfs: Fine-grained datasets with workload-specific tuning
+- archzfs: Separate /var/log, /var/cache, /var/lib/docker
+- archzfs: recordsize=64K for VM storage
+- archzfs: compression=off for media (already compressed)
+
+* ZFS Pool Creation
+
+** zarch Pool Creation (with encryption)
+#+begin_src bash
+zpool create -f \
+ -o ashift=12 \
+ -O compression=lz4 \
+ -O acltype=posixacl \
+ -O xattr=sa \
+ -O relatime=off \
+ -O atime=off \
+ -O encryption=aes-256-gcm \
+ -O keylocation=prompt \
+ -O keyformat=passphrase \
+ -o autotrim=on \
+ -m none \
+ $POOL ${DISK}-part2
+#+end_src
+
+** Our archzfs Pool Creation (with encryption)
+#+begin_src bash
+zpool create -f \
+ -o ashift="$ASHIFT" \
+ -o autotrim=on \
+ -O acltype=posixacl \
+ -O atime=off \
+ -O canmount=off \
+ -O compression="$COMPRESSION" \
+ -O dnodesize=auto \
+ -O normalization=formD \
+ -O relatime=on \
+ -O xattr=sa \
+ -O encryption=aes-256-gcm \
+ -O keyformat=passphrase \
+ -O keylocation=prompt \
+ -O mountpoint=none \
+ -R /mnt \
+ "$POOL_NAME" $pool_config
+#+end_src
+
+** Key Differences
+| Option | zarch | archzfs | Notes |
+|-----------------+-------------------+-----------------------+---------------------------------|
+| compression | lz4 | zstd (configurable) | zstd better ratio, more CPU |
+| atime | off | off | Same |
+| relatime | off | on | archzfs uses relatime instead |
+| dnodesize | (default) | auto | Better extended attribute perf |
+| normalization | (default) | formD | Unicode consistency |
+
+* Snapshot Automation
+
+** zarch: zrepl Configuration
+
+zarch uses zrepl for automated snapshots with this retention grid:
+
+#+begin_example
+1x1h(keep=4) | 24x1h(keep=1) | 7x1d(keep=1) | 4x1w(keep=1) | 12x4w(keep=1) | 1x53w(keep=1)
+#+end_example
+
+This means:
+- Keep 4 snapshots within the last hour
+- Keep 1 snapshot per hour for 24 hours
+- Keep 1 snapshot per day for 7 days
+- Keep 1 snapshot per week for 4 weeks
+- Keep 1 snapshot per 4 weeks for 12 periods (48 weeks)
+- Keep 1 snapshot per year
+
+#+begin_src yaml
+# Example zrepl.yml structure
+jobs:
+ - name: snapjob
+ type: snap
+ filesystems:
+ "zroot<": true
+ snapshotting:
+ type: periodic
+ interval: 15m
+ prefix: zrepl_
+ pruning:
+ keep:
+ - type: grid
+ grid: 1x1h(keep=all) | 24x1h | 14x1d
+ regex: "^zrepl_.*"
+ - type: regex
+ negate: true
+ regex: "^zrepl_.*"
+#+end_src
+
+** archzfs: Pacman Hook Approach
+
+Our approach uses pre-transaction snapshots:
+#+begin_src bash
+# /etc/pacman.d/hooks/zfs-snapshot.hook
+[Trigger]
+Operation = Upgrade
+Operation = Install
+Operation = Remove
+Type = Package
+Target = *
+
+[Action]
+Description = Creating ZFS snapshot before pacman transaction...
+When = PreTransaction
+Exec = /usr/local/bin/zfs-pre-snapshot
+#+end_src
+
+** Comparison: Snapshot Approaches
+| Feature | zrepl (zarch) | Pacman Hook (archzfs) |
+|-------------------+--------------------------+------------------------------|
+| Trigger | Time-based (15 min) | Event-based (pacman) |
+| Retention | Complex grid policy | Manual or sanoid |
+| Granularity | High (frequent) | Package transaction focused |
+| Recovery Point | ~15 minutes | Last package operation |
+| Storage overhead | Higher (more snapshots) | Lower (fewer snapshots) |
+
+** Alternative: sanoid (mentioned in archzfs)
+Sanoid provides similar functionality to zrepl with simpler configuration:
+#+begin_src ini
+# /etc/sanoid/sanoid.conf
+[zroot/ROOT/default]
+use_template = production
+recursive = yes
+
+[template_production]
+frequently = 0
+hourly = 24
+daily = 7
+weekly = 4
+monthly = 12
+yearly = 1
+autosnap = yes
+autoprune = yes
+#+end_src
+
+* EFI and Boot Partition Strategy
+
+** zarch: 512MB EFI, ZFSBootMenu
+- Single 512MB EFI partition (type EF00)
+- ZFSBootMenu EFI binary downloaded from upstream
+- No GRUB, no separate boot partition on ZFS
+- Kernel/initramfs stored on ZFS root (ZFSBootMenu reads them)
+
+** archzfs: 1GB EFI, GRUB with ZFS Support
+- 1GB EFI partition per disk
+- GRUB with ZFS module for pool access
+- Redundant EFI partitions synced via rsync
+- Boot files in EFI partition (not ZFS)
+
+** Trade-offs
+
+| Aspect | ZFSBootMenu | GRUB + ZFS |
+|---------------------+--------------------------------+------------------------------|
+| Boot environment | Native (designed for ZFS) | Requires ZFS module |
+| Snapshot booting | Built-in, interactive | Custom GRUB menu entries |
+| Encryption | Prompts for key automatically | More complex setup |
+| EFI space needed | Minimal (~512MB) | Larger (kernel/initramfs) |
+| Complexity | Simpler (single binary) | More moving parts |
+| Recovery | Can browse/rollback at boot | Requires grub.cfg regen |
+
+* Pacman Hooks and Systemd Services
+
+** zarch Services
+#+begin_example
+zfs-import-cache
+zfs-import.target
+zfs-mount
+zfs-zed
+zfs.target
+set-locale-once.service (custom first-boot locale config)
+#+end_example
+
+** archzfs Services
+#+begin_example
+zfs.target
+zfs-import-scan.service (instead of cache-based)
+zfs-mount.service
+zfs-import.target
+NetworkManager
+avahi-daemon
+sshd
+#+end_example
+
+** Key Difference: Import Method
+- zarch: Uses zfs-import-cache (requires cachefile)
+- archzfs: Uses zfs-import-scan (scans with blkid, no cachefile needed)
+
+The scan method is simpler and more portable (works if moving disks between
+systems).
+
+* mkinitcpio Configuration
+
+** zarch Approach
+#+begin_src bash
+sed -i '/^HOOKS=/s/block filesystems/block zfs filesystems/g' /etc/mkinitcpio.conf
+#+end_src
+
+** archzfs Approach
+#+begin_src bash
+HOOKS=(base udev microcode modconf kms keyboard keymap consolefont block zfs filesystems)
+#+end_src
+
+** Important Notes
+- Both use busybox-based udev (not systemd hook)
+- archzfs explicitly removes autodetect to ensure all storage drivers included
+- archzfs removes fsck (ZFS doesn't use it)
+- archzfs includes microcode early loading
+
+* Useful Patterns to Consider
+
+** 1. Profile-Based Configuration
+zarch uses a profile directory system:
+#+begin_example
+default/
+ archpkg.txt # Official packages
+ aurpkg.txt # AUR packages
+ services.txt # Services to enable
+ zarch.conf # Core configuration
+ custom-chroot.sh # Custom post-install
+#+end_example
+
+This allows maintaining multiple configurations (desktop, server, VM) cleanly.
+
+** 2. ZFSBootMenu for Simpler Boot
+For future consideration:
+- Native ZFS boot environment support
+- Interactive snapshot selection at boot
+- Simpler encryption key handling
+- Smaller EFI partition needs
+
+** 3. zrepl for Time-Based Snapshots
+For systems needing frequent snapshots beyond pacman transactions:
+- 15-minute intervals for development machines
+- Complex retention policies
+- Replication to remote systems
+
+** 4. AUR Helper Installation Pattern
+#+begin_src bash
+# Build yay as regular user, install as root
+su -c "git clone https://aur.archlinux.org/yay-bin.git" "$USER_NAME"
+arch-chroot -u "$USER_NAME" /mnt makepkg -D /home/$USER_NAME/yay-bin -s
+pacman -U --noconfirm yay-bin-*.pkg.tar.*
+#+end_src
+
+* References
+
+- [[https://github.com/sandreas/zarch][sandreas/zarch GitHub Repository]]
+- [[https://zfsbootmenu.org/][ZFSBootMenu Official Site]]
+- [[https://docs.zfsbootmenu.org/en/latest/][ZFSBootMenu Documentation]]
+- [[https://zrepl.github.io/][zrepl Documentation]]
+- [[https://wiki.archlinux.org/title/ZFS][Arch Wiki: ZFS]]
+- [[https://github.com/acrion/zfs-autosnap][zfs-autosnap - Pre-upgrade Snapshots]]
+- [[https://aur.archlinux.org/packages/pacman-zfs-hook][pacman-zfs-hook AUR Package]]
+- [[https://florianesser.ch/posts/20220714-arch-install-zbm/][Guide: Install Arch Linux on encrypted zpool with ZFSBootMenu]]
+
+* Action Items for archzfs
+
+Based on this research, potential improvements:
+
+1. [ ] Consider adding ZFSBootMenu as alternative bootloader option
+2. [ ] Evaluate zrepl for systems needing frequent time-based snapshots
+3. [ ] Document the grub-zfs-snap vs ZFSBootMenu trade-offs
+4. [ ] Consider profile-based configuration for different use cases
+5. [ ] Add sanoid configuration to archsetup for automated snapshot retention