Skip to content

Commit e94b53f

Browse files
osandovDarrick J. Wong
authored andcommitted
xfs: cache last bitmap block in realtime allocator
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. Signed-off-by: Omar Sandoval <osandov@fb.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
1 parent 41f33d8 commit e94b53f

File tree

4 files changed

+135
-144
lines changed

4 files changed

+135
-144
lines changed

fs/xfs/libxfs/xfs_rtbitmap.c

Lines changed: 76 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,23 @@ const struct xfs_buf_ops xfs_rtbuf_ops = {
4747
.verify_write = xfs_rtbuf_verify_write,
4848
};
4949

50+
/* Release cached rt bitmap and summary buffers. */
51+
void
52+
xfs_rtbuf_cache_relse(
53+
struct xfs_rtalloc_args *args)
54+
{
55+
if (args->rbmbp) {
56+
xfs_trans_brelse(args->tp, args->rbmbp);
57+
args->rbmbp = NULL;
58+
args->rbmoff = NULLFILEOFF;
59+
}
60+
if (args->sumbp) {
61+
xfs_trans_brelse(args->tp, args->sumbp);
62+
args->sumbp = NULL;
63+
args->sumoff = NULLFILEOFF;
64+
}
65+
}
66+
5067
/*
5168
* Get a buffer for the bitmap or summary file block specified.
5269
* The buffer is returned read and locked.
@@ -59,13 +76,42 @@ xfs_rtbuf_get(
5976
struct xfs_buf **bpp) /* output: buffer for the block */
6077
{
6178
struct xfs_mount *mp = args->mp;
79+
struct xfs_buf **cbpp; /* cached block buffer */
80+
xfs_fileoff_t *coffp; /* cached block number */
6281
struct xfs_buf *bp; /* block buffer, result */
6382
struct xfs_inode *ip; /* bitmap or summary inode */
6483
struct xfs_bmbt_irec map;
84+
enum xfs_blft type;
6585
int nmap = 1;
6686
int error;
6787

68-
ip = issum ? mp->m_rsumip : mp->m_rbmip;
88+
if (issum) {
89+
cbpp = &args->sumbp;
90+
coffp = &args->sumoff;
91+
ip = mp->m_rsumip;
92+
type = XFS_BLFT_RTSUMMARY_BUF;
93+
} else {
94+
cbpp = &args->rbmbp;
95+
coffp = &args->rbmoff;
96+
ip = mp->m_rbmip;
97+
type = XFS_BLFT_RTBITMAP_BUF;
98+
}
99+
100+
/*
101+
* If we have a cached buffer, and the block number matches, use that.
102+
*/
103+
if (*cbpp && *coffp == block) {
104+
*bpp = *cbpp;
105+
return 0;
106+
}
107+
/*
108+
* Otherwise we have to have to get the buffer. If there was an old
109+
* one, get rid of it first.
110+
*/
111+
if (*cbpp) {
112+
xfs_trans_brelse(args->tp, *cbpp);
113+
*cbpp = NULL;
114+
}
69115

70116
error = xfs_bmapi_read(ip, block, 1, &map, &nmap, 0);
71117
if (error)
@@ -81,9 +127,9 @@ xfs_rtbuf_get(
81127
if (error)
82128
return error;
83129

84-
xfs_trans_buf_set_type(args->tp, bp, issum ? XFS_BLFT_RTSUMMARY_BUF
85-
: XFS_BLFT_RTBITMAP_BUF);
86-
*bpp = bp;
130+
xfs_trans_buf_set_type(args->tp, bp, type);
131+
*cbpp = *bpp = bp;
132+
*coffp = block;
87133
return 0;
88134
}
89135

@@ -153,7 +199,6 @@ xfs_rtfind_back(
153199
/*
154200
* Different. Mark where we are and return.
155201
*/
156-
xfs_trans_brelse(args->tp, bp);
157202
i = bit - XFS_RTHIBIT(wdiff);
158203
*rtx = start - i + 1;
159204
return 0;
@@ -167,7 +212,6 @@ xfs_rtfind_back(
167212
/*
168213
* If done with this block, get the previous one.
169214
*/
170-
xfs_trans_brelse(args->tp, bp);
171215
error = xfs_rtbuf_get(args, --block, 0, &bp);
172216
if (error) {
173217
return error;
@@ -194,7 +238,6 @@ xfs_rtfind_back(
194238
/*
195239
* Different, mark where we are and return.
196240
*/
197-
xfs_trans_brelse(args->tp, bp);
198241
i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff);
199242
*rtx = start - i + 1;
200243
return 0;
@@ -208,7 +251,6 @@ xfs_rtfind_back(
208251
/*
209252
* If done with this block, get the previous one.
210253
*/
211-
xfs_trans_brelse(args->tp, bp);
212254
error = xfs_rtbuf_get(args, --block, 0, &bp);
213255
if (error) {
214256
return error;
@@ -236,7 +278,6 @@ xfs_rtfind_back(
236278
/*
237279
* Different, mark where we are and return.
238280
*/
239-
xfs_trans_brelse(args->tp, bp);
240281
i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff);
241282
*rtx = start - i + 1;
242283
return 0;
@@ -246,7 +287,6 @@ xfs_rtfind_back(
246287
/*
247288
* No match, return that we scanned the whole area.
248289
*/
249-
xfs_trans_brelse(args->tp, bp);
250290
*rtx = start - i + 1;
251291
return 0;
252292
}
@@ -316,7 +356,6 @@ xfs_rtfind_forw(
316356
/*
317357
* Different. Mark where we are and return.
318358
*/
319-
xfs_trans_brelse(args->tp, bp);
320359
i = XFS_RTLOBIT(wdiff) - bit;
321360
*rtx = start + i - 1;
322361
return 0;
@@ -330,7 +369,6 @@ xfs_rtfind_forw(
330369
/*
331370
* If done with this block, get the previous one.
332371
*/
333-
xfs_trans_brelse(args->tp, bp);
334372
error = xfs_rtbuf_get(args, ++block, 0, &bp);
335373
if (error) {
336374
return error;
@@ -357,7 +395,6 @@ xfs_rtfind_forw(
357395
/*
358396
* Different, mark where we are and return.
359397
*/
360-
xfs_trans_brelse(args->tp, bp);
361398
i += XFS_RTLOBIT(wdiff);
362399
*rtx = start + i - 1;
363400
return 0;
@@ -371,7 +408,6 @@ xfs_rtfind_forw(
371408
/*
372409
* If done with this block, get the next one.
373410
*/
374-
xfs_trans_brelse(args->tp, bp);
375411
error = xfs_rtbuf_get(args, ++block, 0, &bp);
376412
if (error) {
377413
return error;
@@ -397,7 +433,6 @@ xfs_rtfind_forw(
397433
/*
398434
* Different, mark where we are and return.
399435
*/
400-
xfs_trans_brelse(args->tp, bp);
401436
i += XFS_RTLOBIT(wdiff);
402437
*rtx = start + i - 1;
403438
return 0;
@@ -407,7 +442,6 @@ xfs_rtfind_forw(
407442
/*
408443
* No match, return that we scanned the whole area.
409444
*/
410-
xfs_trans_brelse(args->tp, bp);
411445
*rtx = start + i - 1;
412446
return 0;
413447
}
@@ -442,8 +476,6 @@ xfs_rtmodify_summary_int(
442476
int log, /* log2 of extent size */
443477
xfs_fileoff_t bbno, /* bitmap block number */
444478
int delta, /* change to make to summary info */
445-
struct xfs_buf **rbpp, /* in/out: summary block buffer */
446-
xfs_fileoff_t *rsb, /* in/out: summary block number */
447479
xfs_suminfo_t *sum) /* out: summary info for this block */
448480
{
449481
struct xfs_mount *mp = args->mp;
@@ -461,30 +493,11 @@ xfs_rtmodify_summary_int(
461493
* Compute the block number in the summary file.
462494
*/
463495
sb = xfs_rtsumoffs_to_block(mp, so);
464-
/*
465-
* If we have an old buffer, and the block number matches, use that.
466-
*/
467-
if (*rbpp && *rsb == sb)
468-
bp = *rbpp;
469-
/*
470-
* Otherwise we have to get the buffer.
471-
*/
472-
else {
473-
/*
474-
* If there was an old one, get rid of it first.
475-
*/
476-
if (*rbpp)
477-
xfs_trans_brelse(args->tp, *rbpp);
478-
error = xfs_rtbuf_get(args, sb, 1, &bp);
479-
if (error) {
480-
return error;
481-
}
482-
/*
483-
* Remember this buffer and block for the next call.
484-
*/
485-
*rbpp = bp;
486-
*rsb = sb;
487-
}
496+
497+
error = xfs_rtbuf_get(args, sb, 1, &bp);
498+
if (error)
499+
return error;
500+
488501
/*
489502
* Point to the summary information, modify/log it, and/or copy it out.
490503
*/
@@ -512,11 +525,9 @@ xfs_rtmodify_summary(
512525
struct xfs_rtalloc_args *args,
513526
int log, /* log2 of extent size */
514527
xfs_fileoff_t bbno, /* bitmap block number */
515-
int delta, /* change to make to summary info */
516-
struct xfs_buf **rbpp, /* in/out: summary block buffer */
517-
xfs_fileoff_t *rsb) /* in/out: summary block number */
528+
int delta) /* in/out: summary block number */
518529
{
519-
return xfs_rtmodify_summary_int(args, log, bbno, delta, rbpp, rsb, NULL);
530+
return xfs_rtmodify_summary_int(args, log, bbno, delta, NULL);
520531
}
521532

522533
/* Log rtbitmap block from the word @from to the byte before @next. */
@@ -687,9 +698,7 @@ int
687698
xfs_rtfree_range(
688699
struct xfs_rtalloc_args *args,
689700
xfs_rtxnum_t start, /* starting rtext to free */
690-
xfs_rtxlen_t len, /* length to free */
691-
struct xfs_buf **rbpp, /* in/out: summary block buffer */
692-
xfs_fileoff_t *rsb) /* in/out: summary block number */
701+
xfs_rtxlen_t len) /* in/out: summary block number */
693702
{
694703
struct xfs_mount *mp = args->mp;
695704
xfs_rtxnum_t end; /* end of the freed extent */
@@ -718,7 +727,7 @@ xfs_rtfree_range(
718727
* Find the next allocated block (end of allocated extent).
719728
*/
720729
error = xfs_rtfind_forw(args, end, mp->m_sb.sb_rextents - 1,
721-
&postblock);
730+
&postblock);
722731
if (error)
723732
return error;
724733
/*
@@ -727,8 +736,8 @@ xfs_rtfree_range(
727736
*/
728737
if (preblock < start) {
729738
error = xfs_rtmodify_summary(args,
730-
XFS_RTBLOCKLOG(start - preblock),
731-
xfs_rtx_to_rbmblock(mp, preblock), -1, rbpp, rsb);
739+
XFS_RTBLOCKLOG(start - preblock),
740+
xfs_rtx_to_rbmblock(mp, preblock), -1);
732741
if (error) {
733742
return error;
734743
}
@@ -739,8 +748,8 @@ xfs_rtfree_range(
739748
*/
740749
if (postblock > end) {
741750
error = xfs_rtmodify_summary(args,
742-
XFS_RTBLOCKLOG(postblock - end),
743-
xfs_rtx_to_rbmblock(mp, end + 1), -1, rbpp, rsb);
751+
XFS_RTBLOCKLOG(postblock - end),
752+
xfs_rtx_to_rbmblock(mp, end + 1), -1);
744753
if (error) {
745754
return error;
746755
}
@@ -749,10 +758,9 @@ xfs_rtfree_range(
749758
* Increment the summary information corresponding to the entire
750759
* (new) free extent.
751760
*/
752-
error = xfs_rtmodify_summary(args,
753-
XFS_RTBLOCKLOG(postblock + 1 - preblock),
754-
xfs_rtx_to_rbmblock(mp, preblock), 1, rbpp, rsb);
755-
return error;
761+
return xfs_rtmodify_summary(args,
762+
XFS_RTBLOCKLOG(postblock + 1 - preblock),
763+
xfs_rtx_to_rbmblock(mp, preblock), 1);
756764
}
757765

758766
/*
@@ -822,7 +830,6 @@ xfs_rtcheck_range(
822830
/*
823831
* Different, compute first wrong bit and return.
824832
*/
825-
xfs_trans_brelse(args->tp, bp);
826833
i = XFS_RTLOBIT(wdiff) - bit;
827834
*new = start + i;
828835
*stat = 0;
@@ -837,7 +844,6 @@ xfs_rtcheck_range(
837844
/*
838845
* If done with this block, get the next one.
839846
*/
840-
xfs_trans_brelse(args->tp, bp);
841847
error = xfs_rtbuf_get(args, ++block, 0, &bp);
842848
if (error) {
843849
return error;
@@ -864,7 +870,6 @@ xfs_rtcheck_range(
864870
/*
865871
* Different, compute first wrong bit and return.
866872
*/
867-
xfs_trans_brelse(args->tp, bp);
868873
i += XFS_RTLOBIT(wdiff);
869874
*new = start + i;
870875
*stat = 0;
@@ -879,7 +884,6 @@ xfs_rtcheck_range(
879884
/*
880885
* If done with this block, get the next one.
881886
*/
882-
xfs_trans_brelse(args->tp, bp);
883887
error = xfs_rtbuf_get(args, ++block, 0, &bp);
884888
if (error) {
885889
return error;
@@ -905,7 +909,6 @@ xfs_rtcheck_range(
905909
/*
906910
* Different, compute first wrong bit and return.
907911
*/
908-
xfs_trans_brelse(args->tp, bp);
909912
i += XFS_RTLOBIT(wdiff);
910913
*new = start + i;
911914
*stat = 0;
@@ -916,7 +919,6 @@ xfs_rtcheck_range(
916919
/*
917920
* Successful, return.
918921
*/
919-
xfs_trans_brelse(args->tp, bp);
920922
*new = start + i;
921923
*stat = 1;
922924
return 0;
@@ -961,8 +963,6 @@ xfs_rtfree_extent(
961963
.tp = tp,
962964
};
963965
int error;
964-
xfs_fsblock_t sb; /* summary file block number */
965-
struct xfs_buf *sumbp = NULL; /* summary file block buffer */
966966

967967
ASSERT(mp->m_rbmip->i_itemp != NULL);
968968
ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
@@ -974,10 +974,10 @@ xfs_rtfree_extent(
974974
/*
975975
* Free the range of realtime blocks.
976976
*/
977-
error = xfs_rtfree_range(&args, start, len, &sumbp, &sb);
978-
if (error) {
979-
return error;
980-
}
977+
error = xfs_rtfree_range(&args, start, len);
978+
if (error)
979+
goto out;
980+
981981
/*
982982
* Mark more blocks free in the superblock.
983983
*/
@@ -993,7 +993,10 @@ xfs_rtfree_extent(
993993
*(uint64_t *)&VFS_I(mp->m_rbmip)->i_atime = 0;
994994
xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
995995
}
996-
return 0;
996+
error = 0;
997+
out:
998+
xfs_rtbuf_cache_relse(&args);
999+
return error;
9971000
}
9981001

9991002
/*
@@ -1084,6 +1087,7 @@ xfs_rtalloc_query_range(
10841087
rtstart = rtend + 1;
10851088
}
10861089

1090+
xfs_rtbuf_cache_relse(&args);
10871091
return error;
10881092
}
10891093

@@ -1122,6 +1126,7 @@ xfs_rtalloc_extent_is_free(
11221126
int error;
11231127

11241128
error = xfs_rtcheck_range(&args, start, len, 1, &end, &matches);
1129+
xfs_rtbuf_cache_relse(&args);
11251130
if (error)
11261131
return error;
11271132

0 commit comments

Comments
 (0)