From dd2bd44bc2ed9aab840cf76a74f175f20a57ddc4 Mon Sep 17 00:00:00 2001 From: Ryan Yin Date: Mon, 2 Nov 2026 00:30:30 +0800 Subject: [PATCH] fix(youko): apply /data tmpfiles in a pass of their own 89d7a9bd made systemd-tmpfiles-setup RequiresMountsFor the five nofail USB-disk mounts. One failed mount then skipped every tmpfiles rule on the host, and sysinit.target waited for the disks and the LUKS unlock even on success. Leave the boot-wide pass as upstream ships it and add data-tmpfiles: `systemd-tmpfiles --prefix=/data` with WantsMountsFor on the /data mounts, ordered before the services that use them. Assisted-by: Claude Code (claude-opus-5-5) --- .../homelab-services/data-tmpfiles.nix | 30 +++++++++++++++++++ .../homelab-services/disko-fs.nix | 12 -------- .../tests/youko-tmpfiles/expected.nix | 9 ++++-- .../tests/youko-tmpfiles/expr.nix | 9 ++++-- 4 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 hosts/12kingdoms-youko/homelab-services/data-tmpfiles.nix diff --git a/hosts/12kingdoms-youko/homelab-services/data-tmpfiles.nix b/hosts/12kingdoms-youko/homelab-services/data-tmpfiles.nix new file mode 100644 index 00000000..d095411d --- /dev/null +++ b/hosts/12kingdoms-youko/homelab-services/data-tmpfiles.nix @@ -0,0 +1,30 @@ +{ config, lib, ... }: +let + consumers = map (n: "${n}.service") [ + "immich-server" + "jellyfin" + "nginx" + "restic-backups-homelab" + "restic-rest-server" + "restic-server-snapshot" + "rustfs" + "sftpgo" + "transmission" + ]; +in +{ + # The nofail /data mounts can finish after systemd-tmpfiles-setup, so apply + # the /data rules again once they are mounted. + systemd.services.data-tmpfiles = { + description = "Create tmpfiles.d entries on the /data mounts"; + wantedBy = [ "multi-user.target" ] ++ consumers; + before = consumers; + unitConfig.WantsMountsFor = lib.filter (lib.hasPrefix "/data/") (lib.attrNames config.fileSystems); + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${config.systemd.package}/bin/systemd-tmpfiles --create --remove --boot --prefix=/data"; + SuccessExitStatus = "DATAERR CANTCREAT"; + }; + }; +} diff --git a/hosts/12kingdoms-youko/homelab-services/disko-fs.nix b/hosts/12kingdoms-youko/homelab-services/disko-fs.nix index 7c9caf77..488d989f 100644 --- a/hosts/12kingdoms-youko/homelab-services/disko-fs.nix +++ b/hosts/12kingdoms-youko/homelab-services/disko-fs.nix @@ -33,18 +33,6 @@ in fileSystems."/data/fileshare/public".depends = [ "/data/fileshare" ]; - # The nofail data mounts finish after local-fs.target. systemd-tmpfiles-setup - # only orders itself after local-fs.target, so without an explicit dependency - # it can run while /data is still the read-only fallback tmpfs and fail to - # create the Transmission, Immich, RustFS and restic directories at boot. - systemd.services.systemd-tmpfiles-setup.unitConfig.RequiresMountsFor = [ - "/data/apps" - "/data/fileshare" - "/data/fileshare/public" - "/data/backups" - "/data/apps-snapshots" - ]; - # By adding this crypttab entry, the disk will be unlocked by systemd-cryptsetup@xxx.service at boot time. # This systemd service is running after agenix, so that the keyfile is already available. environment.etc = { diff --git a/outputs/x86_64-linux/tests/youko-tmpfiles/expected.nix b/outputs/x86_64-linux/tests/youko-tmpfiles/expected.nix index fe7eb1fa..7901abb9 100644 --- a/outputs/x86_64-linux/tests/youko-tmpfiles/expected.nix +++ b/outputs/x86_64-linux/tests/youko-tmpfiles/expected.nix @@ -1,10 +1,15 @@ -{ ... }: +{ outputs, ... }: +let + systemd = outputs.nixosConfigurations.youko.config.systemd.package; +in { - requiresMountsFor = [ + wantsMountsFor = [ "/data/apps" "/data/apps-snapshots" "/data/backups" "/data/fileshare" "/data/fileshare/public" ]; + execStart = "${systemd}/bin/systemd-tmpfiles --create --remove --boot --prefix=/data"; + setupWaitsForData = false; } diff --git a/outputs/x86_64-linux/tests/youko-tmpfiles/expr.nix b/outputs/x86_64-linux/tests/youko-tmpfiles/expr.nix index 421d852e..e6d9c298 100644 --- a/outputs/x86_64-linux/tests/youko-tmpfiles/expr.nix +++ b/outputs/x86_64-linux/tests/youko-tmpfiles/expr.nix @@ -1,11 +1,14 @@ { - lib, outputs, ... }: let - unit = outputs.nixosConfigurations.youko.config.systemd.services.systemd-tmpfiles-setup; + services = outputs.nixosConfigurations.youko.config.systemd.services; + unit = services.data-tmpfiles; in { - requiresMountsFor = builtins.sort builtins.lessThan unit.unitConfig.RequiresMountsFor; + wantsMountsFor = builtins.sort builtins.lessThan unit.unitConfig.WantsMountsFor; + execStart = unit.serviceConfig.ExecStart; + setupWaitsForData = + (services.systemd-tmpfiles-setup or { }).unitConfig.RequiresMountsFor or [ ] != [ ]; }