Skip to content

Remove resume kernel parameters when removing hibernation - #13584

Open
STRd6 wants to merge 3 commits into
omacom:quattrofrom
STRd6:fix/hibernation-remove-resume-dropin
Open

STRd6 wants to merge 3 commits into
omacom:quattrofrom
STRd6:fix/hibernation-remove-resume-dropin

Conversation

@STRd6

@STRd6 STRd6 commented Sep 28, 2026 •

Copy link
Copy Markdown

Fixes #13583

omarchy-hibernation-remove deleted the swapfile and the mkinitcpio resume hook but left /etc/limine-entry-tool.d/resume.conf, so the rebuilt UKI kept resume=/resume_offset= for a swapfile that no longer exists. Because omarchy-hibernation-setup only writes that drop-in when it's absent, setting hibernation up again kept the old offset and resume silently failed. (omarchy-system-factory-reset already works around this same trap.)

  • Remove resume.conf before limine-mkinitcpio runs
  • Add test/shell.d/hibernation-remove-test.sh, which fails without the fix

./test/cli has one failure (vscode generated theme references current theme file), which also fails on quattro without this change.

🤖 Generated with Claude Code

https://claude.ai/code/session_01U2bEgE2TAqMqbeQqZK6jfc

hibernation-setup only writes resume.conf when it is absent, so leaving it
behind pins a later setup to the old swapfile's resume_offset.

Fixes omacom#13583

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U2bEgE2TAqMqbeQqZK6jfc
@llstrk

llstrk commented Sep 28, 2026

Copy link
Copy Markdown

Automated AI review

Community review: Independent automated community review, unaffiliated with the Omarchy team, intended to help prepare PRs for their review.

Outcome: Machines that already ran the old remove keep the stale resume_offset.

Existing leftover resume.conf is not repaired

The old remove deleted omarchy_resume.conf but left resume.conf. There, the fixed remove exits with "Hibernation is not set up", and setup still skips resume.conf when it exists (line 131), so re-setup keeps the old offset. Impact: #13583 persists for machines already in that state (see #10037, #10374, #12096).

Suggested change: drop setup's if [[ ! -f $RESUME_DROP_IN ]] guard so a fresh setup rewrites resume.conf from the current swapfile.

Reproducer (fails at e870b4b)

Save as test/shell.d/hibernation-stale-resume-test.sh at the PR head (e870b4b) and run bash test/shell.d/hibernation-stale-resume-test.sh. It runs the real omarchy-hibernation-remove and omarchy-hibernation-setup, with their hard-coded system paths rewritten into a temp directory and sudo, btrfs, swapon, swapoff, swaplabel, findmnt, chattr, gum and limine-mkinitcpio stubbed. It starts from the state the pre-fix remove leaves behind (no resume hook, resume.conf with the old offset), then runs the fixed remove and a new setup whose swapfile maps to a different offset.

#!/bin/bash

source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"

# A machine that ran the old remove has resume.conf but no resume hook. After
# updating, running remove and then setup again must not keep the deleted
# swapfile's resume_offset.

tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
fake="$tmp/root"
stub="$tmp/bin"
mkdir -p "$stub" "$fake/etc/limine-entry-tool.d" "$fake/etc/mkinitcpio.conf.d" \
  "$fake/sys/power" "$fake/usr/lib/systemd/system-sleep"

cat >"$stub/sudo" <<'SH'
#!/bin/bash
# Unprivileged test: drop the root ownership flags install_root_file passes.
if [[ $1 == "/usr/bin/install" ]]; then
  shift
  args=()
  while (($#)); do
    case $1 in
      -o | -g) shift 2 ;;
      *) args+=("$1"); shift ;;
    esac
  done
  exec /usr/bin/install "${args[@]}"
