Btrfs:Balancing

I’ve been using Btrfs on all of my systems for a
couple of years now. Thus far, it’s be surprisingly stable. In those two years
I only had one real issue. However, today I ran into
a new problem. Now that I know what the issue is, it’s hardly a problem, but
hey, semantics.

For my setup at home, I have a Linux server running all the time which hosts my
backups. My backups are copied via rsync. For security, my home directories on
all systems are encrypted block devices using
dm-crypt with a
LUKS header. To force myself to clean up
my files occasionally, I only give myself some 5 gigs of leeway. If I manage to
remove for example 10 gigs of files, I reduce the size of the filesystem and
block device container so I still only have about 2-5 gigs free (depends on
what I’m doing hobby-wise at the time). This is where my problem with Btrfs
comes in.

This section might be super boring for some or most folks because it talks
about the innards of Btrfs. If you aren’t interested, make like a Tatooine
speeder and move along…​ move along.

As more storage is needed for the filesystem, chunks of raw storage are
consumed by default 1 gigabyte at a time. As the
kernel.org
page describes, these chunks are used for file data and/or metadata storage.
As more files are written to the filesystem, more metadata chunks are required
to describe the additional files (data to metadata ratios can be specified at
filesystem creation). By default, a metadata chunk cannot be used for data and
a data chunk cannot be used for metadata (kind of - there is a mixed mode which
is tremendously slow on filesystems larger than 1G). On a large storage device
this is fine, but if you are constantly deleting files like me, you may run
into the issue I ran into where the available space value is incorrect because
the various space checking commands check for available data space, not
taking into account metadata. Because I delete so many files so often, there is
a lot of metadata storage that is allocated but is no longer used because the
files that the metadata were describing no longer exist, and thus the metadata
for those files do not either. Consequently, the metadata chunks are no longer
fully used (remember, they are allocated 1 G at a time). Due to the fact that
metadata and data chunks cannot be mixed by default, the underused metadata
chunks just consume storage from the overall available, reducing the amount of
available storage for data.

The solution to this issue is called a rebalance (or balance as the btrfs
subcommand is called). What it will do is rewrite all of the data on the given
block device, sending it through the allocator algorithm before being rewritten
to the storage. This will cause the datas' metadata to be reallocated and
rewritten. What results is your metadata being "restacked", potentially causing
you to end up with completely empty 1G metadata chunks, thus freeing that
storage space for data. This isn’t a complete analogy, but you can think of
this a [very] little like a defragment and cleanup process for metadata. Here’s
the command.

btrfs balance start /path/to/mount

If you’re interested in metrics, run

btrfs filesystem df /path/to/mount

before and after you run the balance and compare your metadata values.