Guide: Set up Suspend-then-hibernate

I know there are a few posts about this, but I think things have changed gradually in the last few months, and so I thought I would post a comprehensive (I think!) set of instructions for suspend-then-hibernate on a framework laptop, so that it’s not at 0% battery every time you open the lid! This is based on prior art:

Fedora Magazine: Update on Hibernation in Fedora Workstation

xoid.net: Configuring Hibernate on Linux Laptop

This works with secure boot, and with LUKS encryption :party_popper:

Steps to Enable

  1. Create a btrfs subvolume containing a swapfile of the appropriate size
SWAPSIZE=$(free | awk '/Mem/ {x=$2/1024/1024; printf "%.0fG", (x<2 ? 2*x : x<8 ? 1.5*x : x) }')
sudo btrfs subvolume create /var/swap
sudo chattr +C /var/swap
sudo restorecon /var/swap
sudo mkswap --file -L SWAPFILE --size $SWAPSIZE /var/swap/swapfile
sudo bash -c 'echo /var/swap/swapfile none swap defaults 0 0 >>/etc/fstab'
sudo swapon -av
  1. Add the appropriate SELinux rules to allow systemd to hibernate.

You have two options here - one is to try systemctl hibernate a few times and look at the output of audit2allow to figure out what is preventing it from working as per the steps in the forum post referenced above - but I’m guessing that the same base rules will apply to any silverblue installation, so you can also create a file systemd_hibernate.te with the following content:

module systemd_hibernate 1.0;

require {
type systemd_logind_t;
type init_var_lib_t;
type systemd_sleep_t;
type swapfile_t;
class dir { add_name search write };
class cap_userns sys_ptrace;
}

#============= systemd_logind_t ==============
allow systemd_logind_t self:cap_userns sys_ptrace;
allow systemd_logind_t swapfile_t:dir search;

#============= systemd_sleep_t ==============
allow systemd_sleep_t init_var_lib_t:dir write;
allow systemd_sleep_t init_var_lib_t:dir add_name;
allow systemd_sleep_t swapfile_t:dir search;

Then check, build and install the module:

sudo checkmodule -M -m -o systemd_hibernate.mod systemd_hibernate.te
sudo semodule_package -o systemd_hibernate.pp -m systemd_hibernate.mod
sudo semodule -i systemd_hibernate.pp

After a quick reboot, you can now test out whether systemctl hibernate works - if the light on the power button goes off, and you can boot back up to the state that you were previously in, it has! If it doesn’t work, you’ll need to do some troubleshooting, first thing is to run audit2allow -b and see if any rules have prevented the system from hibernating. The output will look similar to the above file, and you can generate further rules with sudo audit2allow -b -M systemctl_hibernate2 and then examine the systemctl_hibernate2.te file to understand what further rules need adding to the file above. I would recommend trying to keep all the related rules in a single file/module - it can get confusing otherwise. If this reveals nothing, you will be digging through kernel/boot logs (journalctl -b) and looking for anything related to systemd-sleep, hibernate, suspend-then-hibernate, etc.

  1. Set up lid-close and sleep settings

For me, the optimal behaviour was to suspend then hibernate after a period of time - I want my laptop to come back on straight away if I have only been away a few minutes, but then to hibernate and preserve battery after say 30 minutes. Unfortunately, Gnome hijacks some of these settings, so it’s not as easy as just setting up the systemd config. Here’s what worked for me.

First of all, tell Gnome to go idle after 5 minutes, keep its hands off the sleep settings, and set a 15 minute timeout on battery and a 30 minute timeout when charging:

gsettings set org.gnome.desktop.session idle-delay 300
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-battery-timeout 900
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-battery-type 'nothing'
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-timeout 1800
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-type 'nothing'

Then we need to create some config files to tell systemd how to sleep and hibernate. You can see the default files in /usr/lib/systemd/ if you want to see all the options available - use man logind.conf and man systemd-sleep.conf to see the details of the various options. First of all, create /etc/systemd/logind.conf as follows:

[Login]
LidSwitchIgnoreInhibited=yes
HoldoffTimeoutSec=20s
IdleAction=suspend-then-hibernate
IdleActionSec=30s

Then create /etc/systemd/sleep.conf:

