From: Brian Foster <bfoster@redhat.com>
To: linux-xfs@vger.kernel.org
Subject: [PATCH v3 3/4] xfs: calculate AGFL max to support multiple-alloc transactions
Date: Wed, 2 Sep 2026 13:40:24 -0400 [thread overview]
Message-ID: <20260902174025.284387-4-bfoster@redhat.com> (raw)
In-Reply-To: <20260902174025.284387-1-bfoster@redhat.com>
Rework xfs_alloc_min_freelist() to return an (optional) max value
along with the historical min freelist value. The max value
includes an extra level in the btree based calculation to account
for btree splits in the first allocation of a multi-alloc sequence.
This value reflects the worst case AGFL requirement that can be
expected across multiple allocations within a single AG and single
transaction. For example, consider the case of allocating an inode
chunk and then an inobt block on inode record insertion.
While here, rename the need variable in xfs_alloc_fix_freelist() for
clarity with upcoming changes.
Note that no callers calculate the max AGFL value as of yet. No
functional changes in this patch.
Assisted-by: LLM
Signed-off-by: Brian Foster <bfoster@redhat.com>
---
fs/xfs/libxfs/xfs_alloc.c | 35 ++++++++++++++++++++++-------------
fs/xfs/libxfs/xfs_alloc.h | 4 ++--
fs/xfs/libxfs/xfs_bmap.c | 5 +++--
fs/xfs/libxfs/xfs_ialloc.c | 4 +++-
4 files changed, 30 insertions(+), 18 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index dbb85fb6314b..1377c65d694e 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -2445,7 +2445,7 @@ xfs_alloc_longest_free_extent(
* multi-allocation transactions.
*/
static unsigned int
-__xfs_alloc_min_freelist(
+__xfs_alloc_freelist(
struct xfs_mount *mp,
struct xfs_perag *pag,
unsigned int extra_levels)
@@ -2492,12 +2492,21 @@ __xfs_alloc_min_freelist(
return min_free;
}
-unsigned int
-xfs_alloc_min_freelist(
+/*
+ * Compute the minimum and maximum length of the AGFL in the given AG. The max
+ * value in this context refers to the max requirement the AG might see in a
+ * multi-alloc transaction. If @pag is NULL, return the largest possible values.
+ */
+void
+xfs_alloc_freelist(
struct xfs_mount *mp,
- struct xfs_perag *pag)
+ struct xfs_perag *pag,
+ unsigned int *min_free,
+ unsigned int *max_free)
{
- return __xfs_alloc_min_freelist(mp, pag, 0);
+ *min_free = __xfs_alloc_freelist(mp, pag, 0);
+ if (max_free)
+ *max_free = __xfs_alloc_freelist(mp, pag, 1);
}
/*
@@ -2849,7 +2858,7 @@ xfs_alloc_fix_freelist(
struct xfs_buf *agflbp = NULL;
struct xfs_alloc_arg targs; /* local allocation arguments */
xfs_agblock_t bno; /* freelist block */
- xfs_extlen_t need; /* total blocks needed in freelist */
+ xfs_extlen_t min_free;/* total blocks needed in freelist */
int error = 0;
/* deferred ops (AGFL block frees) require permanent transactions */
@@ -2877,8 +2886,8 @@ xfs_alloc_fix_freelist(
goto out_agbp_relse;
}
- need = xfs_alloc_min_freelist(mp, pag);
- if (!xfs_alloc_space_available(args, need, alloc_flags |
+ xfs_alloc_freelist(mp, pag, &min_free, NULL);
+ if (!xfs_alloc_space_available(args, min_free, alloc_flags |
XFS_ALLOC_FLAG_CHECK))
goto out_agbp_relse;
@@ -2901,8 +2910,8 @@ xfs_alloc_fix_freelist(
xfs_agfl_reset(tp, agbp, pag);
/* If there isn't enough total space or single-extent, reject it. */
- need = xfs_alloc_min_freelist(mp, pag);
- if (!xfs_alloc_space_available(args, need, alloc_flags))
+ xfs_alloc_freelist(mp, pag, &min_free, NULL);
+ if (!xfs_alloc_space_available(args, min_free, alloc_flags))
goto out_agbp_relse;
if (IS_ENABLED(CONFIG_XFS_DEBUG) && args->alloc_minlen_only) {
@@ -2944,7 +2953,7 @@ xfs_alloc_fix_freelist(
else
targs.oinfo = XFS_RMAP_OINFO_AG;
while (!(alloc_flags & XFS_ALLOC_FLAG_NOSHRINK) &&
- pag->pagf_flcount > need) {
+ pag->pagf_flcount > min_free) {
error = xfs_alloc_get_freelist(pag, tp, agbp, &bno, 0);
if (error)
goto out_agbp_relse;
@@ -2978,9 +2987,9 @@ xfs_alloc_fix_freelist(
goto out_agbp_relse;
/* Make the freelist longer if it's too short. */
- while (pag->pagf_flcount < need) {
+ while (pag->pagf_flcount < min_free) {
targs.agbno = 0;
- targs.maxlen = need - pag->pagf_flcount;
+ targs.maxlen = min_free - pag->pagf_flcount;
targs.resv = XFS_AG_RESV_AGFL;
/* Allocate as many blocks as possible at once. */
diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h
index 50ef79a1ed41..44a10f4a22a2 100644
--- a/fs/xfs/libxfs/xfs_alloc.h
+++ b/fs/xfs/libxfs/xfs_alloc.h
@@ -71,8 +71,8 @@ unsigned int xfs_alloc_ag_max_usable(struct xfs_mount *mp);
xfs_extlen_t xfs_alloc_longest_free_extent(struct xfs_perag *pag,
xfs_extlen_t need, xfs_extlen_t reserved);
-unsigned int xfs_alloc_min_freelist(struct xfs_mount *mp,
- struct xfs_perag *pag);
+void xfs_alloc_freelist(struct xfs_mount *mp, struct xfs_perag *pag,
+ unsigned int *min_free, unsigned int *max_free);
int xfs_alloc_get_freelist(struct xfs_perag *pag, struct xfs_trans *tp,
struct xfs_buf *agfbp, xfs_agblock_t *bnop, int btreeblk);
int xfs_alloc_put_freelist(struct xfs_perag *pag, struct xfs_trans *tp,
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index d64defeda645..17604e510ffc 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -3150,6 +3150,7 @@ xfs_bmap_longest_free_extent(
xfs_extlen_t *blen)
{
xfs_extlen_t longest;
+ unsigned int min_free;
int error = 0;
if (!xfs_perag_initialised_agf(pag)) {
@@ -3159,8 +3160,8 @@ xfs_bmap_longest_free_extent(
return error;
}
- longest = xfs_alloc_longest_free_extent(pag,
- xfs_alloc_min_freelist(pag_mount(pag), pag),
+ xfs_alloc_freelist(pag_mount(pag), pag, &min_free, NULL);
+ longest = xfs_alloc_longest_free_extent(pag, min_free,
xfs_ag_resv_needed(pag, XFS_AG_RESV_NONE));
if (*blen < longest)
*blen = longest;
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index edcda77b11ac..56aba1eff8af 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -3074,6 +3074,7 @@ xfs_ialloc_calc_rootino(
{
struct xfs_ino_geometry *igeo = M_IGEO(mp);
xfs_agblock_t first_bno;
+ unsigned int min_free;
/*
* Pre-calculate the geometry of AG 0. We know what it looks like
@@ -3092,7 +3093,8 @@ xfs_ialloc_calc_rootino(
first_bno += 1;
/* ...the initial AGFL... */
- first_bno += xfs_alloc_min_freelist(mp, NULL);
+ xfs_alloc_freelist(mp, NULL, &min_free, NULL);
+ first_bno += min_free;
/* ...the free inode btree root... */
if (xfs_has_finobt(mp))
--
2.55.0
next prev parent reply other threads:[~2026-09-02 17:40 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-02 17:40 [PATCH v3 0/4] xfs: fix a couple sparse chunk alloc problems Brian Foster
2026-09-02 17:40 ` [PATCH v3 1/4] xfs: set minleft correctly for sparse chunk errortag allocation Brian Foster
2026-09-02 17:40 ` [PATCH v3 2/4] xfs: support additional levels in the agfl minimum calculation Brian Foster
2026-09-03 16:58 ` [External] : " Mark Tinguely
2026-09-02 17:40 ` Brian Foster [this message]
2026-09-04 13:55 ` [External] : [PATCH v3 3/4] xfs: calculate AGFL max to support multiple-alloc transactions Mark Tinguely
2026-09-02 17:40 ` [PATCH v3 4/4] xfs: incorporate increased AGFL min requirement for minleft allocs Brian Foster
2026-09-04 14:00 ` [External] : " Mark Tinguely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260902174025.284387-4-bfoster@redhat.com \
--to=bfoster@redhat.com \
--cc=linux-xfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox