[PATCH 03/24] xfs: rework the rtalloc fallback handling

Darrick J. Wong
2024-08-23T00:15:26Z

From: Christoph Hellwig <hch@lst.de>

xfs_rtallocate currently has two fallbacks, when an allocation fails:

1) drop the requested extent size alignment, if any, and retry
2) ignore the locality hint

Oddly enough it does those in order, as trying a different location
is more in line with what the user asked for, and does it in a very
unstructured way.

Lift the fallback to try to allocate without the locality hint into
xfs_rtallocate to both perform them in a more sensible order and to
clean up the code.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
fs/xfs/xfs_rtalloc.c | 69 +++++++++++++++++++++++++-------------------------
1 file changed, 34 insertions(+), 35 deletions(-)

diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index 861a82471b5d0..f39f05397201a 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -1277,6 +1277,8 @@ xfs_rtallocate(
xfs_rtxlen_t maxlen,
xfs_rtxlen_t prod,
bool wasdel,
+ bool initial_user_data,
+ bool *rtlocked,
xfs_rtblock_t *bno,
xfs_extlen_t *blen)
{
@@ -1286,12 +1288,38 @@ xfs_rtallocate(
};
xfs_rtxnum_t rtx;
xfs_rtxlen_t len = 0;
- int error;
+ int error = 0;
+
+ /*
+ * Lock out modifications to both the RT bitmap and summary inodes.
+ */
+ if (!*rtlocked) {
+ xfs_rtbitmap_lock(args.mp);
+ xfs_rtbitmap_trans_join(tp);
+ *rtlocked = true;
+ }
+
+ /*
+ * For an allocation to an empty file at offset 0, pick an extent that
+ * will space things out in the rt area.
+ */
+ if (!start && initial_user_data)
+ start = xfs_rtpick_extent(args.mp, tp, maxlen);

if (start) {
error = xfs_rtallocate_extent_near(&args, start, minlen, maxlen,
&len, prod, &rtx);
- } else {
+ /*
+ * If we can't allocate near a specific rt extent, try again
+ * without locality criteria.
+ */
+ if (error == -ENOSPC) {
+ xfs_rtbuf_cache_relse(&args);
+ error = 0;
+ }
+ }
+
+ if (!error) {
error = xfs_rtallocate_extent_size(&args, minlen, maxlen, &len,
prod, &rtx);
}
@@ -1320,7 +1348,7 @@ xfs_bmap_rtalloc(
{
struct xfs_mount *mp = ap->ip->i_mount;
xfs_fileoff_t orig_offset = ap->offset;
- xfs_rtxnum_t start; /* allocation hint rtextent no */
+ xfs_rtxnum_t start = 0; /* allocation hint rtextent no */
xfs_rtxlen_t prod = 0; /* product factor for allocators */
xfs_extlen_t mod = 0; /* product factor for allocators */
xfs_rtxlen_t ralen = 0; /* realtime allocation length */
@@ -1329,7 +1357,6 @@ xfs_bmap_rtalloc(
xfs_extlen_t minlen = mp->m_sb.sb_rextsize;
xfs_rtxlen_t raminlen;
bool rtlocked = false;
- bool ignore_locality = false;
int error;

align = xfs_get_extsz_hint(ap->ip);
@@ -1367,28 +1394,8 @@ xfs_bmap_rtalloc(
ASSERT(raminlen > 0);
ASSERT(raminlen <= ralen);

- /*
- * Lock out modifications to both the RT bitmap and summary inodes
- */
- if (!rtlocked) {
- xfs_rtbitmap_lock(mp);
- xfs_rtbitmap_trans_join(ap->tp);
- rtlocked = true;
- }
-
- if (ignore_locality) {
- start = 0;
- } else if (xfs_bmap_adjacent(ap)) {
+ if (xfs_bmap_adjacent(ap))
start = xfs_rtb_to_rtx(mp, ap->blkno);
- } else if (ap->datatype & XFS_ALLOC_INITIAL_USER_DATA) {
- /*
- * If it's an allocation to an empty file at offset 0, pick an
- * extent that will space things out in the rt area.
- */
- start = xfs_rtpick_extent(mp, ap->tp, ralen);
- } else {
- start = 0;
- }

/*
* Only bother calculating a real prod factor if offset & length are
@@ -1404,7 +1411,8 @@ xfs_bmap_rtalloc(
}

error = xfs_rtallocate(ap->tp, start, raminlen, ralen, prod, ap->wasdel,
- &ap->blkno, &ap->length);
+ ap->datatype & XFS_ALLOC_INITIAL_USER_DATA, &rtlocked,
+ &ap->blkno, &ap->length);
if (error == -ENOSPC) {
if (align > mp->m_sb.sb_rextsize) {
/*
@@ -1420,15 +1428,6 @@ xfs_bmap_rtalloc(
goto retry;
}

- if (!ignore_locality && start != 0) {
- /*
- * If we can't allocate near a specific rt extent, try
- * again without locality criteria.
- */
- ignore_locality = true;
- goto retry;
- }
-
ap->blkno = NULLFSBLOCK;
ap->length = 0;
return 0;