For a while now I use Ubuntu family of Linux on my Framework. While the exact flavor might change (Kubuntu rules! :)), two things remain the same. ZFS and hibernation. If you want to install system from scratch, you can find post for many different Ubuntu releases. What I don’t have is a separate post with just a hibernation steps. So, here it is.
First, let’s discuss prerequisites. You MUST have a separate swap partition if you want to hibernate to a file on ZFS. My setup is usually something like this:
Partition | Type | Size (MB) | Description | |
---|---|---|---|---|
EFI | EF00 | FAT32 | 255 | Small EFI partition |
Boot | 8300 | EXT4 | 1,792 | Linux boot partition |
Swap | 8200 | - | 65,536 | Swap, minimum 40% of RAM |
(else) | 8309 | (whatever) | one or more partitions for system and data |
If you don’t have a separate partition, you can stop reading now and find somebody smarter. And no, the swap partition doesn’t need to be same size or larger than the amount of RAM you have. Minimum is actually 40% of your RAM (controlled by image_size parameter). Now, I’ve been guilty of having the swap the same size as RAM too. But that is not a requirement.
You also must have the Secure Boot disabled. If you don’t have it disabled, it will all seemingly work but system will never restore.
Steps I am giving here are for encrypted swap. I personally think that you should NEVER have unencrypted data on disk. NEVER. However, I am aware that most of people don’t care and see password entry as a chore. In one of the next posts, I will add instructions for non-encrypted swap too. So, if you are “one of those”, stay tuned.
Order of operations is quite fungible but, for the purpose of this guide, I will start with config files. There are two and whether you will modify them both depends on what you want to achieve.
In sleep.conf
, I adjust suspend settings to allow for Suspend-then-Hibernate setup. My preference is to have system hibernate after 13
minutes of sleep but you can change that to your liking.
sudo sed -i 's/.*AllowSuspend=.*/AllowSuspend=yes/' /etc/systemd/sleep.conf
sudo sed -i 's/.*AllowHibernation=.*/AllowHibernation=yes/' /etc/systemd/sleep.conf
sudo sed -i 's/.*AllowSuspendThenHibernate=.*/AllowSuspendThenHibernate=yes/' /etc/systemd/sleep.conf
sudo sed -i 's/.*HibernateMode=.*/HibernateMode=platform shutdown/' /etc/systemd/sleep.conf
sudo sed -i 's/.*HibernateDelaySec=.*/HibernateDelaySec=13min/' /etc/systemd/sleep.conf
Second config file is to reassign power button to hibernation. This is just my preference and, if you want power button to stay as-is, you can omit this step. For this, you need to install pm-utils
package, if not already present on your system. Again, these are settings I like so adjust as needed.
sudo apt install -y pm-utils
sudo sed -i 's/.*HandlePowerKey=.*/HandlePowerKey=hibernate/' /etc/systemd/logind.conf
sudo sed -i 's/.*HandleLidSwitch=.*/HandleLidSwitch=suspend-then-hibernate/' /etc/systemd/logind.conf
sudo sed -i 's/.*HandleLidSwitchExternalPower=.*/HandleLidSwitchExternalPower=ignore/' /etc/systemd/logind.conf
sudo sed -i 's/.*HoldoffTimeoutSec=.*/HoldoffTimeoutSec=13s/' /etc/systemd/logind.conf
With this sorted out, you need to make sure computer doesn’t wake up. This step can be skipped quite often, but not so with Framework. With Framework laptops you need to manually disable wakeup for i2c_hid_acpi
and xhci_hcd
devices.
These commands will generate script I personally use and allow for its execution upon sleep.
cat << EOF | sudo tee /usr/lib/systemd/system-sleep/framework
#!/bin/sh
case \$1 in
pre)
for DRIVER_LINK in \$(find /sys/devices/ -name "driver" -print); do
DEVICE_PATH=\$(dirname \$DRIVER_LINK)
if [ ! -f "\$DEVICE_PATH/power/wakeup" ]; then continue; fi
DRIVER=\$( basename \$(readlink -f \$DRIVER_LINK) )
if [ "\$DRIVER" = "i2c_hid_acpi" ] || [ "\$DRIVER" = "xhci_hcd" ]; then
echo disabled > \$DEVICE_PATH/power/wakeup
fi
done
;;
esac
EOF
sudo chmod +x /usr/lib/systemd/system-sleep/framework
Now, we can setup swap. For this I strongly recommend using variables as to avoid any naming issues. Replace/dev/disk/by-id/whatever-part3
).
PART=<part>
UUID=`sudo blkid -s PARTUUID -o value $PART`
Assuming your swap is not initialized, you need to do so.
sudo cryptsetup luksFormat -q --type luks2 \
--sector-size 4096 \
--cipher aes-xts-plain64 --key-size 256 \
--pbkdf argon2i /dev/disk/by-partuuid/$UUID
sudo cryptsetup luksOpen \
--persistent --allow-discards \
--perf-no_write_workqueue --perf-no_read_workqueue \
/dev/disk/by-partuuid/$UUID $UUID
mkswap /dev/mapper/$UUID
Of course, adding this to both crypttab
and fstab
is also needed for swap to work properly.
echo "$UUID PARTUUID=$UUID none luks,discard,initramfs,keyscript=decrypt_keyctl" | sudo tee -a /etc/crypttab
echo "/dev/mapper/$UUID none swap sw,nofail 0 0" | sudo tee -a /etc/fstab
The final step is adding swap as RESUME
into grub. Note that swap will be identified based on partition UUID.
sudo sed -i "s/^GRUB_CMDLINE_LINUX_DEFAULT.*/GRUB_CMDLINE_LINUX_DEFAULT=\"quiet splash \
rtc_cmos.use_acpi_alarm=1 \
RESUME=UUID=$(blkid -s UUID -o value /dev/mapper/$UUID)\"/" \
/etc/default/grub
With these things in place, you should be able to use hibernate. To check, use systemctl
.
sudo systemctl hibernate
And yes, you can probably use these steps with any laptop, not just Framework. However, I tested this on Framework and thus will not make other claims. :)