fi
exec "$@"
SH
cat >"$stub/btrfs" <<'SH'
#!/bin/bash
case "$1 $2" in
  "subvolume show") [[ -f $3/.subvolume ]] ;;
  "subvolume create") mkdir -p "$3" && touch "$3/.subvolume" ;;
  "subvolume delete") rm -rf -- "$3" ;;
  "filesystem mkswapfile") : >"${@: -1}" ;;
  "inspect-internal map-swapfile") [[ -f ${@: -1} ]] && echo "$NEW_OFFSET" ;;
  *) exit 1 ;;
esac
SH
printf '#!/bin/bash\n[[ -f $1 ]]\n' >"$stub/swaplabel"
printf '#!/bin/bash\necho /dev/mapper/root\n' >"$stub/findmnt"
for cmd in gum swapon swapoff chattr limine-mkinitcpio; do
  printf '#!/bin/bash\nexit 0\n' >"$stub/$cmd"
done
chmod +x "$stub"/*

# The helpers hard-code system paths; run copies pointed at the scratch root.
for helper in omarchy-hibernation-remove omarchy-hibernation-setup; do
  sed -e "s#/etc/#$fake/etc/#g" \
    -e "s#/sys/power/#$fake/sys/power/#g" \
    -e "s#/usr/lib/systemd/system-sleep/#$fake/usr/lib/systemd/system-sleep/#g" \
    -e "s#\"/swap\"#\"$fake/swap\"#" \
    -e "s#\"/swap/swapfile\"#\"$fake/swap/swapfile\"#" \
    "$ROOT/bin/$helper" >"$tmp/$helper"
  if sed "s#$fake#@#g" "$tmp/$helper" | grep -vE '^[[:space:]]*#' |
    grep -qE '(^|[^@[:alnum:]_])/(etc|sys|swap|usr/lib/systemd)([/"]|$)'; then
    fail "$helper only touches the scratch root"
  fi
done

# State left by the old remove: swapfile, subvolume, fstab entry and resume
# hook are gone, resume.conf still has the old swapfile's offset.
printf 'UUID=root / btrfs rw 0 0\n' >"$fake/etc/fstab"
printf '1000\n' >"$fake/sys/power/image_size"
printf 's2idle [deep]\n' >"$fake/sys/power/mem_sleep"
echo 'KERNEL_CMDLINE[default]+=" resume=/dev/mapper/root resume_offset=1929151"' \
  >"$fake/etc/limine-entry-tool.d/resume.conf"

run() {
  PATH="$stub:$ROOT/bin:$PATH" OMARCHY_PATH="$ROOT" NEW_OFFSET=2222222 bash "$tmp/$1" "${@:2}" 2>&1
}

remove_output=$(run omarchy-hibernation-remove)
run omarchy-hibernation-setup --force >/dev/null

grep -Fq 'resume_offset=2222222"' "$fake/etc/limine-entry-tool.d/resume.conf" ||
  fail "setup after an earlier remove points resume_offset at the new swapfile" \
    "remove printed: $remove_output"$'\n'"resume.conf after setup: $(<"$fake/etc/limine-entry-tool.d/resume.conf")"
pass "setup after an earlier remove points resume_offset at the new swapfile"

Actual output at e870b4b (exit 1):

remove printed: Hibernation is not set up
resume.conf after setup: KERNEL_CMDLINE[default]+=" resume=/dev/mapper/root resume_offset=1929151"
not ok - setup after an earlier remove points resume_offset at the new swapfile

The same test fails the same way at the base (b18ab49). With the if [[ ! -f $RESUME_DROP_IN ]]; then guard at bin/omarchy-hibernation-setup line 131 replaced by if true; then, it prints:

ok - setup after an earlier remove points resume_offset at the new swapfile

and the PR's own hibernation-remove-test.sh still passes on that tree:

ok - hibernation remove deletes the resume drop-ins setup writes
ok - hibernation remove drops resume parameters before rebuilding the UKI

Overlaps open #8199 and #12155

#8199 makes the same removal and adds a test at the same path; #12155 adds an equivalent block. Both conflict with this PR's remove. Impact: only one can land as is.

Suggested change: coordinate with #8199 and list the older issues the chosen fix closes.

Details

Verified:

  • On a machine that has not yet run remove, resume.conf is now deleted before sudo limine-mkinitcpio, and a stubbed setup/remove/setup cycle writes the new offset (the base keeps the old one).
  • limine-entry-tool 1.40.0 builds the UKI and limine.conf cmdline from its config layers, so deleting the drop-in drops the params unless another layer carries them.
  • The new test is auto-registered, fails at the base and passes at the head.
  • ./test/cli stops at vscode generated theme references current theme file at both base and head, as described.

Optional notes:


Review information

Test scope: Source and stubbed sandbox tests at e870b4b; no real boot or resume.

AI process: Opus 5.5 Medium coordination and synthesis, Opus 5.5 Xhigh technical review and final fact check, GPT 6 Sol Xhigh search for related issues, Opus 5.5 Medium editorial check.

Opt out: To stop receiving these reviews, reply to this comment saying so.

omarchybot and others added 2 commits October 3, 2026 09:26
A machine that removed hibernation before remove cleaned up still carries the old resume.conf, and setup kept it because it only wrote the drop-in when absent, so a later setup baked the deleted swapfile's offset into the UKI. Setup reaches this path only when hibernation is not configured, so an existing drop-in is always stale: rewrite it, and drop it when no offset can be found.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Codex Medium <noreply@openai.com>
Rejecting only the old existence guard passed with the whole rewrite block deleted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Codex Medium <noreply@openai.com>
@greptile-apps

greptile-apps Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 3/5

[High risk] Changes system boot configuration and hibernation setup.

The PR is not safe to merge until interrupted removal and failed offset calculation can be retried without leaving broken resume configuration.

Findings

  1. P1 Cleanup cannot be retried ▶
  2. P1 Offset failure prevents recovery ▶
  3. P2 Test misses skipped cleanup ▶
  4. P2 Comment describes outdated setup behavior ▶

Summary

The PR removes Limine resume parameters during hibernation removal and recalculates them during setup, with a new shell regression test.

  • The cleanup is skipped on retry if the resume hook was already removed.
  • An offset-calculation failure can delete valid parameters and leave setup unable to repair them on retry.
  • The new test checks source text rather than those runtime states.

Reviews (1) · Last reviewed commit: "Check that hibernation setup still write..."

Comment on lines +54 to +57
if [[ -f $RESUME_DROP_IN ]]; then
echo "Removing resume kernel parameters"
sudo rm "$RESUME_DROP_IN"
fi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Cleanup cannot be retried If removal is interrupted after deleting the resume hook but before deleting resume.conf, a second run exits because the hook is missing. It never removes the old resume parameters or rebuilds the UKI, so rerunning removal leaves boot settings for the deleted swapfile in place.

Comment on lines +139 to 142
else
sudo rm -f "$RESUME_DROP_IN"
echo "Warning: Could not determine resume offset for $SWAP_FILE" >&2
fi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Offset failure prevents recovery If a valid resume.conf remains after the hook configuration was removed and map-swapfile temporarily fails, this branch deletes the valid parameters. Setup then rebuilds without them. Because it has already written the hook, a later setup run exits before recalculating the offset, leaving hibernation unable to resume until the partial configuration is repaired.

Comment on lines +15 to +21
remove_line=$(grep -n 'sudo rm "$RESUME_DROP_IN"' "$ROOT/bin/omarchy-hibernation-remove" | cut -d: -f1)
rebuild_line=$(grep -n '^sudo limine-mkinitcpio' "$ROOT/bin/omarchy-hibernation-remove" | cut -d: -f1)
[[ -n $remove_line && -n $rebuild_line ]] ||
fail "hibernation remove keeps recognizable drop-in removal and rebuild steps"
(( remove_line < rebuild_line )) ||
fail "hibernation remove drops resume parameters before rebuilding the UKI"
pass "hibernation remove drops resume parameters before rebuilding the UKI"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Test misses skipped cleanup This test checks that deletion appears before the rebuild in the source, but never runs the removal script. It passes even when a missing hook makes the script exit before deleting a stale resume.conf, so it cannot catch that cleanup regression. A behavioral test of the partial state would cover it.

Comment on lines +52 to +53
# Remove resume kernel parameters. hibernation-setup only writes these when the
# drop-in is absent, so a stale one would pin a later setup to this swapfile's offset.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Comment describes outdated setup behavior Setup now rewrites resume.conf whenever it reaches the resume-parameter step, rather than writing it only when absent. This comment gives future maintainers the wrong reason for deleting the file and makes the cleanup harder to understand.

Suggested change
# Remove resume kernel parameters. hibernation-setup only writes these when the
# drop-in is absent, so a stale one would pin a later setup to this swapfile's offset.
# Remove resume kernel parameters so the rebuilt UKI no longer points to
# the deleted swapfile.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@omarchybot omarchybot added verified Omarchy Triage has verified that this issue is ready for final review ready Good to merge labels Oct 3, 2026
@omarchybot

Copy link
Copy Markdown
Collaborator

Reviewed and reproduced on a disposable VM built from the Omarchy ISO (btrfs root, Limine UKI), with a second opinion from Codex Medium.

The bug is real and this fixes it. On quattro, omarchy-hibernation-remove left /etc/limine-entry-tool.d/resume.conf behind, and the next omarchy-hibernation-setup kept it: the drop-in and the rebuilt UKI's cmdline both said resume_offset=1627847 while the new swapfile sat at 4084497. At this head, remove deletes the drop-in, and neither the default Limine entry nor the UKI's embedded cmdline carries resume= afterwards. The install-time snapshot entry keeps its own, which is right for that snapshot. Setup then writes the live offset.

Pushed one fix to your branch (9007748, plus 0e2b5a2 tightening its test). Fixing remove only helps machines that remove hibernation from now on. A machine that already ran the old remove still has the stale drop-in, and setup skipped writing one that existed, so #13583's step 5 still failed there. I reproduced that on the VM (old remove, then this branch's setup: drop-in 1627847, swapfile 2893056). Setup reaches that block only when hibernation is not configured, so any drop-in there is stale. It now always rewrites it, and deletes it when no offset can be found rather than keeping the old one. Re-run on the VM: the stale drop-in becomes 2893056 in the drop-in and the UKI, and setup on an already-configured machine is still a no-op. The new test check fails with setup reverted, with the rewrite block deleted, and with the empty-offset removal deleted.

Tests on the VM: ./test/cli has one failure, vscode generated theme references current theme file, which fails identically on quattro. hibernation-remove-test.sh, unowned-system-paths-test.sh and system-sleep-ownership-migration-test.sh all pass. Your test checks the scripts' source rather than running them, so the VM reproduction above is what the verdict rests on.

Second opinion: Codex Medium independently raised that the test only matched source text, which led to 0e2b5a2. On the stale drop-in it agreed with a finding already in its brief, so its independence there is not guaranteed. Its last round, on this head, found nothing left to act on.

Competing fix: #13768 fixes the same issue with the same two script changes and a larger behavioural test. Asked to compare them without being given an answer, Codex Medium preferred this one, as did I. This one deletes a stale drop-in when the offset can't be found, which #13768 keeps. #13768's test does run the scripts, which this one's doesn't. #13908 rewrites the same block in setup for #12630, so whichever lands second will need a merge. Waiting on the maintainer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ready Good to merge verified Omarchy Triage has verified that this issue is ready for final review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

omarchy hibernation remove leaves resume.conf behind, so a later setup keeps a stale resume_offset

3 participants