[Sleep]
HibernateDelaySec=300s

You can obviously adjust the timings above to your liking, to tinker with the gaps between screen-off, sleep, suspend and hibernate.

Hope this helps someone!

14 Likes

It turns out that this working with secure-boot was a bug :frowning:
Bug 2333706 - Kernel 6.12.6 kernel lockdown disabled

This now only works if you disable secure boot

3 Likes

@davepwsmith would it make sense to create a ujust script for these steps asking the user to reboot after executing ujust enable-hibernation? Inculding the gsettings configuration, they make a lot of sense.

Hello all,

Yes, this should work on some devices, will only work some of the time on others. AI 300 Series for example is going to be great 3 times in a row, fail out of no where to boot up to saved state. It’s a bug. 7040 Series, etc, this likely works great.

it is critical when putting a guide out to be hyper clear on specs tested with. :slight_smile:

Sure but that applies to everything. It works for the majority and the minority will need a few extra steps. And bugs are bugs that can be introduced for any system.

Still think a just script integrated in the UB releases would be great. I have this working for years (steps from Fedora forum for Silverblue) on several devices. From Intel 7th gen to Intel 12th gen and even AMD 4800u to 6600H.

Worked fine every time.

I love the idea and FWIW, as the Linux Support Lead for Framework, am interested in progress with that. But I want to make sure I am following which hardware this was tested on.

So Framework specifically, 12th gen (hibernate works in my past tests), I asked as there are quirks and other related considerations with the latest generation of AMD offerings we have out currently. But yes, for older gen offerings, should work great. :grinning_face:

Same for 7040 Series, hibernate should work like a treat. AI 300, in my exhaustive testing, it was good 6 out of 11 times for coming out of hibernate.

Again, not disparaging at all, just important to set expectations for those trying this. Because it ends up as a ticket for my team later. :sweat_smile:

This was on an 11th gen Intel i7 fwiw - to be honest the state of hibernation and suspend on Linux seems like a bit of a shitshow anyway - I don’t know if the framework model that I have is particularly unlucky for battery life in suspend, or whether (as I suspect) it’s Linux-on-laptops in general, but it’s hilariously bad, it barely lasts overnight. Which is why I was so happy to get hibernate working. It’s a shame it was so difficult because I love everything else about the machine.

I know that it’s not a very fair comparison but I’m pretty sure I could leave my company’s MacBook Pro closed for a month and just pick up where I left off!

The next challenge is to get all this working alongside closed-lid docking on usb-c.

I appreciate that you don’t want extra support tickets, but it was a total arse-ache to cobble together all the bits of information I needed from the depths of people’s blogs and whatever, and so I thought I would document clearly what has worked for me in the hopes of saving someone else the hassle. I don’t think it would fly as a generic script, there’s too much possibility of borking something I expect. I think it’s abundantly clear from the hoops you have to jump through that this isn’t going to ‘just work’… and in no way could this be construed as official framework advice, this isn’t even a framework forum :man_shrugging:

1 Like

This also entails that there would be somekind of support for this, which we cannot provide.

So it might work for some, but when it doesn’t it would be a support request to the maintainers to check why it wont work.

As this can work and not work between kernel releases, software updates and whatnot, it better to let users do these on their own machines. Officially we don’t support hibernation, until Fedora supports it officially on their end.

I get your point. But waiting for Fedora means it will never be supported. I even saw a statement on their forum that officially they don’t support laptops :sweat_smile:

I wonder how this works for Framework Laptops, surely Framework supports hibernating their laptops on Linux?

@davepwsmith I am missing a few steps:

  1. Should the offset for btrfs not be calculated? This was the case last time I setup hibernation (over a year ago)
  2. systemctl hibernate seems too early, since it hasn’t been enabled yet after step 1:
    ``
    systemctl hibernate
    Call to Hibernate failed: Sleep verb ‘hibernate’ is not configured or configuration is not supported by kernel
    ```
  3. you can also create a file systemd_hibernate.te with the following content:” could you add to this guide how one should do that? I believe there was a way to check what semodules are currently being used, to ensure the user captures all of them in the new file.. but the guide on the Fedora forum has been demolished by its moderators in their attempt to make it more clear..