diff --git a/bin/omarchy-hibernation-available b/bin/omarchy-hibernation-available index 701a8f7202..e66d10a4ec 100755 --- a/bin/omarchy-hibernation-available +++ b/bin/omarchy-hibernation-available @@ -12,7 +12,7 @@ SWAPSIZE=$(( 1024 * ${SWAPSIZE_KB:-0} )) HIBERNATION_IMAGE_SIZE=$(cat /sys/power/image_size) -if (( SWAPSIZE > HIBERNATION_IMAGE_SIZE )) && [[ -f /etc/mkinitcpio.conf.d/omarchy_resume.conf ]]; then +if (( SWAPSIZE > HIBERNATION_IMAGE_SIZE )) && grep -q "resume" /etc/mkinitcpio.conf.d/omarchy_hooks.conf 2>/dev/null; then exit 0 else exit 1 diff --git a/bin/omarchy-hibernation-remove b/bin/omarchy-hibernation-remove index 49bad5bd6e..a0bcf28795 100755 --- a/bin/omarchy-hibernation-remove +++ b/bin/omarchy-hibernation-remove @@ -3,10 +3,10 @@ # omarchy:summary=Remove hibernation setup including swap and boot resume settings # omarchy:requires-sudo=true -MKINITCPIO_CONF="/etc/mkinitcpio.conf.d/omarchy_resume.conf" +HOOKS_CONF="/etc/mkinitcpio.conf.d/omarchy_hooks.conf" # Check if hibernation is configured -if [[ ! -f $MKINITCPIO_CONF ]] || ! grep -q "^HOOKS+=(resume)$" "$MKINITCPIO_CONF"; then +if [[ ! -f $HOOKS_CONF ]] || ! grep -q "resume" "$HOOKS_CONF"; then echo "Hibernation is not set up" exit 0 fi @@ -48,10 +48,13 @@ fi echo "Removing suspend-then-hibernate configuration" sudo rm -f /etc/systemd/logind.conf.d/lid.conf sudo rm -f /etc/systemd/sleep.conf.d/hibernate.conf +sudo rm -f /etc/systemd/system/systemd-logind.service.d/hibernate.conf +sudo rm -f /etc/systemd/system/systemd-hibernate.service.d/bypass.conf # Remove mkinitcpio resume hook -echo "Removing resume hook" -sudo rm "$MKINITCPIO_CONF" +echo "Removing resume hook from $HOOKS_CONF" +sudo sed -i 's/resume //' "$HOOKS_CONF" +sudo rm -f /etc/mkinitcpio.conf.d/omarchy_resume.conf echo "Regenerating initramfs..." sudo limine-mkinitcpio diff --git a/bin/omarchy-hibernation-setup b/bin/omarchy-hibernation-setup index d8e32c94e2..1b43e0258b 100755 --- a/bin/omarchy-hibernation-setup +++ b/bin/omarchy-hibernation-setup @@ -26,12 +26,12 @@ if ! $NO_REBUILD && ! command -v limine-mkinitcpio &>/dev/null; then exit 0 fi -MKINITCPIO_CONF="/etc/mkinitcpio.conf.d/omarchy_resume.conf" +HOOKS_CONF="/etc/mkinitcpio.conf.d/omarchy_hooks.conf" SWAP_FILE="/swap/swapfile" RESUME_DROP_IN="/etc/limine-entry-tool.d/resume.conf" # Check if hibernation is already configured -if [[ -f $MKINITCPIO_CONF ]] && grep -q "^HOOKS+=(resume)$" "$MKINITCPIO_CONF"; then +if [[ -f $HOOKS_CONF ]] && grep -q "resume" "$HOOKS_CONF"; then # Fix empty resume_offset if btrfs map-swapfile failed during initial setup if [[ -f $RESUME_DROP_IN ]] && grep -q 'resume_offset="$' "$RESUME_DROP_IN" && [[ -f $SWAP_FILE ]]; then RESUME_OFFSET=$(sudo btrfs inspect-internal map-swapfile -r "$SWAP_FILE" 2>/dev/null) @@ -82,21 +82,27 @@ if ! swapon --show | grep -q "$SWAP_FILE"; then sudo swapon -p 0 "$SWAP_FILE" fi -# Add resume hook to mkinitcpio -sudo mkdir -p /etc/mkinitcpio.conf.d -echo "Adding resume hook to $MKINITCPIO_CONF" -echo "HOOKS+=(resume)" | sudo tee "$MKINITCPIO_CONF" >/dev/null +# Add resume hook to mkinitcpio — must come before filesystems so the kernel +# can restore the hibernation image before root is mounted read-write. +if [[ -f $HOOKS_CONF ]] && ! grep -q "resume" "$HOOKS_CONF"; then + echo "Inserting resume hook before filesystems in $HOOKS_CONF" + sudo sed -i 's/\bfilesystems\b/resume filesystems/' "$HOOKS_CONF" +fi +# Remove legacy append-style config that put resume in the wrong position +sudo rm -f /etc/mkinitcpio.conf.d/omarchy_resume.conf # Ensure keyboard backlight doesn't prevent sleep sudo cp -p "$OMARCHY_PATH/default/systemd/system-sleep/keyboard-backlight" /usr/lib/systemd/system-sleep/ +# Resolve resume device and offset +sudo swapon -p 0 "$SWAP_FILE" 2>/dev/null +RESUME_DEVICE=$(findmnt -no SOURCE -T "$SWAP_FILE" | sed 's/\[.*\]//') +RESUME_OFFSET=$(sudo btrfs inspect-internal map-swapfile -r "$SWAP_FILE") + # 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. if [[ ! -f $RESUME_DROP_IN ]]; then echo "Adding resume kernel parameters" - sudo swapon -p 0 "$SWAP_FILE" 2>/dev/null - RESUME_DEVICE=$(findmnt -no SOURCE -T "$SWAP_FILE" | sed 's/\[.*\]//') - RESUME_OFFSET=$(sudo btrfs inspect-internal map-swapfile -r "$SWAP_FILE") if [[ -n $RESUME_OFFSET ]]; then sudo mkdir -p /etc/limine-entry-tool.d echo "KERNEL_CMDLINE[default]+=\" resume=$RESUME_DEVICE resume_offset=$RESUME_OFFSET\"" | sudo tee "$RESUME_DROP_IN" >/dev/null @@ -104,6 +110,26 @@ if [[ ! -f $RESUME_DROP_IN ]]; then else echo "Warning: Could not determine resume offset for $SWAP_FILE" >&2 fi +elif [[ -n $RESUME_OFFSET ]] && ! grep -q "resume_offset=$RESUME_OFFSET" "$RESUME_DROP_IN"; then + echo "Updating stale resume_offset in $RESUME_DROP_IN" + sudo sed -i "s/resume_offset=[0-9]*/resume_offset=$RESUME_OFFSET/" "$RESUME_DROP_IN" + sudo sed -i "s/resume_offset=[0-9]*/resume_offset=$RESUME_OFFSET/" /etc/default/limine +fi + +# Work around systemd not being able to resolve btrfs swapfiles on dm-crypt +# as valid hibernation devices (see https://github.com/systemd/systemd/issues/30083) +LOGIND_DROP_IN="/etc/systemd/system/systemd-logind.service.d/hibernate.conf" +if [[ ! -f $LOGIND_DROP_IN ]]; then + echo "Adding systemd-logind hibernation bypass" + sudo mkdir -p /etc/systemd/system/systemd-logind.service.d + printf '[Service]\nEnvironment="SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1"\n' | sudo tee "$LOGIND_DROP_IN" >/dev/null +fi + +HIBERNATE_DROP_IN="/etc/systemd/system/systemd-hibernate.service.d/bypass.conf" +if [[ ! -f $HIBERNATE_DROP_IN ]]; then + echo "Adding systemd-hibernate bypass" + sudo mkdir -p /etc/systemd/system/systemd-hibernate.service.d + printf '[Service]\nEnvironment="SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1"\n' | sudo tee "$HIBERNATE_DROP_IN" >/dev/null fi # Use ACPI alarm for RTC wakeup on s2idle systems (needed for suspend-then-hibernate) diff --git a/migrations/1778497305.sh b/migrations/1778497305.sh new file mode 100644 index 0000000000..a78b958199 --- /dev/null +++ b/migrations/1778497305.sh @@ -0,0 +1,44 @@ +echo "Fix hibernation on btrfs swapfiles with dm-crypt (systemd 256+)" + +HOOKS_CONF="/etc/mkinitcpio.conf.d/omarchy_hooks.conf" +LEGACY_RESUME_CONF="/etc/mkinitcpio.conf.d/omarchy_resume.conf" +SWAP_FILE="/swap/swapfile" +RESUME_DROP_IN="/etc/limine-entry-tool.d/resume.conf" + +# Only apply if hibernation is configured +if ! grep -q "resume" "$HOOKS_CONF" 2>/dev/null && [[ ! -f $LEGACY_RESUME_CONF ]]; then + exit 0 +fi + +# Move resume hook from appended position (after fsck) to before filesystems, +# so the kernel can restore the hibernation image before root is mounted rw. +if [[ -f $HOOKS_CONF ]] && ! grep -q "resume" "$HOOKS_CONF"; then + sudo sed -i 's/\bfilesystems\b/resume filesystems/' "$HOOKS_CONF" +fi +sudo rm -f "$LEGACY_RESUME_CONF" + +# Add systemd bypass drop-ins for btrfs swapfile on dm-crypt +# (see https://github.com/systemd/systemd/issues/30083) +LOGIND_DROP_IN="/etc/systemd/system/systemd-logind.service.d/hibernate.conf" +if [[ ! -f $LOGIND_DROP_IN ]]; then + sudo mkdir -p /etc/systemd/system/systemd-logind.service.d + printf '[Service]\nEnvironment="SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1"\n' | sudo tee "$LOGIND_DROP_IN" >/dev/null +fi + +HIBERNATE_DROP_IN="/etc/systemd/system/systemd-hibernate.service.d/bypass.conf" +if [[ ! -f $HIBERNATE_DROP_IN ]]; then + sudo mkdir -p /etc/systemd/system/systemd-hibernate.service.d + printf '[Service]\nEnvironment="SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1"\n' | sudo tee "$HIBERNATE_DROP_IN" >/dev/null +fi + +# Fix stale resume_offset if swapfile was recreated at a different physical location +if [[ -f $RESUME_DROP_IN ]] && [[ -f $SWAP_FILE ]]; then + RESUME_OFFSET=$(sudo btrfs inspect-internal map-swapfile -r "$SWAP_FILE" 2>/dev/null) + if [[ -n $RESUME_OFFSET ]] && ! grep -q "resume_offset=$RESUME_OFFSET" "$RESUME_DROP_IN"; then + sudo sed -i "s/resume_offset=[0-9]*/resume_offset=$RESUME_OFFSET/" "$RESUME_DROP_IN" + sudo sed -i "s/resume_offset=[0-9]*/resume_offset=$RESUME_OFFSET/" /etc/default/limine + sudo limine-mkinitcpio + fi +fi + +omarchy-state set reboot-required