If you have a Linux laptop you probably wonder where's hibernation and hybrid sleep – especially if you're using an Ubuntu-based distribution such as Ubuntu Desktop, Kubuntu, TUXEDO OS, KDE Neon, etc. In this article we'll see what hibernation and hybrid sleep are, their caveats, and how to enable them on Linux with special instructions for Ubuntu-based distros. My test machine is a TUXEDO InfinityBook Pro 14" Gen 7, a rebranded Clevo laptop I purchased a couple of years ago. Without further ado, let's dive into it.

What's hibernation?

Having a computer running all the time, even when not using it, is wasting energy. This is especially important on an unplugged laptop as it depletes the battery for no good reason.

The simplest way to deal with that is suspending the Operating System, also known as “sleep”, or “suspend to RAM”. The memory remains powered on, but the CPU and the various chipsets and devices are either completely turned off, or running at a very low power state. This allows for a very fast restoration of the computer state, at the expense of still depleting your battery (albeit at a lower rate).

The alternative to sleep mode is hibernation, also known as “suspend to disk”. The contents of the memory are written to disk, then the computer fully shuts down. When you power it on again, the memory contents are read from disk, and your Operating System is restored to the exact state you had when you put the computer to hibernation. This allows for essentially zero power consumption, at the expense of a longer time to fully restore the computer state – usually a bit less time than a full cold boot.

Hybrid sleep, as the name implies, is a combination of the two. You put your computer to sleep like normal. However, if the battery charge reaches a critical state (typically 5% charge), or the computer has been sleeping for a set period of time the computer will wake up and put itself into hibernation. This combines the benefits of both approaches. You can resume your work quickly if you're taking a short break, but you won't waste your battery charge, or lose your session, if you go on an unexpectedly longer break or your battery charge is really low. This is how modern Windows and Apple laptops work, and you can have it on your Linux laptop, too!

Sleep caveats

First of all, sleep and hibernation must be supported by your computer's CPU and firmware.  You can check if they are supported by doing

cat /sys/power/state

If you see mem in the output your computer supports sleep mode. If you see disk then your computer supports hibernation.

Sleep mode can be implemented in one of many ways. The most common ones are s2idle and deep. You can see which methods are supported by your computer, and which one is used, by doing

cat /sys/power/mem_sleep

The value in brackets is the one which is going to be used. And this is where things start getting confusing. Please stay with me.

Historically, s2idle was (the past tense is important here) the least desirable sleep method as it only put the CPU and devices in a low power state. The system was effectively still running, albeit at a somewhat reduced power draw. Conversely, deep was the most preferred method as it turned everything off except for RAM. The reason there were two vastly different implementations was hardware support; s2idle is implemented purely in software, whereas deep requires firmware support.

If you have a laptop with a 4th gen Intel Core processor or newer you might be surprised to see that the default sleep mode is the supposedly inferior s2idle. Well, here is the confusing part. On these newer processors the s2idle actually refers to a different sleep mode called Modern Sleep or Connected Sleep, implementing Intel's S0ix power state. It allows a power consumption that's as low as deep, but with an even faster restoration time. However, if your firmware is buggy it may end up drawing more power than deep. If you find that your battery depletes in a matter of hours using this sleep mode, you may want to try the deep sleep mode instead.

If you want to change the sleep mode used by the kernel to deep you can edit /etc/default/grub and change the line starting with GRUB_CMDLINE_LINUX_DEFAULT, adding mem_sleep_default=deep into it. Then run sudo update-grub to reinstall the boot loader, and reboot your computer.

Using the deep sleep mode is unlikely to work on modern systems. If your computer fails to wake up from sleep you need to instead use mem_sleep_default=s2idle in GRUB's configuration.

Hibernation pitfalls

Hibernation has to store your RAM contents onto disk. This requires a swap partition or swap file that's at least as big as your RAM, plus however much swap space you normally use. My rule of thumb is amount of RAM plus one or two GiB. Note that this space must be allocated in a SINGLE swap partition or swap file; having two or more swap spaces totaling the right amount won't cut it!

Because of the above, if you have lots of RAM but a small storage device hibernation may present a challenge insofar it “wastes” disk space. That was a legitimate concern a few years ago. Now, you can get a pretty decent 2 TiB NVMe drive for about €100, rendering this point moot for most people. If, however, budget or policy prevent you from upgrading to roomier storage you may want to weigh whether hibernation is more valuable to you than storage space. It all comes down to what is your use case.

