From 3bf2ce07182cf9dfd6504299ba35175aaab37b6c Mon Sep 17 00:00:00 2001 From: DragonSlayer_14 Date: Sun, 20 Sep 2026 22:31:03 +0200 Subject: [PATCH] Fix: Paketinstallation blockiert nicht mehr synchron auf smart-mount-mount.service MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'systemctl enable --now smart-mount-mount.service' im postinst/RPM- Scriptlet wartete synchron auf den kompletten 'mount --all'-Lauf - bei nicht erreichbaren Laufwerken (Netzwerk-Timeouts pro Paar) blieb 'apt'/'dpkg'/'pacman' dadurch minutenlang ohne sichtbare Rückmeldung hängen (Logs gehen ins Journal, nicht ins Paketmanager-Terminal). Jetzt: 'systemctl enable' + 'systemctl start --no-block' für den Mount-Service (stößt den ersten Mount-Versuch nur an, wartet nicht darauf), 'enable --now' bleibt für den Watch-Timer (Timer "armen" ist immer sofort fertig). scripts/package-arch.py unterscheidet das generisch anhand der Dateiendung (.timer vs. .service), ohne den Anwendungsnamen hart zu codieren. Zusätzlich TimeoutStartSec=600 im Unit-File als Obergrenze gegen echte Hänger. Co-Authored-By: Claude Sonnet 5 --- Cargo.toml | 8 ++++++- README.md | 12 +++++++--- packaging/deb/postinst | 10 +++++++- packaging/systemd/smart-mount-mount.service | 8 +++++++ scripts/package-arch.py | 26 ++++++++++++++------- 5 files changed, 51 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 39b1bc3..c3b35d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,7 +110,13 @@ suggests = { "davfs2" = "*", "cifs-utils" = "*", "nfs-utils" = "*" } post_install_script = """ if command -v systemctl >/dev/null 2>&1; then systemctl daemon-reload || true - systemctl enable --now smart-mount-mount.service smart-mount-watch.timer || true + # smart-mount-mount.service mountet echte Netzlaufwerke (kann bei nicht erreichbaren + # Servern pro Paar mehrere zehn Sekunden dauern) - "enable --now" wuerde synchron darauf + # warten und damit die Paketinstallation blockieren, daher aktivieren + nur als + # asynchroner Job starten ("--no-block", kehrt sofort zurueck). + systemctl enable smart-mount-mount.service || true + systemctl start --no-block smart-mount-mount.service || true + systemctl enable --now smart-mount-watch.timer || true fi /usr/lib/smart-mount/setup-cron || true """ diff --git a/README.md b/README.md index 57b91d5..43f0b98 100644 --- a/README.md +++ b/README.md @@ -145,13 +145,19 @@ System-systemd-Dienst ein - kein manueller Schritt nötig. Die dafür paketierte `smart-mount watch` aufruft (Standardintervall: 120s). Die postinst/postrm-Skripte des Pakets (bzw. das `.INSTALL`-Skriptlet bei Arch) aktivieren und -starten beide Units beim Installieren/Upgraden (`systemctl enable --now ...`) und deaktivieren -sie wieder beim Deinstallieren (`systemctl disable --now ...`) - siehe `packaging/deb/postinst` -+ `packaging/deb/postrm` bzw. `[package.metadata.generate-rpm]`/`scripts/package-arch.py` in +deaktivieren beide Units beim Installieren/Deinstallieren - siehe `packaging/deb/postinst` + +`packaging/deb/postrm` bzw. `[package.metadata.generate-rpm]`/`scripts/package-arch.py` in `Cargo.toml`. Welche Laufwerkspaare dabei gemountet werden (und für welchen Nutzer, siehe `owner_user` unten) steuert ausschließlich `/etc/smart-mount/config.toml` - nicht die Unit-Dateien selbst. +`smart-mount-mount.service` mountet dabei echte Netzlaufwerke, was bei einem gerade nicht +erreichbaren Server pro Paar mehrere zehn Sekunden dauern kann (begrenzt auf max. 10 Minuten +insgesamt, siehe `TimeoutStartSec` in der Unit) - das Paket-Setup wird dadurch **nicht** +blockiert: `systemctl start --no-block` stößt den ersten Mount-Versuch beim Installieren nur an, +statt synchron auf ihn zu warten. `smart-mount-watch.timer` wird dagegen sofort synchron +gestartet (das Timer-"Armen" selbst ist immer augenblicklich fertig). + **Anderes Watch-Intervall als der Standard (120s):** `settings.watch_interval_secs` in `config.toml` steuert nur den Cron-Fallback (s. u.) - der paketierte Timer hat ein fest eingebautes Intervall. Zum Anpassen: diff --git a/packaging/deb/postinst b/packaging/deb/postinst index 4eda3a2..c24466e 100755 --- a/packaging/deb/postinst +++ b/packaging/deb/postinst @@ -9,7 +9,15 @@ set -e if [ "$1" = "configure" ]; then if command -v systemctl >/dev/null 2>&1; then systemctl daemon-reload || true - systemctl enable --now smart-mount-mount.service smart-mount-watch.timer || true + # smart-mount-mount.service mountet echte Netzlaufwerke (kann pro konfiguriertem Paar + # mehrere zehn Sekunden dauern, wenn ein Server gerade nicht erreichbar ist) - "enable + # --now" wuerde synchron darauf warten und damit "apt"/"dpkg" fuer die gesamte Dauer + # blockieren. Daher: aktivieren (fuer den naechsten Boot) und der eigentliche Mount-Lauf + # nur als asynchroner Job ("--no-block", kehrt sofort zurueck) - das Paket-Setup selbst + # wartet also nie auf Netzwerk-Timeouts. + systemctl enable smart-mount-mount.service || true + systemctl start --no-block smart-mount-mount.service || true + systemctl enable --now smart-mount-watch.timer || true fi /usr/lib/smart-mount/setup-cron || true fi diff --git a/packaging/systemd/smart-mount-mount.service b/packaging/systemd/smart-mount-mount.service index f02f959..e263139 100644 --- a/packaging/systemd/smart-mount-mount.service +++ b/packaging/systemd/smart-mount-mount.service @@ -11,6 +11,14 @@ Type=oneshot # könnte). RemainAfterExit=yes ExecStart=/usr/bin/smart-mount mount --all +# Harte Obergrenze statt des systemd-Standards (üblicherweise 90s): pro konfiguriertem Paar +# werden Erreichbarkeit UND Mount-Versuch sequenziell geprüft (bis zu ~20s Erreichbarkeits- +# check + 30s Mount-Timeout, siehe crate::mount::MOUNT_TIMEOUT_SECS), bei mehreren Paaren +# summiert sich das - 90s würde bei zwei oder mehr gerade nicht erreichbaren Servern schon +# reichen, um mitten im Mount-Versuch abgebrochen zu werden. 10 Minuten sind großzügig genug für +# eine typische Anzahl Paare, ohne bei einem echten Hänger (z. B. einer verwaisten Dateisperre) +# unbegrenzt zu warten. +TimeoutStartSec=600 # Explizit (statt sich auf den systemd-Standard zu verlassen): stdout/stderr gehen ins Journal, # unter einem festen, von der jeweiligen Unit unabhängigen Tag - 'journalctl -t smart-mount' # zeigt damit die Ausgaben aller smart-mount-Units gebündelt. diff --git a/scripts/package-arch.py b/scripts/package-arch.py index 2376a6e..08efcb7 100755 --- a/scripts/package-arch.py +++ b/scripts/package-arch.py @@ -105,16 +105,26 @@ def build_install_scriptlet(name, installable, all_units, has_cron_helper): Cron-Fallback-Hilfsprogramm ('usr/lib//setup-cron', siehe src/bin/setup-cron.rs) beim Installieren/Upgraden auf bzw. entfernt dessen Cron-Datei beim Entfernen wieder. Rein anhand der tatsächlich gefundenen Unit-Dateien/Hilfsprogramme zusammengesetzt, ohne den - Anwendungsnamen selbst hart zu codieren (der als `name`-Parameter hereinkommt).""" - installable_str = " ".join(installable) + Anwendungsnamen selbst hart zu codieren (der als `name`-Parameter hereinkommt). + + '.service'-Units werden bewusst NICHT über 'enable --now' gestartet: Bei einem oneshot- + Service (typischer Fall für ein Boot-Setup-Skript) würde das den ExecStart-Befehl synchron + ausführen und damit 'pacman' für die gesamte Laufzeit des Skripts blockieren (siehe + packaging/deb/postinst für den konkreten Fall, der das erst sichtbar gemacht hat: ein + Mount-Versuch gegen ein gerade nicht erreichbares Netzlaufwerk). '.timer'-Units sind davon + nicht betroffen - sie nur zu "armen" ist immer sofort fertig - und starten daher weiterhin + synchron mit 'enable --now'.""" + timers = [u for u in installable if u.endswith(".timer")] + services = [u for u in installable if not u.endswith(".timer")] all_units_str = " ".join(all_units) - systemd_enable = ( - " systemctl daemon-reload >/dev/null 2>&1 || true\n" - f" systemctl enable --now {installable_str} >/dev/null 2>&1 || true\n" - if installable - else "" - ) + systemd_enable = " systemctl daemon-reload >/dev/null 2>&1 || true\n" if installable else "" + if timers: + systemd_enable += f" systemctl enable --now {' '.join(timers)} >/dev/null 2>&1 || true\n" + for service in services: + systemd_enable += f" systemctl enable {service} >/dev/null 2>&1 || true\n" + systemd_enable += f" systemctl start --no-block {service} >/dev/null 2>&1 || true\n" + systemd_reload = " systemctl daemon-reload >/dev/null 2>&1 || true\n" if all_units else "" systemd_disable = ( f" systemctl disable --now {all_units_str} >/dev/null 2>&1 || true\n" if all_units else ""