omarchy icon indicating copy to clipboard operation
omarchy copied to clipboard

Added hibernation support

Open killeik opened this issue 3 months ago • 44 comments

Resolves: #105

  • Creates btrfs subvolume for swap file, to not break snapshots
  • Creates swap file with size of ram
  • Adds swap file to /etc/fstab to mount swap file on boot
  • Adds resume module via HOOKS+=(resume) in /etc/mkinitcpio.conf.d/omarchy_resume.conf
  • Adds Hibernate option to Power menu

I'd love to get some feedback 😄

killeik avatar Sep 02 '25 19:09 killeik

Not sure about install step, but I can confirm that the hibernate work like it should be. I'm also on Nvidia which most the problem come from and doesn't have any issue. Hope this get merge soon because I have to create a copy of Omarchy menu just to test it out or just run systemctl hibernate in terminal, but I prefer it under Suspend like this.

nielpattin avatar Sep 03 '25 15:09 nielpattin

@killeik ok, I got some problem with the hyprlock crash(not related), so I tried to reinstall and the first thing I do is to run the hibernate.sh command to test. Run systemctl hibernate like usual. But when power on, it brings me to the Omarchy Bootloader screen. So I'm not sure what wrong.

Boot up to the linux only open a new fresh just like when reboot, others app open or the last state doesn't return.

1756978924210

nielpattin avatar Sep 04 '25 09:09 nielpattin

@nielpattin

it brings me to the Omarchy Bootloader screen

It's okay. The boot sequence from hibernation starts like a fresh boot. It should decrypt the disk and start the kernel. Later on, however, it finds a RAM dump on the disk and loads that instead of loading fresh.

Boot up to the linux only open a new fresh just like when reboot, others app open or the last state doesn't return.

Let's debug I need output of that one (putted them in one command, to not make you Ctrl+C/Ctrl+V all the way :D )

bash -c 'set -x ;
swapon ;
free -h ;
sudo btrfs subvolume show /swap ;
sudo btrfs inspect-internal map-swapfile /swap/swapfile ;
cat /sys/power/resume_offset ;
cat /sys/power/resume ;
cat /etc/fstab ;
cat /etc/mkinitcpio.conf.d/omarchy_resume.conf ;'

And kernel logs after hibernation (they are not so small, so send them as file, maybe) sudo dmesg -TH

For convenience, you can send them to me in DM in Discord, I'm @killeik on omarchy server

killeik avatar Sep 04 '25 10:09 killeik

After some debugging in DM, it was discovered that there was a magical Nvidia, for which the standard mode of operation on Linux is to torment the user. Other than that, everything worked fine.

killeik avatar Sep 04 '25 12:09 killeik

I've tested this on my Framework laptop / AMD Ryzen and it works great 👍 Thanks!

brennandunn avatar Sep 06 '25 06:09 brennandunn

Need to update for current branch, make the Hibernate option conditional on the swap being available, and add a migration with a gum confirm something like "Use XX GB on drive to make hibernate available?".

dhh avatar Sep 16 '25 13:09 dhh

Need to update for current branch, make the Hibernate option conditional on the swap being available, and add a migration with a gum confirm something like "Use XX GB on drive to make hibernate available?".

While you add it. Also make a check if swap is already configured. I have an encrypted swap on my machine so hibernation.sh would break my machine with custom partitions / swap / encryption.

woopstar avatar Sep 18 '25 09:09 woopstar

My apologies. I updated my fork branch to the current active branch, accidentally deleting the changes I had added, and GitHub automatically closed the pull request because the branches started to match.

By the way, I added migration and made the hibernation option in omarchy-menu optional.

killeik avatar Sep 18 '25 14:09 killeik

Tested conditional hibernation in power menu, and migration - everything works correctly.

The only pitfall is that if the user manually created a swap and didn't enable the resume hook, the boot sequence will not resume from the saved hibernation image and will start fresh.

