{"id":127159,"date":"2022-08-10T08:07:00","date_gmt":"2022-08-10T08:07:00","guid":{"rendered":"https:\/\/fedoramagazine.org\/?p=36859"},"modified":"2022-08-10T08:07:00","modified_gmt":"2022-08-10T08:07:00","slug":"hibernation-in-fedora-workstation","status":"publish","type":"post","link":"https:\/\/sickgaming.net\/blog\/2022\/08\/10\/hibernation-in-fedora-workstation\/","title":{"rendered":"Hibernation in Fedora Workstation"},"content":{"rendered":"<p>This article walks you through the manual setup for hibernation in Fedora Linux 36 Workstation using BTRFS and is based on a <a href=\"https:\/\/gist.github.com\/eloylp\/b0d64d3c947dbfb23d13864e0c051c67\" target=\"_blank\" rel=\"noreferrer noopener\">gist by eloylp on github<\/a>.<\/p>\n<p> <span id=\"more-36859\"><\/span> <\/p>\n<h2>Goal and Rationale<\/h2>\n<p>Hibernation stores the current runtime state of your machine &#8211; effectively the contents of your RAM, onto disk and does a clean shutdown. Upon next boot this state is restored from disk to memory such that everything, including open programs, is how you left it.<\/p>\n<p>Fedora Workstation uses ZRAM. This is a sophisticated approach to swap using compression inside a portion of your RAM to avoid the slower on-disk swap files. Unfortunately this means you don&#8217;t have persistent space to move your RAM upon hibernation when powering off your machine.<\/p>\n<h2>How it works<\/h2>\n<p>The technique configures <em>systemd<\/em> and <em>dracut<\/em> to store and restore the contents of your RAM in a temporary swap file on disk. The swap file is created just before and removed right after hibernation to avoid trouble with ZRAM. A persistent swap file is not recommended in conjunction with ZRAM, as it creates some confusing problems compromising your systems stability.<\/p>\n<h2>A word on compatibility and expectations<\/h2>\n<p>Hibernation following this guide might not work flawless on your particular machine(s). Due to possible shortcomings of certain drivers you might experience glitches like non-working wifi or display after resuming from hibernation. In that case feel free to reach out to the comment section of the <a href=\"https:\/\/gist.github.com\/eloylp\/b0d64d3c947dbfb23d13864e0c051c67\" target=\"_blank\" rel=\"noreferrer noopener\">gist on github<\/a>, or try the tips from the troubleshooting section at the bottom of this article.<\/p>\n<p>The changes introduced in this article are linked to the systemd hibernation.service and hibernation.target units and hence won&#8217;t execute on their own nor interfere with your system if you don&#8217;t initiate a hibernation. That being said, if it does not work it still adds some small bloat which you might want to remove.<\/p>\n<h2>Hibernation in Fedora Workstation<\/h2>\n<p>The first step is to create a btrfs sub volume to contain the swap file.<\/p>\n<pre class=\"wp-block-preformatted\">$ <strong>btrfs subvolume create \/swap<\/strong><\/pre>\n<p>In order to calculate the size of your swap file use <em>swapon<\/em> to get the size of your <em>zram<\/em> device.<\/p>\n<pre class=\"wp-block-preformatted\"><strong>$ swapon<\/strong>\nNAME TYPE SIZE USED PRIO\n\/dev\/zram0 partition 8G 0B 100<\/pre>\n<p>In this example the machine has 16G of RAM and a 8G zram device. ZRAM stores roughly double the amount of system RAM compressed in a portion of your RAM. Let that sink in for a moment. This means that in total the memory of this machine can hold 8G * 2 + 8G of RAM which equals 24G uncompressed data. Create and configure the swapfile using the following commands.<\/p>\n<pre class=\"wp-block-preformatted\">$ t<strong>ouch \/swap\/swapfile<\/strong>\n<em># Disable Copy On Write on the file<\/em>\n<strong>$ chattr +C \/swap\/swapfile\n$ fallocate --length 24G \/swap\/swapfile\n$ chmod 600 \/swap\/swapfile $ mkswap \/swap\/swapfile<\/strong><\/pre>\n<p>Modify the dracut configuration and rebuild your initramfs to include the <\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;border:1px solid #9F9F9F;width:435px\">\n<div class=\"text codecolorer\" style=\"padding:5px;font:normal 12px\/1.4em Monaco, Lucida Console, monospace\">resume<\/div>\n<\/div>\n<p> module, so it can later restore the state at boot.<\/p>\n<pre class=\"wp-block-preformatted\"><strong>$ cat &lt;&lt;-EOF | sudo tee \/etc\/dracut.conf.d\/resume.conf<\/strong>\n<strong>add_dracutmodules+=\" resume \"<\/strong>\nEOF\n<strong>$ dracut -f<\/strong><\/pre>\n<p>In order to configure grub to tell the kernel to resume from hibernation using the swapfile, you need the UUID and the physical offset.<\/p>\n<p>Use the following command to determine the UUID of the swap file and take note of it.<\/p>\n<pre class=\"wp-block-preformatted\"><strong>$ findmnt -no UUID -T \/swap\/swapfile<\/strong>\ndbb0f71f-8fe9-491e-bce7-4e0e3125ecb8<\/pre>\n<p>Calculate the correct offset. In order to do this you&#8217;ll unfortunately need <em>gcc<\/em> and the <a href=\"https:\/\/github.com\/osandov\/osandov-linux\/blob\/master\/scripts\/btrfs_map_physical.c\" target=\"_blank\" rel=\"noreferrer noopener\">source of the btrfs_map_physical tool<\/a>, which computes the physical offset of the swapfile on disk. Invoke gcc in the directory you placed the source in and run the tool.<\/p>\n<pre class=\"wp-block-preformatted\"><strong>$ gcc -O2 -o btrfs_map_physical btrfs_map_physical.c<\/strong>\n<strong>$ .\/btrfs_map_physical \/path\/to\/swapfile<\/strong> FILE OFFSET EXTENT TYPE LOGICAL SIZE LOGICAL OFFSET PHYSICAL SIZE DEVID PHYSICAL OFFSET\n0 regular 4096 2927632384 268435456 1 &lt;4009762816&gt;\n4096 prealloc 268431360 2927636480 268431360 1 4009766912\n268435456 prealloc 268435456 3251634176 268435456 1 4333764608\n536870912 prealloc 268435456 3520069632 268435456 1 4602200064\n805306368 prealloc 268435456 3788505088 268435456 1 4870635520\n1073741824 prealloc 268435456 4056940544 268435456 1 5139070976\n1342177280 prealloc 268435456 4325376000 268435456 1 5407506432\n1610612736 prealloc 268435456 4593811456 268435456 1 5675941888<\/pre>\n<p>The first value in the <em>PHYSICAL OFFSET<\/em> column is the relevant one. In the above example it is <strong>4009762816<\/strong>.<\/p>\n<p>Take note of the <em>pagesize<\/em> you get from <em>getconf PAGESIZE<\/em>.<\/p>\n<p>Calculate the kernel <em>resume_offset<\/em> through division of <em>physical offset<\/em> by the <em>pagesize<\/em>. In this example that is <em>4009762816 \/ 4096 = 978946<\/em>.<\/p>\n<p>Update your grub configuration file and add the <em>resume<\/em> and <em>resume_offset<\/em> kernel cmdline parameters.<\/p>\n<pre class=\"wp-block-preformatted\">grubby --args=\"resume=UUID=dbb0f71f-8fe9-491e-bce7-4e0e3125ecb8 resume_offset=2459934\" --update-kernel=ALL<\/pre>\n<p>The created <em>swapfile<\/em> is only used in the hibernation stage of system shutdown and boot hence not configured in <em>fstab<\/em>. Systemd units control this behavior, so create the two units <em>hibernate-preparation.service<\/em> and <em>hibernate-resume.service<\/em>.<\/p>\n<pre class=\"wp-block-preformatted\"><strong>$ cat &lt;&lt;-EOF | sudo tee \/etc\/systemd\/system\/hibernate-preparation.service<\/strong>\n[Unit]\nDescription=Enable swap file and disable zram before hibernate\nBefore=systemd-hibernate.service [Service]\nUser=root\nType=oneshot\nExecStart=\/bin\/bash -c \"\/usr\/sbin\/swapon \/swap\/swapfile &amp;&amp; \/usr\/sbin\/swapoff \/dev\/zram0\" [Install]\nWantedBy=systemd-hibernate.service\nEOF\n<strong>$ systemctl enable hibernate-preparation.service<\/strong>\n<strong>$ cat &lt;&lt;-EOF | sudo tee \/etc\/systemd\/system\/hibernate-resume.service<\/strong>\n[Unit]\nDescription=Disable swap after resuming from hibernation\nAfter=hibernate.target [Service]\nUser=root\nType=oneshot\nExecStart=\/usr\/sbin\/swapoff \/swap\/swapfile [Install]\nWantedBy=hibernate.target\nEOF\n<strong>$ systemctl enable hibernate-resume.service<\/strong><\/pre>\n<p>Systemd does memory checks on login and hibernation. In order to avoid issues when moving the memory back and forth between <em>swapfile<\/em> and <em>zram<\/em> disable some of them.<\/p>\n<pre class=\"wp-block-preformatted\"><strong>$ mkdir -p \/etc\/systemd\/system\/systemd-logind.service.d\/\n$ cat &lt;&lt;-EOF | sudo tee \/etc\/systemd\/system\/systemd-logind.service.d<\/strong>\/override.conf\n[Service]\nEnvironment=SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1\nEOF\n<strong>$ mkdir -p \/etc\/systemd\/system\/systemd-hibernate.service.d\/\n$ cat &lt;&lt;-EOF | sudo tee \/etc\/systemd\/system\/systemd-hibernate.service.d\/override.conf<\/strong>\n[Service]\nEnvironment=SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1\nEOF<\/pre>\n<p><strong>Reboot your machine for the changes to take effect<\/strong>. The following SELinux configuration won&#8217;t work if you don&#8217;t reboot first.<\/p>\n<p>SELinux won&#8217;t like hibernation attempts just yet. Change that with a new policy. An easy although &#8220;brute&#8221; approach is to initiate hibernation and use the audit log of this failed attempt via <em>audit2allow<\/em>. The following command will fail, returning you to a login prompt.<\/p>\n<pre class=\"wp-block-preformatted\">systemctl hibernate<\/pre>\n<p>After you&#8217;ve logged in again check the audit log, compile a policy and install it. The <em>-b<\/em> option filters for audit log entries from last boot. The <em>-M<\/em> option compiles all filtered rules into a module, which is then installed using <em>semodule -i<\/em>.<\/p>\n<pre class=\"wp-block-preformatted\"><strong>$ audit2allow -b<\/strong>\n#============= systemd_sleep_t ==============\nallow systemd_sleep_t unlabeled_t:dir search;\n<strong>$ cd \/tmp\n$ audit2allow -b -M systemd_sleep\n$ semodule -i systemd_sleep.pp<\/strong><\/pre>\n<p>Check that hibernation is working via <em>systemctl hibernate<\/em> again. After resume check that ZRAM is indeed the only active swap device.<\/p>\n<pre class=\"wp-block-preformatted\"><strong>$ swapon<\/strong>\nNAME TYPE SIZE USED PRIO\n\/dev\/zram0 partition 8G 0B 100<\/pre>\n<p>You now have hibernation configured.<\/p>\n<h2>GNOME Shell hibernation integration<\/h2>\n<p>You might want to add a hibernation button to the GNOME Shell &#8220;Power Off \/ Logout&#8221; section. Check out the extension <a href=\"https:\/\/github.com\/arelange\/gnome-shell-extension-hibernate-status\" target=\"_blank\" rel=\"noreferrer noopener\">Hibernate Status Button<\/a> to do so.<\/p>\n<h2>Troubleshooting<\/h2>\n<p>A first place to troubleshoot any problems is through <em>journalctl -b<\/em>. Have a look around the end of the log, after trying to hibernate, to pin-point log entries that tell you what might be wrong.<\/p>\n<p>Another source of information on errors is the Problem Reporting tool. Especially problems, that are not common but more specific to your hardware configuration. Have a look at it before and after attempting hibernation and see if something comes up. Follow up on any issues via BugZilla and see if others experience similar problems.<\/p>\n<h2>Revert the changes<\/h2>\n<p>To reverse the changes made above, follow this check-list:<\/p>\n<ul>\n<li>remove the swapfile<\/li>\n<li>remove the swap subvolume<\/li>\n<li>remove the dracut configuration and rebuild dracut<\/li>\n<li>remove kernel cmdline args via <em>grubby &#8211;remove-args=<\/em><\/li>\n<li>disable and remove hibernation preparation and resume services<\/li>\n<li>remove systemd overrides for <em>systemd-logind.service<\/em> and <em>systemd-hibernation.service<\/em><\/li>\n<li>remove SELinux module via <em>semodule -r systemd_sleep<\/em><\/li>\n<\/ul>\n<h2>Credits and Additional Resources<\/h2>\n<p>This article is a community effort based primarily on the work of eloylp. As author of this article I&#8217;d like to make transparent that I&#8217;ve participated in the discussion to advance the gist behind this but many more minds contributed to make this work. Make certain to check out the <a href=\"https:\/\/gist.github.com\/eloylp\/b0d64d3c947dbfb23d13864e0c051c67?permalink_comment_id=3889734#gistcomment-3889734\" target=\"_blank\" rel=\"noreferrer noopener\">discussion on github<\/a>.<\/p>\n<p>There are already some <em>ansible<\/em> playbooks and shell scripts to automate the process depicted in this guide. For example check out the shell scripts by <a href=\"https:\/\/pastebin.com\/nLSkaMQZ\" target=\"_blank\" rel=\"noreferrer noopener\">krokwen<\/a> and <a href=\"https:\/\/github.com\/pietryszak\/fedora-hibernation\" target=\"_blank\" rel=\"noreferrer noopener\">pietryszak<\/a> or the <em>ansible<\/em> playbook by <a href=\"https:\/\/github.com\/jorp\/fedora_hibernate\" target=\"_blank\" rel=\"noreferrer noopener\">jorp<\/a><\/p>\n<p>See the <a href=\"https:\/\/wiki.archlinux.org\/title\/Power_management\/Suspend_and_hibernate#Hibernation_into_swap_file_on_Btrfs\" target=\"_blank\" rel=\"noreferrer noopener\">arch wiki<\/a> for the full guide on how to calculate the swapfile offset.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article walks you through the manual setup for hibernation in Fedora Linux 36 Workstation using BTRFS and is based on a gist by eloylp on github. Goal and Rationale Hibernation stores the current runtime state of your machine &#8211; effectively the contents of your RAM, onto disk and does a clean shutdown. Upon next [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[48],"tags":[45,61,46,47],"class_list":["post-127159","post","type-post","status-publish","format-standard","hentry","category-fedora-os","tag-fedora","tag-fedora-project-community","tag-magazine","tag-news"],"_links":{"self":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/127159","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/comments?post=127159"}],"version-history":[{"count":0,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/posts\/127159\/revisions"}],"wp:attachment":[{"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/media?parent=127159"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/categories?post=127159"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sickgaming.net\/blog\/wp-json\/wp\/v2\/tags?post=127159"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}