From: Dave Chinner Date: Mon, 22 Aug 2022 14:15:22 +0000 (+0200) Subject: xfs: Pre-calculate per-AG agino geometry X-Git-Tag: v6.0.0-rc0~17 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8aa34dc9b9abad2d76011d1b483856c72d03d004;p=thirdparty%2Fxfsprogs-dev.git xfs: Pre-calculate per-AG agino geometry Source kernel commit: 2d6ca8321c354e1cb6f6b1963c4f7bd053d2e272 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 Reviewed-by: Christoph Hellwig Reviewed-by: Darrick J. Wong Signed-off-by: Carlos Maiolino --- diff --git a/libxfs/xfs_ag.c b/libxfs/xfs_ag.c index 4762d7138..44ed5a592 100644 --- a/libxfs/xfs_ag.c +++ b/libxfs/xfs_ag.c @@ -223,6 +223,41 @@ xfs_ag_block_count( mp->m_sb.sb_dblocks); } +/* Calculate the first and last possible inode number in an AG. */ +static void +__xfs_agino_range( + struct xfs_mount *mp, + xfs_agblock_t eoag, + xfs_agino_t *first, + xfs_agino_t *last) +{ + xfs_agblock_t bno; + + /* + * Calculate the first inode, which will be in the first + * cluster-aligned block after the AGFL. + */ + bno = round_up(XFS_AGFL_BLOCK(mp) + 1, M_IGEO(mp)->cluster_align); + *first = XFS_AGB_TO_AGINO(mp, bno); + + /* + * Calculate the last inode, which will be at the end of the + * last (aligned) cluster that can be allocated in the AG. + */ + bno = round_down(eoag, M_IGEO(mp)->cluster_align); + *last = XFS_AGB_TO_AGINO(mp, bno) - 1; +} + +void +xfs_agino_range( + struct xfs_mount *mp, + xfs_agnumber_t agno, + xfs_agino_t *first, + xfs_agino_t *last) +{ + return __xfs_agino_range(mp, xfs_ag_block_count(mp, agno), first, last); +} + int xfs_initialize_perag( struct xfs_mount *mp, @@ -300,6 +335,8 @@ xfs_initialize_perag( pag->block_count = __xfs_ag_block_count(mp, index, agcount, dblocks); pag->min_block = XFS_AGFL_BLOCK(mp); + __xfs_agino_range(mp, pag->block_count, &pag->agino_min, + &pag->agino_max); } index = xfs_set_inode_alloc(mp, agcount); @@ -966,6 +1003,8 @@ xfs_ag_extend_space( /* Update perag geometry */ pag->block_count = be32_to_cpu(agf->agf_length); + __xfs_agino_range(pag->pag_mount, pag->block_count, &pag->agino_min, + &pag->agino_max); return 0; } diff --git a/libxfs/xfs_ag.h b/libxfs/xfs_ag.h index 77640f140..bb9e91bd3 100644 --- a/libxfs/xfs_ag.h +++ b/libxfs/xfs_ag.h @@ -70,6 +70,8 @@ struct xfs_perag { /* Precalculated geometry info */ xfs_agblock_t block_count; xfs_agblock_t min_block; + xfs_agino_t agino_min; + xfs_agino_t agino_max; #ifdef __KERNEL__ /* -- kernel only structures below this line -- */ @@ -124,6 +126,8 @@ void xfs_perag_put(struct xfs_perag *pag); * Per-ag geometry infomation and validation */ xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno); +void xfs_agino_range(struct xfs_mount *mp, xfs_agnumber_t agno, + xfs_agino_t *first, xfs_agino_t *last); static inline bool 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) return true; } +/* + * Verify that an AG inode number pointer neither points outside the AG + * nor points at static metadata. + */ +static inline bool +xfs_verify_agino(struct xfs_perag *pag, xfs_agino_t agino) +{ + if (agino < pag->agino_min) + return false; + if (agino > pag->agino_max) + return false; + return true; +} + +/* + * Verify that an AG inode number pointer neither points outside the AG + * nor points at static metadata, or is NULLAGINO. + */ +static inline bool +xfs_verify_agino_or_null(struct xfs_perag *pag, xfs_agino_t agino) +{ + if (agino == NULLAGINO) + return true; + return xfs_verify_agino(pag, agino); +} + /* * Perag iteration APIs */ diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c index 60f74b4b2..f18ea6752 100644 --- a/libxfs/xfs_ialloc.c +++ b/libxfs/xfs_ialloc.c @@ -100,7 +100,6 @@ xfs_inobt_get_rec( int *stat) { struct xfs_mount *mp = cur->bc_mp; - xfs_agnumber_t agno = cur->bc_ag.pag->pag_agno; union xfs_btree_rec *rec; int error; uint64_t realfree; @@ -111,7 +110,7 @@ xfs_inobt_get_rec( xfs_inobt_btrec_to_irec(mp, rec, irec); - if (!xfs_verify_agino(mp, agno, irec->ir_startino)) + if (!xfs_verify_agino(cur->bc_ag.pag, irec->ir_startino)) goto out_bad_rec; if (irec->ir_count < XFS_INODES_PER_HOLEMASK_BIT || irec->ir_count > XFS_INODES_PER_CHUNK) @@ -132,7 +131,8 @@ xfs_inobt_get_rec( out_bad_rec: xfs_warn(mp, "%s Inode BTree record corruption in AG %d detected!", - cur->bc_btnum == XFS_BTNUM_INO ? "Used" : "Free", agno); + cur->bc_btnum == XFS_BTNUM_INO ? "Used" : "Free", + cur->bc_ag.pag->pag_agno); xfs_warn(mp, "start inode 0x%x, count 0x%x, free 0x%x freemask 0x%llx, holemask 0x%x", irec->ir_startino, irec->ir_count, irec->ir_freecount, diff --git a/libxfs/xfs_inode_buf.c b/libxfs/xfs_inode_buf.c index cab2ae30a..800c43a3c 100644 --- a/libxfs/xfs_inode_buf.c +++ b/libxfs/xfs_inode_buf.c @@ -10,6 +10,7 @@ #include "xfs_log_format.h" #include "xfs_trans_resv.h" #include "xfs_mount.h" +#include "xfs_ag.h" #include "xfs_inode.h" #include "xfs_errortag.h" #include "xfs_trans.h" @@ -38,14 +39,12 @@ xfs_inode_buf_verify( bool readahead) { struct xfs_mount *mp = bp->b_mount; - xfs_agnumber_t agno; int i; int ni; /* * Validate the magic number and version of every inode in the buffer */ - agno = xfs_daddr_to_agno(mp, xfs_buf_daddr(bp)); ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock; for (i = 0; i < ni; i++) { struct xfs_dinode *dip; @@ -56,7 +55,7 @@ xfs_inode_buf_verify( unlinked_ino = be32_to_cpu(dip->di_next_unlinked); di_ok = xfs_verify_magic16(bp, dip->di_magic) && xfs_dinode_good_version(mp, dip->di_version) && - xfs_verify_agino_or_null(mp, agno, unlinked_ino); + xfs_verify_agino_or_null(bp->b_pag, unlinked_ino); if (unlikely(XFS_TEST_ERROR(!di_ok, mp, XFS_ERRTAG_ITOBP_INOTOBP))) { if (readahead) { diff --git a/libxfs/xfs_types.c b/libxfs/xfs_types.c index bbc86aeb4..87abc8244 100644 --- a/libxfs/xfs_types.c +++ b/libxfs/xfs_types.c @@ -73,40 +73,12 @@ xfs_verify_fsbext( XFS_FSB_TO_AGNO(mp, fsbno + len - 1); } -/* Calculate the first and last possible inode number in an AG. */ -inline void -xfs_agino_range( - struct xfs_mount *mp, - xfs_agnumber_t agno, - xfs_agino_t *first, - xfs_agino_t *last) -{ - xfs_agblock_t bno; - xfs_agblock_t eoag; - - eoag = xfs_ag_block_count(mp, agno); - - /* - * Calculate the first inode, which will be in the first - * cluster-aligned block after the AGFL. - */ - bno = round_up(XFS_AGFL_BLOCK(mp) + 1, M_IGEO(mp)->cluster_align); - *first = XFS_AGB_TO_AGINO(mp, bno); - - /* - * Calculate the last inode, which will be at the end of the - * last (aligned) cluster that can be allocated in the AG. - */ - bno = round_down(eoag, M_IGEO(mp)->cluster_align); - *last = XFS_AGB_TO_AGINO(mp, bno) - 1; -} - /* * Verify that an AG inode number pointer neither points outside the AG * nor points at static metadata. */ -inline bool -xfs_verify_agino( +static inline bool +xfs_verify_agno_agino( struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t agino) @@ -118,19 +90,6 @@ xfs_verify_agino( return agino >= first && agino <= last; } -/* - * Verify that an AG inode number pointer neither points outside the AG - * nor points at static metadata, or is NULLAGINO. - */ -bool -xfs_verify_agino_or_null( - struct xfs_mount *mp, - xfs_agnumber_t agno, - xfs_agino_t agino) -{ - return agino == NULLAGINO || xfs_verify_agino(mp, agno, agino); -} - /* * Verify that an FS inode number pointer neither points outside the * filesystem nor points at static AG metadata. @@ -147,7 +106,7 @@ xfs_verify_ino( return false; if (XFS_AGINO_TO_INO(mp, agno, agino) != ino) return false; - return xfs_verify_agino(mp, agno, agino); + return xfs_verify_agno_agino(mp, agno, agino); } /* Is this an internal inode number? */ @@ -217,12 +176,8 @@ xfs_icount_range( /* root, rtbitmap, rtsum all live in the first chunk */ *min = XFS_INODES_PER_CHUNK; - for_each_perag(mp, agno, pag) { - xfs_agino_t first, last; - - xfs_agino_range(mp, agno, &first, &last); - nr_inos += last - first + 1; - } + for_each_perag(mp, agno, pag) + nr_inos += pag->agino_max - pag->agino_min + 1; *max = nr_inos; } diff --git a/libxfs/xfs_types.h b/libxfs/xfs_types.h index ccf61afb9..a6b7d98cf 100644 --- a/libxfs/xfs_types.h +++ b/libxfs/xfs_types.h @@ -183,12 +183,6 @@ bool xfs_verify_fsbno(struct xfs_mount *mp, xfs_fsblock_t fsbno); bool xfs_verify_fsbext(struct xfs_mount *mp, xfs_fsblock_t fsbno, xfs_fsblock_t len); -void xfs_agino_range(struct xfs_mount *mp, xfs_agnumber_t agno, - xfs_agino_t *first, xfs_agino_t *last); -bool xfs_verify_agino(struct xfs_mount *mp, xfs_agnumber_t agno, - xfs_agino_t agino); -bool xfs_verify_agino_or_null(struct xfs_mount *mp, xfs_agnumber_t agno, - xfs_agino_t agino); bool xfs_verify_ino(struct xfs_mount *mp, xfs_ino_t ino); bool xfs_internal_inum(struct xfs_mount *mp, xfs_ino_t ino); bool xfs_verify_dir_ino(struct xfs_mount *mp, xfs_ino_t ino); diff --git a/repair/dino_chunks.c b/repair/dino_chunks.c index 80c52a439..0e09132b0 100644 --- a/repair/dino_chunks.c +++ b/repair/dino_chunks.c @@ -1134,6 +1134,7 @@ check_uncertain_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno) xfs_agino_t i; xfs_agino_t agino; int got_some; + struct xfs_perag *pag; nrec = NULL; got_some = 0; @@ -1157,6 +1158,7 @@ check_uncertain_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno) do_warn(_("found inodes not in the inode allocation tree\n")); + pag = libxfs_perag_get(mp, agno); do { /* * check every confirmed (which in this case means @@ -1168,7 +1170,7 @@ check_uncertain_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno) agino = i + irec->ino_startnum; - if (!libxfs_verify_agino(mp, agno, agino)) + if (!libxfs_verify_agino(pag, agino)) continue; if (nrec != NULL && nrec->ino_startnum <= agino && @@ -1177,7 +1179,7 @@ check_uncertain_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno) continue; if ((nrec = find_inode_rec(mp, agno, agino)) == NULL) - if (libxfs_verify_agino(mp, agno, agino)) + if (libxfs_verify_agino(pag, agino)) if (verify_aginode_chunk(mp, agno, agino, &start)) got_some = 1; @@ -1188,6 +1190,7 @@ check_uncertain_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno) irec = findfirst_uncertain_inode_rec(agno); } while (irec != NULL); + libxfs_perag_put(pag); if (got_some) do_warn(_("found inodes not in the inode allocation tree\n")); @@ -1228,6 +1231,7 @@ process_uncertain_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno) int cnt; int got_some; struct xfs_ino_geometry *igeo = M_IGEO(mp); + struct xfs_perag *pag; #ifdef XR_INODE_TRACE fprintf(stderr, "in process_uncertain_aginodes, agno = %d\n", agno); @@ -1242,6 +1246,7 @@ process_uncertain_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno) nrec = NULL; + pag = libxfs_perag_get(mp, agno); do { /* * check every confirmed inode @@ -1259,7 +1264,7 @@ process_uncertain_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno) * good tree), bad inode numbers, and inode numbers * pointing to bogus inodes */ - if (!libxfs_verify_agino(mp, agno, agino)) + if (!libxfs_verify_agino(pag, agino)) continue; if (nrec != NULL && nrec->ino_startnum <= agino && @@ -1303,6 +1308,7 @@ process_uncertain_aginodes(xfs_mount_t *mp, xfs_agnumber_t agno) irec = findfirst_uncertain_inode_rec(agno); } while (irec != NULL); + libxfs_perag_put(pag); if (got_some) do_warn(_("found inodes not in the inode allocation tree\n")); diff --git a/repair/dinode.c b/repair/dinode.c index fa841fbaa..e534a01b5 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -2300,6 +2300,7 @@ process_dinode_int(xfs_mount_t *mp, const int is_used = 1; blkmap_t *dblkmap = NULL; xfs_agino_t unlinked_ino; + struct xfs_perag *pag; *dirty = *isa_dir = 0; *used = is_used; @@ -2380,7 +2381,8 @@ process_dinode_int(xfs_mount_t *mp, } unlinked_ino = be32_to_cpu(dino->di_next_unlinked); - if (!xfs_verify_agino_or_null(mp, agno, unlinked_ino)) { + pag = libxfs_perag_get(mp, agno); + if (!xfs_verify_agino_or_null(pag, unlinked_ino)) { retval = 1; if (!uncertain) do_warn(_("bad next_unlinked 0x%x on inode %" PRIu64 "%c"), @@ -2395,6 +2397,7 @@ process_dinode_int(xfs_mount_t *mp, do_warn(_(" would reset next_unlinked\n")); } } + libxfs_perag_put(pag); /* * We don't bother checking the CRC here - we cannot guarantee that when diff --git a/repair/scan.c b/repair/scan.c index a8c5cc5dd..7e4d4d8b8 100644 --- a/repair/scan.c +++ b/repair/scan.c @@ -1546,6 +1546,7 @@ verify_single_ino_chunk_align( xfs_agino_t ino; xfs_agblock_t agbno; int off; + struct xfs_perag *pag; *skip = false; ino = be32_to_cpu(rp->ir_startino); @@ -1579,16 +1580,17 @@ verify_single_ino_chunk_align( * (NULLAGINO). if it gets closer, the agino number will be illegal as * the agbno will be too large. */ - if (!libxfs_verify_agino(mp, agno, ino)) { + pag = libxfs_perag_get(mp, agno); + if (!libxfs_verify_agino(pag, ino)) { do_warn( _("bad starting inode # (%" PRIu64 " (0x%x 0x%x)) in %s rec, skipping rec\n"), lino, agno, ino, inobt_name); *skip = true; + libxfs_perag_put(pag); return ++suspect; } - if (!libxfs_verify_agino(mp, agno, - ino + XFS_INODES_PER_CHUNK - 1)) { + if (!libxfs_verify_agino(pag, ino + XFS_INODES_PER_CHUNK - 1)) { do_warn( _("bad ending inode # (%" PRIu64 " (0x%x 0x%zx)) in %s rec, skipping rec\n"), lino + XFS_INODES_PER_CHUNK - 1, @@ -1596,9 +1598,11 @@ _("bad ending inode # (%" PRIu64 " (0x%x 0x%zx)) in %s rec, skipping rec\n"), ino + XFS_INODES_PER_CHUNK - 1, inobt_name); *skip = true; + libxfs_perag_put(pag); return ++suspect; } + libxfs_perag_put(pag); return suspect; }