Re: [PATCH 1/6] xfs: cache last bitmap block in realtime allocator

Darrick J. Wong
2023-07-12T18:29:35Z

On Tue, Jun 20, 2023 at 02:32:11PM -0700, Omar Sandoval wrote:
> From: Omar Sandoval <osandov@fb.com>
>
> Profiling a workload on a highly fragmented realtime device showed a ton
> of CPU cycles being spent in xfs_trans_read_buf() called by
> xfs_rtbuf_get(). Further tracing showed that much of that was repeated
> calls to xfs_rtbuf_get() for the same block of the realtime bitmap.
> These come from xfs_rtallocate_extent_block(): as it walks through
> ranges of free bits in the bitmap, each call to xfs_rtcheck_range() and
> xfs_rtfind_{forw,back}() gets the same bitmap block. If the bitmap block
> is very fragmented, then this is _a lot_ of buffer lookups.
>
> The realtime allocator already passes around a cache of the last used
> realtime summary block to avoid repeated reads (the parameters rbpp and
> rsb). We can do the same for the realtime bitmap.
>
> This replaces rbpp and rsb with a struct xfs_rtbuf_cache, which caches
> the most recently used block for both the realtime bitmap and summary.
> xfs_rtbuf_get() now handles the caching instead of the callers, which
> requires plumbing xfs_rtbuf_cache to more functions but also makes sure
> we don't miss anything.

Hmm. I initially wondered why rtbitmap blocks wouldn't just stay
attached to the transaction, but then I realized -- this is the
/scanning/ phase that's repeatedly getting and releasing the rtbmp
block, right? The allocator hasn't dirtied any rtbitmap blocks yet, so
each xfs_trans_brelse actually drops the buffer, and that's how the
xfs_rtbuf_get ends up pounding on the bmapi and then the buffer cache?
Repeatedly?

> Signed-off-by: Omar Sandoval <osandov@fb.com>
> ---
> fs/xfs/libxfs/xfs_rtbitmap.c | 167 ++++++++++++++++++-----------------
> fs/xfs/xfs_rtalloc.c | 107 ++++++++++------------
> fs/xfs/xfs_rtalloc.h | 28 ++++--
> 3 files changed, 154 insertions(+), 148 deletions(-)
>
> diff --git a/fs/xfs/libxfs/xfs_rtbitmap.c b/fs/xfs/libxfs/xfs_rtbitmap.c
> index fa180ab66b73..1a832c9a412f 100644
> --- a/fs/xfs/libxfs/xfs_rtbitmap.c
> +++ b/fs/xfs/libxfs/xfs_rtbitmap.c
> @@ -46,6 +46,21 @@ const struct xfs_buf_ops xfs_rtbuf_ops = {
> .verify_write = xfs_rtbuf_verify_write,
> };
>
> +static void
> +xfs_rtbuf_cache_relse(
> + xfs_trans_t *tp, /* transaction pointer */

Please don't introduce more typedef usage.

struct xfs_trans *tp,
struct xfs_rtbuf_cache *cache)

(Also there's a lot of broken indenting in the lines added by this
patch.)

