Anders Tall

Btrfs, end to end: subvolumes, snapshots, compression, scrub

4 min read

Btrfs is the copy-on-write filesystem that ships by default on openSUSE and Fedora Workstation. It gives you subvolumes, cheap snapshots, compression and checksums without ZFS’s separate pool and dataset layers. The videos show the commands; this page explains why they work.

Same model: disk → partition → filesystem, on a disposable 2 GB scratch disk.

Create it

sudo parted -s /dev/sdb mklabel gpt
sudo parted -s /dev/sdb mkpart data btrfs 1MiB 1GiB
sudo mkfs.btrfs -f -L data /dev/sdb1
sudo mkdir -p /mnt/btrfs
sudo mount /dev/sdb1 /mnt/btrfs

Then inspect it:

sudo btrfs filesystem show /mnt/btrfs      # label, UUID, devices
sudo btrfs filesystem usage /mnt/btrfs    # allocation, used, free
sudo blkid /dev/sdb1                      # TYPE="btrfs"

Watch on YouTube →

Subvolumes

A Btrfs filesystem is one pool; subvolumes are the separate namespaces inside it. They are how you separate data from snapshots (and how distros lay out @, @home, @snapshots).

sudo btrfs subvolume create /mnt/btrfs/@data
sudo btrfs subvolume create /mnt/btrfs/@snapshots
sudo btrfs subvolume list /mnt/btrfs

Write your data inside @data, not at the top level, so a snapshot of @data actually contains it. That is the one detail that trips people up.

Watch on YouTube →

Snapshots

A Btrfs snapshot is a subvolume that shares its extents copy-on-write. It is instant and cheap:

echo 'original' | sudo tee /mnt/btrfs/@data/hello.txt
sudo btrfs subvolume snapshot -r /mnt/btrfs/@data /mnt/btrfs/@snapshots/data-1
echo 'changed' | sudo tee /mnt/btrfs/@data/hello.txt
sudo cat /mnt/btrfs/@snapshots/data-1/hello.txt   # original

-r makes the snapshot read-only — the right default for a restore point, and required for btrfs send. The snapshot keeps the old state while the live subvolume changes. To roll back, you swap the subvolumes (or mount the snapshot and copy back). Btrfs itself has no single rollback command like ZFS, though openSUSE ships snapper, which provides snapper rollback; it is also available on Fedora.

Watch on YouTube →

Compression

Btrfs compresses per mount (or per file with btrfs property). Remount with zstd and write something compressible:

sudo umount /mnt/btrfs
sudo mount -o compress=zstd /dev/sdb1 /mnt/btrfs
sudo dd if=/dev/zero of=/mnt/btrfs/zeros.bin bs=1M count=20
sync
sudo compsize /mnt/btrfs/zeros.bin

20 MiB apparent, 640 KiB on disk — 3% of the original, about 32:1. sync first, or the measurement can run before the data is written; btrfs filesystem usage shows the whole filesystem (data plus metadata), not the file. compsize is the per-file tool (package btrfs-compsize on Debian/Ubuntu, compsize on Fedora). The demo writes zeros.bin at the top level for simplicity; compression is per file, so it behaves the same inside @data.

Zeros are the easy case; text and logs compress less, but still well. The same trade-off as always: compression costs CPU on write and read, and it is usually a clear win for text, logs and containers.

Watch on YouTube →

Scrub

Every block has a checksum, and scrub reads the data and verifies it:

sudo btrfs scrub start /mnt/btrfs
sudo btrfs scrub status /mnt/btrfs
sudo btrfs device stats /mnt/btrfs

On a healthy filesystem: finished, no errors found, and all device counters at zero. The counters persist, so they are also the long-term record of I/O and checksum errors.

Watch on YouTube →

A note on check and resize

sudo growpart /dev/sdb 1
sudo btrfs filesystem resize max /mnt/btrfs
sudo btrfs filesystem resize 1g /mnt/btrfs

max grows to the partition size; 1g shrinks back, online (it still needs free space and care). The partition stays the same size; shrinking it is a separate, riskier step. growpart comes from cloud-guest-utils on Debian/Ubuntu and cloud-utils-growpart on the RHEL family.

What to remember

Part of Filesystems, end to end.

#btrfs #filesystem #snapshots #compression #zstd #linux #storage #homelab #devops