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