fedora, btrfs, and hibernation

Here’s how to hibernate to disk when using the automatic partitioning scheme in Fedora 34 (btrfs+zram), optionally with luks enabled.

Originally this post was a lot longer, detailing each and every step suited for you to copy and paste. I decided to go ahead and automate the whole process with ansible instead.

A few things to keep in mind:

  • only run this after you’ve audited the playbook and understand what it’s doing
  • you’re using this at your own risk
  • Secure Boot must be disabled
  • this has only been tested with Fedora 34

FAQ

  • Where can I read more about why I can’t do this anymore?
  • Does btrfs make a difference?

Yes, you may notice the steps to create a swapfile are different than what you’re used to. We’ll have to use kernel 5.0+, and set NOCOW in order to gain btrfs swapfile support. More information is available on the btrfs wiki along with the ArchWiki.

Process

Below provides a very high level overview of the process, for more detail, check out my ansible playbook.

  • create an empty swapfile
    • set its attributes to NOCOW (chattr +C)
    • allocate the swapfile to be the same size as your system’s memory
      • note: you may be okay with a swap partition smaller than the size of your memory
  • set up a Linux swap area on your swapfile
  • enable your swapfile for paging and swapping
  • update /etc/fstab with your swapfile information
  • since there’s already an existing swap target (default zram device), create systemd overrides to avoid false positive errors about swap size.
  • get the physical swap offset by running btrfs_map_physical.c, as recommended by the ArchWiki.
    • since this step includes running some C program from the internet, I’ve opted to use a container (you should be auditing the code regardless though)
  • calculate the real swap offset
    • this is done by dividing the physical swap offset from above by the system’s page size
  • construct resume arguments for grub
    • use the uuid of your swapfile along with the swap offset calculated above
    • use grubby to update kernel arguments to include resume and resume_offset
  • add the resume module to dracut and regenerate the initramfs
    • add resume module under /etc/dracut.conf.d/resume.conf
    • dracut -f

After this, you’ll need to reboot and test hibernation with:

sudo systemctl hibernate

If you’re on GNOME, and would like hibernation back in in the status menu, check out the Hibernate Status Button GNOME shell extension.