I found a way to check if the hooks are enabled on the current initramfs with limine: lsinitcpio /boot/EFI/Linux/*.efi | grep 'hooks/resume' However, I'm unsure if it will work on GRUB and other systems.

killeik avatar Sep 19 '25 16:09 killeik

Did you try the PR? I tried multiple PR in my own fork, and the menu does not work. I suspect this PR might break the omarchy menu system

woopstar avatar Sep 20 '25 17:09 woopstar

Did you try the PR? I tried multiple PR in my own fork, and the menu does not work. I suspect this PR might break the omarchy menu system

I've tested this PR on both of my computers and it works correctly. I actually don't have any ideas how it can break menu, because my change for it is very simple. So can you please give more info what's going on in your fork?

killeik avatar Sep 20 '25 19:09 killeik

I've tested this PR on both of my computers and it works correctly. I actually don't have any ideas how it can break menu, because my change for it is very simple. So can you please give more info what's going on in your fork?

https://github.com/woopstar/omarchy/commits/master/

I will check tomorrow which PR that broke the app launcher then :)

woopstar avatar Sep 20 '25 20:09 woopstar

It was #1661 that broke the menu. I tested this. Works as it should. But it shows the lock menu that "hangs" while it waits for hibernation to be ready. Should we consider showing something else if possible? Would it be possible to have it say "Entering hibernation" instead of showing the lock screen, which you cannot type or do anything in?

woopstar avatar Sep 22 '25 07:09 woopstar

It was https://github.com/basecamp/omarchy/pull/1661 that broke the menu. I tested this. Works as it should.

Thank you!

But it shows the lock menu that "hangs" while it waits for hibernation to be ready. Should we consider showing something else if possible? Would it be possible to have it say "Entering hibernation" instead of showing the lock screen, which you cannot type or do anything in?

Neither hypridle, which invokes the lock screen before sleep or hibernation, nor hyprlock, which works as a lock screen, has any difference between sleep and hibernation. Therefore, it's not possible at this level.

However, systemd has different targets: suspend.target, hibernate.target, hybrid-sleep.target, and suspend-then-hibernate.target. Technically, we could write a service that runs before hibernate.target and changes the hyprlock configuration to display something like "Hibernating, wait" and then changes it back after hibernation. However, it feels like a bad hack, changing user-space config on every hibernation is kinda crazy.

To do that the normal way, we would probably need to create an issue in Hyprildle/Hyprlock.

killeik avatar Sep 22 '25 09:09 killeik

However, systemd has different targets: suspend.target, hibernate.target, hybrid-sleep.target, and suspend-then-hibernate.target. Technically, we could write a service that runs before hibernate.target and changes the hyprlock configuration to display something like "Hibernating, wait" and then changes it back after hibernation. However, it feels like a bad hack, changing user-space config on every hibernation is kinda crazy.

Yeah, let's not walk down that road. But I can confirm the PR works as expected :)

woopstar avatar Sep 22 '25 09:09 woopstar

I am thinking about moving to OMARCHY from my customized ARCH and i think this was the script I used to enable the Swap. I used a swap file instead of a volume (i think the subvolume is the better approach). I drop my config / code as it may be helpful. I am using hibernate when closing the lid. I checked the issues for hibernate as this is an important feature for me.

#!/bin/sh
# check if su or root
if [ "$(id -u)" != "0" ]; then
  echo "This script must be run as root" 1>&2
  exit 1
fi
# check if btrfs
if [ ! -d /sys/fs/btrfs ]; then
  echo "This script is only for btrfs filesystems" 1>&2
  exit 1
fi
# check if swapfile exists if not create it with 96GB
if [ ! -f /swap/swapfile ]; then
  echo "Creating swapfile with 96GB"
  fallocate -l 96G /swap/swapfile
  chmod 600 /swap/swapfile
  mkswap /swap/swapfile
  swapon /swap/swapfile
fi

cd /tmp
# :: btrfs_map_physical :: #
wget https://raw.githubusercontent.com/osandov/osandov-linux/master/scripts/btrfs_map_physical.c
gcc -O2 -o btrfs_map_physical btrfs_map_physical.c

# :: edit grub :: #
offset=$(./btrfs_map_physical /swap/swapfile)
offset_arr=($(echo ${offset}))
offset_pagesize=($(getconf PAGESIZE))
offset=$((offset_arr[25] / offset_pagesize))
btrfsroot=`findmnt / -no UUID`

echo "btrfsroot=$btrfsroot"
echo "offset=$offset"

# create a backup of /etc/default/grub
cp /etc/default/grub /etc/default/grub.bak

# edit /etc/default/grub
sed -i "s#loglevel=3#resume=/dev/mapper/root loglevel=3#" /etc/default/grub
sed -i "s/loglevel=3/resume_offset=$offset loglevelbtrfs property set \/swap\/swapfile compression none=3/" /etc/default/grub

My /etc/systemd/logind.conf

[Login]
#NAutoVTs=6
#ReserveVT=6
#KillUserProcesses=no
#KillOnlyUsers=
#KillExcludeUsers=root
#InhibitDelayMaxSec=5
#UserStopDelaySec=10
#SleepOperation=suspend-then-hibernate suspend
HandlePowerKey=lock
#HandlePowerKeyLongPress=ignore
#HandleRebootKey=reboot
#HandleRebootKeyLongPress=poweroff
#HandleSuspendKey=suspend
#HandleSuspendKeyLongPress=hibernate
#HandleHibernateKey=hibernate
#HandleHibernateKeyLongPress=ignore
HandleLidSwitch=suspend-then-hibernate
HandleLidSwitchExternalPower=suspend-then-hibernate
#HandleLidSwitchDocked=ignore
#PowerKeyIgnoreInhibited=no
#SuspendKeyIgnoreInhibited=no
#HibernateKeyIgnoreInhibited=no
#LidSwitchIgnoreInhibited=yes
#RebootKeyIgnoreInhibited=no
#HoldoffTimeoutSec=30s
#IdleAction=ignore
#IdleActionSec=30min
#RuntimeDirectorySize=10%
#RuntimeDirectoryInodesMax=
#RemoveIPC=yes
#InhibitorsMax=8192
#SessionsMax=8192
#StopIdleSessionSec=infinity

DominicBoettger avatar Sep 22 '25 12:09 DominicBoettger

@killeik I've been thinking if this should also enable the suspend-then-hibernate support.

$ cat /etc/systemd/sleep.conf.d/omarchy.conf
[Sleep]
HibernateDelaySec=60min
AllowSuspendThenHibernate=yes
$ cat /etc/systemd/logind.conf.d/omarchy.conf
[Login]
HandleLidSwitch=suspend-then-hibernate
HandleLidSwitchExternalPower=suspend-then-hibernate
HandleLidSwitchDocked=suspend-then-hibernate

Unsure if we also must:

systemctl enable systemd-suspend-then-hibernate.service

References: https://man.archlinux.org/man/systemd-sleep.conf.5 https://man.archlinux.org/man/logind.conf.5.en

woopstar avatar Sep 24 '25 11:09 woopstar

If we want to do something like this, I suggest using sleep instead of straight-forward suspend-then-hibernate for HandleLidSwitch:

sleep Put the system to sleep, through suspend, hibernate, hybrid-sleep, or suspend-then-hibernate. The sleep operation to use is automatically selected by systemd-logind.service(8). By default, suspend-then-hibernate is used, and falls back to suspend and then hibernate if not supported. Refer to SleepOperation= setting in logind.conf(5) for more details. This command is asynchronous, and will return after the sleep operation is successfully enqueued. It will not wait for the sleep/resume cycle to complete.

Added in version 256.

It will work if the system has or does not have hibernation mode.

I'm also not sure if we really want to change HibernateDelaySec.

Setting the AllowSuspendThenHibernate=yes may actually break users without hibernation. This flag, as I understand it, is intended to turn off the features, not to enable them. Systemd doesn't need any changes to the configuration to find system support for hibernation.

And the systemd-suspend-then-hibernate.service - it's not a daemon. It's a one-shot command to start the suspend-then-hibernate sequence.

Note that systemd-suspend.service, systemd-hibernate.service, systemd-hybrid-sleep.service, and systemd-suspend-then-hibernate.service should never be executed directly. Instead, trigger system sleep with a command such as systemctl suspend or systemctl hibernate.

But I'm not sure if it's a good idea to talk about these improvements in this PR. My idea was just to add support for hibernation.

killeik avatar Sep 24 '25 13:09 killeik

There is an easier way to find resume=UUID=<UUID> and resume_offset cmdline parameters:

findmnt -no UUID -T /swap/swapfile
btrfs inspect-internal map-swapfile -r /swap/swapfile

And I add resume=UUID=<UUID> resume_offset=<the-number-from-inspect-internal> at the end of my cmdline in my limine.conf file. But I'm on my custom Arch Linux setup. Not sure about Omarchy

https://wiki.archlinux.org/title/Power_management/Suspend_and_hibernate#Acquire_swap_file_offset

@DominicBoettger

yovko avatar Sep 28 '25 12:09 yovko

This would be a really cool feature to extend the battery life!

Prajwal-Prathiksh avatar Oct 02 '25 22:10 Prajwal-Prathiksh

Great job. Worked for me too.

I prefer suspend-then-hibernate with a 1 hour delay. So I changed systemctl suspend to systemctl suspend-then-hibernate in the menu.

And similarly for /etc/systemd/logind.conf: HandleLidSwitch=suspend-then-hibernate

And /etc/systemd/sleep.conf: HibernateDelaySec=3600.

lukehowson avatar Oct 21 '25 14:10 lukehowson

Why no merge? dhh likes his bag toasty?

lukehowson avatar Oct 21 '25 23:10 lukehowson

Does this needs more testing reports from more people before it gets merged?

Shirkit avatar Oct 23 '25 15:10 Shirkit

Migration has an interactive prompt we need to sort:

image

Also, some tweaks to the migration:

echo "Offer hibernation if missing as a system-menu option"

if omarchy-hibernation-available; then
  exit 0
fi

MEM_TOTAL_HUMAN="$(free --human |grep "Mem" |awk '{print $2}')"
if gum confirm "Use $MEM_TOTAL_HUMAN on boot drive to make hibernation available?"; then
  source  $OMARCHY_PATH/install/config/hibernation.sh
fi

dhh avatar Oct 26 '25 11:10 dhh

It unfortunately doesn't work consistently on my machine either. There's no feedback while it's trying to write the hibernation file, but even when I left it for a few minutes, it never fully shut down the computer. I manually had to do that.

Then on reboot, it's also stuck on the decryption screen without feedback for a long time. Long enough that you think it might be broken. Eventually it did boot up.

On the second run, I must not have waited long enough for the hibernation write to actually go through, because I shut the computer off after maybe 20 seconds, and when I reboot again, there was no hibernation restored.

I totally get why this is desirable to have, but if we can't get it to work consistently, I don't think we can offer it out of the box.

This was on a 128GB AMD 395+ in the Beelink GTR9 Pro.

dhh avatar Oct 26 '25 11:10 dhh

@dhh, I made the suggested changes. Now, there won't be an interactive prompt. Previously, I had to use mkinitcpio because omarchy wasn't defaulting to use only limine uki.

Regarding the issue with your PC not shutting down, do you have time to debug it? Try adding these parameters to sleep conf: https://wiki.archlinux.org/title/Power_management/Suspend_and_hibernate#System_does_not_power_off_when_hibernating If this solves the problem, I will add the parameters to the installation script

Also, if the system doesn't restore the correct state after hibernation, can you share the output of the command sudo dmesg -TH? There will probably be information explaining why that happened.

killeik avatar Oct 26 '25 13:10 killeik

From my limited understanding (arch noob here), subvolumes aren’t recommended for hibernation and may lead to weird results if CoW and compression aren’t disabled for the subvolume.

Can anyone confirm?

pch avatar Oct 26 '25 14:10 pch

From my limited understanding (arch noob here), subvolumes aren’t recommended for hibernation and may lead to weird results if CoW and compression aren’t disabled for the subvolume.

From https://btrfs.readthedocs.io/en/latest/btrfs-man5.html#swapfile-support

subvolume - cannot be snapshotted if it contains any active swapfiles

So, to create snapshots, it's required to have a separate subvolume for swap.

About compression - newly created subvolume doesn't contain compression flags. And command btrfs filesystem mkswapfile - disables CoW for swapfile

sudo lsattr /swap
---------------C------ /swap/swapfile

killeik avatar Oct 26 '25 15:10 killeik

I've taken the newest .iso of Omarchy, installed it on my ThinkPad X220, and updated it. Then I've copied the changed files from this repo to the folders located in "~/.local/share/omarchy/." and gave them the executable flag. Then I've run the "1758205457.sh" file and rebooted the laptop. Then I've added "HandleLidSwitch=suspend-then-hibernate" to "/etc/systemd/login.conf" and "HibernationDelaySec=2min" (to test it) and "AllowSuspendThenHibernate=yes" in "/etc/systemd/sleep.conf". The "Hibernation" option in Power Menu, and suspend then hibernate works flawlessly, but after entering the password to the "OMARCHY" decryption screen, I have to put the password again into the user login screen (one with the fingerprint icon).

ThinkPad X220 specs: processor: Intel i5-2540M memory: 16GB DDR3 1866MHz disk: 240GB SSD

I am using GitHub for the first time in my life, so if I've done something wrong by leaving this comment, please tell me. I've given a lot of information (this may help in some way).

braintornapart avatar Oct 26 '25 15:10 braintornapart

... The "Hibernation" option in Power Menu, and suspend then hibernate works flawlessly, but after entering the password to the "OMARCHY" decryption screen, I have to put the password again into the user login screen (one with the fingerprint icon).

@braintornapart So, the problem is that you had to enter your password twice?

That's how hypridle/lock works. I wrote about that before.

Neither hypridle, which invokes the lock screen before sleep or hibernation, nor hyprlock, which works as a lock screen, has any difference between sleep and hibernation.

If we want to keep the login screen after sleep mode, we also have to keep it after hibernation mode. The first prompt on the decryption screen is required because of the encrypted disks, and we can't disable it.

It's a bit annoying, but fixing it requires changes to hypridle to differentiate between hibernation and sleep.

killeik avatar Oct 26 '25 16:10 killeik