Proof Portal

Project overview

Omarchy

ProbeLabs65 findings · 95 requirements

A proof layer — requirements, tests and verified fixes — for two of Omarchy's subsystems: the application menu (launcher scripts, QML model, JSONC config, search and selection) and the lock screen (lock scripts, QML, PAM authentication). Scope is deliberately limited to those components of omacom/omarchy; the rest of the distribution is not covered.

Inbox
ReportR-908GitHub issuePublicDecided· Out of scope

SMB shares stop opening in file manager after suspend/resume — gvfs FUSE remount hook killed by suspend cgroup

Reported by IanTeda · filed Sep 6, 2026 · open at source

Decided: Out of scope — decided by agents · verified 3 days ago.

At a glance

1 · What is claimed?
Only the report text below — no validator has restated it as checkable claims yet.
2 · What does it affect?
AreaOutside the audited area· Decided by agents · verified
3 · Is it reproducible?
No validation has been run yet.
4 · What remains unclear?
  • Not validated yet: no claims, no reproducer.
5 · What happens next?
Decided by agents and verified by a second, independent agent — see the decision.

Original report

SMB shares stop opening in file manager after suspend/resume — gvfs FUSE remount hook killed by suspend cgrouprevision 1 · captured 2026-09-28 21:23 UTC via poll

What happened

After the system suspends and resumes (even once), SMB shares mounted via gvfsd-smb become unusable in the file manager: Nautilus still lists/browses the share fine (it talks to gvfsd over D-Bus), but double-clicking a file to open it with an external app fails, because the GVfs FUSE path (/run/user/$UID/gvfs/smb-share:...) that apps use to get a real filesystem path no longer exists.

What was expected

/usr/lib/systemd/system-sleep/unmount-fuse is supposed to handle exactly this: unmount the FUSE bridge before sleep (to stop it blocking the freezer) and restart gvfs-daemon.service after resume so the FUSE bridge comes back. After resume, SMB files should still open normally.

Root cause

The pre-suspend half of the hook works every time (fusermount3 -uz on any fuse.gvfsd-fuse mount succeeds).

The post-resume half does not reliably run. It's implemented as:

