Skip to content

Commit c8c5682

Browse files
author
Darrick J. Wong
committed
xfs: don't include bnobt blocks when reserving free block pool
xfs_reserve_blocks controls the size of the user-visible free space reserve pool. Given the difference between the current and requested pool sizes, it will try to reserve free space from fdblocks. However, the amount requested from fdblocks is also constrained by the amount of space that we think xfs_mod_fdblocks will give us. If we forget to subtract m_allocbt_blks before calling xfs_mod_fdblocks, it will will return ENOSPC and we'll hang the kernel at mount due to the infinite loop. In commit fd43cf6, we decided that xfs_mod_fdblocks should not hand out the "free space" used by the free space btrees, because some portion of the free space btrees hold in reserve space for future btree expansion. Unfortunately, xfs_reserve_blocks' estimation of the number of blocks that it could request from xfs_mod_fdblocks was not updated to include m_allocbt_blks, so if space is extremely low, the caller hangs. Fix this by creating a function to estimate the number of blocks that can be reserved from fdblocks, which needs to exclude the set-aside and m_allocbt_blks. Found by running xfs/306 (which formats a single-AG 20MB filesystem) with an fstests configuration that specifies a 1k blocksize and a specially crafted log size that will consume 7/8 of the space (17920 blocks, specifically) in that AG. Cc: Brian Foster <bfoster@redhat.com> Fixes: fd43cf6 ("xfs: set aside allocation btree blocks from block reservation") Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com>
1 parent 93defd5 commit c8c5682

3 files changed

Lines changed: 17 additions & 2 deletions

File tree

fs/xfs/xfs_fsops.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ xfs_reserve_blocks(
434434
error = -ENOSPC;
435435
do {
436436
free = percpu_counter_sum(&mp->m_fdblocks) -
437-
mp->m_alloc_set_aside;
437+
xfs_fdblocks_unavailable(mp);
438438
if (free <= 0)
439439
break;
440440

fs/xfs/xfs_mount.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1146,7 +1146,7 @@ xfs_mod_fdblocks(
11461146
* problems (i.e. transaction abort, pagecache discards, etc.) than
11471147
* slightly premature -ENOSPC.
11481148
*/
1149-
set_aside = mp->m_alloc_set_aside + atomic64_read(&mp->m_allocbt_blks);
1149+
set_aside = xfs_fdblocks_unavailable(mp);
11501150
percpu_counter_add_batch(&mp->m_fdblocks, delta, batch);
11511151
if (__percpu_counter_compare(&mp->m_fdblocks, set_aside,
11521152
XFS_FDBLOCKS_BATCH) >= 0) {

fs/xfs/xfs_mount.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,21 @@ extern void xfs_unmountfs(xfs_mount_t *);
479479
*/
480480
#define XFS_FDBLOCKS_BATCH 1024
481481

482+
/*
483+
* Estimate the amount of free space that is not available to userspace and is
484+
* not explicitly reserved from the incore fdblocks. This includes:
485+
*
486+
* - The minimum number of blocks needed to support splitting a bmap btree
487+
* - The blocks currently in use by the freespace btrees because they record
488+
* the actual blocks that will fill per-AG metadata space reservations
489+
*/
490+
static inline uint64_t
491+
xfs_fdblocks_unavailable(
492+
struct xfs_mount *mp)
493+
{
494+
return mp->m_alloc_set_aside + atomic64_read(&mp->m_allocbt_blks);
495+
}
496+
482497
extern int xfs_mod_fdblocks(struct xfs_mount *mp, int64_t delta,
483498
bool reserved);
484499
extern int xfs_mod_frextents(struct xfs_mount *mp, int64_t delta);

0 commit comments

Comments
 (0)