Hibernation stores all of your RAM contents into the disk. If you are using an unencrypted swap partition, or a swap file (because swap files can be used with hibernation only if they are stored in unencrypted partitions) you have a security risk. If someone steals your device while it's hibernating they will be able to read your RAM contents as stored on your disk, extracting any secrets stored in memory. This can be detrimental to security. I advise that you always use an encrypted swap partition, or a logical swap partition in a LUKS2-encrypted LVM partition. In fact, I would NOT recommend setting up hibernation if you don't use swap space encryption.

Remember when I said that hibernating your computer uses “essentially zero” power? Well, that's not entirely true. A small amount of power is always used by your computer's firmware so that the computer's power button can work. In practical terms, it takes weeks to drain the battery in this power off state, and it only becomes relevant if you are not using your laptop for weeks or months at a time.

Finally, hibernation can be finicky. Your hardware may simply not work very well with going into or coming out of hibernation. I had a desktop like that. One out of five times it'd come out of hibernation it would simply hang, except if I used an LTS kernel, pointing to some sort of kernel driver issue. I sold that desktop before I had the chance to troubleshoot it, so there's that.

Enabling hibernation

Step 1. Can you hibernate?

If you skimped the information above, start by running cat /sys/power/state and make sure disk is listed in the output. If it's not, hibernation is not supported by your computer's firmware. End of story, so sorry.

Step 2. Locate your swap partition

Make sure you have a swap partition that's big enough. Rule of thumb: the partition size should be the amount of memory you have, plus 1 or 2 GiB. I have 64GiB or RAM, so I created a partition that's 65 GiB.

If you are using LVM you need to delete your swap partition, resize your data partition(s), and create a new swap partition. Don't just resize the swap partition.

Make sure the swap partition is listed in /etc/fstab. For example:

UUID=01234567-c0ff-eede-adbe-ef0123456789       none    swap    defaults        0       0

Note down the UUID you see there. If you see a device name instead (such as /dev/sda1) run blkid and note down the UUID reported for that device. In our example, the UUID will be 01234567-c0ff-eede-adbe-ef0123456789.

Step 3. Make sure Linux knows about the swap partition

Make sure the swap partition is enabled by running swapon. You should see your swap device being listed:

NAME      TYPE      SIZE USED PRIO
/dev/dm-2 partition  65G  44M   -2

Note that you see the device name, not the UUID. If you are using LVM on a LUKS2-encrypted partition like I do you will see a device name similar to /dev/dm-2 which may not ring a bell. If you run ls -l /dev/mapper you will see something that makes a lot more sense:

total 0
drwxr-xr-x  2 root root     120 Apr  20 19:17 ./
drwxr-xr-x 22 root root    4820 Apr  20 19:17 ../
crw-------  1 root root 10, 236 Apr  20 19:17 control
lrwxrwxrwx  1 root root       7 Apr  20 19:17 crypt_dev_nvme0n1p3 -> ../dm-0
lrwxrwxrwx  1 root root       7 Apr  20 19:17 system-root -> ../dm-1
lrwxrwxrwx  1 root root       7 Apr  20 19:17 system-swap -> ../dm-2

That last line tells me that /dev/mapper/system-swap is /dev/dm-2 so, indeed, my logical swap partition on the LUKS2-encrypted LVM is the one that swapon reports as enabled.

If you do not see your swap partition enabled make sure to add it to /etc/fstab and run sudo swapon -a to enable all swap partitions.

Do not proceed until you have verified that your swap partition is enabled, and it's big enough for hibernation.

Step 4. Update the Linux kernel parameters

Edit the file /etc/default/grub e.g. by running sudo nano /etc/default/grub.

Find the line starting with GRUB_CMDLINE_LINUX_DEFAULT and append resume=UUID=01234567-c0ff-eede-adbe-ef0123456789 to it, where 01234567-c0ff-eede-adbe-ef0123456789 is the UUID of the swap partition. For example, if the line reads

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"

change it to read

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash resume=UUID=01234567-c0ff-eede-adbe-ef0123456789"

Then run sudo update-grub to update the boot loader.

Step 5. Update the initial RAM disk

We will need to create a new file /etc/initramfs-tools/conf.d/99-resume which tells the kernel's initial RAM disk where to look for hibernation data. For example, run sudo nano /etc/initramfs-tools/conf.d/99-resume and paste the following:

RESUME=UUID=01234567-c0ff-eede-adbe-ef0123456789

where 01234567-c0ff-eede-adbe-ef0123456789 is the UUID of the swap partition.

Then update the initial RAM disk by running sudo update-initramfs -k all -c

Step 6. Reboot

Reboot your computer.

