I spent time yesterday making HybridSleep
and Hibernate
work in Fedora 32
on a ThinkPad X1 Carbon with an encrypted
disk.
I don’t ever plan to manually use hybrid-sleep or hibernate; I’d instead just
lock my screen or close the laptop lid. So why bother to have these work?
It’s because hybrid sleep and hibernate are useful to have when battery power
runs out. You’ll likely find in /etc/UPower/UPower.conf
that your machine
attempts hybrid-sleep, hibernate, and a full shutdown, in this order, when the
battery runs out. If you don’t want to lose working state, you need either a
working hibernate or a working hybrid-sleep.
$ cat /etc/UPower/UPower.conf | tail -n 3
# If HybridSleep isn't available, Hibernate will be used
# If Hibernate isn't available, PowerOff will be used
CriticalPowerAction=HybridSleep
$
How to use this guide
There are typically 5-6 issues. Each of these is described below, along with
steps to address them. I recommend incrementally addressing the issues and
checking if hibernate works after each step — as opposed to implementing all
fixes, some of which may turn out to be unnecessary in your case.
Does it already just work?
The first thing to do, before doing extra work, is to check whether hibernate
already just works™ in your computer. If you’re one of the lucky ones, then:
$ cat /sys/power/state
freeze mem disk
$
should include the output “disk”. Next try:
Fingers crossed—your screen goes blank and your computer turns off. Turn on
your computer again, log in as usual, and if your open windows were preserved
you’re good to go—hibernate worked! You should try the same with hybrid-sleep.
On the other hand, if the /sys/power/state
output doesn’t include “disk”,
and/or you see a failure message, you need to dig in further.
Sleep verb "hibernate" not supported
SecureBoot
One of the most common reasons for the inability to hibernate, and this is
most likely true for Windows 8/10 laptops, is that SecureBoot is enabled.
Disable SecureBoot in your BIOS; for my ThinkPad this involves:
- Hit [Enter] to interrupt the normal boot process
- [F1] to enter BIOS setup
- Navigate to “Security” in the sidebar
- Navigate to “Secure Boot” in the main area and turn it off
- [F10] to save & exit
As for whether you should disable SecureBoot, I recommend doing some
research into this topic, since SecureBoot provides security benefits you
might value over the ability to hibernate.
Once you’ve disabled SecureBoot, try systemctl hibernate
again.
Insufficient swap
On to more gritty details. You should have swap space that matches or is
larger than the total memory of your machine. Check swap size:
# swapon --show
NAME TYPE SIZE USED PRIO
/dev/dm-2 partition 2.2G 0B -2
Check total memory size in unit kibibyte:
$ cat /proc/meminfo | grep MemTotal | awk '{ print $2 }'
16192912
$
If swap is insufficiently-sized you should disable the existing swap on the
running system:
and disable it for future boots by deleting the corresponding entry from /etc/fstab
.
Now add a sufficiently-sized swap file. Here’s a terse but accurate guide.
# dd if=/dev/zero bs=16192912 count=1024 |
pv |
dd of=/swapfile
# chmod 0600 /swapfile
# mkswap /swapfile
# swapon /swapfile
#
Enable the swap file for future boots in /etc/fstab
:
/swapfile swap swap defaults 0 0
GRUB
Next up, grub has to know to resume from your swap partition.
Inspect the contents of GRUB_CMDLINE_LINUX
.
GRUB_CMDLINE_LINUX="resume=/dev/mapper/fedora_localhost--live-swap rd.lvm.lv=fedora_localhost-live/root rd.luks.uuid=luks-0962d4ff-5b38-4a4e-99e3-30509326c9b1 rd.lvm.lv=fedora_localhost-live/swap rhgb quiet"
The important parts required here are the resume parameter and the
rd.lvm.lv parameter for swap. Their actual values might be different for
you. If either of resume or rd.lvm.lv for swap is missing, you should add
it. But first you need to determine the values to use.
For resume, the value can be found by running the following command. In this
example, the value is /dev/mapper/fedora_localhost--live-swap
.
# systemctl list-units | grep swap
dev-mapper-fedora_localhost\x2d\x2dlive\x2dswap.swap loaded active active /dev/mapper/fedora_localhost--live-swap
swap.target loaded active active Swap
For rd.lvm.lv for swap, the value can be found by running the following
command. In this example, the value is fedora_localhost-live/swap
.
# lvscan
ACTIVE '/dev/fedora_localhost-live/swap' [7.72 GiB] inherit
ACTIVE '/dev/fedora_localhost-live/home' [<102.84 GiB] inherit
ACTIVE '/dev/fedora_localhost-live/root' [<69.99 GiB] inherit
If you’re using a swap file, as opposed to a swap partition, you additionally
need the resume_offset parameter. The value is can be found by running the
following command. In the command output the value you’re looking for is the
first number, without the trailing dots, under the physical_offset column. If
there are multiple lines of output, use only the first line.
After you’ve updated GRUB_CMDLINE_LINUX
in /etc/default/grub
, you must
generate grub.cfg
to reflect the update. Assuming you’re using a UEFI
computer, which most modern computers are, run:
# grub2-mkconfig -o /etc/grub2-efi.cfg
dracut
Finally, the initramfs, which is managed by dracut
. Start by running:
The output (formatted here for readability), if set up correctly for
hibernate, should include the resume parameter.
rd.luks.uuid=luks-0962d4ff-5b38-4a4e-99e3-30509326c9b1
rd.lvm.lv=fedora_localhost-live/swap
rd.lvm.lv=fedora_localhost-live/root
resume=/dev/mapper/fedora_localhost--live-swap
root=/dev/mapper/fedora_localhost--live-root
rootfstype=ext4 rootflags=rw,relatime,seclabel
If it doesn’t, you may need to add “resume” to the list of dracut modules.
Create /etc/dracut.conf.d/resume.conf
with the following content. See the
man page for dracut.conf
to learn more.
add_dracutmodules+=" resume "
Regenerate the initramfs:
and check that the resume parameter is now included.
TODO(nishanths): does this need to list the resume_offset parameter?
With all this done you should be ready to try systemctl hibernate
again,
which, fingers crossed, now works.
More Resources
https://bugzilla.redhat.com/show_bug.cgi?id=1206936
https://ask.fedoraproject.org/t/howto-hibernate-into-swap-file/6542