omarchy icon indicating copy to clipboard operation
omarchy copied to clipboard

Add support for hibernate

Open dhh opened this issue 5 months ago • 11 comments

We need to do some setup to enable hibernate. Currently, this is the error message:

 systemctl hibernate
Call to Hibernate failed: Not enough suitable swap space for hibernation available on compatible block devices and file systems

We need a swap file that's the same size as the memory on the system for this to work.

dhh avatar Jul 09 '25 19:07 dhh

The following may be useful for computing swapfile size:

SWAP_SIZE=$(free | awk '/Mem/ {x=$2/1024/1024; printf "%.0fG", (x<2 ? 2*x : x<8 ? 1.5*x : x) }')

sgloutnikov avatar Jul 11 '25 06:07 sgloutnikov

Should probably be optional during install. I don't want a 64G swap file 🤣

CashWilliams avatar Jul 11 '25 22:07 CashWilliams

This may not be the ideal solution; however, you may suspend first and then hibernate. This shouldn't use nearly as much swap?

systemctl suspend-then-hibernate

Sharp Edges

  • Btrfs swap does not support hibernate mode unless compression is disabled: https://wiki.archlinux.org/title/Power_management/Suspend_and_hibernate#Hibernation_with_a_swap_file_on_Btrfs

Potential solution

We could create dynamic swap based on the current memory usage, mirror that size, and hibernate? Here is a rough example

#!/usr/bin/env bash
#
# dynswap: Create a swapfile sized to current RAM usage (+ margin) for hibernation
# Tested on Arch Linux.  Run as root.

set -euo pipefail

MARGIN_PCT=20           # % safety buffer above current used RAM
SWAPFILE=/swapfile      # path to swap file
FSTAB=/etc/fstab        # fstab path

## 1. Gather current RAM usage (in MiB) ########################################
# 'free --mebi' prints MiB units; field 3 in Mem row = used
USED_MIB=$(free --mebi | awk '/^Mem:/ {print $3}')
if [[ -z "$USED_MIB" ]]; then
  echo "Could not determine used memory" >&2; exit 1
fi

## 2. Calculate swap size with margin ##########################################
SWAP_SIZE_MIB=$(( USED_MIB + (USED_MIB * MARGIN_PCT / 100) ))
echo "Current RAM used: ${USED_MIB} MiB, creating ${SWAP_SIZE_MIB} MiB swapfile."

## 3. Disable and remove any existing swapfile #################################
if swapon --summary | grep -q "$SWAPFILE"; then
  swapoff "$SWAPFILE"
fi
rm -f "$SWAPFILE"

## 4. Create the new swapfile ##################################################
fallocate -l "${SWAP_SIZE_MIB}M" "$SWAPFILE"
chmod 600 "$SWAPFILE"
mkswap "$SWAPFILE"

## 5. Activate swap ############################################################
swapon "$SWAPFILE"

## 6. Ensure /etc/fstab entry exists ###########################################
if ! grep -q "^$SWAPFILE" "$FSTAB"; then
  echo -e "$SWAPFILE\tnone\tswap\tdefaults\t0 0" >> "$FSTAB"
  echo "Added $SWAPFILE to $FSTAB"
fi

## 7. Show result ##############################################################
echo "Swap now active:"
swapon --show

echo "Done.  Remember to keep your GRUB resume=/resume_offset=… parameters updated!
If you re-created the file, run:
  filefrag -v $SWAPFILE | grep \" 0:\" | awk '{print \$4}' | cut -d. -f1
and update resume_offset in /etc/default/grub, then regenerate grub.cfg."

exit 0

ryanyogan avatar Jul 12 '25 04:07 ryanyogan

systemd supports hibernation to a regular file.

# Enable hibernation to a regular file
sudo systemctl enable systemd-hibernate-resume
# Uses /var/lib/systemd/sleep/ for hibernation storage

CyphrRiot avatar Jul 19 '25 01:07 CyphrRiot

