From 751165e2012a37aa32c8de3a240706d4a1c16265 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sun, 26 Jul 2026 19:59:37 -0700 Subject: [PATCH] Don't restart a zram device that exists but is swapped off The resize guard reads the Used column for /dev/zram0 out of /proc/swaps and treats a missing row as an empty device, which is right for a device that doesn't exist yet: the restart is what brings it up against the config daemon-reload just generated. A device that exists and is merely swapped off reads the same, and there the restart resets it first, which returns EBUSY for as long as anything still holds it open. That leaves a bare "Job failed. See 'journalctl -xe' for details." in the migration output and falls through to asking for the reboot that would have resized it anyway. Tell the two apart by whether /sys/block/zram0/disksize is there at all. The test modelled an absent device as a blank disksize file, which no longer stands in for one, so it removes the file instead. Co-Authored-By: Claude Opus 5 (1M context) --- migrations/1785094500.sh | 11 ++++++++++- test/shell.d/zram-resize-test.sh | 19 ++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/migrations/1785094500.sh b/migrations/1785094500.sh index d858ab63..36c05a89 100644 --- a/migrations/1785094500.sh +++ b/migrations/1785094500.sh @@ -30,7 +30,16 @@ if sudo systemctl daemon-reload; then # pressure keeps its old size until the next boot. zram_used=$(awk '$1 == "/dev/zram0" {print $4}' "$swaps") - if [[ ${zram_used:-0} == 0 ]] && sudo systemctl restart dev-zram0.swap; then + # No row at all means the device is not swap right now, and that covers two + # unlike situations. A device that doesn't exist yet is the one worth acting + # on: the restart brings it up against the config daemon-reload just picked + # up. A device that exists but is swapped off is not, because the restart + # resets it first, and reset returns EBUSY for as long as anything still + # holds it open. That leaves a "Job failed" from systemd in the migration + # output and still ends up asking for the reboot, so go straight there. + if [[ -n $zram_used || ! -e $zram_disksize ]] && + [[ ${zram_used:-0} == 0 ]] && + sudo systemctl restart dev-zram0.swap; then exit 0 fi fi diff --git a/test/shell.d/zram-resize-test.sh b/test/shell.d/zram-resize-test.sh index 589c55aa..a71c3800 100644 --- a/test/shell.d/zram-resize-test.sh +++ b/test/shell.d/zram-resize-test.sh @@ -50,7 +50,15 @@ desired_bytes=$((8192 * 1024 * 1024)) run_migration() { local disksize="$1" used="$2" fail_reload="${3:-0}" - printf '%s' "$disksize" >"$TMPDIR/disksize" + # A machine with no zram device has no /sys/block/zram0 at all, so an empty + # size means the file is gone rather than blank; the migration tells those + # two apart now. + if [[ -n $disksize ]]; then + printf '%s' "$disksize" >"$TMPDIR/disksize" + else + rm -f "$TMPDIR/disksize" + fi + printf 'Filename\tType\tSize\tUsed\tPriority\n' >"$TMPDIR/swaps" [[ -n $used ]] && printf '/dev/zram0 partition 8388604 %s 100\n' "$used" >>"$TMPDIR/swaps" @@ -101,6 +109,15 @@ run_migration "" "" did "systemctl restart dev-zram0.swap" || fail "absent device is created" pass "absent device is created" +# A device that exists but is swapped off reads empty too, and there the +# restart resets it, which fails against whatever still holds it open. Nothing +# to gain over the reboot that would have resized it anyway. +run_migration $((4096 * 1024 * 1024)) "" +did "systemctl restart" && fail "swapped-off device is not restarted" +did "omarchy-state set reboot-required" || fail "swapped-off device asks for a reboot" +pass "swapped-off device is not restarted" +pass "swapped-off device asks for a reboot" + # A failed daemon-reload must fall back to asking for a reboot. run_migration $((4096 * 1024 * 1024)) 0 1 did "systemctl restart" && fail "failed reload does not restart"