* [PATCH 0/2] xfs: fix a couple sparse chunk alloc problems @ 2026-07-31 16:33 Brian Foster 2026-07-31 16:33 ` [PATCH 1/2] xfs: set minleft correctly for sparse chunk errortag allocation Brian Foster 2026-07-31 16:33 ` [PATCH 2/2] xfs: consistent low ag space behavior for sparse inode chunk allocs Brian Foster 0 siblings, 2 replies; 7+ messages in thread From: Brian Foster @ 2026-07-31 16:33 UTC (permalink / raw) To: linux-xfs; +Cc: Matt Fleming Hi all, This series is a couple small sparse chunk alloc related fixes. Patch 1 is LLM detected and generated (I rewrote the commit log) during the process of investigating the problem fixed by the second. Patch 2 fixes the problem reported by Matt here [1]. Note that patch 2 is semi-RFC. Personally I'm Ok with using this as the fix, but I don't love it and recognize that it's more of a band-aid. The fundamental problem seems more that the space availability requirements change within a transaction that targets a single AG, but I haven't yet thought of an elegant enough way to fix that for something that is kind of a corner case. The LLM came up with a fix that basically bumps up minleft within the allocator path by the extra space that would be required by the inobt allocation, but I didn't really like that at all and tossed it in favor of this. I had a couple other things I thought about as potential alternatives. One is to perhaps use or repurpose something like the XFS_ALLOC_FLAG_FREEING flag for this pattern where we have a minleft gated allocation followed by a targeted alloc to the same AG. This would presumably allow the allocation to succeed. Another is to perhaps enhance the xfs_alloc_min_freelist() logic to just start to use the allocbt maxlevels value for requirements calculation as an AG starts to approach -ENOSPC. That is more of a heuristic and similar sort of workaround for the problem, but more directly encodes that reliability is priority over squeezing every last block from an AG. I also think it's a little risky as it may involve a new mode of allocation across the board (not just sparse chunk allocs). I also suspect this wouldn't be a problem if the inobt were covered as perag metadata res the way the finobt is, but I haven't thought that through fully. So all in all I'm curious what folks think about any of this or have any other potential ideas. My main concern is that I don't want to introduce something too complex for the single uncommon use case of sparse inodes. I.e., this problem seems a lot like a corner case of a corner case to me. Thoughts? Brian [1] https://lore.kernel.org/linux-xfs/20260717130429.1838767-1-matt@readmodwrite.com/ Brian Foster (2): xfs: set minleft correctly for sparse chunk errortag allocation xfs: consistent low ag space behavior for sparse inode chunk allocs fs/xfs/libxfs/xfs_ialloc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) -- 2.55.0 ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/2] xfs: set minleft correctly for sparse chunk errortag allocation 2026-07-31 16:33 [PATCH 0/2] xfs: fix a couple sparse chunk alloc problems Brian Foster @ 2026-07-31 16:33 ` Brian Foster 2026-07-31 18:02 ` [External] : " Mark Tinguely 2026-07-31 16:33 ` [PATCH 2/2] xfs: consistent low ag space behavior for sparse inode chunk allocs Brian Foster 1 sibling, 1 reply; 7+ messages in thread From: Brian Foster @ 2026-07-31 16:33 UTC (permalink / raw) To: linux-xfs; +Cc: Matt Fleming The errortag instrumentation for forced sparse chunk allocation jumps straight to the allocation path without setting args.minleft. minleft is unconditionally set to ->inobt_maxlevels for the normal allocation path. Lift the assignment to the initial args setup so it covers all possible paths. Assisted-by: LLM Fixes: 1cdadee11f8d ("xfs: randomly do sparse inode allocations in DEBUG mode") Signed-off-by: Brian Foster <bfoster@redhat.com> --- fs/xfs/libxfs/xfs_ialloc.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index ffcdd1f691fd..633b2d6e42c5 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -733,6 +733,10 @@ xfs_ialloc_ag_alloc( igeo->maxicount) return -ENOSPC; args.minlen = args.maxlen = igeo->ialloc_blks; + + /* Allow space for the inode btree to split. */ + args.minleft = igeo->inobt_maxlevels; + /* * First try to allocate inodes contiguous with the last-allocated * chunk of inodes. If the filesystem is striped, this will fill @@ -764,8 +768,6 @@ xfs_ialloc_ag_alloc( args.alignment = 1; args.minalignslop = igeo->cluster_align - 1; - /* Allow space for the inode btree to split. */ - args.minleft = igeo->inobt_maxlevels; error = xfs_alloc_vextent_exact_bno(&args, xfs_agbno_to_fsb(pag, args.agbno)); if (error) @@ -804,10 +806,6 @@ xfs_ialloc_ag_alloc( * Allocate a fixed-size extent of inodes. */ args.prod = 1; - /* - * Allow space for the inode btree to split. - */ - args.minleft = igeo->inobt_maxlevels; error = xfs_alloc_vextent_near_bno(&args, xfs_agbno_to_fsb(pag, be32_to_cpu(agi->agi_root))); -- 2.55.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [External] : [PATCH 1/2] xfs: set minleft correctly for sparse chunk errortag allocation 2026-07-31 16:33 ` [PATCH 1/2] xfs: set minleft correctly for sparse chunk errortag allocation Brian Foster @ 2026-07-31 18:02 ` Mark Tinguely 2026-07-31 18:40 ` Brian Foster 0 siblings, 1 reply; 7+ messages in thread From: Mark Tinguely @ 2026-07-31 18:02 UTC (permalink / raw) To: Brian Foster, linux-xfs; +Cc: Matt Fleming On 7/31/26 11:33 AM, Brian Foster wrote: > The errortag instrumentation for forced sparse chunk allocation > jumps straight to the allocation path without setting args.minleft. > minleft is unconditionally set to ->inobt_maxlevels for the normal > allocation path. Lift the assignment to the initial args setup so > it covers all possible paths. > > Assisted-by: LLM > Fixes: 1cdadee11f8d ("xfs: randomly do sparse inode allocations in DEBUG mode") > Signed-off-by: Brian Foster <bfoster@redhat.com> > --- > fs/xfs/libxfs/xfs_ialloc.c | 10 ++++------ > 1 file changed, 4 insertions(+), 6 deletions(-) > > diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c > index ffcdd1f691fd..633b2d6e42c5 100644 > --- a/fs/xfs/libxfs/xfs_ialloc.c > +++ b/fs/xfs/libxfs/xfs_ialloc.c > @@ -733,6 +733,10 @@ xfs_ialloc_ag_alloc( > igeo->maxicount) > return -ENOSPC; > args.minlen = args.maxlen = igeo->ialloc_blks; > + > + /* Allow space for the inode btree to split. */ > + args.minleft = igeo->inobt_maxlevels; > + > /* > * First try to allocate inodes contiguous with the last-allocated > * chunk of inodes. If the filesystem is striped, this will fill > @@ -764,8 +768,6 @@ xfs_ialloc_ag_alloc( > args.alignment = 1; > args.minalignslop = igeo->cluster_align - 1; > > - /* Allow space for the inode btree to split. */ > - args.minleft = igeo->inobt_maxlevels; > error = xfs_alloc_vextent_exact_bno(&args, > xfs_agbno_to_fsb(pag, args.agbno)); > if (error) > @@ -804,10 +806,6 @@ xfs_ialloc_ag_alloc( > * Allocate a fixed-size extent of inodes. > */ > args.prod = 1; > - /* > - * Allow space for the inode btree to split. > - */ > - args.minleft = igeo->inobt_maxlevels; > error = xfs_alloc_vextent_near_bno(&args, > xfs_agbno_to_fsb(pag, > be32_to_cpu(agi->agi_root))); Reviewed-by: Mark Tinguely <mark.tinguely@oracle.com> I got the patches backwards...I agree we need to increase the minleft in the other patch by 4 blocks (2 btrees * 2 for the level increase) but I wonder why can't a full size inode chunk also split the by-count and by-block btrees and the inode btree allocation also be short when fixing AGFL? ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [External] : [PATCH 1/2] xfs: set minleft correctly for sparse chunk errortag allocation 2026-07-31 18:02 ` [External] : " Mark Tinguely @ 2026-07-31 18:40 ` Brian Foster 0 siblings, 0 replies; 7+ messages in thread From: Brian Foster @ 2026-07-31 18:40 UTC (permalink / raw) To: Mark Tinguely; +Cc: linux-xfs, Matt Fleming On Fri, Jul 31, 2026 at 01:02:50PM -0500, Mark Tinguely wrote: > On 7/31/26 11:33 AM, Brian Foster wrote: > > The errortag instrumentation for forced sparse chunk allocation > > jumps straight to the allocation path without setting args.minleft. > > minleft is unconditionally set to ->inobt_maxlevels for the normal > > allocation path. Lift the assignment to the initial args setup so > > it covers all possible paths. > > > > Assisted-by: LLM > > Fixes: 1cdadee11f8d ("xfs: randomly do sparse inode allocations in DEBUG mode") > > Signed-off-by: Brian Foster <bfoster@redhat.com> > > --- > > fs/xfs/libxfs/xfs_ialloc.c | 10 ++++------ > > 1 file changed, 4 insertions(+), 6 deletions(-) > > > > diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c > > index ffcdd1f691fd..633b2d6e42c5 100644 > > --- a/fs/xfs/libxfs/xfs_ialloc.c > > +++ b/fs/xfs/libxfs/xfs_ialloc.c > > @@ -733,6 +733,10 @@ xfs_ialloc_ag_alloc( > > igeo->maxicount) > > return -ENOSPC; > > args.minlen = args.maxlen = igeo->ialloc_blks; > > + > > + /* Allow space for the inode btree to split. */ > > + args.minleft = igeo->inobt_maxlevels; > > + > > /* > > * First try to allocate inodes contiguous with the last-allocated > > * chunk of inodes. If the filesystem is striped, this will fill > > @@ -764,8 +768,6 @@ xfs_ialloc_ag_alloc( > > args.alignment = 1; > > args.minalignslop = igeo->cluster_align - 1; > > - /* Allow space for the inode btree to split. */ > > - args.minleft = igeo->inobt_maxlevels; > > error = xfs_alloc_vextent_exact_bno(&args, > > xfs_agbno_to_fsb(pag, args.agbno)); > > if (error) > > @@ -804,10 +806,6 @@ xfs_ialloc_ag_alloc( > > * Allocate a fixed-size extent of inodes. > > */ > > args.prod = 1; > > - /* > > - * Allow space for the inode btree to split. > > - */ > > - args.minleft = igeo->inobt_maxlevels; > > error = xfs_alloc_vextent_near_bno(&args, > > xfs_agbno_to_fsb(pag, > > be32_to_cpu(agi->agi_root))); > > > Reviewed-by: Mark Tinguely <mark.tinguely@oracle.com> > Thanks.. > I got the patches backwards...I agree we need to increase the minleft in > the other patch by 4 blocks (2 btrees * 2 for the level increase) but I > wonder why can't a full size inode chunk also split the by-count and > by-block btrees and the inode btree allocation also be short when fixing AGFL? > Yeah, I had the same general question in the original report. I'm not sure it can't happen for full size chunks. I was kind of taking it for granted that sparse inodes seem required to reproduce this just by virtue of smaller allocations and the allocator maybe having enough slop in the various calculations to gate it otherwise, but I'm not confident in that having now looked more through this code. Perhaps Matt can comment on if or how hard we tried to reproduce this with full inode chunks..? I'm curious.. was the creation of the reproducer based on a detected flaw in the code (LLM scan or something?), or a low space stress test or something were this problem just happened to fall out..? If we could reproduce or manufacture this with normal inode chunks, then I suppose that would lend more credence to a more generic solution within the allocator. Brian ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 2/2] xfs: consistent low ag space behavior for sparse inode chunk allocs 2026-07-31 16:33 [PATCH 0/2] xfs: fix a couple sparse chunk alloc problems Brian Foster 2026-07-31 16:33 ` [PATCH 1/2] xfs: set minleft correctly for sparse chunk errortag allocation Brian Foster @ 2026-07-31 16:33 ` Brian Foster 2026-07-31 17:54 ` [External] : " Mark Tinguely 2026-08-01 0:11 ` Dave Chinner 1 sibling, 2 replies; 7+ messages in thread From: Brian Foster @ 2026-07-31 16:33 UTC (permalink / raw) To: linux-xfs; +Cc: Matt Fleming Matt Fleming reports a filesystem shutdown due to inobt block allocation failure during sparse chunk allocation. Inode creation can involve multiple allocations in a transaction via the initial chunk allocation and inode btree growth via the subsequent inobt record insertion. Technically this should be safe as the chunk allocation sets the allocation minleft parameter to the max depth of the inode btree, which means the allocation selects an AG only if there is enough free space for record insertion after the allocation. The record insertion naturally occurs in the same AG as the allocation and the associated AGF is locked and held by the current transaction. The situation that reproduces this failure is a bit of a corner case. The allocation and inode btrees are all completely full and require a split on the next insertion. The AG has just enough available space to satisfy inode creation through sparse allocation (i.e. 7 blocks in this example). The block allocation occurs within an existing free space record, splitting the free space record into two and triggering the aforementioned allocbt splits. The sparse chunk allocation consumes 4 blocks for the chunk, and 4 blocks from the AGFL for the two allocbt splits. This leaves the AGFL with 4 remaining blocks and 3 available blocks in the AG. The record insertion attempts block allocation for the inobt split, but even though space is available, the geometry change has changed the minimum allocation requirements enforced by xfs_alloc_fix_freelist(). The min freelist value jumps from 8 to 12 due to the alloc btree level increases, so the available space calculation goes from something like this before the allocation: free + agfl - res - minfree - minleft = avail 2514 + 8 - 2505 - 8 - 2 = 7 ... to this after it: 2510 + 4 - 2505 - 12 - 0 = -3 Essentially the minleft value of 2 for the chunk alloc is not sufficient to overcome the additional requirements imposed on the subsequent inobt alloc due to the allocbt geometry changes caused by the first. Technically this shouldn't be a concern because a full split of any of the allocation btrees in one transaction means that we're not going to see another full split in the lifetime of that transaction, but the allocation path does not behave that way. Absent of a clear way to lock in the agfl state for the particular case of multiple allocations into a single AG, this patch works around the problem by increasing the minleft requirement for sparse chunk allocations. Specifically, we increase minleft by the number of blocks that the alloc length was reduced by. The reasoning behind this is to generally preserve the AG level no space behavior between full and sparse inode chunk allocations. The purpose of sparse inode chunks is to facilitate allocation in AGs under severe free space fragmentation and thus prevent premature -ENOSPC conditions across the broader fs, not necessarily squeeze every last block out of any single AG. Therefore, this helps ensure the low AG space boundary conditions for sparse inode chunks are relatively well tested compared to full inode chunks. Fixes: 56d1115c9bc7 ("xfs: allocate sparse inode chunks on full chunk allocation failure") Reported-by: Matt Fleming <matt@readmodwrite.com> Signed-off-by: Brian Foster <bfoster@redhat.com> --- fs/xfs/libxfs/xfs_ialloc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index 633b2d6e42c5..7e71c33fbefa 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -840,6 +840,14 @@ xfs_ialloc_ag_alloc( args.minlen = igeo->ialloc_min_blks; args.maxlen = args.minlen; + /* + * Bump minleft by the alloc size delta to maintain consistent + * out of space behavior with normal sized chunks. This isn't a + * requirement, but helps avoid sparse chunk and inobt block + * allocation quirks at or close to AG depletion. + */ + args.minleft += igeo->ialloc_blks - igeo->ialloc_min_blks; + /* * The inode record will be aligned to full chunk size. We must * prevent sparse allocation from AG boundaries that result in -- 2.55.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [External] : [PATCH 2/2] xfs: consistent low ag space behavior for sparse inode chunk allocs 2026-07-31 16:33 ` [PATCH 2/2] xfs: consistent low ag space behavior for sparse inode chunk allocs Brian Foster @ 2026-07-31 17:54 ` Mark Tinguely 2026-08-01 0:11 ` Dave Chinner 1 sibling, 0 replies; 7+ messages in thread From: Mark Tinguely @ 2026-07-31 17:54 UTC (permalink / raw) To: Brian Foster, linux-xfs; +Cc: Matt Fleming On 7/31/26 11:33 AM, Brian Foster wrote: > Matt Fleming reports a filesystem shutdown due to inobt block > allocation failure during sparse chunk allocation. Inode creation > can involve multiple allocations in a transaction via the initial > chunk allocation and inode btree growth via the subsequent inobt > record insertion. Technically this should be safe as the chunk > allocation sets the allocation minleft parameter to the max depth of > the inode btree, which means the allocation selects an AG only if > there is enough free space for record insertion after the > allocation. The record insertion naturally occurs in the same AG as > the allocation and the associated AGF is locked and held by the > current transaction. > > The situation that reproduces this failure is a bit of a corner > case. The allocation and inode btrees are all completely full and > require a split on the next insertion. The AG has just enough > available space to satisfy inode creation through sparse allocation > (i.e. 7 blocks in this example). The block allocation occurs within > an existing free space record, splitting the free space record into > two and triggering the aforementioned allocbt splits. > > The sparse chunk allocation consumes 4 blocks for the chunk, and 4 > blocks from the AGFL for the two allocbt splits. This leaves the > AGFL with 4 remaining blocks and 3 available blocks in the AG. The > record insertion attempts block allocation for the inobt split, but > even though space is available, the geometry change has changed the > minimum allocation requirements enforced by > xfs_alloc_fix_freelist(). The min freelist value jumps from 8 to 12 > due to the alloc btree level increases, so the available space > calculation goes from something like this before the allocation: > > free + agfl - res - minfree - minleft = avail > 2514 + 8 - 2505 - 8 - 2 = 7 > > ... to this after it: > > 2510 + 4 - 2505 - 12 - 0 = -3 > > Essentially the minleft value of 2 for the chunk alloc is not > sufficient to overcome the additional requirements imposed on the > subsequent inobt alloc due to the allocbt geometry changes caused by > the first. > > Technically this shouldn't be a concern because a full split of any > of the allocation btrees in one transaction means that we're not > going to see another full split in the lifetime of that transaction, > but the allocation path does not behave that way. > > Absent of a clear way to lock in the agfl state for the particular > case of multiple allocations into a single AG, this patch works > around the problem by increasing the minleft requirement for sparse > chunk allocations. Specifically, we increase minleft by the number > of blocks that the alloc length was reduced by. The reasoning behind > this is to generally preserve the AG level no space behavior between > full and sparse inode chunk allocations. > > The purpose of sparse inode chunks is to facilitate allocation in > AGs under severe free space fragmentation and thus prevent premature > -ENOSPC conditions across the broader fs, not necessarily squeeze > every last block out of any single AG. Therefore, this helps ensure > the low AG space boundary conditions for sparse inode chunks are > relatively well tested compared to full inode chunks. > > Fixes: 56d1115c9bc7 ("xfs: allocate sparse inode chunks on full chunk allocation failure") > Reported-by: Matt Fleming <matt@readmodwrite.com> > Signed-off-by: Brian Foster <bfoster@redhat.com> > --- > fs/xfs/libxfs/xfs_ialloc.c | 8 ++++++++ > 1 file changed, 8 insertions(+) > > diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c > index 633b2d6e42c5..7e71c33fbefa 100644 > --- a/fs/xfs/libxfs/xfs_ialloc.c > +++ b/fs/xfs/libxfs/xfs_ialloc.c > @@ -840,6 +840,14 @@ xfs_ialloc_ag_alloc( > args.minlen = igeo->ialloc_min_blks; > args.maxlen = args.minlen; > > + /* > + * Bump minleft by the alloc size delta to maintain consistent > + * out of space behavior with normal sized chunks. This isn't a > + * requirement, but helps avoid sparse chunk and inobt block > + * allocation quirks at or close to AG depletion. > + */ > + args.minleft += igeo->ialloc_blks - igeo->ialloc_min_blks; > + > /* > * The inode record will be aligned to full chunk size. We must > * prevent sparse allocation from AG boundaries that result in Good catch. Reviewed-by: Mark Tinguely <mark.tinguely@oracle.com> ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] xfs: consistent low ag space behavior for sparse inode chunk allocs 2026-07-31 16:33 ` [PATCH 2/2] xfs: consistent low ag space behavior for sparse inode chunk allocs Brian Foster 2026-07-31 17:54 ` [External] : " Mark Tinguely @ 2026-08-01 0:11 ` Dave Chinner 1 sibling, 0 replies; 7+ messages in thread From: Dave Chinner @ 2026-08-01 0:11 UTC (permalink / raw) To: Brian Foster; +Cc: linux-xfs, Matt Fleming Hi Brian, On Fri, Jul 31, 2026 at 12:33:37PM -0400, Brian Foster wrote: > Matt Fleming reports a filesystem shutdown due to inobt block > allocation failure during sparse chunk allocation. Inode creation > can involve multiple allocations in a transaction via the initial > chunk allocation and inode btree growth via the subsequent inobt > record insertion. Technically this should be safe as the chunk > allocation sets the allocation minleft parameter to the max depth of > the inode btree, which means the allocation selects an AG only if > there is enough free space for record insertion after the > allocation. The record insertion naturally occurs in the same AG as > the allocation and the associated AGF is locked and held by the > current transaction. > > The situation that reproduces this failure is a bit of a corner > case. The allocation and inode btrees are all completely full and > require a split on the next insertion. The AG has just enough > available space to satisfy inode creation through sparse allocation > (i.e. 7 blocks in this example). The block allocation occurs within > an existing free space record, splitting the free space record into > two and triggering the aforementioned allocbt splits. > > The sparse chunk allocation consumes 4 blocks for the chunk, and 4 > blocks from the AGFL for the two allocbt splits. This leaves the > AGFL with 4 remaining blocks and 3 available blocks in the AG. The > record insertion attempts block allocation for the inobt split, but > even though space is available, the geometry change has changed the > minimum allocation requirements enforced by > xfs_alloc_fix_freelist(). The min freelist value jumps from 8 to 12 > due to the alloc btree level increases, so the available space > calculation goes from something like this before the allocation: Ok, in my own words, the problem is that the minleft takes into account the space needed by the inobt/finobt allocations, but the allocator doesn't take into account that the AGFL requirement may increase for the second allocation in the transaction because the first allocation split the free space trees? Is that an accurate summary of the issue? If that is the case, then I think the root cause of the issue is that amount we are reserving for the AGFL on the first transaction is insufficient. ENOSPC needs to be detected before we modify anything, so it has to be done at the first allocation. However, it appears to be based on the current level of the bno/cnt btrees, not the potential for the level to increase and the AGFL require a larger block reservation than we've accounted for with minleft. Therefore, we need to account for the AGFL demand increase in the first reservation that might occur for the second (and subsequent allocations. i.e. if minleft != 0, then the agfl btree block reservations need to be done for (current level + 1) to take into account space for the trees to split during the dependent allocation chain that minleft != 0 implies is about to occur. This isn't an issue just for inobt/finobt blocks on inode chunk alloc, it's also an issue for anything that sets minleft for a dependent, multi-allocation operation (e.g. data extent allocation + BMBT block allocation). So from this perspective, I think the fix needs to be made to the calculation in xfs_alloc_min_freelist() to take into account minleft needing a larger AGFL reservation if any of the allocations in the chain splits. Hmmmm. I'm not sure the calculation in xfs_alloc_min_freelist() is correct, either: /* * For a btree shorter than the maximum height, the worst case is that * every level gets split and a new level is added, then while inserting * another entry to refill the AGFL, every level under the old root gets * split again. This is: * * (full height split reservation) + (AGFL refill split height) * = (current height + 1) + (current height - 1) * = (new height) + (new height - 2) * = 2 * new height - 2 i.e. I think the AGFL refill split height is wrong. Look at it this way: we do the AGFL refill -first-, so if that splits, we consume (current height + 1) blocks, and then new_height = (current height + 1). Then if the actual data allocation does a full split again (i.e. all except for the root block), that needs (new_height -1) blocks. So that becomes: new_height = current height + 1; blocks = new_height + (new_height - 1) = 2 * new_height - 1. IOWs, I think there's an existing off-by one in the AGFL btree block reservation calculation that contributes to this problem as well. Put these two things together: /* * if minleft is set, we are going to do multiple * allocations in this * transaction (e.g. inode chunk followed by inobt). Hence * we need to make sure we have enough space for fixing up * the freelists after the split as the btree level * increases the AGFL reservation size mid-transaction. If * we are close to ENOSPC, this AGFL reservation increase may * trigger ENOSPC from the subsequent allocation attempt, * and then we shutdown the filesystem. Hence if minleft is * set, reserve enough AGFL space for a potential split * during the allocation chain in this transaction up front. */ split_space = 1; if (minleft) split_space = 2; /* space needed by-bno freespace btree */ min_free = min(bno_level + split_space, mp->m_alloc_maxlevels) * 2 - 1; /* space needed by-size freespace btree */ min_free += min(cnt_level + split_space, mp->m_alloc_maxlevels) * 2 - 1; /* space needed reverse mapping used space btree */ if (xfs_has_rmapbt(mp)) min_free += min(rmap_level + split_space, mp->m_rmap_maxlevels) * 2 - 1; return min_free; This is all off the top of my head, I haven't verified it so it'll need checking. However, I think handling this situation generically in the allocator is a better solution than trying to work around it with caller-based minleft heuristics. Cheers, Dave. -- Dave Chinner dgc@kernel.org ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-08-01 0:11 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-31 16:33 [PATCH 0/2] xfs: fix a couple sparse chunk alloc problems Brian Foster 2026-07-31 16:33 ` [PATCH 1/2] xfs: set minleft correctly for sparse chunk errortag allocation Brian Foster 2026-07-31 18:02 ` [External] : " Mark Tinguely 2026-07-31 18:40 ` Brian Foster 2026-07-31 16:33 ` [PATCH 2/2] xfs: consistent low ag space behavior for sparse inode chunk allocs Brian Foster 2026-07-31 17:54 ` [External] : " Mark Tinguely 2026-08-01 0:11 ` Dave Chinner
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.