diff mbox series

[5/5] xfs: include min freelist in m_ag_max_usable

Message ID 4b9b30af3719389701c2dd00f8cb20f12043b3ee.1723688622.git.kjlx@templeofstupid.com (mailing list archive)
State New, archived
Headers show
Series [1/5] xfs: count the number of blocks in a per-ag reservation | expand

Commit Message

Krister Johansen Aug. 15, 2024, 7:35 p.m. UTC
If agfl_reserve blocks are conditionally withheld from consideration in
xfs_alloc_space_available, then m_ag_max_usable overstates the amount of
max available space on an empty filesystem by the amount of blocks that
mkfs placed into the AGFL on our behalf.

While this space _is_ technically free, it's not usable for a maximum
sized allocation on an empty filesystem, because the blocks must remain
in the AGFL in order for an allocation to succeed.  Without this, stripe
aligned allocations on an empty AG pick a size that they can't actually
get which leads to allocations which can't be satisfied and that
consequently come back unaligned.

Signed-off-by: Krister Johansen <kjlx@templeofstupid.com>
---
 fs/xfs/libxfs/xfs_alloc.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index 4dd401d407c2..26447e6061b3 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -246,7 +246,9 @@  xfs_alloc_set_aside(
  *	- the AG superblock, AGF, AGI and AGFL
  *	- the AGF (bno and cnt) and AGI btree root blocks, and optionally
  *	  the AGI free inode and rmap btree root blocks.
- *	- blocks on the AGFL according to xfs_alloc_set_aside() limits
+ *	- blocks on the AGFL when the filesystem is empty
+ *	- blocks on needed to AGFL while performing dependent allocations close
+ *	  to ENOSPC as given by xfs_allocbt_agfl_reserve()
  *	- the rmapbt root block
  *
  * The AG headers are sector sized, so the amount of space they take up is
@@ -259,6 +261,13 @@  xfs_alloc_ag_max_usable(
 	unsigned int		blocks;
 
 	blocks = XFS_BB_TO_FSB(mp, XFS_FSS_TO_BB(mp, 4)); /* ag headers */
+	/*
+	 * Minimal freelist length when filesystem is completely empty.
+	 * xfs_alloc_min_freelist needs m_alloc_maxlevels so this is computed in
+	 * our second invocation of xfs_alloc_ag_max_usable
+	 */
+	if (mp->m_alloc_maxlevels > 0)
+		blocks += xfs_alloc_min_freelist(mp, NULL);
 	blocks += xfs_allocbt_agfl_reserve(mp);
 	blocks += 3;			/* AGF, AGI btree root blocks */
 	if (xfs_has_finobt(mp))