Balance Btrfs
1. Check
Because of the way that Btrfs works, the command df may not
always be accurate. For example it cannot tell how much unallocated
disk space is available.
To see details on Btrfs disk usage, we need to use btrfs
filesystem usage. This shows how each chunk type is allocated and how
much unallocated space is available.
# overall check
btrfs filesystem show
# mount the disk used as a storage by incus
mkdir mnt
mount /dev/nvme1n1 mnt
ls mnt/
# check usage
btrfs filesystem df mnt/
btrfs filesystem usage mnt/
btrfs filesystem usage -T mnt/
# unmount
umount mnt
ls mnt/
rmdir mnt/
2. Balance
We can do it with btrfs balance start. However, running it
without any filters, would re-write every data and metadata chunk in
the filesystem. Usually, this is not what we want. Instead, we use
balance filters to limit what chunks should be balanced.
With the option -dusage=5 we limit balance to compact data
blocks that are less than 5% full. This is a good start, and we can
increase it to 10-15% or more if needed. The goal here is to make sure
there is enough unallocated space on each device in the filesystem to
avoid the out-of-space error situations.
# mount the disk used as a storage by incus
mount /dev/nvme1n1 mnt
# balance
btrfs filesystem usage -T mnt/
btrfs balance start -dusage=5 mnt/
btrfs filesystem usage -T mnt/
# unmount
umount mnt
rmdir mnt/
3. Automate
We can automate the commands above with a script:
cat <<'EOF' > /root/misc/btrfs-balance.sh
#!/bin/bash -x
disk=${1:-/dev/nvme1n1}
mnt=$(dirname $0)/mnt/
mkdir -p $mnt
mount -t btrfs $disk $mnt
btrfs balance start -dusage=10 $mnt
umount $mnt
rmdir $mnt
EOF
chmod +x /root/misc/btrfs-balance.sh
Then we can create a cron job to call it periodically:
cat <<EOF > /etc/cron.d/btrfs-balance
0 3 * * 6 root /root/misc/btrfs-balance.sh &>/dev/null
EOF