Difficulty: ★★★☆☆
Create and activate a Swap Device
- Set the root device:
export fs_uuid=$(findmnt / -o UUID -n) && echo ${fs_uuid}
- Temporarily mount your btrfs filesystem to a folder, create a subvolume and mount it to the root filesystem.
sudo mount -m -U $fs_uuid /mnt/system-${fs_uuid}
sudo btrfs subvolume create /mnt/system-${fs_uuid}/@swap
sudo umount /mnt/system-${fs_uuid}
sudo mount -m -U ${fs_uuid} -o subvol=@swap,nodatacow /swap
- Create a swapfile and set permissions/attributes
sudo truncate -s 0 /swap/swapfile
sudo chattr +C /swap/swapfile
export swp_size=$(echo "$(grep "MemTotal" /proc/meminfo | tr -d "[:blank:],[:alpha:],:") * 1.6 / 1000" | bc ) && echo ${swp_size}M
sudo fallocate -l ${swp_size}M /swap/swapfile
sudo chmod 0600 /swap/swapfile
sudo mkswap /swap/swapfile
Needs testing, please report back in the comments if that replaces step 2 entirely:
btrfs filesystem mkswapfile
export swp_size=$(echo "$(grep "MemTotal" /proc/meminfo | tr -d "[:blank:],[:alpha:],:") * 1.6 / 1000" | bc ) && echo ${swp_size}m sudo btrfs filesystem mkswapfile --size ${swp_size}m --uuid clear /swap/swapfile
- Add 2 entries and enable the swapfile in
/etc/fstab
sudo umount /swap
echo -e "UUID=$fs_uuid\t/swap\tbtrfs\tsubvol=@swap,nodatacow,noatime,nospace_cache\t0\t0" | sudo tee -a /etc/fstab
echo -e "/swap/swapfile\tnone\tswap\tdefaults\t0\t0" | sudo tee -a /etc/fstab
sudo systemctl daemon-reload
sudo mount /swap
sudo swapon -a
swapon -s
Enable Hibernation
- Configure hibernation
export swp_uuid=$(findmnt -no UUID -T /swap/swapfile) && echo $swp_uuid
curl -s "https://raw.githubusercontent.com/osandov/osandov-linux/master/scripts/btrfs_map_physical.c" > bmp.c
gcc -O2 -o bmp bmp.c
swp_offset=$(echo "$(sudo ./bmp /swap/swapfile | egrep "^0\s+" | cut -f9) / $(getconf PAGESIZE)" | bc) && echo $swp_offset
echo -e "GRUB_CMDLINE_LINUX_DEFAULT+=\" resume=UUID=$swp_uuid resume_offset=$swp_offset \"" | sudo tee -a /etc/default/grub
echo -e "HOOKS+=( resume )" | sudo tee -a /etc/mkinitcpio.conf
sudo mkdir -pv /etc/systemd/system/{systemd-logind.service.d,systemd-hibernate.service.d}
echo -e "[Service]\nEnvironment=SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1" | sudo tee /etc/systemd/system/systemd-logind.service.d/override.conf
echo -e "[Service]\nEnvironment=SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1" | sudo tee /etc/systemd/system/systemd-hibernate.service.d/override.conf
- If everything has been made, then update initcpio + grub and reboot
sudo mkinitcpio -P && sudo grub-mkconfig -o /boot/grub/grub.cfg
reboot
Test it with sudo systemctl hibernate
after you reboot once.
Tips & Tricks
Don’t do a full balancing, it will break the swapfile
Thanks to @Zesko for pointing that out:
Running btrfs balance start --full-balance /
seems to rebalance everything and ignore the +C
(nodatacow) attribute at all, because you get this message in dmesg
if you activate a swapfile after doing a full balancing:
kernel: BTRFS warning (device XY): swapfile must not be copy-on-write
That means that every file regardless of the attribute seems to be relocated and converted to COW. That essentially breaks it.
Based on the comment of David Sterba using filters: btrfs balance -dusage=90 /
, it seems not to reach the swapfile and therefore does not affect it.
It is probably a bug, which have to be solved, but for now don’t balance or balance with care, that means with filters, if you use a swapfile on btrfs.
btrfs-assistant
is known to do a full balancing, which leads to the swap and hibernation problems as described.
This is a wiki article. You are free to copy, share, or edit the content without restrictions as long as it doesn’t miss the main topic.