]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
xfs: refactor xfs_iread_extents to use xfs_btree_visit_blocks
authorDarrick J. Wong <darrick.wong@oracle.com>
Mon, 28 Oct 2019 23:12:35 +0000 (16:12 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Tue, 29 Oct 2019 16:50:12 +0000 (09:50 -0700)
xfs_iread_extents open-codes everything in xfs_btree_visit_blocks, so
refactor the btree helper to be able to iterate only the records on
level 0, then port iread_extents to use it.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_btree.c
fs/xfs/libxfs/xfs_btree.h
fs/xfs/scrub/bitmap.c

index f16c6cdf2c582c6a729345ed96f1c362e303d9cf..77e52874e8c5951ce64cd01f8630af5243ed7193 100644 (file)
@@ -1155,6 +1155,65 @@ xfs_bmap_add_attrfork(
  * Internal and external extent tree search functions.
  */
 
+struct xfs_iread_state {
+       struct xfs_iext_cursor  icur;
+       xfs_extnum_t            loaded;
+};
+
+/* Stuff every bmbt record from this block into the incore extent map. */
+static int
+xfs_iread_bmbt_block(
+       struct xfs_btree_cur    *cur,
+       int                     level,
+       void                    *priv)
+{
+       struct xfs_iread_state  *ir = priv;
+       struct xfs_mount        *mp = cur->bc_mp;
+       struct xfs_inode        *ip = cur->bc_private.b.ip;
+       struct xfs_btree_block  *block;
+       struct xfs_buf          *bp;
+       struct xfs_bmbt_rec     *frp;
+       xfs_extnum_t            num_recs;
+       xfs_extnum_t            j;
+       int                     whichfork = cur->bc_private.b.whichfork;
+
+       block = xfs_btree_get_block(cur, level, &bp);
+
+       /* Abort if we find more records than nextents. */
+       num_recs = xfs_btree_get_numrecs(block);
+       if (unlikely(ir->loaded + num_recs >
+                    XFS_IFORK_NEXTENTS(ip, whichfork))) {
+               xfs_warn(ip->i_mount, "corrupt dinode %llu, (btree extents).",
+                               (unsigned long long)ip->i_ino);
+               xfs_inode_verifier_error(ip, -EFSCORRUPTED, __func__, block,
+                               sizeof(*block), __this_address);
+               return -EFSCORRUPTED;
+       }
+
+       /* Copy records into the incore cache. */
+       frp = XFS_BMBT_REC_ADDR(mp, block, 1);
+       for (j = 0; j < num_recs; j++, frp++, ir->loaded++) {
+               struct xfs_bmbt_irec    new;
+               xfs_failaddr_t          fa;
+
+               xfs_bmbt_disk_get_all(frp, &new);
+               fa = xfs_bmap_validate_extent(ip, whichfork, &new);
+               if (fa) {
+                       xfs_inode_verifier_error(ip, -EFSCORRUPTED,
+                                       "xfs_iread_extents(2)", frp,
+                                       sizeof(*frp), fa);
+                       return -EFSCORRUPTED;
+               }
+               xfs_iext_insert(ip, &ir->icur, &new,
+                               xfs_bmap_fork_to_state(whichfork));
+               trace_xfs_read_extent(ip, &ir->icur,
+                               xfs_bmap_fork_to_state(whichfork), _THIS_IP_);
+               xfs_iext_next(XFS_IFORK_PTR(ip, whichfork), &ir->icur);
+       }
+
+       return 0;
+}
+
 /*
  * Read in extents from a btree-format inode.
  */
@@ -1164,134 +1223,38 @@ xfs_iread_extents(
        struct xfs_inode        *ip,
        int                     whichfork)
 {
-       struct xfs_mount        *mp = ip->i_mount;
-       int                     state = xfs_bmap_fork_to_state(whichfork);
+       struct xfs_iread_state  ir;
        struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
-       xfs_extnum_t            nextents = XFS_IFORK_NEXTENTS(ip, whichfork);
-       struct xfs_btree_block  *block = ifp->if_broot;
-       struct xfs_iext_cursor  icur;
-       struct xfs_bmbt_irec    new;
-       xfs_fsblock_t           bno;
-       struct xfs_buf          *bp;
-       xfs_extnum_t            i, j;
-       int                     level;
-       __be64                  *pp;
+       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_btree_cur    *cur;
        int                     error;
 
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 
        if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
                XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
-               return -EFSCORRUPTED;
-       }
-
-       /*
-        * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out.
-        */
-       level = be16_to_cpu(block->bb_level);
-       if (unlikely(level == 0)) {
-               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
-               return -EFSCORRUPTED;
-       }
-       pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);
-       bno = be64_to_cpu(*pp);
-
-       /*
-        * Go down the tree until leaf level is reached, following the first
-        * pointer (leftmost) at each level.
-        */
-       while (level-- > 0) {
-               error = xfs_btree_read_bufl(mp, tp, bno, &bp,
-                               XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops);
-               if (error)
-                       goto out;
-               block = XFS_BUF_TO_BLOCK(bp);
-               if (level == 0)
-                       break;
-               pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
-               bno = be64_to_cpu(*pp);
-               XFS_WANT_CORRUPTED_GOTO(mp,
-                       xfs_verify_fsbno(mp, bno), out_brelse);
-               xfs_trans_brelse(tp, bp);
+               error = -EFSCORRUPTED;
+               goto out;
        }
 
-       /*
-        * Here with bp and block set to the leftmost leaf node in the tree.
-        */
-       i = 0;
-       xfs_iext_first(ifp, &icur);
-
-       /*
-        * Loop over all leaf nodes.  Copy information to the extent records.
-        */
-       for (;;) {
-               xfs_bmbt_rec_t  *frp;
-               xfs_fsblock_t   nextbno;
-               xfs_extnum_t    num_recs;
-
-               num_recs = xfs_btree_get_numrecs(block);
-               if (unlikely(i + num_recs > nextents)) {
-                       xfs_warn(ip->i_mount,
-                               "corrupt dinode %Lu, (btree extents).",
-                               (unsigned long long) ip->i_ino);
-                       xfs_inode_verifier_error(ip, -EFSCORRUPTED,
-                                       __func__, block, sizeof(*block),
-                                       __this_address);
-                       error = -EFSCORRUPTED;
-                       goto out_brelse;
-               }
-               /*
-                * Read-ahead the next leaf block, if any.
-                */
-               nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
-               if (nextbno != NULLFSBLOCK)
-                       xfs_btree_reada_bufl(mp, nextbno, 1,
-                                            &xfs_bmbt_buf_ops);
-               /*
-                * Copy records into the extent records.
-                */
-               frp = XFS_BMBT_REC_ADDR(mp, block, 1);
-               for (j = 0; j < num_recs; j++, frp++, i++) {
-                       xfs_failaddr_t  fa;
-
-                       xfs_bmbt_disk_get_all(frp, &new);
-                       fa = xfs_bmap_validate_extent(ip, whichfork, &new);
-                       if (fa) {
-                               error = -EFSCORRUPTED;
-                               xfs_inode_verifier_error(ip, error,
-                                               "xfs_iread_extents(2)",
-                                               frp, sizeof(*frp), fa);
-                               goto out_brelse;
-                       }
-                       xfs_iext_insert(ip, &icur, &new, state);
-                       trace_xfs_read_extent(ip, &icur, state, _THIS_IP_);
-                       xfs_iext_next(ifp, &icur);
-               }
-               xfs_trans_brelse(tp, bp);
-               bno = nextbno;
-               /*
-                * If we've reached the end, stop.
-                */
-               if (bno == NULLFSBLOCK)
-                       break;
-               error = xfs_btree_read_bufl(mp, tp, bno, &bp,
-                               XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops);
-               if (error)
-                       goto out;
-               block = XFS_BUF_TO_BLOCK(bp);
-       }
+       ir.loaded = 0;
+       xfs_iext_first(ifp, &ir.icur);
+       cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
+       error = xfs_btree_visit_blocks(cur, xfs_iread_bmbt_block,
+                       XFS_BTREE_VISIT_RECORDS, &ir);
+       xfs_btree_del_cursor(cur, error);
+       if (error)
+               goto out;
 
-       if (i != XFS_IFORK_NEXTENTS(ip, whichfork)) {
+       if (ir.loaded != XFS_IFORK_NEXTENTS(ip, whichfork)) {
+               XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp);
                error = -EFSCORRUPTED;
                goto out;
        }
-       ASSERT(i == xfs_iext_count(ifp));
+       ASSERT(ir.loaded == xfs_iext_count(ifp));
 
        ifp->if_flags |= XFS_IFEXTENTS;
        return 0;
-
-out_brelse:
-       xfs_trans_brelse(tp, bp);
 out:
        xfs_iext_destroy(ifp);
        return error;
index 71de937f9e64d2cef3bc0591bb33a884a9f08cf0..4fd89c80c821a3d44a528620ac92b838efcc61fb 100644 (file)
@@ -4286,6 +4286,7 @@ int
 xfs_btree_visit_blocks(
        struct xfs_btree_cur            *cur,
        xfs_btree_visit_blocks_fn       fn,
+       unsigned int                    flags,
        void                            *data)
 {
        union xfs_btree_ptr             lptr;
@@ -4311,6 +4312,11 @@ xfs_btree_visit_blocks(
 
                        /* save for the next iteration of the loop */
                        xfs_btree_copy_ptrs(cur, &lptr, ptr, 1);
+
+                       if (!(flags & XFS_BTREE_VISIT_LEAVES))
+                               continue;
+               } else if (!(flags & XFS_BTREE_VISIT_RECORDS)) {
+                       continue;
                }
 
                /* for each buffer in the level */
@@ -4413,7 +4419,7 @@ xfs_btree_change_owner(
        bbcoi.buffer_list = buffer_list;
 
        return xfs_btree_visit_blocks(cur, xfs_btree_block_change_owner,
-                       &bbcoi);
+                       XFS_BTREE_VISIT_ALL, &bbcoi);
 }
 
 /* Verify the v5 fields of a long-format btree block. */
@@ -4865,7 +4871,7 @@ xfs_btree_count_blocks(
 {
        *blocks = 0;
        return xfs_btree_visit_blocks(cur, xfs_btree_count_blocks_helper,
-                       blocks);
+                       XFS_BTREE_VISIT_ALL, blocks);
 }
 
 /* Compare two btree pointers. */
index b4e3ec1d7ff95231d8022081805fa42cd7adfe0c..6670120cd6901cfade4b2d79f6982f917d8cc016 100644 (file)
@@ -485,8 +485,15 @@ int xfs_btree_query_all(struct xfs_btree_cur *cur, xfs_btree_query_range_fn fn,
 
 typedef int (*xfs_btree_visit_blocks_fn)(struct xfs_btree_cur *cur, int level,
                void *data);
+/* Visit record blocks. */
+#define XFS_BTREE_VISIT_RECORDS                (1 << 0)
+/* Visit leaf blocks. */
+#define XFS_BTREE_VISIT_LEAVES         (1 << 1)
+/* Visit all blocks. */
+#define XFS_BTREE_VISIT_ALL            (XFS_BTREE_VISIT_RECORDS | \
+                                        XFS_BTREE_VISIT_LEAVES)
 int xfs_btree_visit_blocks(struct xfs_btree_cur *cur,
-               xfs_btree_visit_blocks_fn fn, void *data);
+               xfs_btree_visit_blocks_fn fn, unsigned int flags, void *data);
 
 int xfs_btree_count_blocks(struct xfs_btree_cur *cur, xfs_extlen_t *blocks);
 
index 3d47d111be5ae9413ee28e5f1e1e8da0852b7bb0..18a684e18a6926a6343f7b7122f63128d1ac170d 100644 (file)
@@ -294,5 +294,6 @@ xfs_bitmap_set_btblocks(
        struct xfs_bitmap       *bitmap,
        struct xfs_btree_cur    *cur)
 {
-       return xfs_btree_visit_blocks(cur, xfs_bitmap_collect_btblock, bitmap);
+       return xfs_btree_visit_blocks(cur, xfs_bitmap_collect_btblock,
+                       XFS_BTREE_VISIT_ALL, bitmap);
 }