Problem is that default swap file is only 4G. Far short of most people's RAM. So that's part of what needs to change.

dhh avatar Jul 19 '25 02:07 dhh

Problem is that default swap file is only 4G. Far short of most people's RAM. So that's part of what needs to change.

The swap omarchy already have - is not the swap file, it's zram. Zram is stored in RAM, so hibernation (sleep to disk) with it is absolutely not possible. It comes by default with Arch and is brought up by [email protected] with default config:

~ > cat /etc/systemd/zram-generator.conf
[zram0]

If we want to make hibernation possible while keeping zram as swap, we need to:

  1. Create a swap file. Btrfs#Swap File - ArchWiki
  2. To not use a slower swapfile instead of faster zram, we need to have a lower priority for the swapfile. It can be done like that in /etc/fstab:
/swap/swapfile none swap defaults,pri=0 0 0

But probably it's not even needed, because man swapon(8) says that:

            When no priority is defined, Linux kernel defaults to negative numbers.

And the man zram-generator.conf(5) says:

       •   swap-priority=
           Controls the relative swap priority, a value between -1 and 32767. Higher numbers indicate higher priority.
           If unset, 100 is used.

So by default, zram will have a higher priority and be used first. 3. We need to enable the resume hook in initrafms Suspend and hibernate#Configure_the_initramfs - ArchWiki

  1. Ensure tht /usr/lib/systemd/system-generators/systemd-hibernate-resume-generator exists - it enables the systemd-hibernate-resume.service ( By default systemctl hibernate will automatically pick a suitable swap space to hibernate into, and put the information of the used swap space to the HibernateLocation EFI variable. When the system will boot systemd-hibernate-resume.service will read HibernateLocation EFI variable and resume the system from it.)

After that, hibernation will work properly

If needed, I can add scripts for this; it's actually quite simple. But I need to understand whether adding the swap file should be optional? If so, what would be the mechanism for this optionality?

killeik avatar Aug 26 '25 21:08 killeik

@killeik can you provide the scripts? I already have the swapfile that 2x my current RAM. I need the instruction of later part. Because I can't get it working or not sure if I'm done right. Tks!

nielpattin avatar Aug 27 '25 03:08 nielpattin

This script was written with llm assist, but I have read it more than 10 times and added all the necessary reasonable checks, so it should not harm the system. I have also tested it several times on my system with omarchy 2.0

Important note: it will only work on systems with limine as the bootloader and if no swap file has been created previously. @nielpattin In your specific case, please delete the existing swap file so that the script can recreate it to match the size of your RAM.

And as always, read the scripts before executing them, and be really careful if you have important, unbacked-up data on your system.

UPD: use script from #1417 it's handwritten and just better

killeik avatar Aug 27 '25 12:08 killeik

Btrfs cannot snapshot subvolumes containing an active swapfile. To enable hibernation without breaking snapshot functionality we should place the swapfile on its own dedicated btrfs subvolume. Otherwise, the root subvolume will no longer be snapshottable.

Related effort on snapshots: https://github.com/basecamp/omarchy/issues/722 https://github.com/basecamp/omarchy/pull/998

mfornasa avatar Aug 27 '25 21:08 mfornasa

This script was written with llm assist, but I have read it more than 10 times and added all the necessary reasonable checks, so it should not harm the system. I have also tested it several times on my system with omarchy 2.0

where does this stand? im eager to try out this script.

what would we need to implement this in omarchy?

kromsam avatar Sep 02 '25 14:09 kromsam

what would we need to implement this in omarchy?

Nothing really, so I made PR #1417 :D

killeik avatar Sep 02 '25 19:09 killeik

I used to make it work and it was so cool to have you laptop last for weeks without recharging!!!

ElBrodino avatar Sep 13 '25 21:09 ElBrodino

Working on it in https://github.com/basecamp/omarchy/pull/1417 👌

dhh avatar Sep 16 '25 14:09 dhh