From 3321f0fe09b545a7ae3cfd98a80111bb43c0e448 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 12 Apr 2026 22:57:54 -0400 Subject: refactor: remove dead installer/lib/zfs.sh The library was sourced but only zfs_preflight was reachable from install_zfs(); the other ten functions either had names that were never called (create_zfs_datasets, configure_zfs_pacman_hook, etc.) or were shadowed by same-named definitions in the monolithic installer/archangel (create_zfs_pool, configure_zfsbootmenu, configure_zfs_services). Inlined zfs_preflight into archangel and dropped the source line. Removes a trap where fixes appear to be "mirrored" but only one copy actually runs. --- installer/archangel | 9 +- installer/lib/zfs.sh | 377 --------------------------------------------------- 2 files changed, 8 insertions(+), 378 deletions(-) delete mode 100644 installer/lib/zfs.sh (limited to 'installer') diff --git a/installer/archangel b/installer/archangel index 9c6da97..615829d 100755 --- a/installer/archangel +++ b/installer/archangel @@ -28,7 +28,6 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/lib/common.sh" source "$SCRIPT_DIR/lib/config.sh" source "$SCRIPT_DIR/lib/disk.sh" -source "$SCRIPT_DIR/lib/zfs.sh" source "$SCRIPT_DIR/lib/btrfs.sh" ############################# @@ -83,6 +82,14 @@ preflight_checks() { require_root } +zfs_preflight() { + if ! lsmod | grep -q zfs; then + info "Loading ZFS module..." + modprobe zfs || error "Failed to load ZFS module. Is zfs-linux-lts installed?" + fi + info "ZFS module loaded successfully." +} + # Filesystem-specific preflight (called after filesystem is selected) filesystem_preflight() { if [[ "$FILESYSTEM" == "zfs" ]]; then diff --git a/installer/lib/zfs.sh b/installer/lib/zfs.sh deleted file mode 100644 index bf8af35..0000000 --- a/installer/lib/zfs.sh +++ /dev/null @@ -1,377 +0,0 @@ -#!/usr/bin/env bash -# zfs.sh - ZFS-specific functions for archangel installer -# Source this file after common.sh, config.sh, disk.sh - -############################# -# ZFS Constants -############################# - -POOL_NAME="${POOL_NAME:-zroot}" -ASHIFT="${ASHIFT:-12}" -COMPRESSION="${COMPRESSION:-zstd}" - -############################# -# ZFS Pre-flight -############################# - -zfs_preflight() { - # Check ZFS module - if ! lsmod | grep -q zfs; then - info "Loading ZFS module..." - modprobe zfs || error "Failed to load ZFS module. Is zfs-linux-lts installed?" - fi - info "ZFS module loaded successfully." -} - -############################# -# ZFS Pool Creation -############################# - -create_zfs_pool() { - local encryption="${1:-true}" - local passphrase="$2" - - step "Creating ZFS Pool" - - # Destroy existing pool if present - if zpool list "$POOL_NAME" &>/dev/null; then - warn "Pool $POOL_NAME already exists. Destroying..." - zpool destroy -f "$POOL_NAME" - fi - - # Get root partitions - local zfs_parts=() - for disk in "${SELECTED_DISKS[@]}"; do - zfs_parts+=("$(get_root_partition "$disk")") - done - - # Build pool configuration based on RAID level - local pool_config - if [[ "$RAID_LEVEL" == "stripe" ]]; then - pool_config="${zfs_parts[*]}" - info "Creating striped pool with ${#zfs_parts[@]} disks (NO redundancy)..." - warn "Data loss will occur if ANY disk fails!" - elif [[ -n "$RAID_LEVEL" ]]; then - pool_config="$RAID_LEVEL ${zfs_parts[*]}" - info "Creating $RAID_LEVEL pool with ${#zfs_parts[@]} disks..." - else - pool_config="${zfs_parts[0]}" - info "Creating single-disk pool..." - fi - - # Base pool options - local pool_opts=( - -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 mountpoint=none - -R /mnt - ) - - # Create pool (with or without encryption) - if [[ "$encryption" == "false" ]]; then - warn "Creating pool WITHOUT encryption" - zpool create "${pool_opts[@]}" "$POOL_NAME" $pool_config - else - info "Creating encrypted pool..." - echo "$passphrase" | zpool create "${pool_opts[@]}" \ - -O encryption=aes-256-gcm \ - -O keyformat=passphrase \ - -O keylocation=prompt \ - "$POOL_NAME" $pool_config - fi - - info "ZFS pool created successfully." - zpool status "$POOL_NAME" -} - -############################# -# ZFS Dataset Creation -############################# - -create_zfs_datasets() { - step "Creating ZFS Datasets" - - # Root dataset container - zfs create -o mountpoint=none -o canmount=off "$POOL_NAME/ROOT" - - # Calculate reservation (20% of pool, capped 5-20G) - local pool_size_bytes - pool_size_bytes=$(zpool get -Hp size "$POOL_NAME" | awk '{print $3}') - local pool_size_gb=$((pool_size_bytes / 1024 / 1024 / 1024)) - local reserve_gb=$((pool_size_gb / 5)) - [[ $reserve_gb -gt 20 ]] && reserve_gb=20 - [[ $reserve_gb -lt 5 ]] && reserve_gb=5 - - # Main root filesystem - zfs create -o mountpoint=/ -o canmount=noauto -o reservation=${reserve_gb}G "$POOL_NAME/ROOT/default" - zfs mount "$POOL_NAME/ROOT/default" - - # Home - zfs create -o mountpoint=/home "$POOL_NAME/home" - zfs create -o mountpoint=/root "$POOL_NAME/home/root" - - # Media - compression off for already-compressed files - zfs create -o mountpoint=/media -o compression=off "$POOL_NAME/media" - - # VMs - 64K recordsize for VM disk images - zfs create -o mountpoint=/vms -o recordsize=64K "$POOL_NAME/vms" - - # Var datasets - zfs create -o mountpoint=/var -o canmount=off "$POOL_NAME/var" - zfs create -o mountpoint=/var/log "$POOL_NAME/var/log" - zfs create -o mountpoint=/var/cache "$POOL_NAME/var/cache" - zfs create -o mountpoint=/var/lib -o canmount=off "$POOL_NAME/var/lib" - zfs create -o mountpoint=/var/lib/pacman "$POOL_NAME/var/lib/pacman" - zfs create -o mountpoint=/var/lib/docker "$POOL_NAME/var/lib/docker" - - # /var/tmp - ZFS-backed, persists across reboots, excluded from snapshots - zfs create -o mountpoint=/var/tmp -o com.sun:auto-snapshot=false "$POOL_NAME/var/tmp" - chmod 1777 /mnt/var/tmp - - # /tmp - tmpfs via fstab (not ZFS: ZFS statx() returns ENOLINK on - # systemd PrivateTmp paths, breaking systemd-tmpfiles-clean every boot) - mkdir -p /mnt/tmp - chmod 1777 /mnt/tmp - - info "Datasets created:" - zfs list -r "$POOL_NAME" -o name,mountpoint,compression -} - -############################# -# ZFSBootMenu Configuration -############################# - -configure_zfsbootmenu() { - step "Configuring ZFSBootMenu" - - # Ensure hostid exists - if [[ ! -f /etc/hostid ]]; then - zgenhostid - fi - local host_id - host_id=$(hostid) - - # Copy hostid to installed system - cp /etc/hostid /mnt/etc/hostid - - # Create ZFSBootMenu directory on EFI - mkdir -p /mnt/efi/EFI/ZBM - - # Download ZFSBootMenu release EFI binary - info "Downloading ZFSBootMenu..." - local zbm_url="https://get.zfsbootmenu.org/efi" - if ! curl -fsSL -o /mnt/efi/EFI/ZBM/zfsbootmenu.efi "$zbm_url"; then - error "Failed to download ZFSBootMenu" - fi - info "ZFSBootMenu binary installed." - - # Set kernel command line on the ROOT PARENT dataset - local cmdline="rw loglevel=3" - - # Add AMD GPU workarounds if needed - if lspci | grep -qi "amd.*display\|amd.*vga"; then - info "AMD GPU detected - adding workaround parameters" - cmdline="$cmdline amdgpu.pg_mask=0 amdgpu.cwsr_enable=0" - fi - - zfs set org.zfsbootmenu:commandline="$cmdline" "$POOL_NAME/ROOT" - info "Kernel command line set on $POOL_NAME/ROOT" - - # Set bootfs property - zpool set bootfs="$POOL_NAME/ROOT/default" "$POOL_NAME" - info "Default boot filesystem set to $POOL_NAME/ROOT/default" - - # Create EFI boot entries for each disk - local zbm_cmdline="spl_hostid=0x${host_id} zbm.timeout=3 zbm.prefer=${POOL_NAME} zbm.import_policy=hostid" - - for i in "${!SELECTED_DISKS[@]}"; do - local disk="${SELECTED_DISKS[$i]}" - local label="ZFSBootMenu" - if [[ ${#SELECTED_DISKS[@]} -gt 1 ]]; then - label="ZFSBootMenu-disk$((i+1))" - fi - - info "Creating EFI boot entry: $label on $disk" - efibootmgr --create \ - --disk "$disk" \ - --part 1 \ - --label "$label" \ - --loader '\EFI\ZBM\zfsbootmenu.efi' \ - --unicode "$zbm_cmdline" \ - --quiet - done - - # Set as primary boot option - local bootnum - bootnum=$(efibootmgr | grep "ZFSBootMenu" | head -1 | grep -oP 'Boot\K[0-9A-F]+') - if [[ -n "$bootnum" ]]; then - local current_order - current_order=$(efibootmgr | grep "BootOrder" | cut -d: -f2 | tr -d ' ') - efibootmgr --bootorder "$bootnum,$current_order" --quiet - info "ZFSBootMenu set as primary boot option" - fi - - info "ZFSBootMenu configuration complete." -} - -############################# -# ZFS Services -############################# - -configure_zfs_services() { - step "Configuring ZFS Services" - - arch-chroot /mnt systemctl enable zfs.target - arch-chroot /mnt systemctl disable zfs-import-cache.service - arch-chroot /mnt systemctl enable zfs-import-scan.service - arch-chroot /mnt systemctl enable zfs-mount.service - arch-chroot /mnt systemctl enable zfs-import.target - - # Disable cachefile - we use zfs-import-scan - zpool set cachefile=none "$POOL_NAME" - rm -f /mnt/etc/zfs/zpool.cache - - info "ZFS services configured." -} - -############################# -# Pacman Snapshot Hook -############################# - -configure_zfs_pacman_hook() { - step "Configuring Pacman Snapshot Hook" - - mkdir -p /mnt/etc/pacman.d/hooks - - cat > /mnt/etc/pacman.d/hooks/zfs-snapshot.hook << EOF -[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 -EOF - - cat > /mnt/usr/local/bin/zfs-pre-snapshot << 'EOF' -#!/bin/bash -POOL="zroot" -DATASET="$POOL/ROOT/default" -LOCKFILE="/run/zfs-pre-snapshot.lock" -MIN_INTERVAL=60 - -# Dedup bursts of back-to-back pacman transactions (e.g. archsetup runs) -# into a single snapshot. Lockfile on tmpfs — clears on reboot. -if [ -f "$LOCKFILE" ]; then - last=$(stat -c %Y "$LOCKFILE" 2>/dev/null || echo 0) - now=$(date +%s) - if (( now - last < MIN_INTERVAL )); then - exit 0 - fi -fi - -TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S) -SNAPSHOT_NAME="pre-pacman_$TIMESTAMP" - -if zfs snapshot "$DATASET@$SNAPSHOT_NAME"; then - echo "Created snapshot: $DATASET@$SNAPSHOT_NAME" - touch "$LOCKFILE" -else - echo "Warning: Failed to create snapshot" >&2 -fi -EOF - - chmod +x /mnt/usr/local/bin/zfs-pre-snapshot - info "Pacman hook configured." -} - -############################# -# ZFS Tools -############################# - -install_zfs_tools() { - step "Installing ZFS Management Tools" - - # Copy ZFS management scripts - cp /usr/local/bin/zfssnapshot /mnt/usr/local/bin/zfssnapshot - cp /usr/local/bin/zfsrollback /mnt/usr/local/bin/zfsrollback - chmod +x /mnt/usr/local/bin/zfssnapshot - chmod +x /mnt/usr/local/bin/zfsrollback - - info "ZFS management scripts installed: zfssnapshot, zfsrollback" -} - -############################# -# EFI Sync (Multi-disk) -############################# - -sync_zfs_efi_partitions() { - local efi_parts=() - for disk in "${SELECTED_DISKS[@]}"; do - efi_parts+=("$(get_efi_partition "$disk")") - done - - # Skip if only one disk - [[ ${#efi_parts[@]} -le 1 ]] && return - - step "Syncing EFI partitions for redundancy" - - for ((i=1; i<${#efi_parts[@]}; i++)); do - local secondary="${efi_parts[$i]}" - local tmp_mount="/tmp/efi_sync_$$" - - mkdir -p "$tmp_mount" - mount "$secondary" "$tmp_mount" - rsync -a /mnt/efi/ "$tmp_mount/" - umount "$tmp_mount" - rmdir "$tmp_mount" - - info "Synced EFI to $secondary" - done -} - -############################# -# Genesis Snapshot -############################# - -create_zfs_genesis_snapshot() { - step "Creating Genesis Snapshot" - - local snapshot_name="genesis" - zfs snapshot -r "$POOL_NAME@$snapshot_name" - - info "Genesis snapshot created: $POOL_NAME@$snapshot_name" - info "You can restore to this point anytime with: zfsrollback $snapshot_name" -} - -############################# -# ZFS Cleanup -############################# - -zfs_cleanup() { - step "Cleaning up ZFS" - - # Unmount all ZFS datasets - zfs unmount -a 2>/dev/null || true - - # Unmount EFI - umount /mnt/efi 2>/dev/null || true - - # Export pool (important for clean import on boot) - zpool export "$POOL_NAME" - - info "ZFS pool exported cleanly." -} -- cgit v1.2.3