cd ~/>cat multi-boot-partitioning-btrfs-metadata-balance.md

Multi-boot partitioning / btrfs metadata and balance

#linux#btrfs#disk#partitioning

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
  • df may 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.

// END OF TRANSMISSION
See you, Space Cowboy.

Connection closed. Returning to terminal...