From f92712541d415450d8db972f09e52577dc3edbbb Mon Sep 17 00:00:00 2001 From: Alan Sikora Date: Sun, 8 Mar 2026 20:39:33 -0300 Subject: [PATCH 1/8] Unmount FUSE filesystems before suspend/hibernate to prevent silent failures --- bin/omarchy-hibernation-setup | 3 +++ default/systemd/system-sleep/unmount-fuse | 14 ++++++++++++++ migrations/1773012889.sh | 4 ++++ 3 files changed, 21 insertions(+) create mode 100755 default/systemd/system-sleep/unmount-fuse create mode 100644 migrations/1773012889.sh diff --git a/bin/omarchy-hibernation-setup b/bin/omarchy-hibernation-setup index da4629df..a70ec2b1 100755 --- a/bin/omarchy-hibernation-setup +++ b/bin/omarchy-hibernation-setup @@ -66,6 +66,9 @@ echo "HOOKS+=(resume)" | sudo tee "$MKINITCPIO_CONF" >/dev/null # Ensure keyboard backlight doesn't prevent sleep sudo cp -p "$OMARCHY_PATH/default/systemd/system-sleep/keyboard-backlight" /usr/lib/systemd/system-sleep/ +# Ensure FUSE mounts don't prevent sleep +sudo cp -p "$OMARCHY_PATH/default/systemd/system-sleep/unmount-fuse" /usr/lib/systemd/system-sleep/ + # Add resume= kernel parameters so the initramfs resume hook knows where to find the # hibernation image. Without these, resume happens late (after GPU drivers load) and fails. RESUME_DROP_IN="/etc/limine-entry-tool.d/resume.conf" diff --git a/default/systemd/system-sleep/unmount-fuse b/default/systemd/system-sleep/unmount-fuse new file mode 100755 index 00000000..6b8654e6 --- /dev/null +++ b/default/systemd/system-sleep/unmount-fuse @@ -0,0 +1,14 @@ +#!/bin/bash + +# Lazy-unmount all FUSE filesystems before suspend/hibernate to prevent the +# kernel's process freeze from timing out. FUSE daemons (like gvfsd-fuse from +# Nautilus) can block in uninterruptible sleep during freeze, causing suspend +# to silently fail. The FUSE daemons restart automatically on wake. + +if [[ $1 == "pre" ]]; then + while IFS=' ' read -r _ mountpoint _ fstype _; do + if [[ $fstype == fuse.* ]]; then + fusermount3 -uz "$mountpoint" 2>/dev/null || fusermount -uz "$mountpoint" 2>/dev/null || true + fi + done < /proc/mounts +fi diff --git a/migrations/1773012889.sh b/migrations/1773012889.sh new file mode 100644 index 00000000..ba96067c --- /dev/null +++ b/migrations/1773012889.sh @@ -0,0 +1,4 @@ +echo "Install system-sleep hook to unmount FUSE before suspend/hibernate" + +sudo mkdir -p /usr/lib/systemd/system-sleep +sudo cp -p "$OMARCHY_PATH/default/systemd/system-sleep/unmount-fuse" /usr/lib/systemd/system-sleep/ From 505c15e624b2b57d240aaf720108f0b2560ff541 Mon Sep 17 00:00:00 2001 From: Alan Sikora Date: Sun, 8 Mar 2026 20:46:11 -0300 Subject: [PATCH 2/8] Fix field parsing in unmount-fuse hook The read command had an extra _ placeholder that was swallowing the fstype field, causing the fuse.* pattern to never match. --- default/systemd/system-sleep/unmount-fuse | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default/systemd/system-sleep/unmount-fuse b/default/systemd/system-sleep/unmount-fuse index 6b8654e6..46cd0118 100755 --- a/default/systemd/system-sleep/unmount-fuse +++ b/default/systemd/system-sleep/unmount-fuse @@ -6,7 +6,7 @@ # to silently fail. The FUSE daemons restart automatically on wake. if [[ $1 == "pre" ]]; then - while IFS=' ' read -r _ mountpoint _ fstype _; do + while IFS=' ' read -r _ mountpoint fstype _; do if [[ $fstype == fuse.* ]]; then fusermount3 -uz "$mountpoint" 2>/dev/null || fusermount -uz "$mountpoint" 2>/dev/null || true fi From 24ca8e2bffdb4ccc3d900603cad4130775271ba5 Mon Sep 17 00:00:00 2001 From: Alan Sikora Date: Sun, 8 Mar 2026 20:58:56 -0300 Subject: [PATCH 3/8] Restart gvfs after wake to restore FUSE mount gvfsd-fuse is spawned by gvfsd during init and not respawned if it dies. After lazy-unmounting in pre-sleep, restart gvfs-daemon.service in post-sleep so the FUSE mount at /run/user/*/gvfs is restored. --- default/systemd/system-sleep/unmount-fuse | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/default/systemd/system-sleep/unmount-fuse b/default/systemd/system-sleep/unmount-fuse index 46cd0118..c15fddf0 100755 --- a/default/systemd/system-sleep/unmount-fuse +++ b/default/systemd/system-sleep/unmount-fuse @@ -3,7 +3,7 @@ # Lazy-unmount all FUSE filesystems before suspend/hibernate to prevent the # kernel's process freeze from timing out. FUSE daemons (like gvfsd-fuse from # Nautilus) can block in uninterruptible sleep during freeze, causing suspend -# to silently fail. The FUSE daemons restart automatically on wake. +# to silently fail. After wake, restart gvfs so the FUSE mount is restored. if [[ $1 == "pre" ]]; then while IFS=' ' read -r _ mountpoint fstype _; do @@ -12,3 +12,15 @@ if [[ $1 == "pre" ]]; then fi done < /proc/mounts fi + +if [[ $1 == "post" ]]; then + for uid_dir in /run/user/*; do + uid=$(basename "$uid_dir") + if [[ -S $uid_dir/bus ]]; then + sudo -u "#$uid" \ + DBUS_SESSION_BUS_ADDRESS="unix:path=$uid_dir/bus" \ + XDG_RUNTIME_DIR="$uid_dir" \ + systemctl --user restart gvfs-daemon.service 2>/dev/null || true + fi + done +fi From a89c4f849dff474b9612221df69f00ec76e81775 Mon Sep 17 00:00:00 2001 From: Alan Sikora Date: Sun, 8 Mar 2026 22:30:56 -0300 Subject: [PATCH 4/8] Use install instead of cp -p to ensure root ownership of sleep hook cp -p preserves the original user ownership from ~/.local/share/omarchy, which would allow an unprivileged user to modify a script that runs as root during suspend/hibernate. --- bin/omarchy-hibernation-setup | 2 +- migrations/1773012889.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/omarchy-hibernation-setup b/bin/omarchy-hibernation-setup index a70ec2b1..4714bbce 100755 --- a/bin/omarchy-hibernation-setup +++ b/bin/omarchy-hibernation-setup @@ -67,7 +67,7 @@ echo "HOOKS+=(resume)" | sudo tee "$MKINITCPIO_CONF" >/dev/null sudo cp -p "$OMARCHY_PATH/default/systemd/system-sleep/keyboard-backlight" /usr/lib/systemd/system-sleep/ # Ensure FUSE mounts don't prevent sleep -sudo cp -p "$OMARCHY_PATH/default/systemd/system-sleep/unmount-fuse" /usr/lib/systemd/system-sleep/ +sudo install -m 0755 -o root -g root "$OMARCHY_PATH/default/systemd/system-sleep/unmount-fuse" /usr/lib/systemd/system-sleep/ # Add resume= kernel parameters so the initramfs resume hook knows where to find the # hibernation image. Without these, resume happens late (after GPU drivers load) and fails. diff --git a/migrations/1773012889.sh b/migrations/1773012889.sh index ba96067c..585df7e0 100644 --- a/migrations/1773012889.sh +++ b/migrations/1773012889.sh @@ -1,4 +1,4 @@ echo "Install system-sleep hook to unmount FUSE before suspend/hibernate" sudo mkdir -p /usr/lib/systemd/system-sleep -sudo cp -p "$OMARCHY_PATH/default/systemd/system-sleep/unmount-fuse" /usr/lib/systemd/system-sleep/ +sudo install -m 0755 -o root -g root "$OMARCHY_PATH/default/systemd/system-sleep/unmount-fuse" /usr/lib/systemd/system-sleep/ From e490ca7d78279935197f77e2c9e10245e2268601 Mon Sep 17 00:00:00 2001 From: Alan Sikora Date: Sun, 8 Mar 2026 23:14:40 -0300 Subject: [PATCH 5/8] Background gvfs restart to avoid blocking user.slice thaw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The post-sleep hook runs before systemd thaws user.slice, so a synchronous systemctl --user restart hangs for ~90 seconds waiting for the frozen user manager to respond — blocking the entire resume. Background the restart with a short delay so it executes after user.slice is thawed. Co-Authored-By: Claude Opus 4.6 --- default/systemd/system-sleep/unmount-fuse | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/default/systemd/system-sleep/unmount-fuse b/default/systemd/system-sleep/unmount-fuse index c15fddf0..64444c1d 100755 --- a/default/systemd/system-sleep/unmount-fuse +++ b/default/systemd/system-sleep/unmount-fuse @@ -14,13 +14,18 @@ if [[ $1 == "pre" ]]; then fi if [[ $1 == "post" ]]; then - for uid_dir in /run/user/*; do - uid=$(basename "$uid_dir") - if [[ -S $uid_dir/bus ]]; then - sudo -u "#$uid" \ - DBUS_SESSION_BUS_ADDRESS="unix:path=$uid_dir/bus" \ - XDG_RUNTIME_DIR="$uid_dir" \ - systemctl --user restart gvfs-daemon.service 2>/dev/null || true - fi - done + # Run in background — user.slice is still frozen at this point, so a + # synchronous restart would block the thaw for up to 90 seconds. + ( + sleep 5 + for uid_dir in /run/user/*; do + uid=$(basename "$uid_dir") + if [[ -S $uid_dir/bus ]]; then + sudo -u "#$uid" \ + DBUS_SESSION_BUS_ADDRESS="unix:path=$uid_dir/bus" \ + XDG_RUNTIME_DIR="$uid_dir" \ + systemctl --user restart gvfs-daemon.service 2>/dev/null || true + fi + done + ) & fi From cce8d878ec399ae97b81ef6ca19907d2a1723903 Mon Sep 17 00:00:00 2001 From: Alan Sikora Date: Sun, 8 Mar 2026 23:42:01 -0300 Subject: [PATCH 6/8] Decode octal-escaped mountpoints and disown backgrounded restart /proc/mounts uses octal escaping for special characters (e.g. \040 for spaces). Decode with printf before passing to fusermount so paths with spaces are handled correctly. Add disown after backgrounding the gvfs restart so it survives systemd-sleep's cgroup cleanup when the hook script exits. --- default/systemd/system-sleep/unmount-fuse | 2 ++ 1 file changed, 2 insertions(+) diff --git a/default/systemd/system-sleep/unmount-fuse b/default/systemd/system-sleep/unmount-fuse index 64444c1d..125f4cc8 100755 --- a/default/systemd/system-sleep/unmount-fuse +++ b/default/systemd/system-sleep/unmount-fuse @@ -8,6 +8,7 @@ if [[ $1 == "pre" ]]; then while IFS=' ' read -r _ mountpoint fstype _; do if [[ $fstype == fuse.* ]]; then + mountpoint=$(printf '%b' "$mountpoint") fusermount3 -uz "$mountpoint" 2>/dev/null || fusermount -uz "$mountpoint" 2>/dev/null || true fi done < /proc/mounts @@ -28,4 +29,5 @@ if [[ $1 == "post" ]]; then fi done ) & + disown fi From a3839551e382e8d62c2be96e5481d2f7e88230ce Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Mon, 9 Mar 2026 15:28:20 +0100 Subject: [PATCH 7/8] Restrict FUSE unmount to gvfsd-fuse Unmounting all FUSE filesystems breaks xdg-document-portal and AppImages that rely on FUSE to stay mounted. It also doesn't restart them. --- bin/omarchy-hibernation-setup | 2 +- default/systemd/system-sleep/unmount-fuse | 6 +++--- migrations/1773012889.sh | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bin/omarchy-hibernation-setup b/bin/omarchy-hibernation-setup index 4714bbce..0eba2487 100755 --- a/bin/omarchy-hibernation-setup +++ b/bin/omarchy-hibernation-setup @@ -66,7 +66,7 @@ echo "HOOKS+=(resume)" | sudo tee "$MKINITCPIO_CONF" >/dev/null # Ensure keyboard backlight doesn't prevent sleep sudo cp -p "$OMARCHY_PATH/default/systemd/system-sleep/keyboard-backlight" /usr/lib/systemd/system-sleep/ -# Ensure FUSE mounts don't prevent sleep +# Ensure gvfsd-fuse mounts don't prevent sleep sudo install -m 0755 -o root -g root "$OMARCHY_PATH/default/systemd/system-sleep/unmount-fuse" /usr/lib/systemd/system-sleep/ # Add resume= kernel parameters so the initramfs resume hook knows where to find the diff --git a/default/systemd/system-sleep/unmount-fuse b/default/systemd/system-sleep/unmount-fuse index 125f4cc8..54a4206d 100755 --- a/default/systemd/system-sleep/unmount-fuse +++ b/default/systemd/system-sleep/unmount-fuse @@ -1,13 +1,13 @@ #!/bin/bash -# Lazy-unmount all FUSE filesystems before suspend/hibernate to prevent the +# Lazy-unmount gvfsd-fuse filesystems before suspend/hibernate to prevent the # kernel's process freeze from timing out. FUSE daemons (like gvfsd-fuse from # Nautilus) can block in uninterruptible sleep during freeze, causing suspend # to silently fail. After wake, restart gvfs so the FUSE mount is restored. if [[ $1 == "pre" ]]; then while IFS=' ' read -r _ mountpoint fstype _; do - if [[ $fstype == fuse.* ]]; then + if [[ $fstype == fuse.gvfsd-fuse ]]; then mountpoint=$(printf '%b' "$mountpoint") fusermount3 -uz "$mountpoint" 2>/dev/null || fusermount -uz "$mountpoint" 2>/dev/null || true fi @@ -22,7 +22,7 @@ if [[ $1 == "post" ]]; then for uid_dir in /run/user/*; do uid=$(basename "$uid_dir") if [[ -S $uid_dir/bus ]]; then - sudo -u "#$uid" \ + sudo -u "#$uid" env \ DBUS_SESSION_BUS_ADDRESS="unix:path=$uid_dir/bus" \ XDG_RUNTIME_DIR="$uid_dir" \ systemctl --user restart gvfs-daemon.service 2>/dev/null || true diff --git a/migrations/1773012889.sh b/migrations/1773012889.sh index 585df7e0..d8dd1619 100644 --- a/migrations/1773012889.sh +++ b/migrations/1773012889.sh @@ -1,4 +1,4 @@ -echo "Install system-sleep hook to unmount FUSE before suspend/hibernate" +echo "Install system-sleep hook to unmount gvfsd-fuse before suspend/hibernate" sudo mkdir -p /usr/lib/systemd/system-sleep sudo install -m 0755 -o root -g root "$OMARCHY_PATH/default/systemd/system-sleep/unmount-fuse" /usr/lib/systemd/system-sleep/ From dd86a893cb513f78eb93f047231c7128b6596339 Mon Sep 17 00:00:00 2001 From: Alan Sikora Date: Mon, 9 Mar 2026 16:36:14 -0300 Subject: [PATCH 8/8] Move FUSE unmount hook to its own installer The hook prevents gvfsd-fuse from blocking suspend, not just hibernation. Install it during the config phase so every system gets it, not only those that run hibernation setup. --- bin/omarchy-hibernation-setup | 3 --- install/config/all.sh | 1 + install/config/unmount-fuse.sh | 2 ++ 3 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 install/config/unmount-fuse.sh diff --git a/bin/omarchy-hibernation-setup b/bin/omarchy-hibernation-setup index 0eba2487..da4629df 100755 --- a/bin/omarchy-hibernation-setup +++ b/bin/omarchy-hibernation-setup @@ -66,9 +66,6 @@ echo "HOOKS+=(resume)" | sudo tee "$MKINITCPIO_CONF" >/dev/null # Ensure keyboard backlight doesn't prevent sleep sudo cp -p "$OMARCHY_PATH/default/systemd/system-sleep/keyboard-backlight" /usr/lib/systemd/system-sleep/ -# Ensure gvfsd-fuse mounts don't prevent sleep -sudo install -m 0755 -o root -g root "$OMARCHY_PATH/default/systemd/system-sleep/unmount-fuse" /usr/lib/systemd/system-sleep/ - # Add resume= kernel parameters so the initramfs resume hook knows where to find the # hibernation image. Without these, resume happens late (after GPU drivers load) and fails. RESUME_DROP_IN="/etc/limine-entry-tool.d/resume.conf" diff --git a/install/config/all.sh b/install/config/all.sh index 14480206..830abbb0 100644 --- a/install/config/all.sh +++ b/install/config/all.sh @@ -18,6 +18,7 @@ run_logged $OMARCHY_INSTALL/config/remove-fcitx5-autostart.sh run_logged $OMARCHY_INSTALL/config/localdb.sh run_logged $OMARCHY_INSTALL/config/walker-elephant.sh run_logged $OMARCHY_INSTALL/config/fast-shutdown.sh +run_logged $OMARCHY_INSTALL/config/unmount-fuse.sh run_logged $OMARCHY_INSTALL/config/sudoless-asdcontrol.sh run_logged $OMARCHY_INSTALL/config/input-group.sh run_logged $OMARCHY_INSTALL/config/makima.sh diff --git a/install/config/unmount-fuse.sh b/install/config/unmount-fuse.sh new file mode 100644 index 00000000..9c44e17f --- /dev/null +++ b/install/config/unmount-fuse.sh @@ -0,0 +1,2 @@ +sudo mkdir -p /usr/lib/systemd/system-sleep +sudo install -m 0755 -o root -g root "$OMARCHY_PATH/default/systemd/system-sleep/unmount-fuse" /usr/lib/systemd/system-sleep/