Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Dave Chinner and committed by
Dave Chinner
2d6ca832 0800169e

+95 -81
+39
fs/xfs/libxfs/xfs_ag.c
··· 225 225 mp->m_sb.sb_dblocks); 226 226 } 227 227 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 + 228 263 int 229 264 xfs_initialize_perag( 230 265 struct xfs_mount *mp, ··· 337 302 pag->block_count = __xfs_ag_block_count(mp, index, agcount, 338 303 dblocks); 339 304 pag->min_block = XFS_AGFL_BLOCK(mp); 305 + __xfs_agino_range(mp, pag->block_count, &pag->agino_min, 306 + &pag->agino_max); 340 307 } 341 308 342 309 index = xfs_set_inode_alloc(mp, agcount); ··· 1005 968 1006 969 /* Update perag geometry */ 1007 970 pag->block_count = be32_to_cpu(agf->agf_length); 971 + __xfs_agino_range(pag->pag_mount, pag->block_count, &pag->agino_min, 972 + &pag->agino_max); 1008 973 return 0; 1009 974 } 1010 975
+30
fs/xfs/libxfs/xfs_ag.h
··· 70 70 /* Precalculated geometry info */ 71 71 xfs_agblock_t block_count; 72 72 xfs_agblock_t min_block; 73 + xfs_agino_t agino_min; 74 + xfs_agino_t agino_max; 73 75 74 76 #ifdef __KERNEL__ 75 77 /* -- kernel only structures below this line -- */ ··· 126 124 * Per-ag geometry infomation and validation 127 125 */ 128 126 xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno); 127 + void xfs_agino_range(struct xfs_mount *mp, xfs_agnumber_t agno, 128 + xfs_agino_t *first, xfs_agino_t *last); 129 129 130 130 static inline bool 131 131 xfs_verify_agbno(struct xfs_perag *pag, xfs_agblock_t agbno) ··· 137 133 if (agbno <= pag->min_block) 138 134 return false; 139 135 return true; 136 + } 137 + 138 + /* 139 + * Verify that an AG inode number pointer neither points outside the AG 140 + * nor points at static metadata. 141 + */ 142 + static inline bool 143 + xfs_verify_agino(struct xfs_perag *pag, xfs_agino_t agino) 144 + { 145 + if (agino < pag->agino_min) 146 + return false; 147 + if (agino > pag->agino_max) 148 + return false; 149 + return true; 150 + } 151 + 152 + /* 153 + * Verify that an AG inode number pointer neither points outside the AG 154 + * nor points at static metadata, or is NULLAGINO. 155 + */ 156 + static inline bool 157 + xfs_verify_agino_or_null(struct xfs_perag *pag, xfs_agino_t agino) 158 + { 159 + if (agino == NULLAGINO) 160 + return true; 161 + return xfs_verify_agino(pag, agino); 140 162 } 141 163 142 164 /*
+3 -3
fs/xfs/libxfs/xfs_ialloc.c
··· 105 105 int *stat) 106 106 { 107 107 struct xfs_mount *mp = cur->bc_mp; 108 - xfs_agnumber_t agno = cur->bc_ag.pag->pag_agno; 109 108 union xfs_btree_rec *rec; 110 109 int error; 111 110 uint64_t realfree; ··· 115 116 116 117 xfs_inobt_btrec_to_irec(mp, rec, irec); 117 118 118 - if (!xfs_verify_agino(mp, agno, irec->ir_startino)) 119 + if (!xfs_verify_agino(cur->bc_ag.pag, irec->ir_startino)) 119 120 goto out_bad_rec; 120 121 if (irec->ir_count < XFS_INODES_PER_HOLEMASK_BIT || 121 122 irec->ir_count > XFS_INODES_PER_CHUNK) ··· 136 137 out_bad_rec: 137 138 xfs_warn(mp, 138 139 "%s Inode BTree record corruption in AG %d detected!", 139 - cur->bc_btnum == XFS_BTNUM_INO ? "Used" : "Free", agno); 140 + cur->bc_btnum == XFS_BTNUM_INO ? "Used" : "Free", 141 + cur->bc_ag.pag->pag_agno); 140 142 xfs_warn(mp, 141 143 "start inode 0x%x, count 0x%x, free 0x%x freemask 0x%llx, holemask 0x%x", 142 144 irec->ir_startino, irec->ir_count, irec->ir_freecount,
+2 -3
fs/xfs/libxfs/xfs_inode_buf.c
··· 10 10 #include "xfs_log_format.h" 11 11 #include "xfs_trans_resv.h" 12 12 #include "xfs_mount.h" 13 + #include "xfs_ag.h" 13 14 #include "xfs_inode.h" 14 15 #include "xfs_errortag.h" 15 16 #include "xfs_error.h" ··· 42 41 bool readahead) 43 42 { 44 43 struct xfs_mount *mp = bp->b_mount; 45 - xfs_agnumber_t agno; 46 44 int i; 47 45 int ni; 48 46 49 47 /* 50 48 * Validate the magic number and version of every inode in the buffer 51 49 */ 52 - agno = xfs_daddr_to_agno(mp, xfs_buf_daddr(bp)); 53 50 ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock; 54 51 for (i = 0; i < ni; i++) { 55 52 struct xfs_dinode *dip; ··· 58 59 unlinked_ino = be32_to_cpu(dip->di_next_unlinked); 59 60 di_ok = xfs_verify_magic16(bp, dip->di_magic) && 60 61 xfs_dinode_good_version(mp, dip->di_version) && 61 - xfs_verify_agino_or_null(mp, agno, unlinked_ino); 62 + xfs_verify_agino_or_null(bp->b_pag, unlinked_ino); 62 63 if (unlikely(XFS_TEST_ERROR(!di_ok, mp, 63 64 XFS_ERRTAG_ITOBP_INOTOBP))) { 64 65 if (readahead) {
+5 -50
fs/xfs/libxfs/xfs_types.c
··· 73 73 XFS_FSB_TO_AGNO(mp, fsbno + len - 1); 74 74 } 75 75 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 - 104 76 /* 105 77 * Verify that an AG inode number pointer neither points outside the AG 106 78 * nor points at static metadata. 107 79 */ 108 - inline bool 109 - xfs_verify_agino( 80 + static inline bool 81 + xfs_verify_agno_agino( 110 82 struct xfs_mount *mp, 111 83 xfs_agnumber_t agno, 112 84 xfs_agino_t agino) ··· 88 116 89 117 xfs_agino_range(mp, agno, &first, &last); 90 118 return agino >= first && agino <= last; 91 - } 92 - 93 - /* 94 - * Verify that an AG inode number pointer neither points outside the AG 95 - * nor points at static metadata, or is NULLAGINO. 96 - */ 97 - bool 98 - xfs_verify_agino_or_null( 99 - struct xfs_mount *mp, 100 - xfs_agnumber_t agno, 101 - xfs_agino_t agino) 102 - { 103 - return agino == NULLAGINO || xfs_verify_agino(mp, agno, agino); 104 119 } 105 120 106 121 /* ··· 106 147 return false; 107 148 if (XFS_AGINO_TO_INO(mp, agno, agino) != ino) 108 149 return false; 109 - return xfs_verify_agino(mp, agno, agino); 150 + return xfs_verify_agno_agino(mp, agno, agino); 110 151 } 111 152 112 153 /* Is this an internal inode number? */ ··· 176 217 /* root, rtbitmap, rtsum all live in the first chunk */ 177 218 *min = XFS_INODES_PER_CHUNK; 178 219 179 - for_each_perag(mp, agno, pag) { 180 - xfs_agino_t first, last; 181 - 182 - xfs_agino_range(mp, agno, &first, &last); 183 - nr_inos += last - first + 1; 184 - } 220 + for_each_perag(mp, agno, pag) 221 + nr_inos += pag->agino_max - pag->agino_min + 1; 185 222 *max = nr_inos; 186 223 } 187 224
-6
fs/xfs/libxfs/xfs_types.h
··· 183 183 bool xfs_verify_fsbext(struct xfs_mount *mp, xfs_fsblock_t fsbno, 184 184 xfs_fsblock_t len); 185 185 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); 192 186 bool xfs_verify_ino(struct xfs_mount *mp, xfs_ino_t ino); 193 187 bool xfs_internal_inum(struct xfs_mount *mp, xfs_ino_t ino); 194 188 bool xfs_verify_dir_ino(struct xfs_mount *mp, xfs_ino_t ino);
+3 -3
fs/xfs/scrub/agheader.c
··· 901 901 902 902 /* Check inode pointers */ 903 903 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)) 905 905 xchk_block_set_corrupt(sc, sc->sa.agi_bp); 906 906 907 907 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)) 909 909 xchk_block_set_corrupt(sc, sc->sa.agi_bp); 910 910 911 911 /* Check unlinked inode buckets */ 912 912 for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) { 913 913 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)) 915 915 xchk_block_set_corrupt(sc, sc->sa.agi_bp); 916 916 } 917 917
+3 -3
fs/xfs/scrub/ialloc.c
··· 421 421 const union xfs_btree_rec *rec) 422 422 { 423 423 struct xfs_mount *mp = bs->cur->bc_mp; 424 + struct xfs_perag *pag = bs->cur->bc_ag.pag; 424 425 struct xchk_iallocbt *iabt = bs->private; 425 426 struct xfs_inobt_rec_incore irec; 426 427 uint64_t holes; 427 - xfs_agnumber_t agno = bs->cur->bc_ag.pag->pag_agno; 428 428 xfs_agino_t agino; 429 429 xfs_extlen_t len; 430 430 int holecount; ··· 446 446 447 447 agino = irec.ir_startino; 448 448 /* 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)) { 451 451 xchk_btree_set_corrupt(bs->sc, bs->cur, 0); 452 452 goto out; 453 453 }
+3 -6
fs/xfs/scrub/repair.c
··· 220 220 usedlen = aglen - freelen; 221 221 xfs_buf_relse(bp); 222 222 } 223 - xfs_perag_put(pag); 224 223 225 224 /* If the icount is impossible, make some worst-case assumptions. */ 226 225 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; 232 228 } 229 + xfs_perag_put(pag); 233 230 234 231 /* If the block counts are impossible, make worst-case assumptions. */ 235 232 if (aglen == NULLAGBLOCK ||
+7 -7
fs/xfs/xfs_inode.c
··· 2008 2008 xfs_agino_t old_value; 2009 2009 int offset; 2010 2010 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)); 2012 2012 2013 2013 old_value = be32_to_cpu(agi->agi_unlinked[bucket_index]); 2014 2014 trace_xfs_iunlink_update_bucket(tp->t_mountp, pag->pag_agno, bucket_index, ··· 2045 2045 struct xfs_mount *mp = tp->t_mountp; 2046 2046 int offset; 2047 2047 2048 - ASSERT(xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino)); 2048 + ASSERT(xfs_verify_agino_or_null(pag, next_agino)); 2049 2049 2050 2050 trace_xfs_iunlink_update_dinode(mp, pag->pag_agno, agino, 2051 2051 be32_to_cpu(dip->di_next_unlinked), next_agino); ··· 2075 2075 xfs_agino_t old_value; 2076 2076 int error; 2077 2077 2078 - ASSERT(xfs_verify_agino_or_null(mp, pag->pag_agno, next_agino)); 2078 + ASSERT(xfs_verify_agino_or_null(pag, next_agino)); 2079 2079 2080 2080 error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &ibp); 2081 2081 if (error) ··· 2084 2084 2085 2085 /* Make sure the old pointer isn't garbage. */ 2086 2086 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)) { 2088 2088 xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, dip, 2089 2089 sizeof(*dip), __this_address); 2090 2090 error = -EFSCORRUPTED; ··· 2155 2155 */ 2156 2156 next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]); 2157 2157 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)) { 2159 2159 xfs_buf_mark_corrupt(agibp); 2160 2160 error = -EFSCORRUPTED; 2161 2161 goto out; ··· 2291 2291 * Make sure this pointer is valid and isn't an obvious 2292 2292 * infinite loop. 2293 2293 */ 2294 - if (!xfs_verify_agino(mp, pag->pag_agno, unlinked_agino) || 2294 + if (!xfs_verify_agino(pag, unlinked_agino) || 2295 2295 next_agino == unlinked_agino) { 2296 2296 XFS_CORRUPTION_ERROR(__func__, 2297 2297 XFS_ERRLEVEL_LOW, mp, ··· 2338 2338 * go on. Make sure the head pointer isn't garbage. 2339 2339 */ 2340 2340 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)) { 2342 2342 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, 2343 2343 agi, sizeof(*agi)); 2344 2344 return -EFSCORRUPTED;