]> git.hungrycats.org Git - linux/commit
btrfs: allow changing system dev_extent size via sysfs topics/dev-extent-defrag
authorZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Sat, 30 Sep 2023 06:47:08 +0000 (02:47 -0400)
committerZygo Blaxell <ce3g8jdj@umail.furryterror.org>
Wed, 29 Jul 2026 15:46:05 +0000 (11:46 -0400)
commitad465dc49a9ce8ca9442c797ab8ab50f0ac1f6db
treeef59440222f1b2fc681526900987179059ab044b
parentfc02acf6ac0ccde0c805c2daa9148683cdd01ba8
btrfs: allow changing system dev_extent size via sysfs

When a filesystem using striped profiles such as raid0, raid10, raid5,
or raid6 is repeatedly resized and balanced, severe and disruptive
dev_extent fragmentation can occur when dev_extents are allowed to have
different sizes.

On filesystems over 50 GiB in size, data and metadata dev_extents are both
1 GiB each, but the system dev_extents are always 32 MiB regardless of
filesystem size.  This can leave some devices with odd-sized dev_extent
holes on filesystems with more devices than the metadata's stripe count.

Striped profile allocators will try to allocate the widest block
groups possible, so as the devices fill up, eventually block groups
are allocated that have dev_extents shorter than 1 GiB, and these will
be allocated on all devices because that's what striping profiles do.

As storage is expanded, these block groups are balanced and removed,
leaving behind small free space holes.  These holes limit the size of
future block group allocations, causing small dev_extents to multiply.
This repeats until the filesystem has hundreds of thousands of dev_extents
at the minimum 1 MiB size, instead of hundreds of extents at the normal
1 GiB size.

Block groups made from these small dev_extents cannot hold the largest
btrfs extents (128 MiB), making their space effectively unusable.
The btrfs allocator has several functions that are O(n) in the number of
block groups, which start to slow down significantly as the dev_extents
fragment.

This fragmentation is avoidable by:

1.  round down the device sizes to an exact multiple of 1 GiB +
1 MiB. (The 1 MiB is reserved by btrfs at the beginning of each
device, so this means 1 GiB dev_extents will always fit exactly
on the device with no fragmentation.)

2.  set all block group dev_extent sizes to 1 GiB, so that all
dev_extents and all free space holes are exactly 1 GiB in length.

3.  balance existing block groups so that they are all aligned
to 1 GiB boundaries (offset by the reserved 1 MiB at the start).

Of these, only #2 requires a kernel change.

Signed-off-by: Zygo Blaxell <ce3g8jdj@umail.furryterror.org>
fs/btrfs/sysfs.c