Multi-boot partitioning / btrfs metadata and balance
What btrfs metadata is
Every btrfs filesystem maintains several internal B-trees:
- extent tree — maps logical addresses to physical locations on disk, tracks CoW references and reflinks
- checksum tree — stores checksums for all data blocks
- inode tree — stores inode metadata (permissions, timestamps, sizes)
- directory tree — maps filenames to inodes
- chunk tree — maps logical chunk addresses to device extents
All of these live in metadata block groups. They grow as you add files, create snapshots, and write data. Snapshots are particularly metadata-heavy — a snapshot creates references in the extent tree for every shared block, even though no data is duplicated.
Metadata and data occupy separate block group pools. A filesystem can have abundant unallocated space while metadata block groups are completely full.
The metadata-full symptom
When metadata block groups are exhausted:
- The filesystem transitions to read-only
- Writes fail with
ENOSPC dfmay show available space (because it measures data block groups)- The kernel logs show:
BTRFS error (device nvme0n1p5): could not allocate metadata
btrfs filesystem df /
If Metadata shows used ≈ total, this is the problem:
Metadata, single: total=8.00GiB, used=7.98GiB
Data, single: total=604.00GiB, used=400.00GiB
Unallocated device space exists but btrfs has not yet assigned it to a new metadata block group. This happens when block groups are fragmented — many partially-filled groups consuming space that could be consolidated.
btrfs balance
Balance migrates data between block groups, consolidates partially-filled groups, and reclaims unallocated device space by freeing sparse groups. It also allows converting between RAID profiles (single, DUP, RAID1, etc.).
Balance is expensive. It reads and rewrites large amounts of data. On a busy filesystem, a full balance can take hours and generates significant I/O. Do not run it on a schedule. Run it when you have a specific reason.
Valid reasons:
- Metadata block groups are nearly full despite available device space
- The filesystem is heavily fragmented after bulk deletes
- You need to convert a RAID profile
- You are preparing to remove a device from a multi-device pool
Not valid reasons:
- “I heard balance is good for btrfs”
- Running it weekly as preventive maintenance
- Before every update
The usage filter
Without filters, balance processes every block group, including those that are nearly full. This is usually unnecessary and wastes time. The usage filter restricts balance to block groups that are less than N% full:
btrfs balance start -dusage=50 -musage=50 /
This processes only data block groups with less than 50% occupancy and metadata block groups with less than 50% occupancy. Sparse block groups get consolidated; dense block groups are left alone. On a typical system, this completes in minutes rather than hours.
Progress can be monitored while balance runs:
btrfs balance status /
Cancel if needed:
btrfs balance cancel /
Forcing new metadata block group allocation
An alternative to balance when metadata is nearly full but unallocated space exists: force btrfs to allocate a new metadata block group before the current ones fill completely.
btrfs balance start -musage=0 /
-musage=0 targets only completely empty metadata block groups (none exist), effectively causing btrfs to allocate fresh ones from unallocated space. This is faster than a full balance and buys time to investigate the underlying cause.
Metadata DUP on single-device systems
Single-device btrfs systems use single allocation profile for both data and metadata by default. The single profile stores one copy. Metadata corruption on a single-device single-profile filesystem is unrecoverable.
Converting metadata to DUP stores two copies of all metadata on the same device, in different locations. It does not protect against device failure (both copies are on the same disk), but it does protect against localized corruption — the kind that a single bad sector produces.
btrfs balance start -mconvert=dup /
This rewrites all metadata block groups with the DUP profile. Metadata space usage doubles. On a filesystem with 8G of metadata, this consumes 16G. Verify there is enough unallocated space before converting.
Check current profiles:
btrfs filesystem df /
# look for Metadata, DUP vs Metadata, single
The tradeoff: 2× metadata storage for protection against the failure mode most likely to occur on a spinning disk or aging NVMe. On a brand-new, high-quality NVMe, the gain is marginal. On older drives, it is worth having.
After a large snapshot deletion
Deleting many btrfs snapshots — especially large ones — releases extent references but does not immediately return block groups to the unallocated pool. The block groups remain allocated but sparse. btrfs fi usage shows the gap between “Device allocated” and “Used.” Running balance with -dusage=20 -musage=20 consolidates the sparse groups and returns device space.
# after deleting snapshots
btrfs balance start -dusage=20 -musage=20 /
This is the most common valid use case for balance on a single-device system.
Connection closed. Returning to terminal...