> + struct xfs_rtbuf_cache *cache) /* cached blocks */
> +{
> + if (cache->bbuf) {
> + xfs_trans_brelse(tp, cache->bbuf);
> + cache->bbuf = NULL;
> + }
> + if (cache->sbuf) {
> + xfs_trans_brelse(tp, cache->sbuf);
> + cache->sbuf = NULL;
> + }
> +}
> +
> /*
> * Get a buffer for the bitmap or summary file block specified.
> * The buffer is returned read and locked.
> @@ -56,14 +71,35 @@ xfs_rtbuf_get(
> xfs_trans_t *tp, /* transaction pointer */
> xfs_rtblock_t block, /* block number in bitmap or summary */
> int issum, /* is summary not bitmap */
> + struct xfs_rtbuf_cache *cache, /* in/out: cached blocks */
> struct xfs_buf **bpp) /* output: buffer for the block */
> {
> + struct xfs_buf **cbpp; /* cached block buffer */
> + xfs_fsblock_t *cbp; /* cached block number */
> struct xfs_buf *bp; /* block buffer, result */
> xfs_inode_t *ip; /* bitmap or summary inode */
> xfs_bmbt_irec_t map;
> int nmap = 1;
> int error; /* error value */
>
> + cbpp = issum ? &cache->bbuf : &cache->sbuf;
> + cbp = issum ? &cache->bblock : &cache->sblock;
> + /*
> + * If we have a cached buffer, and the block number matches, use that.
> + */
> + if (*cbpp && *cbp == block) {
> + *bpp = *cbpp;
> + return 0;
> + }
> + /*
> + * Otherwise we have to have to get the buffer. If there was an old
> + * one, get rid of it first.
> + */
> + if (*cbpp) {
> + xfs_trans_brelse(tp, *cbpp);
> + *cbpp = NULL;
> + }
> +
> ip = issum ? mp->m_rsumip : mp->m_rbmip;
>
> error = xfs_bmapi_read(ip, block, 1, &map, &nmap, 0);
> @@ -82,7 +118,8 @@ xfs_rtbuf_get(
>
> xfs_trans_buf_set_type(tp, bp, issum ? XFS_BLFT_RTSUMMARY_BUF
> : XFS_BLFT_RTBITMAP_BUF);
> - *bpp = bp;
> + *cbpp = *bpp = bp;
> + *cbp = block;
> return 0;
> }
>
> @@ -96,6 +133,7 @@ xfs_rtfind_back(
> xfs_trans_t *tp, /* transaction pointer */
> xfs_rtblock_t start, /* starting block to look at */
> xfs_rtblock_t limit, /* last block to look at */
> + struct xfs_rtbuf_cache *rtbufc, /* in/out: cache of realtime blocks */
> xfs_rtblock_t *rtblock) /* out: start block found */
> {
> xfs_rtword_t *b; /* current word in buffer */
> @@ -116,7 +154,7 @@ xfs_rtfind_back(
> * Compute and read in starting bitmap block for starting block.
> */
> block = XFS_BITTOBLOCK(mp, start);
> - error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
> + error = xfs_rtbuf_get(mp, tp, block, 0, rtbufc, &bp);
> if (error) {
> return error;
> }
> @@ -153,7 +191,6 @@ xfs_rtfind_back(
> /*
> * Different. Mark where we are and return.
> */
> - xfs_trans_brelse(tp, bp);
> i = bit - XFS_RTHIBIT(wdiff);
> *rtblock = start - i + 1;
> return 0;
> @@ -167,8 +204,7 @@ xfs_rtfind_back(
> /*
> * If done with this block, get the previous one.
> */
> - xfs_trans_brelse(tp, bp);
> - error = xfs_rtbuf_get(mp, tp, --block, 0, &bp);
> + error = xfs_rtbuf_get(mp, tp, --block, 0, rtbufc, &bp);
> if (error) {
> return error;
> }
> @@ -199,7 +235,6 @@ xfs_rtfind_back(
> /*
> * Different, mark where we are and return.
> */
> - xfs_trans_brelse(tp, bp);
> i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff);
> *rtblock = start - i + 1;
> return 0;
> @@ -213,8 +248,7 @@ xfs_rtfind_back(
> /*
> * If done with this block, get the previous one.
> */
> - xfs_trans_brelse(tp, bp);
> - error = xfs_rtbuf_get(mp, tp, --block, 0, &bp);
> + error = xfs_rtbuf_get(mp, tp, --block, 0, rtbufc, &bp);
> if (error) {
> return error;
> }
> @@ -246,7 +280,6 @@ xfs_rtfind_back(
> /*
> * Different, mark where we are and return.
> */
> - xfs_trans_brelse(tp, bp);
> i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff);
> *rtblock = start - i + 1;
> return 0;
> @@ -256,7 +289,6 @@ xfs_rtfind_back(
> /*
> * No match, return that we scanned the whole area.
> */
> - xfs_trans_brelse(tp, bp);
> *rtblock = start - i + 1;
> return 0;
> }
> @@ -271,6 +303,7 @@ xfs_rtfind_forw(
> xfs_trans_t *tp, /* transaction pointer */
> xfs_rtblock_t start, /* starting block to look at */
> xfs_rtblock_t limit, /* last block to look at */
> + struct xfs_rtbuf_cache *rtbufc, /* in/out: cache of realtime blocks */
> xfs_rtblock_t *rtblock) /* out: start block found */
> {
> xfs_rtword_t *b; /* current word in buffer */
> @@ -291,7 +324,7 @@ xfs_rtfind_forw(
> * Compute and read in starting bitmap block for starting block.
> */
> block = XFS_BITTOBLOCK(mp, start);
> - error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
> + error = xfs_rtbuf_get(mp, tp, block, 0, rtbufc, &bp);
> if (error) {
> return error;
> }
> @@ -327,7 +360,6 @@ xfs_rtfind_forw(
> /*
> * Different. Mark where we are and return.
> */
> - xfs_trans_brelse(tp, bp);
> i = XFS_RTLOBIT(wdiff) - bit;
> *rtblock = start + i - 1;
> return 0;
> @@ -341,8 +373,7 @@ xfs_rtfind_forw(
> /*
> * If done with this block, get the previous one.
> */
> - xfs_trans_brelse(tp, bp);
> - error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
> + error = xfs_rtbuf_get(mp, tp, ++block, 0, rtbufc, &bp);
> if (error) {
> return error;
> }
> @@ -372,7 +403,6 @@ xfs_rtfind_forw(
> /*
> * Different, mark where we are and return.
> */
> - xfs_trans_brelse(tp, bp);
> i += XFS_RTLOBIT(wdiff);
> *rtblock = start + i - 1;
> return 0;
> @@ -386,8 +416,7 @@ xfs_rtfind_forw(
> /*
> * If done with this block, get the next one.
> */
> - xfs_trans_brelse(tp, bp);
> - error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
> + error = xfs_rtbuf_get(mp, tp, ++block, 0, rtbufc, &bp);
> if (error) {
> return error;
> }
> @@ -416,7 +445,6 @@ xfs_rtfind_forw(
> /*
> * Different, mark where we are and return.
> */
> - xfs_trans_brelse(tp, bp);
> i += XFS_RTLOBIT(wdiff);
> *rtblock = start + i - 1;
> return 0;
> @@ -426,7 +454,6 @@ xfs_rtfind_forw(
> /*
> * No match, return that we scanned the whole area.
> */
> - xfs_trans_brelse(tp, bp);
> *rtblock = start + i - 1;
> return 0;
> }
> @@ -447,8 +474,7 @@ xfs_rtmodify_summary_int(
> int log, /* log2 of extent size */
> xfs_rtblock_t bbno, /* bitmap block number */
> int delta, /* change to make to summary info */
> - struct xfs_buf **rbpp, /* in/out: summary block buffer */
> - xfs_fsblock_t *rsb, /* in/out: summary block number */
> + struct xfs_rtbuf_cache *rtbufc, /* in/out: cache of realtime blocks */
> xfs_suminfo_t *sum) /* out: summary info for this block */
> {
> struct xfs_buf *bp; /* buffer for the summary block */
> @@ -465,30 +491,9 @@ xfs_rtmodify_summary_int(
> * Compute the block number in the summary file.
> */
> sb = XFS_SUMOFFSTOBLOCK(mp, so);
> - /*
> - * If we have an old buffer, and the block number matches, use that.
> - */
> - if (*rbpp && *rsb == sb)
> - bp = *rbpp;
> - /*
> - * Otherwise we have to get the buffer.
> - */
> - else {
> - /*
> - * If there was an old one, get rid of it first.
> - */
> - if (*rbpp)
> - xfs_trans_brelse(tp, *rbpp);
> - error = xfs_rtbuf_get(mp, tp, sb, 1, &bp);
> - if (error) {
> - return error;
> - }
> - /*
> - * Remember this buffer and block for the next call.
> - */
> - *rbpp = bp;
> - *rsb = sb;
> - }
> + error = xfs_rtbuf_get(mp, tp, sb, 1, rtbufc, &bp);
> + if (error)
> + return error;
> /*
> * Point to the summary information, modify/log it, and/or copy it out.
> */
> @@ -517,11 +522,9 @@ xfs_rtmodify_summary(
> int log, /* log2 of extent size */
> xfs_rtblock_t bbno, /* bitmap block number */
> int delta, /* change to make to summary info */
> - struct xfs_buf **rbpp, /* in/out: summary block buffer */
> - xfs_fsblock_t *rsb) /* in/out: summary block number */
> + struct xfs_rtbuf_cache *rtbufc) /* in/out: cache of realtime blocks */
> {
> - return xfs_rtmodify_summary_int(mp, tp, log, bbno,
> - delta, rbpp, rsb, NULL);
> + return xfs_rtmodify_summary_int(mp, tp, log, bbno, delta, rtbufc, NULL);
> }
>
> /*
> @@ -534,7 +537,8 @@ xfs_rtmodify_range(
> xfs_trans_t *tp, /* transaction pointer */
> xfs_rtblock_t start, /* starting block to modify */
> xfs_extlen_t len, /* length of extent to modify */
> - int val) /* 1 for free, 0 for allocated */
> + int val, /* 1 for free, 0 for allocated */
> + struct xfs_rtbuf_cache *rtbufc) /* in/out: cache of realtime blocks */
> {
> xfs_rtword_t *b; /* current word in buffer */
> int bit; /* bit number in the word */
> @@ -555,7 +559,7 @@ xfs_rtmodify_range(
> /*
> * Read the bitmap block, and point to its data.
> */
> - error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
> + error = xfs_rtbuf_get(mp, tp, block, 0, rtbufc, &bp);
> if (error) {
> return error;
> }
> @@ -600,7 +604,7 @@ xfs_rtmodify_range(
> xfs_trans_log_buf(tp, bp,
> (uint)((char *)first - (char *)bufp),
> (uint)((char *)b - (char *)bufp));
> - error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
> + error = xfs_rtbuf_get(mp, tp, ++block, 0, rtbufc, &bp);
> if (error) {
> return error;
> }
> @@ -640,7 +644,7 @@ xfs_rtmodify_range(
> xfs_trans_log_buf(tp, bp,
> (uint)((char *)first - (char *)bufp),
> (uint)((char *)b - (char *)bufp));
> - error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
> + error = xfs_rtbuf_get(mp, tp, ++block, 0, rtbufc, &bp);
> if (error) {
> return error;
> }
> @@ -690,8 +694,7 @@ xfs_rtfree_range(
> xfs_trans_t *tp, /* transaction pointer */
> xfs_rtblock_t start, /* starting block to free */
> xfs_extlen_t len, /* length to free */
> - struct xfs_buf **rbpp, /* in/out: summary block buffer */
> - xfs_fsblock_t *rsb) /* in/out: summary block number */
> + struct xfs_rtbuf_cache *rtbufc) /* in/out: cache of realtime blocks */
> {
> xfs_rtblock_t end; /* end of the freed extent */
> int error; /* error value */
> @@ -702,7 +705,7 @@ xfs_rtfree_range(
> /*
> * Modify the bitmap to mark this extent freed.
> */
> - error = xfs_rtmodify_range(mp, tp, start, len, 1);
> + error = xfs_rtmodify_range(mp, tp, start, len, 1, rtbufc);
> if (error) {
> return error;
> }
> @@ -711,7 +714,7 @@ xfs_rtfree_range(
> * We need to find the beginning and end of the extent so we can
> * properly update the summary.
> */
> - error = xfs_rtfind_back(mp, tp, start, 0, &preblock);
> + error = xfs_rtfind_back(mp, tp, start, 0, rtbufc, &preblock);
> if (error) {
> return error;
> }
> @@ -719,7 +722,7 @@ xfs_rtfree_range(
> * Find the next allocated block (end of allocated extent).
> */
> error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1,
> - &postblock);
> + rtbufc, &postblock);
> if (error)
> return error;
> /*
> @@ -729,7 +732,7 @@ xfs_rtfree_range(
> if (preblock < start) {
> error = xfs_rtmodify_summary(mp, tp,
> XFS_RTBLOCKLOG(start - preblock),
> - XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb);
> + XFS_BITTOBLOCK(mp, preblock), -1, rtbufc);
> if (error) {
> return error;
> }
> @@ -741,7 +744,7 @@ xfs_rtfree_range(
> if (postblock > end) {
> error = xfs_rtmodify_summary(mp, tp,
> XFS_RTBLOCKLOG(postblock - end),
> - XFS_BITTOBLOCK(mp, end + 1), -1, rbpp, rsb);
> + XFS_BITTOBLOCK(mp, end + 1), -1, rtbufc);
> if (error) {
> return error;
> }
> @@ -752,7 +755,7 @@ xfs_rtfree_range(
> */
> error = xfs_rtmodify_summary(mp, tp,
> XFS_RTBLOCKLOG(postblock + 1 - preblock),
> - XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb);
> + XFS_BITTOBLOCK(mp, preblock), 1, rtbufc);
> return error;
> }
>
> @@ -767,6 +770,7 @@ xfs_rtcheck_range(
> xfs_rtblock_t start, /* starting block number of extent */
> xfs_extlen_t len, /* length of extent */
> int val, /* 1 for free, 0 for allocated */
> + struct xfs_rtbuf_cache *rtbufc, /* in/out: cache of realtime blocks */
> xfs_rtblock_t *new, /* out: first block not matching */
> int *stat) /* out: 1 for matches, 0 for not */
> {
> @@ -789,7 +793,7 @@ xfs_rtcheck_range(
> /*
> * Read the bitmap block.
> */
> - error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
> + error = xfs_rtbuf_get(mp, tp, block, 0, rtbufc, &bp);
> if (error) {
> return error;
> }
> @@ -824,7 +828,6 @@ xfs_rtcheck_range(
> /*
> * Different, compute first wrong bit and return.
> */
> - xfs_trans_brelse(tp, bp);
> i = XFS_RTLOBIT(wdiff) - bit;
> *new = start + i;
> *stat = 0;
> @@ -839,8 +842,7 @@ xfs_rtcheck_range(
> /*
> * If done with this block, get the next one.
> */
> - xfs_trans_brelse(tp, bp);
> - error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
> + error = xfs_rtbuf_get(mp, tp, ++block, 0, rtbufc, &bp);
> if (error) {
> return error;
> }
> @@ -870,7 +872,6 @@ xfs_rtcheck_range(
> /*
> * Different, compute first wrong bit and return.
> */
> - xfs_trans_brelse(tp, bp);
> i += XFS_RTLOBIT(wdiff);
> *new = start + i;
> *stat = 0;
> @@ -885,8 +886,7 @@ xfs_rtcheck_range(
> /*
> * If done with this block, get the next one.
> */
> - xfs_trans_brelse(tp, bp);
> - error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
> + error = xfs_rtbuf_get(mp, tp, ++block, 0, rtbufc, &bp);
> if (error) {
> return error;
> }
> @@ -915,7 +915,6 @@ xfs_rtcheck_range(
> /*
> * Different, compute first wrong bit and return.
> */
> - xfs_trans_brelse(tp, bp);
> i += XFS_RTLOBIT(wdiff);
> *new = start + i;
> *stat = 0;
> @@ -926,7 +925,6 @@ xfs_rtcheck_range(
> /*
> * Successful, return.
> */
> - xfs_trans_brelse(tp, bp);
> *new = start + i;
> *stat = 1;
> return 0;
> @@ -941,20 +939,21 @@ xfs_rtcheck_alloc_range(
> xfs_mount_t *mp, /* file system mount point */
> xfs_trans_t *tp, /* transaction pointer */
> xfs_rtblock_t bno, /* starting block number of extent */
> - xfs_extlen_t len) /* length of extent */
> + xfs_extlen_t len, /* length of extent */
> + struct xfs_rtbuf_cache *rtbufc) /* in/out: cached blocks */
> {
> xfs_rtblock_t new; /* dummy for xfs_rtcheck_range */
> int stat;
> int error;
>
> - error = xfs_rtcheck_range(mp, tp, bno, len, 0, &new, &stat);
> + error = xfs_rtcheck_range(mp, tp, bno, len, 0, rtbufc, &new, &stat);
> if (error)
> return error;
> ASSERT(stat);
> return 0;
> }
> #else
> -#define xfs_rtcheck_alloc_range(m,t,b,l) (0)
> +#define xfs_rtcheck_alloc_range(m,t,b,l,r) (0)
> #endif
> /*
> * Free an extent in the realtime subvolume. Length is expressed in
> @@ -968,22 +967,21 @@ xfs_rtfree_extent(
> {
> int error; /* error value */
> xfs_mount_t *mp; /* file system mount structure */
> - xfs_fsblock_t sb; /* summary file block number */
> - struct xfs_buf *sumbp = NULL; /* summary file block buffer */
> + struct xfs_rtbuf_cache rtbufc = {}; /* cache of realtime blocks */
>
> mp = tp->t_mountp;
>
> ASSERT(mp->m_rbmip->i_itemp != NULL);
> ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
>
> - error = xfs_rtcheck_alloc_range(mp, tp, bno, len);
> + error = xfs_rtcheck_alloc_range(mp, tp, bno, len, &rtbufc);
> if (error)
> return error;
>
> /*
> * Free the range of realtime blocks.
> */
> - error = xfs_rtfree_range(mp, tp, bno, len, &sumbp, &sb);
> + error = xfs_rtfree_range(mp, tp, bno, len, &rtbufc);
> if (error) {
> return error;
> }
> @@ -1021,6 +1019,7 @@ xfs_rtalloc_query_range(
> xfs_rtblock_t high_key;
> int is_free;
> int error = 0;
> + struct xfs_rtbuf_cache rtbufc = {};
>
> if (low_rec->ar_startext > high_rec->ar_startext)
> return -EINVAL;
> @@ -1034,13 +1033,14 @@ xfs_rtalloc_query_range(
> rtstart = low_rec->ar_startext;
> while (rtstart <= high_key) {
> /* Is the first block free? */
> - error = xfs_rtcheck_range(mp, tp, rtstart, 1, 1, &rtend,
> - &is_free);
> + error = xfs_rtcheck_range(mp, tp, rtstart, 1, 1, &rtbufc,
> + &rtend, &is_free);
> if (error)
> break;
>
> /* How long does the extent go for? */
> - error = xfs_rtfind_forw(mp, tp, rtstart, high_key, &rtend);
> + error = xfs_rtfind_forw(mp, tp, rtstart, high_key, &rtbufc,
> + &rtend);
> if (error)
> break;
>
> @@ -1056,6 +1056,8 @@ xfs_rtalloc_query_range(
> rtstart = rtend + 1;
> }
>
> + xfs_rtbuf_cache_relse(tp, &rtbufc);
> +
> return error;
> }
>
> @@ -1085,11 +1087,14 @@ xfs_rtalloc_extent_is_free(
> xfs_extlen_t len,
> bool *is_free)
> {
> + struct xfs_rtbuf_cache rtbufc = {};
> xfs_rtblock_t end;
> int matches;
> int error;
>
> - error = xfs_rtcheck_range(mp, tp, start, len, 1, &end, &matches);
> + error = xfs_rtcheck_range(mp, tp, start, len, 1, &rtbufc, &end,
> + &matches);
> + xfs_rtbuf_cache_relse(tp, &rtbufc);
> if (error)
> return error;
>
> diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
> index 16534e9873f6..61ef13286654 100644
> --- a/fs/xfs/xfs_rtalloc.c
> +++ b/fs/xfs/xfs_rtalloc.c
> @@ -32,11 +32,10 @@ xfs_rtget_summary(
> xfs_trans_t *tp, /* transaction pointer */
> int log, /* log2 of extent size */
> xfs_rtblock_t bbno, /* bitmap block number */
> - struct xfs_buf **rbpp, /* in/out: summary block buffer */
> - xfs_fsblock_t *rsb, /* in/out: summary block number */
> + struct xfs_rtbuf_cache *rtbufc, /* in/out: cache of realtime blocks */
> xfs_suminfo_t *sum) /* out: summary info for this block */
> {
> - return xfs_rtmodify_summary_int(mp, tp, log, bbno, 0, rbpp, rsb, sum);
> + return xfs_rtmodify_summary_int(mp, tp, log, bbno, 0, rtbufc, sum);
> }
>
> /*
> @@ -50,8 +49,7 @@ xfs_rtany_summary(
> int low, /* low log2 extent size */
> int high, /* high log2 extent size */
> xfs_rtblock_t bbno, /* bitmap block number */
> - struct xfs_buf **rbpp, /* in/out: summary block buffer */
> - xfs_fsblock_t *rsb, /* in/out: summary block number */
> + struct xfs_rtbuf_cache *rtbufc, /* in/out: cache of realtime blocks */
> int *stat) /* out: any good extents here? */
> {
> int error; /* error value */
> @@ -69,7 +67,7 @@ xfs_rtany_summary(
> /*
> * Get one summary datum.
> */
> - error = xfs_rtget_summary(mp, tp, log, bbno, rbpp, rsb, &sum);
> + error = xfs_rtget_summary(mp, tp, log, bbno, rtbufc, &sum);
> if (error) {
> return error;
> }
> @@ -104,29 +102,27 @@ xfs_rtcopy_summary(
> xfs_trans_t *tp) /* transaction pointer */
> {
> xfs_rtblock_t bbno; /* bitmap block number */
> - struct xfs_buf *bp; /* summary buffer */
> + struct xfs_rtbuf_cache rtbufc = {}; /* cache of realtime blocks */
> int error; /* error return value */
> int log; /* summary level number (log length) */
> xfs_suminfo_t sum; /* summary data */
> - xfs_fsblock_t sumbno; /* summary block number */
>
> - bp = NULL;
> for (log = omp->m_rsumlevels - 1; log >= 0; log--) {
> for (bbno = omp->m_sb.sb_rbmblocks - 1;
> (xfs_srtblock_t)bbno >= 0;
> bbno--) {
> - error = xfs_rtget_summary(omp, tp, log, bbno, &bp,
> - &sumbno, &sum);
> + error = xfs_rtget_summary(omp, tp, log, bbno, &rtbufc,
> + &sum);
> if (error)
> return error;
> if (sum == 0)
> continue;
> error = xfs_rtmodify_summary(omp, tp, log, bbno, -sum,
> - &bp, &sumbno);
> + &rtbufc);
> if (error)
> return error;
> error = xfs_rtmodify_summary(nmp, tp, log, bbno, sum,
> - &bp, &sumbno);
> + &rtbufc);
> if (error)
> return error;
> ASSERT(sum > 0);
> @@ -144,8 +140,7 @@ xfs_rtallocate_range(
> xfs_trans_t *tp, /* transaction pointer */
> xfs_rtblock_t start, /* start block to allocate */
> xfs_extlen_t len, /* length to allocate */
> - struct xfs_buf **rbpp, /* in/out: summary block buffer */
> - xfs_fsblock_t *rsb) /* in/out: summary block number */
> + struct xfs_rtbuf_cache *rtbufc) /* in/out: cache of realtime blocks */
> {
> xfs_rtblock_t end; /* end of the allocated extent */
> int error; /* error value */
> @@ -158,14 +153,14 @@ xfs_rtallocate_range(
> * We need to find the beginning and end of the extent so we can
> * properly update the summary.
> */
> - error = xfs_rtfind_back(mp, tp, start, 0, &preblock);
> + error = xfs_rtfind_back(mp, tp, start, 0, rtbufc, &preblock);
> if (error) {
> return error;
> }
> /*
> * Find the next allocated block (end of free extent).
> */
> - error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1,
> + error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1, rtbufc,
> &postblock);
> if (error) {
> return error;
> @@ -176,7 +171,7 @@ xfs_rtallocate_range(
> */
> error = xfs_rtmodify_summary(mp, tp,
> XFS_RTBLOCKLOG(postblock + 1 - preblock),
> - XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb);
> + XFS_BITTOBLOCK(mp, preblock), -1, rtbufc);
> if (error) {
> return error;
> }
> @@ -187,7 +182,7 @@ xfs_rtallocate_range(
> if (preblock < start) {
> error = xfs_rtmodify_summary(mp, tp,
> XFS_RTBLOCKLOG(start - preblock),
> - XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb);
> + XFS_BITTOBLOCK(mp, preblock), 1, rtbufc);
> if (error) {
> return error;
> }
> @@ -199,7 +194,7 @@ xfs_rtallocate_range(
> if (postblock > end) {
> error = xfs_rtmodify_summary(mp, tp,
> XFS_RTBLOCKLOG(postblock - end),
> - XFS_BITTOBLOCK(mp, end + 1), 1, rbpp, rsb);
> + XFS_BITTOBLOCK(mp, end + 1), 1, rtbufc);
> if (error) {
> return error;
> }
> @@ -207,7 +202,7 @@ xfs_rtallocate_range(
> /*
> * Modify the bitmap to mark this extent allocated.
> */
> - error = xfs_rtmodify_range(mp, tp, start, len, 0);
> + error = xfs_rtmodify_range(mp, tp, start, len, 0, rtbufc);
> return error;
> }
>
> @@ -226,8 +221,7 @@ xfs_rtallocate_extent_block(
> xfs_extlen_t maxlen, /* maximum length to allocate */
> xfs_extlen_t *len, /* out: actual length allocated */
> xfs_rtblock_t *nextp, /* out: next block to try */
> - struct xfs_buf **rbpp, /* in/out: summary block buffer */
> - xfs_fsblock_t *rsb, /* in/out: summary block number */
> + struct xfs_rtbuf_cache *rtbufc, /* in/out: cache of realtime blocks */
> xfs_extlen_t prod, /* extent product factor */
> xfs_rtblock_t *rtblock) /* out: start block allocated */
> {
> @@ -254,7 +248,8 @@ xfs_rtallocate_extent_block(
> * See if there's a free extent of maxlen starting at i.
> * If it's not so then next will contain the first non-free.
> */
> - error = xfs_rtcheck_range(mp, tp, i, maxlen, 1, &next, &stat);
> + error = xfs_rtcheck_range(mp, tp, i, maxlen, 1, rtbufc, &next,
> + &stat);
> if (error) {
> return error;
> }
> @@ -262,8 +257,7 @@ xfs_rtallocate_extent_block(
> /*
> * i for maxlen is all free, allocate and return that.
> */
> - error = xfs_rtallocate_range(mp, tp, i, maxlen, rbpp,
> - rsb);
> + error = xfs_rtallocate_range(mp, tp, i, maxlen, rtbufc);
> if (error) {
> return error;
> }
> @@ -290,7 +284,7 @@ xfs_rtallocate_extent_block(
> * If not done yet, find the start of the next free space.
> */
> if (next < end) {
> - error = xfs_rtfind_forw(mp, tp, next, end, &i);
> + error = xfs_rtfind_forw(mp, tp, next, end, rtbufc, &i);
> if (error) {
> return error;
> }
> @@ -315,7 +309,7 @@ xfs_rtallocate_extent_block(
> /*
> * Allocate besti for bestlen & return that.
> */
> - error = xfs_rtallocate_range(mp, tp, besti, bestlen, rbpp, rsb);
> + error = xfs_rtallocate_range(mp, tp, besti, bestlen, rtbufc);
> if (error) {
> return error;
> }
> @@ -344,9 +338,8 @@ xfs_rtallocate_extent_exact(
> xfs_rtblock_t bno, /* starting block number to allocate */
> xfs_extlen_t minlen, /* minimum length to allocate */
> xfs_extlen_t maxlen, /* maximum length to allocate */
> + struct xfs_rtbuf_cache *rtbufc, /* in/out: cache of realtime blocks */
> xfs_extlen_t *len, /* out: actual length allocated */
> - struct xfs_buf **rbpp, /* in/out: summary block buffer */
> - xfs_fsblock_t *rsb, /* in/out: summary block number */
> xfs_extlen_t prod, /* extent product factor */
> xfs_rtblock_t *rtblock) /* out: start block allocated */
> {
> @@ -359,7 +352,8 @@ xfs_rtallocate_extent_exact(
> /*
> * Check if the range in question (for maxlen) is free.
> */
> - error = xfs_rtcheck_range(mp, tp, bno, maxlen, 1, &next, &isfree);
> + error = xfs_rtcheck_range(mp, tp, bno, maxlen, 1, rtbufc, &next,
> + &isfree);
> if (error) {
> return error;
> }
> @@ -367,7 +361,7 @@ xfs_rtallocate_extent_exact(
> /*
> * If it is, allocate it and return success.
> */
> - error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb);
> + error = xfs_rtallocate_range(mp, tp, bno, maxlen, rtbufc);
> if (error) {
> return error;
> }
> @@ -402,7 +396,7 @@ xfs_rtallocate_extent_exact(
> /*
> * Allocate what we can and return it.
> */
> - error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb);
> + error = xfs_rtallocate_range(mp, tp, bno, maxlen, rtbufc);
> if (error) {
> return error;
> }
> @@ -424,8 +418,7 @@ xfs_rtallocate_extent_near(
> xfs_extlen_t minlen, /* minimum length to allocate */
> xfs_extlen_t maxlen, /* maximum length to allocate */
> xfs_extlen_t *len, /* out: actual length allocated */
> - struct xfs_buf **rbpp, /* in/out: summary block buffer */
> - xfs_fsblock_t *rsb, /* in/out: summary block number */
> + struct xfs_rtbuf_cache *rtbufc, /* in/out: cache of realtime blocks */
> xfs_extlen_t prod, /* extent product factor */
> xfs_rtblock_t *rtblock) /* out: start block allocated */
> {
> @@ -456,8 +449,8 @@ xfs_rtallocate_extent_near(
> /*
> * Try the exact allocation first.
> */
> - error = xfs_rtallocate_extent_exact(mp, tp, bno, minlen, maxlen, len,
> - rbpp, rsb, prod, &r);
> + error = xfs_rtallocate_extent_exact(mp, tp, bno, minlen, maxlen, rtbufc,
> + len, prod, &r);
> if (error) {
> return error;
> }
> @@ -481,7 +474,7 @@ xfs_rtallocate_extent_near(
> * starting in this bitmap block.
> */
> error = xfs_rtany_summary(mp, tp, log2len, mp->m_rsumlevels - 1,
> - bbno + i, rbpp, rsb, &any);
> + bbno + i, rtbufc, &any);
> if (error) {
> return error;
> }
> @@ -499,8 +492,8 @@ xfs_rtallocate_extent_near(
> * this block.
> */
> error = xfs_rtallocate_extent_block(mp, tp,
> - bbno + i, minlen, maxlen, len, &n, rbpp,
> - rsb, prod, &r);
> + bbno + i, minlen, maxlen, len, &n,
> + rtbufc, prod, &r);
> if (error) {
> return error;
> }
> @@ -529,7 +522,7 @@ xfs_rtallocate_extent_near(
> */
> error = xfs_rtany_summary(mp, tp,
> log2len, mp->m_rsumlevels - 1,
> - bbno + j, rbpp, rsb, &any);
> + bbno + j, rtbufc, &any);
> if (error) {
> return error;
> }
> @@ -545,7 +538,7 @@ xfs_rtallocate_extent_near(
> continue;
> error = xfs_rtallocate_extent_block(mp,
> tp, bbno + j, minlen, maxlen,
> - len, &n, rbpp, rsb, prod, &r);
> + len, &n, rtbufc, prod, &r);
> if (error) {
> return error;
> }
> @@ -566,8 +559,8 @@ xfs_rtallocate_extent_near(
> * that we found.
> */
> error = xfs_rtallocate_extent_block(mp, tp,
> - bbno + i, minlen, maxlen, len, &n, rbpp,
> - rsb, prod, &r);
> + bbno + i, minlen, maxlen, len, &n,
> + rtbufc, prod, &r);
> if (error) {
> return error;
> }
> @@ -626,8 +619,7 @@ xfs_rtallocate_extent_size(
> xfs_extlen_t minlen, /* minimum length to allocate */
> xfs_extlen_t maxlen, /* maximum length to allocate */
> xfs_extlen_t *len, /* out: actual length allocated */
> - struct xfs_buf **rbpp, /* in/out: summary block buffer */
> - xfs_fsblock_t *rsb, /* in/out: summary block number */
> + struct xfs_rtbuf_cache *rtbufc, /* in/out: cache of realtime blocks */
> xfs_extlen_t prod, /* extent product factor */
> xfs_rtblock_t *rtblock) /* out: start block allocated */
> {
> @@ -656,7 +648,7 @@ xfs_rtallocate_extent_size(
> /*
> * Get the summary for this level/block.
> */
> - error = xfs_rtget_summary(mp, tp, l, i, rbpp, rsb,
> + error = xfs_rtget_summary(mp, tp, l, i, rtbufc,
> &sum);
> if (error) {
> return error;
> @@ -670,7 +662,7 @@ xfs_rtallocate_extent_size(
> * Try allocating the extent.
> */
> error = xfs_rtallocate_extent_block(mp, tp, i, maxlen,
> - maxlen, len, &n, rbpp, rsb, prod, &r);
> + maxlen, len, &n, rtbufc, prod, &r);
> if (error) {
> return error;
> }
> @@ -715,7 +707,7 @@ xfs_rtallocate_extent_size(
> /*
> * Get the summary information for this level/block.
> */
> - error = xfs_rtget_summary(mp, tp, l, i, rbpp, rsb,
> + error = xfs_rtget_summary(mp, tp, l, i, rtbufc,
> &sum);
> if (error) {
> return error;
> @@ -733,7 +725,7 @@ xfs_rtallocate_extent_size(
> error = xfs_rtallocate_extent_block(mp, tp, i,
> XFS_RTMAX(minlen, 1 << l),
> XFS_RTMIN(maxlen, (1 << (l + 1)) - 1),
> - len, &n, rbpp, rsb, prod, &r);
> + len, &n, rtbufc, prod, &r);
> if (error) {
> return error;
> }
> @@ -922,7 +914,6 @@ xfs_growfs_rt(
> xfs_extlen_t rbmblocks; /* current number of rt bitmap blocks */
> xfs_extlen_t rsumblocks; /* current number of rt summary blks */
> xfs_sb_t *sbp; /* old superblock */
> - xfs_fsblock_t sumbno; /* summary block number */
> uint8_t *rsum_cache; /* old summary cache */
>
> sbp = &mp->m_sb;
> @@ -1025,6 +1016,7 @@ xfs_growfs_rt(
> bmbno++) {
> struct xfs_trans *tp;
> xfs_rfsblock_t nrblocks_step;
> + struct xfs_rtbuf_cache rtbufc = {}; /* cache of realtime blocks */
>
> *nmp = *mp;
> nsbp = &nmp->m_sb;
> @@ -1111,9 +1103,8 @@ xfs_growfs_rt(
> /*
> * Free new extent.
> */
> - bp = NULL;
> error = xfs_rtfree_range(nmp, tp, sbp->sb_rextents,
> - nsbp->sb_rextents - sbp->sb_rextents, &bp, &sumbno);
> + nsbp->sb_rextents - sbp->sb_rextents, &rtbufc);
> if (error) {
> error_cancel:
> xfs_trans_cancel(tp);
> @@ -1185,8 +1176,7 @@ xfs_rtallocate_extent(
> xfs_mount_t *mp = tp->t_mountp;
> int error; /* error value */
> xfs_rtblock_t r; /* result allocated block */
> - xfs_fsblock_t sb; /* summary file block number */
> - struct xfs_buf *sumbp; /* summary file block buffer */
> + struct xfs_rtbuf_cache rtbufc = {}; /* cache of realtime blocks */
>
> ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
> ASSERT(minlen > 0 && minlen <= maxlen);
> @@ -1208,13 +1198,14 @@ xfs_rtallocate_extent(
> }
>
> retry:
> - sumbp = NULL;
> + rtbufc.bbuf = NULL;
> + rtbufc.sbuf = NULL;

xfs_rtbuf_cache_relse?

> if (bno == 0) {
> error = xfs_rtallocate_extent_size(mp, tp, minlen, maxlen, len,
> - &sumbp, &sb, prod, &r);
> + &rtbufc, prod, &r);
> } else {
> error = xfs_rtallocate_extent_near(mp, tp, bno, minlen, maxlen,
> - len, &sumbp, &sb, prod, &r);
> + len, &rtbufc, prod, &r);
> }
>
> if (error)
> diff --git a/fs/xfs/xfs_rtalloc.h b/fs/xfs/xfs_rtalloc.h
> index 62c7ad79cbb6..888552c4f287 100644
> --- a/fs/xfs/xfs_rtalloc.h
> +++ b/fs/xfs/xfs_rtalloc.h
> @@ -101,29 +101,39 @@ xfs_growfs_rt(
> /*
> * From xfs_rtbitmap.c
> */
> +struct xfs_rtbuf_cache {
> + struct xfs_buf *bbuf; /* bitmap block buffer */
> + xfs_fsblock_t bblock; /* bitmap block number */
> + struct xfs_buf *sbuf; /* summary block buffer */
> + xfs_fsblock_t sblock; /* summary block number */

These are really offsets into the data fork, right? They ought to be
xfs_fileoff_t, except that none of the rtalloc code uses the correct
type?

And yes I do want to merge the fixes for that:
https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux.git/log/?h=clean-up-realtime-units

--D

> +};
> +
> int xfs_rtbuf_get(struct xfs_mount *mp, struct xfs_trans *tp,
> - xfs_rtblock_t block, int issum, struct xfs_buf **bpp);
> + xfs_rtblock_t block, int issum, struct xfs_rtbuf_cache *cache,
> + struct xfs_buf **bpp);
> int xfs_rtcheck_range(struct xfs_mount *mp, struct xfs_trans *tp,
> xfs_rtblock_t start, xfs_extlen_t len, int val,
> - xfs_rtblock_t *new, int *stat);
> + struct xfs_rtbuf_cache *rtbufc, xfs_rtblock_t *new,
> + int *stat);
> int xfs_rtfind_back(struct xfs_mount *mp, struct xfs_trans *tp,
> xfs_rtblock_t start, xfs_rtblock_t limit,
> - xfs_rtblock_t *rtblock);
> + struct xfs_rtbuf_cache *rtbufc, xfs_rtblock_t *rtblock);
> int xfs_rtfind_forw(struct xfs_mount *mp, struct xfs_trans *tp,
> xfs_rtblock_t start, xfs_rtblock_t limit,
> - xfs_rtblock_t *rtblock);
> + struct xfs_rtbuf_cache *rtbufc, xfs_rtblock_t *rtblock);
> int xfs_rtmodify_range(struct xfs_mount *mp, struct xfs_trans *tp,
> - xfs_rtblock_t start, xfs_extlen_t len, int val);
> + xfs_rtblock_t start, xfs_extlen_t len, int val,
> + struct xfs_rtbuf_cache *rtbufc);
> int xfs_rtmodify_summary_int(struct xfs_mount *mp, struct xfs_trans *tp,
> int log, xfs_rtblock_t bbno, int delta,
> - struct xfs_buf **rbpp, xfs_fsblock_t *rsb,
> + struct xfs_rtbuf_cache *rtbufc,
> xfs_suminfo_t *sum);
> int xfs_rtmodify_summary(struct xfs_mount *mp, struct xfs_trans *tp, int log,
> - xfs_rtblock_t bbno, int delta, struct xfs_buf **rbpp,
> - xfs_fsblock_t *rsb);
> + xfs_rtblock_t bbno, int delta,
> + struct xfs_rtbuf_cache *rtbufc);
> int xfs_rtfree_range(struct xfs_mount *mp, struct xfs_trans *tp,
> xfs_rtblock_t start, xfs_extlen_t len,
> - struct xfs_buf **rbpp, xfs_fsblock_t *rsb);
> + struct xfs_rtbuf_cache *rtbufc);
> int xfs_rtalloc_query_range(struct xfs_mount *mp, struct xfs_trans *tp,
> const struct xfs_rtalloc_rec *low_rec,
> const struct xfs_rtalloc_rec *high_rec,
> --
> 2.41.0
>