One feature desktop Linux has been lacking out of the box is hybrid-suspend, supported as of Kernel versions 3.6+.
The following guide lets you suspend to both memory and disk, so you never lose your work if your battery is depleted while suspended. The workflow looks like this:
- Suspend to RAM and create a hibernate image (for example, when you shut your lid)
- If you resume with battery power – you resume from memory
- If you run out of battery while suspended, use the hibernate image to resume
This allows you to never lose your work due to your battery going out.
Here’s how you set it up (example: Fedora 22+).
NOTE: You don’t need to have your swap partition space match your physical memory, you only need enough swap space to suspend your current memory usage footprint (usually a lot less).
1) Tell Your Desktop Environment to let systemd handle Power Management
(run as normal user)
XFCE
Use the xconf-query command below to tell systemd to handle power management.
xfconf-query -c xfce4-power-manager -p \
/xfce4-power-manager/logind-handle-lid-switch -s true
Note: In later versions of XFCE (4.13 or 4.14+) this xconf-query setting may not exist, in this case you’ll want to create it first.
xfconf-query -c xfce4-power-manager -p /logind-handle-lid-switch -n -t bool -s true
Now you can re-run the original command to set it.
You can query what the value is at any time by removing the -s true
xfconf-query -c xfce4-power-manager -p /xfce4-power-manager/logind-handle-lid-switch true
GNOME
This should work as-is with logind.conf settings below. I don’t run GNOME so this is untested – please comment if this doesn’t work and I’ll update the guide.
KDE/Plasma
You need to tell powerdevil to perform no action when the lid is closed.
After that you need to follow the instructions on comment #5 of this KDE bug report.
Update 2017-10: KDE now has an option to set lid close event to hybrid suspend in later versions.
Other Windows Managers (Awesome, i3, etc)
This should work out of the box.
2) Make Systemd (logind) Handle Close Lid Events with Hybrid Suspend
(run as root)
Uncomment/Edit the following lines in /etc/systemd/logind.conf
(you need both due to BZ#1039364)
HandleLidSwitch=hybrid-sleep
HandleLidSwitchDocked=hybrid-sleep
3) Install Systemd target to Lock Screen on Resume
(run as root)
Since systemd is now handling pm-suspend events, it has no way of telling your respective screensaver to lock. We need to utilize a systemd unit file to invoke screensaver on resume. I am going to focus on xscreensaver here as that’s the default for XFCE but see the below notes on other desktop environments.
** GNOME USERS ** Skip this step and see the stack exchange thread on gnome-screensaver via dbus
** KDE USERS ** You can skip this step.
** NOTE ** Change to your non-root username below before pasting the second part.
myuser=username
cat > /etc/systemd/system/screenlock.service << EOF [Unit] Description=Lock the screen on resume from suspend [Service] User=$myuser Environment=DISPLAY=:0 ExecStart=/usr/bin/xscreensaver-command -lock [Install] WantedBy=hybrid-sleep.target EOF
4) Start / Enable Systemd Lockscreen Service
(run as root)
systemctl restart systemd-logind
systemctl enable screenlock.service
systemctl start screenlock.service
Start the screenlock service, your screen will lock – unlock it once and off you go.
systemctl enable screenlock.service
5) Setup Kernel to use Swap Partition for Hibernate
(run as root)
5A) Obtain the UUID of your swap partition
** NOTE ** You need to take the output of blkid
like below for the next step.
blkid | grep swap
Note your output:
/dev/mapper/fedora-swap: UUID="cc4ed223-58db-43b9-9dd4-34bfabd0043a" TYPE="swap"
5B) Now set a temporary variable for swap UUID
swapuuid="cc4ed223-58db-43b9-9dd4-34bfabd0043a" && echo $swapuuid
5C) Add Resume line into Grub
This next command does a sed in-line edit on the GRUB_CMDLINE_LINUX_DEFAULT portion of grub.conf, use with care. We choose to append after “quiet” because everyone probably has that set.
cp /etc/default/grub /root/grub-backup && sed -i \ "s/quiet/quiet resume=\/dev\/disk\/by-uuid\/$swapuuid/" \ /etc/default/grub
5D) Regenerate your initrd so it contains resume= option
grub2-mkconfig -o /boot/grub2/grub.cfg
At this point you need to reboot to take effect, but everything should work.
Suspend when closing lid will take a few seconds longer than normal since you’re also copying a hibernate image but I think it’s well worth the price.
Is it Working?
If things are working correctly you should see both the lid sleep trigger via Systemd and PM utils saving your hibernated image. On Fedora 22+ a simple journalctl -xr showed this activity.
I have not found a way to quickly test hybrid suspend resume from hibernation without depleting the battery to 1-2% and closing the lid. Google Hangouts or similar activities always kills my battery quickly. It does work for me and others however and saved my work a few times.
example.com systemd-logind[1078]: Hibernating and suspending... example.com systemd-logind[1078]: Lid closed.
example.com kernel: PM: Wrote 2751856 kbytes in 4.02 seconds (684.54 MB/s) example.com kernel: PM: Image saving done. example.com kernel: PM: Image saving progress: 100% example.com kernel: PM: Image saving progress: 90% example.com kernel: PM: Image saving progress: 80% example.com kernel: PM: Image saving progress: 70% example.com kernel: PM: Image saving progress: 60% example.com kernel: PM: Image saving progress: 50% example.com kernel: PM: Image saving progress: 40% example.com kernel: PM: Image saving progress: 30% example.com kernel: PM: Image saving progress: 20% example.com kernel: PM: Image saving progress: 10% example.com kernel: PM: Image saving progress: 0% example.com kernel: PM: Using 3 thread(s) for compression. : Compressing and saving image data (687964 pages)...
Black Screen on Hibernate Resume
Sometimes you’ll get what appears to be a black screen when your battery is depleted and you resume from an hibernate image. Simply increase your screen brightness. This might just be a bug and you can also use the following entry in /etc/default/grub for a permanent fix:
video.use_native_backlight=0
Using Lots of Memory prior to Hybrid Suspend
One limitation to hibernate is that you cannot be using more physical memory than the size allotted to your swap partition. While this is rare (Swap is usually the amount of your memory or around 8GB) it can happen.
Note, this does not mean that you need a swap partition equal to your total memory, only that your active memory usage shouldn’t exceed your swap partition size. This is usually rare in modern Linux operating systems. Below you can find some instructions to work around this if you run into this issue.
Resizing Swap Partition
Here’s some generic steps to expand your swap partition, stealing storage from your /home. Note: this will NOT work on XFS as there’s no way to shrink partitions, only grow them.
- Reboot into runlevel 1
- Unmount /home
- Resize your /home partition
lvresize --resizefs --size SIZE /dev/fedora/home
Note: SIZE should probably be the current size minus 8GB or whatever you’d need to make swap match your system memory.
- Extend your swap partition
swapoff -a ; lvextend /dev/fedora/swap -l +100%FREE ; swapon -a
Hey Will,
thanks a lot for the guide. One quick question. What is the best way to verify that the setup works as expected (except suspending and leave the notebook for 1 week to get the battery empty :D). Is there any log files to see, or any files created (like the hybrid image) that can be checked?
I am trying to implement the setup on RHEL 7.
Cheers
Oliver
LikeLiked by 1 person
Howdy Oliver, you should see both hybrid suspend being called by the lid close action and Systemd firing off to do that. Next, you’ll see the actual hibernate image creation in the logs. Below is an example. I have not found a way to “test” it other than do some task like running bluejeans or hangouts (they seem to kill laptop battery) until around 1-2% then closing the lid. Good question, I’ll add it to the guide.
(Lid Sleep Notification)
(hybrid suspend being called)
(saving of image – viewable via journalctl -xr for example)
LikeLike
thanks a lot, you saved me tons of time
LikeLike