(
  sleep 5
  for uid_dir in /run/user/*; do
    ...
    systemctl --user restart gvfs-daemon.service
    ...
  done
) &

This background job is a child process still inside the cgroup of systemd-suspend.service (and the hibernate/hybrid-sleep/suspend-then-hibernate equivalents). Those units run with KillMode=control-group:

$ systemctl show systemd-suspend.service -p KillMode
KillMode=control-group

so the moment the sleep hook script returns (which happens immediately after backgrounding the job with &), systemd tears down the unit's cgroup and kills the still-sleeping backgrounded job before the 5-second delay elapses and before systemctl --user restart gvfs-daemon.service ever runs.

Observed on my machine: gvfsd had the same PID since boot despite 5 suspend/resume cycles that day. Running the exact systemctl --user restart gvfs-daemon.service invocation from the hook manually (outside the suspend cgroup) fixed it instantly — a fresh gvfsd and gvfsd-fuse spawned and the FUSE mount reappeared under /run/user/$UID/gvfs/.

Steps to reproduce

  1. Mount an SMB share via the file manager (smb://server/share) so it shows up in gio mount -l.
  2. Suspend and resume the laptop (systemctl suspend or lid close/open).
  3. Check ls /run/user/$UID/gvfs/ — the FUSE mount for the share is gone, and ps aux | grep gvfsd-fuse shows no process, even though gio mount -l / Nautilus still report the share as mounted.
  4. Try to open a file from that share in Nautilus with an external app — it fails.

Suggested fix

Escape the cgroup instead of relying on a backgrounded subshell surviving past the hook's return, e.g. schedule the delayed restart as its own transient unit via systemd-run (system-level, targeting the user's session bus), which is not part of systemd-suspend.service's cgroup and survives the freezer/thaw:

systemd-run --uid="$uid" --quiet \
  --setenv=DBUS_SESSION_BUS_ADDRESS="unix:path=$uid_dir/bus" \
  --setenv=XDG_RUNTIME_DIR="$uid_dir" \
  /bin/bash -c 'sleep 5; systemctl --user restart gvfs-daemon.service'

Happy to open a PR with this change if useful.

System details

  • Omarchy: 4.0.2-1
  • Kernel: 7.1.9-arch1-2 (x86_64)
  • Desktop: Hyprland 0.56.2, display manager SDDM
  • Machine: Lenovo ThinkPad T480s
  • systemd: 261 (261.2-1-arch)
  • Packages: gvfs 1.60.2-1, gvfs-smb 1.60.2-1, cifs-utils 7.5-1, nautilus 50.2.2-1

Full omarchy debug --no-sudo --print output available on request.

View raw text
## What happened

After the system suspends and resumes (even once), SMB shares mounted via `gvfsd-smb` become unusable in the file manager: Nautilus still lists/browses the share fine (it talks to `gvfsd` over D-Bus), but double-clicking a file to open it with an external app fails, because the GVfs FUSE path (`/run/user/$UID/gvfs/smb-share:...`) that apps use to get a real filesystem path no longer exists.

## What was expected

`/usr/lib/systemd/system-sleep/unmount-fuse` is supposed to handle exactly this: unmount the FUSE bridge before sleep (to stop it blocking the freezer) and restart `gvfs-daemon.service` after resume so the FUSE bridge comes back. After resume, SMB files should still open normally.

## Root cause

The **pre**-suspend half of the hook works every time (`fusermount3 -uz` on any `fuse.gvfsd-fuse` mount succeeds).

The **post**-resume half does not reliably run. It's implemented as:

```bash
(
  sleep 5
  for uid_dir in /run/user/*; do
    ...
    systemctl --user restart gvfs-daemon.service
    ...
  done
) &
```

This background job is a child process still inside the cgroup of `systemd-suspend.service` (and the hibernate/hybrid-sleep/suspend-then-hibernate equivalents). Those units run with `KillMode=control-group`:

```
$ systemctl show systemd-suspend.service -p KillMode
KillMode=control-group
```

so the moment the sleep hook script returns (which happens immediately after backgrounding the job with `&`), systemd tears down the unit's cgroup and kills the still-sleeping backgrounded job before the 5-second delay elapses and before `systemctl --user restart gvfs-daemon.service` ever runs.

Observed on my machine: `gvfsd` had the same PID since boot despite 5 suspend/resume cycles that day. Running the exact `systemctl --user restart gvfs-daemon.service` invocation from the hook manually (outside the suspend cgroup) fixed it instantly — a fresh `gvfsd` and `gvfsd-fuse` spawned and the FUSE mount reappeared under `/run/user/$UID/gvfs/`.

## Steps to reproduce

1. Mount an SMB share via the file manager (`smb://server/share`) so it shows up in `gio mount -l`.
2. Suspend and resume the laptop (`systemctl suspend` or lid close/open).
3. Check `ls /run/user/$UID/gvfs/` — the FUSE mount for the share is gone, and `ps aux | grep gvfsd-fuse` shows no process, even though `gio mount -l` / Nautilus still report the share as mounted.
4. Try to open a file from that share in Nautilus with an external app — it fails.

## Suggested fix

Escape the cgroup instead of relying on a backgrounded subshell surviving past the hook's return, e.g. schedule the delayed restart as its own transient unit via `systemd-run` (system-level, targeting the user's session bus), which is not part of `systemd-suspend.service`'s cgroup and survives the freezer/thaw:

```bash
systemd-run --uid="$uid" --quiet \
  --setenv=DBUS_SESSION_BUS_ADDRESS="unix:path=$uid_dir/bus" \
  --setenv=XDG_RUNTIME_DIR="$uid_dir" \
  /bin/bash -c 'sleep 5; systemctl --user restart gvfs-daemon.service'
```

Happy to open a PR with this change if useful.

## System details

- Omarchy: 4.0.2-1
- Kernel: 7.1.9-arch1-2 (x86_64)
- Desktop: Hyprland 0.56.2, display manager SDDM
- Machine: Lenovo ThinkPad T480s
- systemd: 261 (261.2-1-arch)
- Packages: `gvfs 1.60.2-1`, `gvfs-smb 1.60.2-1`, `cifs-utils 7.5-1`, `nautilus 50.2.2-1`

Full `omarchy debug --no-sudo --print` output available on request.

Validation

Not checked yet. A validator will restate this report as checkable claims, map it to the project's requirements and write a reproducer that the proof engine runs.

Linked

Not linked to any known issue, other report or change yet.

Decision

Decisions are recorded by our staff — or, where this project allows it, by agents: checked by a second, independent agent, or by a single agent where the project's policy says so. Any decision reached so far is shown below.

  • Out of scopeDecided by agents · verified · 2026-10-09 10:56 UTC