Skip to content

Commit fd43cf6

Browse files
Brian FosterDarrick J. Wong
authored andcommitted
xfs: set aside allocation btree blocks from block reservation
The blocks used for allocation btrees (bnobt and countbt) are technically considered free space. This is because as free space is used, allocbt blocks are removed and naturally become available for traditional allocation. However, this means that a significant portion of free space may consist of in-use btree blocks if free space is severely fragmented. On large filesystems with large perag reservations, this can lead to a rare but nasty condition where a significant amount of physical free space is available, but the majority of actual usable blocks consist of in-use allocbt blocks. We have a record of a (~12TB, 32 AG) filesystem with multiple AGs in a state with ~2.5GB or so free blocks tracked across ~300 total allocbt blocks, but effectively at 100% full because the the free space is entirely consumed by refcountbt perag reservation. Such a large perag reservation is by design on large filesystems. The problem is that because the free space is so fragmented, this AG contributes the 300 or so allocbt blocks to the global counters as free space. If this pattern repeats across enough AGs, the filesystem lands in a state where global block reservation can outrun physical block availability. For example, a streaming buffered write on the affected filesystem continues to allow delayed allocation beyond the point where writeback starts to fail due to physical block allocation failures. The expected behavior is for the delalloc block reservation to fail gracefully with -ENOSPC before physical block allocation failure is a possibility. To address this problem, set aside in-use allocbt blocks at reservation time and thus ensure they cannot be reserved until truly available for physical allocation. This allows alloc btree metadata to continue to reside in free space, but dynamically adjusts reservation availability based on internal state. Note that the logic requires that the allocbt counter is fully populated at reservation time before it is fully effective. We currently rely on the mount time AGF scan in the perag reservation initialization code for this dependency on filesystems where it's most important (i.e. with active perag reservations). Signed-off-by: Brian Foster <[email protected]> Reviewed-by: Chandan Babu R <[email protected]> Reviewed-by: Allison Henderson <[email protected]> Reviewed-by: Darrick J. Wong <[email protected]> Signed-off-by: Darrick J. Wong <[email protected]>
1 parent 16eaab8 commit fd43cf6

File tree

1 file changed

+14
-1
lines changed

1 file changed

+14
-1
lines changed

fs/xfs/xfs_mount.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,7 @@ xfs_mod_fdblocks(
11881188
int64_t lcounter;
11891189
long long res_used;
11901190
s32 batch;
1191+
uint64_t set_aside;
11911192

11921193
if (delta > 0) {
11931194
/*
@@ -1227,8 +1228,20 @@ xfs_mod_fdblocks(
12271228
else
12281229
batch = XFS_FDBLOCKS_BATCH;
12291230

1231+
/*
1232+
* Set aside allocbt blocks because these blocks are tracked as free
1233+
* space but not available for allocation. Technically this means that a
1234+
* single reservation cannot consume all remaining free space, but the
1235+
* ratio of allocbt blocks to usable free blocks should be rather small.
1236+
* The tradeoff without this is that filesystems that maintain high
1237+
* perag block reservations can over reserve physical block availability
1238+
* and fail physical allocation, which leads to much more serious
1239+
* problems (i.e. transaction abort, pagecache discards, etc.) than
1240+
* slightly premature -ENOSPC.
1241+
*/
1242+
set_aside = mp->m_alloc_set_aside + atomic64_read(&mp->m_allocbt_blks);
12301243
percpu_counter_add_batch(&mp->m_fdblocks, delta, batch);
1231-
if (__percpu_counter_compare(&mp->m_fdblocks, mp->m_alloc_set_aside,
1244+
if (__percpu_counter_compare(&mp->m_fdblocks, set_aside,
12321245
XFS_FDBLOCKS_BATCH) >= 0) {
12331246
/* we had space! */
12341247
return 0;

0 commit comments

Comments
 (0)