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
Steps to Enable
- 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
- 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.
- 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!