xfs: refactor the ifork block counting function
authorDarrick J. Wong <darrick.wong@oracle.com>
Fri, 16 Jun 2017 18:00:12 +0000 (11:00 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Tue, 20 Jun 2017 17:45:21 +0000 (10:45 -0700)
Refactor the inode fork block counting function to count extents for us
at the same time.  This will be used by the bmbt scrubber function.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
fs/xfs/xfs_bmap_util.c
fs/xfs/xfs_bmap_util.h

index 424e3bd127004ad6cab8c26c72d9eb285aa5e488..93e955262d07e1467cba2013c90013f9e452ddf9 100644 (file)
@@ -225,7 +225,8 @@ xfs_bmap_eof(
 STATIC void
 xfs_bmap_count_leaves(
        struct xfs_ifork        *ifp,
-       int                     *count)
+       xfs_extnum_t            *numrecs,
+       xfs_filblks_t           *count)
 {
        xfs_extnum_t            i;
        xfs_extnum_t            nr_exts = xfs_iext_count(ifp);
@@ -233,6 +234,7 @@ xfs_bmap_count_leaves(
        for (i = 0; i < nr_exts; i++) {
                xfs_bmbt_rec_host_t *frp = xfs_iext_get_ext(ifp, i);
                if (!isnullstartblock(xfs_bmbt_get_startblock(frp))) {
+                       (*numrecs)++;
                        *count += xfs_bmbt_get_blockcount(frp);
                }
        }
@@ -247,7 +249,7 @@ xfs_bmap_disk_count_leaves(
        struct xfs_mount        *mp,
        struct xfs_btree_block  *block,
        int                     numrecs,
-       int                     *count)
+       xfs_filblks_t           *count)
 {
        int             b;
        xfs_bmbt_rec_t  *frp;
@@ -262,17 +264,18 @@ xfs_bmap_disk_count_leaves(
  * Recursively walks each level of a btree
  * to count total fsblocks in use.
  */
-STATIC int                                     /* error */
+STATIC int
 xfs_bmap_count_tree(
-       xfs_mount_t     *mp,            /* file system mount point */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       xfs_fsblock_t   blockno,        /* file system block number */
-       int             levelin,        /* level in btree */
-       int             *count)         /* Count of blocks */
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       struct xfs_ifork        *ifp,
+       xfs_fsblock_t           blockno,
+       int                     levelin,
+       xfs_extnum_t            *nextents,
+       xfs_filblks_t           *count)
 {
        int                     error;
-       xfs_buf_t               *bp, *nbp;
+       struct xfs_buf          *bp, *nbp;
        int                     level = levelin;
        __be64                  *pp;
        xfs_fsblock_t           bno = blockno;
@@ -305,8 +308,9 @@ xfs_bmap_count_tree(
                /* Dive to the next level */
                pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
                bno = be64_to_cpu(*pp);
-               if (unlikely((error =
-                    xfs_bmap_count_tree(mp, tp, ifp, bno, level, count)) < 0)) {
+               error = xfs_bmap_count_tree(mp, tp, ifp, bno, level, nextents,
+                               count);
+               if (error) {
                        xfs_trans_brelse(tp, bp);
                        XFS_ERROR_REPORT("xfs_bmap_count_tree(1)",
                                         XFS_ERRLEVEL_LOW, mp);
@@ -318,6 +322,7 @@ xfs_bmap_count_tree(
                for (;;) {
                        nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
                        numrecs = be16_to_cpu(block->bb_numrecs);
+                       (*nextents) += numrecs;
                        xfs_bmap_disk_count_leaves(mp, block, numrecs, count);
                        xfs_trans_brelse(tp, bp);
                        if (nextbno == NULLFSBLOCK)
@@ -339,44 +344,61 @@ xfs_bmap_count_tree(
  * Count fsblocks of the given fork.  Delayed allocation extents are
  * not counted towards the totals.
  */
-static int                                     /* error */
+int
 xfs_bmap_count_blocks(
-       xfs_trans_t             *tp,            /* transaction pointer */
-       xfs_inode_t             *ip,            /* incore inode */
-       int                     whichfork,      /* data or attr fork */
-       int                     *count)         /* out: count of blocks */
+       struct xfs_trans        *tp,
+       struct xfs_inode        *ip,
+       int                     whichfork,
+       xfs_extnum_t            *nextents,
+       xfs_filblks_t           *count)
 {
+       struct xfs_mount        *mp;    /* file system mount structure */
+       __be64                  *pp;    /* pointer to block address */
        struct xfs_btree_block  *block; /* current btree block */
+       struct xfs_ifork        *ifp;   /* fork structure */
        xfs_fsblock_t           bno;    /* block # of "block" */
-       xfs_ifork_t             *ifp;   /* fork structure */
        int                     level;  /* btree level, for checking */
-       xfs_mount_t             *mp;    /* file system mount structure */
-       __be64                  *pp;    /* pointer to block address */
+       int                     error;
 
        bno = NULLFSBLOCK;
        mp = ip->i_mount;
+       *nextents = 0;
+       *count = 0;
        ifp = XFS_IFORK_PTR(ip, whichfork);
-       if ( XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS ) {
-               xfs_bmap_count_leaves(ifp, count);
+       if (!ifp)
                return 0;
-       }
 
-       /*
-        * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out.
-        */
-       block = ifp->if_broot;
-       level = be16_to_cpu(block->bb_level);
-       ASSERT(level > 0);
-       pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);
-       bno = be64_to_cpu(*pp);
-       ASSERT(bno != NULLFSBLOCK);
-       ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount);
-       ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks);
-
-       if (unlikely(xfs_bmap_count_tree(mp, tp, ifp, bno, level, count) < 0)) {
-               XFS_ERROR_REPORT("xfs_bmap_count_blocks(2)", XFS_ERRLEVEL_LOW,
-                                mp);
-               return -EFSCORRUPTED;
+       switch (XFS_IFORK_FORMAT(ip, whichfork)) {
+       case XFS_DINODE_FMT_EXTENTS:
+               xfs_bmap_count_leaves(ifp, nextents, count);
+               return 0;
+       case XFS_DINODE_FMT_BTREE:
+               if (!(ifp->if_flags & XFS_IFEXTENTS)) {
+                       error = xfs_iread_extents(tp, ip, whichfork);
+                       if (error)
+                               return error;
+               }
+
+               /*
+                * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out.
+                */
+               block = ifp->if_broot;
+               level = be16_to_cpu(block->bb_level);
+               ASSERT(level > 0);
+               pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);
+               bno = be64_to_cpu(*pp);
+               ASSERT(bno != NULLFSBLOCK);
+               ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount);
+               ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks);
+
+               error = xfs_bmap_count_tree(mp, tp, ifp, bno, level,
+                               nextents, count);
+               if (error) {
+                       XFS_ERROR_REPORT("xfs_bmap_count_blocks(2)",
+                                       XFS_ERRLEVEL_LOW, mp);
+                       return -EFSCORRUPTED;
+               }
+               return 0;
        }
 
        return 0;
@@ -1792,8 +1814,9 @@ xfs_swap_extent_forks(
        int                     *target_log_flags)
 {
        struct xfs_ifork        tempifp, *ifp, *tifp;
-       int                     aforkblks = 0;
-       int                     taforkblks = 0;
+       xfs_filblks_t           aforkblks = 0;
+       xfs_filblks_t           taforkblks = 0;
+       xfs_extnum_t            junk;
        xfs_extnum_t            nextents;
        uint64_t                tmp;
        int                     error;
@@ -1803,14 +1826,14 @@ xfs_swap_extent_forks(
         */
        if ( ((XFS_IFORK_Q(ip) != 0) && (ip->i_d.di_anextents > 0)) &&
             (ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) {
-               error = xfs_bmap_count_blocks(tp, ip, XFS_ATTR_FORK,
+               error = xfs_bmap_count_blocks(tp, ip, XFS_ATTR_FORK, &junk,
                                &aforkblks);
                if (error)
                        return error;
        }
        if ( ((XFS_IFORK_Q(tip) != 0) && (tip->i_d.di_anextents > 0)) &&
             (tip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) {
-               error = xfs_bmap_count_blocks(tp, tip, XFS_ATTR_FORK,
+               error = xfs_bmap_count_blocks(tp, tip, XFS_ATTR_FORK, &junk,
                                &taforkblks);
                if (error)
                        return error;
index 135d8267e2846b2552f6ae426cac1a8c41877f74..0cede104357170425e1864d63cc934596977a166 100644 (file)
@@ -70,4 +70,8 @@ int   xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip,
 
 xfs_daddr_t xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb);
 
+int xfs_bmap_count_blocks(struct xfs_trans *tp, struct xfs_inode *ip,
+                         int whichfork, xfs_extnum_t *nextents,
+                         xfs_filblks_t *count);
+
 #endif /* __XFS_BMAP_UTIL_H__ */