From 64260df38906e68b3d75169b8cae3b69715f5bc6 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 12 Apr 2026 22:55:02 -0400 Subject: fix: drop zroot/tmp dataset and dedup pacman snapshot hook - /tmp on ZFS breaks systemd-tmpfiles-clean (statx ENOLINK on PrivateTmp paths). Use tmpfs via fstab instead; keep zroot/var/tmp. - zfs-pre-snapshot gains a 60s lockfile in /run so burst transactions (archsetup produced 357 snapshots in one run) collapse to one. Both fixes mirrored in installer/archangel and installer/lib/zfs.sh. Already applied and verified on velox. --- installer/archangel | 30 +++++++++++++++++++++++++----- installer/lib/zfs.sh | 24 +++++++++++++++++++++--- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/installer/archangel b/installer/archangel index 814f12b..9c6da97 100755 --- a/installer/archangel +++ b/installer/archangel @@ -893,10 +893,14 @@ create_datasets() { zfs create -o mountpoint=/var/lib/pacman "$POOL_NAME/var/lib/pacman" zfs create -o mountpoint=/var/lib/docker "$POOL_NAME/var/lib/docker" - # Temp directories - excluded from snapshots + # /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" - zfs create -o mountpoint=/tmp -o com.sun:auto-snapshot=false "$POOL_NAME/tmp" - chmod 1777 /mnt/tmp /mnt/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 @@ -1003,10 +1007,13 @@ install_base_btrfs() { configure_system() { step "Configuring System" - # fstab (only for EFI - /boot is on ZFS root) + # fstab (EFI + tmpfs /tmp; /boot is on ZFS root) info "Generating fstab..." echo "# /efi - EFI System Partition (ZFSBootMenu binary)" > /mnt/etc/fstab echo "UUID=$(blkid -s UUID -o value "${EFI_PARTS[0]}") /efi vfat defaults,noatime 0 2" >> /mnt/etc/fstab + echo "" >> /mnt/etc/fstab + echo "# /tmp - tmpfs (avoids ZFS statx ENOLINK on systemd PrivateTmp paths)" >> /mnt/etc/fstab + echo "tmpfs /tmp tmpfs defaults,nosuid,nodev,mode=1777 0 0" >> /mnt/etc/fstab # Timezone info "Setting timezone to $TIMEZONE..." @@ -1318,15 +1325,28 @@ 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 diff --git a/installer/lib/zfs.sh b/installer/lib/zfs.sh index feda91d..bf8af35 100644 --- a/installer/lib/zfs.sh +++ b/installer/lib/zfs.sh @@ -133,10 +133,14 @@ create_zfs_datasets() { zfs create -o mountpoint=/var/lib/pacman "$POOL_NAME/var/lib/pacman" zfs create -o mountpoint=/var/lib/docker "$POOL_NAME/var/lib/docker" - # Temp directories - excluded from snapshots + # /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" - zfs create -o mountpoint=/tmp -o com.sun:auto-snapshot=false "$POOL_NAME/tmp" - chmod 1777 /mnt/tmp /mnt/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 @@ -266,11 +270,25 @@ 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 -- cgit v1.2.3