Technically not necessary, but it's always a good idea to make sure the computer reboots normally i.e. we didn't botch anything up to this point.

Step 7. Check hibernation works

Open a terminal and run systemctl hibernate

At this point you will see your session being paused, like when you enter sleep mode, and your screen may turn off and turn on again. Do not touch anything. After a few seconds your computer will shut down.

Wait a few seconds, then power up your computer again. After entering your disk encryption password (if you use any encrypted partitions) you should see a message that the system is resuming from such and such device. Wait a few seconds and you should be back to your display manager's login screen. Log in and you should you see your desktop, exactly as you left it. Success!

If you are on an Ubuntu-based distribution you may NOT see the hibernation menu item in your log out menu, nor have any control over hibernation configuration. This is normal, and we'll address it further below. Cool your jets.

Step 7. Configure hybrid sleep

Edit the /etc/systemd/sleep.conf file, e.g. sudo nano /etc/systemd/sleep.conf and append the following:

AllowHybridSleep=yes
HibernateDelaySec=30m

This tells systemd to enable hybrid sleep (suspend-then-hibernate), with the time threshold being 30 minutes. In other words, if your computer stays sleeping for 30 minutes it will wake up and hibernate itself. You can of course change that to your liking. If you want to test you can set this to 2 or 3 minutes; don't use smaller values, you may run into problems because entering sleep does take some amount of time.

Necessary tweaks for Ubuntu-based distros

If you are on an Ubuntu-based distribution you may have noted that you are missing a logout menu icon to hibernate your computer, and your power settings appear to be completely unaware of the fact that your computer now supports hibernation. That's because Ubuntu is explicitly disabling hibernation in all of its desktops. This unfortunately applies to downstream distributions like Kubuntu, KDE Neon, and TUXEDO OS.

We have to do TWO changes.

First, run sudo mkdir -p /var/lib/polkit-1/localauthority/50-local.d to create a new PolKit configuration directory, then sudo nano /var/lib/polkit-1/localauthority/50-local.d/99-hibernate.pkla and paste the following into the new file:

[Re-enable hibernate by default in upower]
Identity=unix-user:*
Action=org.freedesktop.upower.hibernate
ResultActive=yes

[Re-enable hibernate by default in logind]
Identity=unix-user:*
Action=org.freedesktop.login1.hibernate;org.freedesktop.login1.handle-hibernate-key;org.freedesktop.login1;org.freedesktop.login1.hibernate-multiple-sessions;org.freedesktop.login1.hibernate-ignore-inhibit;org.freedesktop.login1.manager.hibernate
ResultActive=yes
In some distributions you may have to create the file /etc/polkit-1/localauthority/50-local.d instead.

If you are wondering, this undoes Ubuntu's upstream disabling of hibernation in /var/lib/polkit-1/localauthority/10-vendor.d/com.ubuntu.desktop.pkla.

While this was enough for Ubuntu up to 20.04, newer versions of Ubuntu apply further PolKit rules which prevent non-root users from managing hibernation. Groan. So, let's create a new /etc/polkit-1/rules.d/99-hibernate.rules file to undo these changes. Run sudo nano /etc/polkit-1/rules.d/99-hibernate.rules and paste the following:

polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.login1.suspend" ||
        action.id == "org.freedesktop.login1.suspend-multiple-sessions" ||
        action.id == "org.freedesktop.login1.hibernate" ||
        action.id == "org.freedesktop.login1.hibernate-multiple-sessions" ||
        action.id == "org.freedesktop.login1.handle-hibernate-key" ||
        action.id == "org.freedesktop.login1.hibernate-ignore-inhibit" ||
        action.id == "org.freedesktop.login1" ||
        action.id == "org.freedesktop.login1.manager.hibernate") {
        return polkit.Result.YES;
    }
});

Now run systemctl restart polkit to apply our PolKit changes.

Log out, and then log back in for the desktop environment to see the PolKit changes.

At this point you should see the Hibernate icon (at least I do, in KDE), and be able to manage hibernation settings in your desktop environment's power settings.

To test that our changes did work run the following in a terminal window:

dbus-send --system --print-reply --dest=org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager.Hibernate boolean:true

You should see that your system goes into the hibernation procedure once you press ENTER.

Nicholas K. Dionysopoulos

A Mechanical Engineer turned Software Engineer, Nicholas has been active with Open Source Software since the 1990's and Joomla! in particular since it was called Mambo all the way back in 2004. Mostly known as the lead developer of Akeeba software, such as Akeeba Backup and Admin Tools, Nicholas has been a frequent core contributor to Joomla and author of several extensions.

No comments