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.

The Really (Exciting|Boring) Details

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 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.

*takes a deep breath*

The Solution

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.

Category:Btrfs Category:Linux Category:Filesystems