Skip to content

Commit 2d6ca83

Browse files
dgchinnerdchinner
authored andcommitted
xfs: Pre-calculate per-AG agino geometry
There is a lot of overhead in functions like xfs_verify_agino() that repeatedly calculate the geometry limits of an AG. These can be pre-calculated as they are static and the verification context has a per-ag context it can quickly reference. In the case of xfs_verify_agino(), we now always have a perag context handy, so we can store the minimum and maximum agino values in the AG in the perag. This means we don't have to calculate it on every call and it can be inlined in callers if we move it to xfs_ag.h. xfs_verify_agino_or_null() gets the same perag treatment. xfs_agino_range() is moved to xfs_ag.c as it's not really a type function, and it's use is largely restricted as the first and last aginos can be grabbed straight from the perag in most cases. Note that we leave the original xfs_verify_agino in place in xfs_types.c as a static function as other callers in that file do not have per-ag contexts so still need to go the long way. It's been renamed to xfs_verify_agno_agino() to indicate it takes both an agno and an agino to differentiate it from new function. $ size --totals fs/xfs/built-in.a text data bss dec hex filename before 1482185 329588 572 1812345 1ba779 (TOTALS) after 1481937 329588 572 1812097 1ba681 (TOTALS) Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Darrick J. Wong <djwong@kernel.org>
1 parent 0800169 commit 2d6ca83

10 files changed

Lines changed: 95 additions & 81 deletions

File tree

fs/xfs/libxfs/xfs_ag.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,41 @@ xfs_ag_block_count(
225225
mp->m_sb.sb_dblocks);
226226
}
227227

228+
/* Calculate the first and last possible inode number in an AG. */
229+
static void
230+
__xfs_agino_range(
231+
struct xfs_mount *mp,
232+
xfs_agblock_t eoag,
233+
xfs_agino_t *first,
234+
xfs_agino_t *last)
235+
{
236+
xfs_agblock_t bno;
237+
238+
/*
239+
* Calculate the first inode, which will be in the first
240+
* cluster-aligned block after the AGFL.
241+
*/
242+
bno = round_up(XFS_AGFL_BLOCK(mp) + 1, M_IGEO(mp)->cluster_align);
243+
*first = XFS_AGB_TO_AGINO(mp, bno);
244+
245+
/*
246+
* Calculate the last inode, which will be at the end of the
247+
* last (aligned) cluster that can be allocated in the AG.
248+
*/
249+
bno = round_down(eoag, M_IGEO(mp)->cluster_align);
250+
*last = XFS_AGB_TO_AGINO(mp, bno) - 1;
251+
}
252+
253+
void
254+
xfs_agino_range(
255+
struct xfs_mount *mp,
256+
xfs_agnumber_t agno,
257+
xfs_agino_t *first,
258+
xfs_agino_t *last)
259+
{
260+
return __xfs_agino_range(mp, xfs_ag_block_count(mp, agno), first, last);
261+
}
262+
228263
int
229264
xfs_initialize_perag(
230265
struct xfs_mount *mp,
@@ -302,6 +337,8 @@ xfs_initialize_perag(
302337
pag->block_count = __xfs_ag_block_count(mp, index, agcount,
303338
dblocks);
304339
pag->min_block = XFS_AGFL_BLOCK(mp);
340+
__xfs_agino_range(mp, pag->block_count, &pag->agino_min,
341+
&pag->agino_max);
305342
}
306343

307344
index = xfs_set_inode_alloc(mp, agcount);
@@ -968,6 +1005,8 @@ xfs_ag_extend_space(
9681005

9691006
/* Update perag geometry */
9701007
pag->block_count = be32_to_cpu(agf->agf_length);
1008+
__xfs_agino_range(pag->pag_mount, pag->block_count, &pag->agino_min,
1009+
&pag->agino_max);
9711010
return 0;
9721011
}
9731012

fs/xfs/libxfs/xfs_ag.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ struct xfs_perag {
7070
/* Precalculated geometry info */
7171
xfs_agblock_t block_count;
7272
xfs_agblock_t min_block;
73+
xfs_agino_t agino_min;
74+
xfs_agino_t agino_max;
7375

7476
#ifdef __KERNEL__
7577
/* -- kernel only structures below this line -- */
@@ -124,6 +126,8 @@ void xfs_perag_put(struct xfs_perag *pag);
124126
* Per-ag geometry infomation and validation
125127
*/
126128
xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno);
129+
void xfs_agino_range(struct xfs_mount *mp, xfs_agnumber_t agno,
130+
xfs_agino_t *first, xfs_agino_t *last);
127131

128132
static inline bool
129133
xfs_verify_agbno(struct xfs_perag *pag, xfs_agblock_t agbno)
@@ -135,6 +139,32 @@ xfs_verify_agbno(struct xfs_perag *pag, xfs_agblock_t agbno)
135139
return true;
136140
}
137141

