Disclaimer

This guide hopes to help anyone interested in having a try for compression & deduplication feature of btrfs in Qubes OS. Also serve as my personal note.

Make sure you back up everything before experiment and practicing.

Btrfs, intro

Despite many added feature, btrfs is closer to ext4 rather than lvm - it is a tree of file and directories rooted at /, and can be mounted anywhere mostly.

Compression & Dedup features are enabled runtime rather than on filesystem creation.

Btrfs supports compression, and zstd is the best compression methods. By default it does not compress, and mount flag is required to enable the feature.

Btrfs supports offline deduplication, and this does not require mount flag. Rather you will need a userspace program (duperemove here) to find out duplicate blocks of all the files in the filesystem (some smart hash algorithms and data structures to accelerate the finding) and then tell btrfs modules where are the duplicate parts of the file, then btrfs module verify whether they are the same. Btrfs will attempt to dedup after verification and the disk usage reduces then. See relevant documentation for more details.

Btrfs in Qubes OS, Intro

(Mainly R4.2 as I experiment btrfs only there)

When Qubes OS uses btrfs, the default setup of partition is like:

Dom0 uses the whole btrfs partition. VM images (root.img, private.img) are regular files under /var/lib/qubes and they are raw. They are probably the largest files in the whole file system. Other than that, the VM image file can be mostly sparse, there are no distinguishment of VM image file and other regular files in dom0. This is different as case in LVM, where dom0 root and VM images are different volumes in LVM. This makes compression & deduplication mostly no different from other OS using btrfs.

Recipe

  1. Reinstall Qubes OS (R4.2). Of course a proper backup of current VMs are assumed here. It is suggested to do a TRIM on your disk before installing, as in many cases writing on dirty blocks can be slower in some devices.
  2. When you get into the OS, do not be hurry to restore the backup. Follow the steps to organize the filesystem first.
  3. Edit /etc/fstab to add compress=zstd or compress-force=zstd (I suggest the former, if heuristic disappoint you, you can do chattr -m file; chattr +c file any time), and then reboot.
  4. Note that when you set the compression flag, only new created file are compressed
  5. sudo qubes-dom0-update, then sudo qubes-dom0-update compsize duperemove. These two are essential when we dedup (duperemove) and when we evaluate whether compression and deduplication works as expected (compsize to see the effect)
  6. To compress existing file in dom0 by:
sudo btrfs filesystem defragment -v -r -czstd /usr /etc /srv /var/lib/dnf /var/log /var/lib/qubes/vm-kernels

Here we do not compress VM image now as they can be very big and very time consuming. After doing these, you can find many large file under /usr (example: libLLVMGold.so) and also the kernel module file at /var/lib/qubes/vm-kernels/*/modules.img uncompressed. * To check out whether they are compressed quickly, use sudo lsattr <path>, and see if the file has "m" flag, which disables compression for the file. In brief btrfs compresses the first block of the file and find it hard to compress, so it marks the file as incompressible. * To compress them by force, sudo chattr -m <path> && sudo chattr +c <path>

  1. Check out how your compression is working by:

    sudo compsize -x /
    
    This can show the actual total disk usage of one path, along with the size of compressed and uncompressed part, and also it shows the deduplication result somehow.

  2. Shutdown all vms. Then, remove all temp vm image files: /var/lib/qubes/{appvms,vm-templates}/*/*{Z,-precache.img}. Basically for each vm at most "root.img" and "private.img" are kept (there are some xmls, of course they should not be deleted). Whenever you want to dedup or recompress, doing this step is preferred.

  3. Now you are familiar to compression and how to evaluate the filesystem, compress the whole filesystem by

    sudo btrfs filesystem defragment -v -r -czstd /
    

Similarly, when you find that the VM images (under /var/log/qubes/*/*/*.img) are not compressed (as lsattr tells), mark it to be compressed forcefully and redo this step.

  1. dedup.
    sudo duperemove -r -d -v --hashfile=/var/duperemove.hashfile --dedupe-options=same,partial --exclude=/var/duperemove.hashfile /
    
    comments:
  2. -A does not work, do not use it
  3. same is important, partial is time consuming but also important as this can really dedup more in general case.
  4. hashfile is useful as a cache since you may dedup many times later You can check your dedup effect with compsize or btrfs filesystem df

  5. reboot, and install and update your new templates, and then dedup (compression is automatically done)

  6. maybe e4defrag your template vm root is also important. I will test later

  7. restore your backup, and then dedup

Comment

This guide should be updated later with more experiment

Reference

https://forum.qubes-os.org/t/about-btrfs-with-compression-in-qubes-os/19707 https://forum.qubes-os.org/t/pool-level-deduplication/12654 https://btrfs.readthedocs.io/en/latest/Introduction.html https://wiki.archlinux.org/title/Btrfs