142+
/*
143+
* Verify that an AG inode number pointer neither points outside the AG
144+
* nor points at static metadata.
145+
*/
146+
static inline bool
147+
xfs_verify_agino(struct xfs_perag *pag, xfs_agino_t agino)
148+
{
149+
if (agino < pag->agino_min)
150+
return false;
151+
if (agino > pag->agino_max)
152+
return false;
153+
return true;
154+
}
155+
156+
/*
157+
* Verify that an AG inode number pointer neither points outside the AG
158+
* nor points at static metadata, or is NULLAGINO.
159+
*/
160+
static inline bool
161+
xfs_verify_agino_or_null(struct xfs_perag *pag, xfs_agino_t agino)
162+
{
163+
if (agino == NULLAGINO)
164+
return true;
165+
return xfs_verify_agino(pag, agino);
166+
}
167+
138168
/*
139169
* Perag iteration APIs
140170
*/

fs/xfs/libxfs/xfs_ialloc.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ xfs_inobt_get_rec(
105105
int *stat)
106106
{
107107
struct xfs_mount *mp = cur->bc_mp;
108-
xfs_agnumber_t agno = cur->bc_ag.pag->pag_agno;
109108
union xfs_btree_rec *rec;
110109
int error;
111110
uint64_t realfree;
@@ -116,7 +115,7 @@ xfs_inobt_get_rec(
116115

117116
xfs_inobt_btrec_to_irec(mp, rec, irec);
118117

119-
if (!xfs_verify_agino(mp, agno, irec->ir_startino))
118+
if (!xfs_verify_agino(cur->bc_ag.pag, irec->ir_startino))
120119
goto out_bad_rec;
121120
if (irec->ir_count < XFS_INODES_PER_HOLEMASK_BIT ||
122121
irec->ir_count > XFS_INODES_PER_CHUNK)
@@ -137,7 +136,8 @@ xfs_inobt_get_rec(
137136
out_bad_rec:
138137
xfs_warn(mp,
139138
"%s Inode BTree record corruption in AG %d detected!",
140-
cur->bc_btnum == XFS_BTNUM_INO ? "Used" : "Free", agno);
139+
cur->bc_btnum == XFS_BTNUM_INO ? "Used" : "Free",
140+
cur->bc_ag.pag->pag_agno);
141141
xfs_warn(mp,
142142
"start inode 0x%x, count 0x%x, free 0x%x freemask 0x%llx, holemask 0x%x",
143143
irec->ir_startino, irec->ir_count, irec->ir_freecount,

fs/xfs/libxfs/xfs_inode_buf.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "xfs_log_format.h"
1111
#include "xfs_trans_resv.h"
1212
#include "xfs_mount.h"
13+
#include "xfs_ag.h"
1314
#include "xfs_inode.h"
1415
#include "xfs_errortag.h"
1516
#include "xfs_error.h"
@@ -41,14 +42,12 @@ xfs_inode_buf_verify(
4142
bool readahead)
4243
{
4344
struct xfs_mount *mp = bp->b_mount;
44-
xfs_agnumber_t agno;
4545
int i;
4646
int ni;
4747

4848
/*
4949
* Validate the magic number and version of every inode in the buffer
5050
*/
51-
agno = xfs_daddr_to_agno(mp, xfs_buf_daddr(bp));
5251
ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock;
5352
for (i = 0; i < ni; i++) {
5453
struct xfs_dinode *dip;
@@ -59,7 +58,7 @@ xfs_inode_buf_verify(
5958
unlinked_ino = be32_to_cpu(dip->di_next_unlinked);
6059
di_ok = xfs_verify_magic16(bp, dip->di_magic) &&
6160
xfs_dinode_good_version(mp, dip->di_version) &&
62-
xfs_verify_agino_or_null(mp, agno, unlinked_ino);
61+
xfs_verify_agino_or_null(bp->b_pag, unlinked_ino);
6362
if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
6463
XFS_ERRTAG_ITOBP_INOTOBP))) {
6564
if (readahead) {

fs/xfs/libxfs/xfs_types.c

Lines changed: 5 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -73,40 +73,12 @@ xfs_verify_fsbext(
7373
XFS_FSB_TO_AGNO(mp, fsbno + len - 1);
7474
}
7575

76-
/* Calculate the first and last possible inode number in an AG. */
77-
inline void
78-
xfs_agino_range(
79-
struct xfs_mount *mp,
80-
xfs_agnumber_t agno,
81-
xfs_agino_t *first,
82-
xfs_agino_t *last)
83-
{
84-
xfs_agblock_t bno;
85-
xfs_agblock_t eoag;
86-
87-
eoag = xfs_ag_block_count(mp, agno);
88-
89-
/*
90-
* Calculate the first inode, which will be in the first
91-
* cluster-aligned block after the AGFL.
92-
*/
93-
bno = round_up(XFS_AGFL_BLOCK(mp) + 1, M_IGEO(mp)->cluster_align);
94-
*first = XFS_AGB_TO_AGINO(mp, bno);
95-
96-
/*
97-
* Calculate the last inode, which will be at the end of the
98-
* last (aligned) cluster that can be allocated in the AG.
99-
*/
100-
bno = round_down(eoag, M_IGEO(mp)->cluster_align);
101-
*last = XFS_AGB_TO_AGINO(mp, bno) - 1;
102-
}
103-
10476
/*
10577
* Verify that an AG inode number pointer neither points outside the AG
10678
* nor points at static metadata.
10779
*/
108-
inline bool
109-
xfs_verify_agino(
80+
static inline bool
81+
xfs_verify_agno_agino(
11082
struct xfs_mount *mp,
11183
xfs_agnumber_t agno,
11284
xfs_agino_t agino)
@@ -118,19 +90,6 @@ xfs_verify_agino(
11890
return agino >= first && agino <= last;
11991
}
12092

121-
/*
122-
* Verify that an AG inode number pointer neither points outside the AG
123-
* nor points at static metadata, or is NULLAGINO.
124-
*/
125-
bool
126-
xfs_verify_agino_or_null(
127-
struct xfs_mount *mp,
128-
xfs_agnumber_t agno,
129-
xfs_agino_t agino)
130-
{
131-
return agino == NULLAGINO || xfs_verify_agino(mp, agno, agino);
132-
}
133-
13493
/*
13594
* Verify that an FS inode number pointer neither points outside the
13695
* filesystem nor points at static AG metadata.
@@ -147,7 +106,7 @@ xfs_verify_ino(
147106
return false;
148107
if (XFS_AGINO_TO_INO(mp, agno, agino) != ino)
149108
return false;
150-
return xfs_verify_agino(mp, agno, agino);
109+
return xfs_verify_agno_agino(mp, agno, agino);
151110
}
152111

153112
/* Is this an internal inode number? */
@@ -217,12 +176,8 @@ xfs_icount_range(
217176
/* root, rtbitmap, rtsum all live in the first chunk */
218177
*min = XFS_INODES_PER_CHUNK;
219178

220-
for_each_perag(mp, agno, pag) {
221-
xfs_agino_t first, last;
222-
223-
xfs_agino_range(mp, agno, &first, &last);
224-
nr_inos += last - first + 1;
225-
}
179+
for_each_perag(mp, agno, pag)
180+
nr_inos += pag->agino_max - pag->agino_min + 1;
226181
*max = nr_inos;
227182
}
228183

fs/xfs/libxfs/xfs_types.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,6 @@ bool xfs_verify_fsbno(struct xfs_mount *mp, xfs_fsblock_t fsbno);
183183
bool xfs_verify_fsbext(struct xfs_mount *mp, xfs_fsblock_t fsbno,
184184
xfs_fsblock_t len);
185185

186-
void xfs_agino_range(struct xfs_mount *mp, xfs_agnumber_t agno,
187-
xfs_agino_t *first, xfs_agino_t *last);
188-
bool xfs_verify_agino(struct xfs_mount *mp, xfs_agnumber_t agno,
189-
xfs_agino_t agino);
190-
bool xfs_verify_agino_or_null(struct xfs_mount *mp, xfs_agnumber_t agno,
191-
xfs_agino_t agino);
192186
bool xfs_verify_ino(struct xfs_mount *mp, xfs_ino_t ino);
193187
bool xfs_internal_inum(struct xfs_mount *mp, xfs_ino_t ino);
194188
bool xfs_verify_dir_ino(struct xfs_mount *mp, xfs_ino_t ino);

fs/xfs/scrub/agheader.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -901,17 +901,17 @@ xchk_agi(
901901

902902
/* Check inode pointers */
903903
agino = be32_to_cpu(agi->agi_newino);
904-
if (!xfs_verify_agino_or_null(mp, agno, agino))
904+
if (!xfs_verify_agino_or_null(pag, agino))
905905
xchk_block_set_corrupt(sc, sc->sa.agi_bp);
906906

907907
agino = be32_to_cpu(agi->agi_dirino);
908-
if (!xfs_verify_agino_or_null(mp, agno, agino))
908+
if (!xfs_verify_agino_or_null(pag, agino))
909909
xchk_block_set_corrupt(sc, sc->sa.agi_bp);
910910

911911
/* Check unlinked inode buckets */
912912
for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) {
913913
agino = be32_to_cpu(agi->agi_unlinked[i]);
914-
if (!xfs_verify_agino_or_null(mp, agno, agino))
914+
if (!xfs_verify_agino_or_null(pag, agino))
915915
xchk_block_set_corrupt(sc, sc->sa.agi_bp);
916916
}
917917

fs/xfs/scrub/ialloc.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -421,10 +421,10 @@ xchk_iallocbt_rec(
421421
const union xfs_btree_rec *rec)
422422
{
423423
struct xfs_mount *mp = bs->cur->bc_mp;
424+
struct xfs_perag *pag = bs->cur->bc_ag.pag;
424425
struct xchk_iallocbt *iabt = bs->private;
425426
struct xfs_inobt_rec_incore irec;
426427
uint64_t holes;
427-
xfs_agnumber_t agno = bs->cur->bc_ag.pag->pag_agno;
428428
xfs_agino_t agino;
429429
xfs_extlen_t len;
430430
int holecount;
@@ -446,8 +446,8 @@ xchk_iallocbt_rec(
446446

447447
agino = irec.ir_startino;
448448
/* Record has to be properly aligned within the AG. */
449-
if (!xfs_verify_agino(mp, agno, agino) ||
450-
!xfs_verify_agino(mp, agno, agino + XFS_INODES_PER_CHUNK - 1)) {
449+
if (!xfs_verify_agino(pag, agino) ||
450+
!xfs_verify_agino(pag, agino + XFS_INODES_PER_CHUNK - 1)) {
451451
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
452452
goto out;
453453
}

fs/xfs/scrub/repair.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -220,16 +220,13 @@ xrep_calc_ag_resblks(
220220
usedlen = aglen - freelen;
221221
xfs_buf_relse(bp);
222222
}
223-
xfs_perag_put(pag);
224223

225224
/* If the icount is impossible, make some worst-case assumptions. */
226225
if (icount == NULLAGINO ||
227-
!xfs_verify_agino(mp, sm->sm_agno, icount)) {
228-
xfs_agino_t first, last;
229-
230-
xfs_agino_range(mp, sm->sm_agno, &first, &last);
231-
icount = last - first + 1;
226+
!xfs_verify_agino(pag, icount)) {
227+
icount = pag->agino_max - pag->agino_min + 1;
232228
}
229+
xfs_perag_put(pag);
233230

234231
/* If the block counts are impossible, make worst-case assumptions. */
235232
if (aglen == NULLAGBLOCK ||

fs/xfs/xfs_inode.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2008,7 +2008,7 @@ xfs_iunlink_update_bucket(
20082008
xfs_agino_t old_value;
20092009
int offset;
20102010

2011-
ASSERT(xfs_verify_agino_or_null(tp->t_mountp, pag->pag_agno, new_agino));
2011+
ASSERT(xfs_verify_agino_or_null(pag, new_agino));
20122012

20132013
old_value = be32_to_cpu(agi->agi_unlinked[bucket_index]);
20142014
trace_xfs_iunlink_update_bucket(tp->t_mountp, pag->pag_agno, bucket_index,
@@ -2045,7 +2045,7 @@ xfs_iunlink_update_dinode(
20452045
struct xfs_mount *mp = tp->t_mountp;
20462046
int offset;
20472047

2048-
ASSERT(xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino));
2048+
ASSERT(xfs_verify_agino_or_null(pag, next_agino));
20492049

20502050
trace_xfs_iunlink_update_dinode(mp, pag->pag_agno, agino,
20512051
be32_to_cpu(dip->di_next_unlinked), next_agino);
@@ -2075,7 +2075,7 @@ xfs_iunlink_update_inode(
20752075
xfs_agino_t old_value;
20762076
int error;
20772077

2078-
ASSERT(xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino));
2078+
ASSERT(xfs_verify_agino_or_null(pag, next_agino));
20792079

20802080
error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &ibp);
20812081
if (error)
@@ -2084,7 +2084,7 @@ xfs_iunlink_update_inode(
20842084

20852085
/* Make sure the old pointer isn't garbage. */
20862086
old_value = be32_to_cpu(dip->di_next_unlinked);
2087-
if (!xfs_verify_agino_or_null(mp, pag->pag_agno, old_value)) {
2087+
if (!xfs_verify_agino_or_null(pag, old_value)) {
20882088
xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip,
20892089
sizeof(*dip), __this_address);
20902090
error = -EFSCORRUPTED;
@@ -2155,7 +2155,7 @@ xfs_iunlink(
21552155
*/
21562156
next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
21572157
if (next_agino == agino ||
2158-
!xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino)) {
2158+
!xfs_verify_agino_or_null(pag, next_agino)) {
21592159
xfs_buf_mark_corrupt(agibp);
21602160
error = -EFSCORRUPTED;
21612161
goto out;
@@ -2291,7 +2291,7 @@ xfs_iunlink_map_prev(
22912291
* Make sure this pointer is valid and isn't an obvious
22922292
* infinite loop.
22932293
*/
2294-
if (!xfs_verify_agino(mp, pag->pag_agno, unlinked_agino) ||
2294+
if (!xfs_verify_agino(pag, unlinked_agino) ||
22952295
next_agino == unlinked_agino) {
22962296
XFS_CORRUPTION_ERROR(__func__,
22972297
XFS_ERRLEVEL_LOW, mp,
@@ -2338,7 +2338,7 @@ xfs_iunlink_remove(
23382338
* go on. Make sure the head pointer isn't garbage.
23392339
*/
23402340
head_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
2341-
if (!xfs_verify_agino(mp, pag->pag_agno, head_agino)) {
2341+
if (!xfs_verify_agino(pag, head_agino)) {
23422342
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
23432343
agi, sizeof(*agi));
23442344
return -EFSCORRUPTED;

0 commit comments

Comments
 (0)