xfs: refactor dir format helpers
authorChristoph Hellwig <hch@lst.de>
Thu, 25 Apr 2024 13:17:03 +0000 (15:17 +0200)
committerChandan Babu R <chandanbabu@kernel.org>
Fri, 26 Apr 2024 05:51:46 +0000 (11:21 +0530)
Add a new enum and a xfs_dir2_format helper that returns it to allow
the code to switch on the format of a directory in a single operation
and switch all helpers of xfs_dir2_isblock and xfs_dir2_isleaf to it.

This also removes the explicit xfs_iread_extents call in a few of the
call sites given that xfs_bmap_last_offset already takes care of it
underneath.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>
Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>
fs/xfs/libxfs/xfs_dir2.c
fs/xfs/libxfs/xfs_dir2.h
fs/xfs/libxfs/xfs_exchmaps.c
fs/xfs/scrub/dir.c
fs/xfs/scrub/readdir.c
fs/xfs/xfs_dir2_readdir.c

index d3d4d80c2098d38be3705156ac6e98da9c561acf..457f9a38f850456be9817ecf6fc693808807c6aa 100644 (file)
@@ -256,31 +256,60 @@ xfs_dir_init(
        return error;
 }
 
+enum xfs_dir2_fmt
+xfs_dir2_format(
+       struct xfs_da_args      *args,
+       int                     *error)
+{
+       struct xfs_inode        *dp = args->dp;
+       struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_da_geometry  *geo = mp->m_dir_geo;
+       xfs_fileoff_t           eof;
+
+       xfs_assert_ilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL);
+
+       *error = 0;
+       if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL)
+               return XFS_DIR2_FMT_SF;
+
+       *error = xfs_bmap_last_offset(dp, &eof, XFS_DATA_FORK);
+       if (*error)
+               return XFS_DIR2_FMT_ERROR;
+
+       if (eof == XFS_B_TO_FSB(mp, geo->blksize)) {
+               if (XFS_IS_CORRUPT(mp, dp->i_disk_size != geo->blksize)) {
+                       xfs_da_mark_sick(args);
+                       *error = -EFSCORRUPTED;
+                       return XFS_DIR2_FMT_ERROR;
+               }
+               return XFS_DIR2_FMT_BLOCK;
+       }
+       if (eof == geo->leafblk + geo->fsbcount)
+               return XFS_DIR2_FMT_LEAF;
+       return XFS_DIR2_FMT_NODE;
+}
+
 int
 xfs_dir_createname_args(
        struct xfs_da_args      *args)
 {
-       bool                    is_block, is_leaf;
        int                     error;
 
        if (!args->inumber)
                args->op_flags |= XFS_DA_OP_JUSTCHECK;
 
-       if (args->dp->i_df.if_format == XFS_DINODE_FMT_LOCAL)
+       switch (xfs_dir2_format(args, &error)) {
+       case XFS_DIR2_FMT_SF:
                return xfs_dir2_sf_addname(args);
-
-       error = xfs_dir2_isblock(args, &is_block);
-       if (error)
-               return error;
-       if (is_block)
+       case XFS_DIR2_FMT_BLOCK:
                return xfs_dir2_block_addname(args);
-
-       error = xfs_dir2_isleaf(args, &is_leaf);
-       if (error)
-               return error;
-       if (is_leaf)
+       case XFS_DIR2_FMT_LEAF:
                return xfs_dir2_leaf_addname(args);
-       return xfs_dir2_node_addname(args);
+       case XFS_DIR2_FMT_NODE:
+               return xfs_dir2_node_addname(args);
+       default:
+               return error;
+       }
 }
 
 /*
@@ -359,36 +388,25 @@ int
 xfs_dir_lookup_args(
        struct xfs_da_args      *args)
 {
-       bool                    is_block, is_leaf;
        int                     error;
 
-       if (args->dp->i_df.if_format == XFS_DINODE_FMT_LOCAL) {
+       switch (xfs_dir2_format(args, &error)) {
+       case XFS_DIR2_FMT_SF:
                error = xfs_dir2_sf_lookup(args);
-               goto out;
-       }
-
-       /* dir2 functions require that the data fork is loaded */
-       error = xfs_iread_extents(args->trans, args->dp, XFS_DATA_FORK);
-       if (error)
-               goto out;
-
-       error = xfs_dir2_isblock(args, &is_block);
-       if (error)
-               goto out;
-
-       if (is_block) {
+               break;
+       case XFS_DIR2_FMT_BLOCK:
                error = xfs_dir2_block_lookup(args);
-               goto out;
-       }
-
-       error = xfs_dir2_isleaf(args, &is_leaf);
-       if (error)
-               goto out;
-       if (is_leaf)
+               break;
+       case XFS_DIR2_FMT_LEAF:
                error = xfs_dir2_leaf_lookup(args);
-       else
+               break;
+       case XFS_DIR2_FMT_NODE:
                error = xfs_dir2_node_lookup(args);
-out:
+               break;
+       default:
+               break;
+       }
+
        if (error != -EEXIST)
                return error;
        return 0;
@@ -448,24 +466,20 @@ int
 xfs_dir_removename_args(
        struct xfs_da_args      *args)
 {
-       bool                    is_block, is_leaf;
        int                     error;
 
-       if (args->dp->i_df.if_format == XFS_DINODE_FMT_LOCAL)
+       switch (xfs_dir2_format(args, &error)) {
+       case XFS_DIR2_FMT_SF:
                return xfs_dir2_sf_removename(args);
-
-       error = xfs_dir2_isblock(args, &is_block);
-       if (error)
-               return error;
-       if (is_block)
+       case XFS_DIR2_FMT_BLOCK:
                return xfs_dir2_block_removename(args);
-
-       error = xfs_dir2_isleaf(args, &is_leaf);
-       if (error)
-               return error;
-       if (is_leaf)
+       case XFS_DIR2_FMT_LEAF:
                return xfs_dir2_leaf_removename(args);
-       return xfs_dir2_node_removename(args);
+       case XFS_DIR2_FMT_NODE:
+               return xfs_dir2_node_removename(args);
+       default:
+               return error;
+       }
 }
 
 /*
@@ -509,25 +523,20 @@ int
 xfs_dir_replace_args(
        struct xfs_da_args      *args)
 {
-       bool                    is_block, is_leaf;
        int                     error;
 
-       if (args->dp->i_df.if_format == XFS_DINODE_FMT_LOCAL)
+       switch (xfs_dir2_format(args, &error)) {
+       case XFS_DIR2_FMT_SF:
                return xfs_dir2_sf_replace(args);
-
-       error = xfs_dir2_isblock(args, &is_block);
-       if (error)
-               return error;
-       if (is_block)
+       case XFS_DIR2_FMT_BLOCK:
                return xfs_dir2_block_replace(args);
-
-       error = xfs_dir2_isleaf(args, &is_leaf);
-       if (error)
-               return error;
-       if (is_leaf)
+       case XFS_DIR2_FMT_LEAF:
                return xfs_dir2_leaf_replace(args);
-
-       return xfs_dir2_node_replace(args);
+       case XFS_DIR2_FMT_NODE:
+               return xfs_dir2_node_replace(args);
+       default:
+               return error;
+       }
 }
 
 /*
@@ -633,57 +642,6 @@ xfs_dir2_grow_inode(
        return 0;
 }
 
-/*
- * See if the directory is a single-block form directory.
- */
-int
-xfs_dir2_isblock(
-       struct xfs_da_args      *args,
-       bool                    *isblock)
-{
-       struct xfs_mount        *mp = args->dp->i_mount;
-       xfs_fileoff_t           eof;
-       int                     error;
-
-       error = xfs_bmap_last_offset(args->dp, &eof, XFS_DATA_FORK);
-       if (error)
-               return error;
-
-       *isblock = false;
-       if (XFS_FSB_TO_B(mp, eof) != args->geo->blksize)
-               return 0;
-
-       *isblock = true;
-       if (XFS_IS_CORRUPT(mp, args->dp->i_disk_size != args->geo->blksize)) {
-               xfs_da_mark_sick(args);
-               return -EFSCORRUPTED;
-       }
-       return 0;
-}
-
-/*
- * See if the directory is a single-leaf form directory.
- */
-int
-xfs_dir2_isleaf(
-       struct xfs_da_args      *args,
-       bool                    *isleaf)
-{
-       xfs_fileoff_t           eof;
-       int                     error;
-
-       error = xfs_bmap_last_offset(args->dp, &eof, XFS_DATA_FORK);
-       if (error)
-               return error;
-
-       *isleaf = false;
-       if (eof != args->geo->leafblk + args->geo->fsbcount)
-               return 0;
-
-       *isleaf = true;
-       return 0;
-}
-
 /*
  * Remove the given block from the directory.
  * This routine is used for data and free blocks, leaf/node are done
index 6c00fe24a8987ec160e46522ed05c3b50066d159..6dbe6e9ecb491f69e87e2b8ba2dc54a73f59355a 100644 (file)
@@ -36,6 +36,16 @@ xfs_dir2_samename(
        return !memcmp(n1->name, n2->name, n1->len);
 }
 
+enum xfs_dir2_fmt {
+       XFS_DIR2_FMT_SF,
+       XFS_DIR2_FMT_BLOCK,
+       XFS_DIR2_FMT_LEAF,
+       XFS_DIR2_FMT_NODE,
+       XFS_DIR2_FMT_ERROR,
+};
+
+enum xfs_dir2_fmt xfs_dir2_format(struct xfs_da_args *args, int *error);
+
 /*
  * Convert inode mode to directory entry filetype
  */
@@ -79,8 +89,6 @@ extern int xfs_dir2_sf_to_block(struct xfs_da_args *args);
 /*
  * Interface routines used by userspace utilities
  */
-extern int xfs_dir2_isblock(struct xfs_da_args *args, bool *isblock);
-extern int xfs_dir2_isleaf(struct xfs_da_args *args, bool *isleaf);
 extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db,
                                struct xfs_buf *bp);
 
index 44ab6a9235c0bdc2b17bb11c9a9452f102c084b4..2021396651de272820aaf3b2408506b751552b3d 100644 (file)
@@ -465,17 +465,12 @@ xfs_exchmaps_dir_to_sf(
        };
        struct xfs_dir2_sf_hdr  sfh;
        struct xfs_buf          *bp;
-       bool                    isblock;
        int                     size;
-       int                     error;
+       int                     error = 0;
 
-       error = xfs_dir2_isblock(&args, &isblock);
-       if (error)
+       if (xfs_dir2_format(&args, &error) != XFS_DIR2_FMT_BLOCK)
                return error;
 
-       if (!isblock)
-               return 0;
-
        error = xfs_dir3_block_read(tp, xmi->xmi_ip2, xmi->xmi_ip2->i_ino, &bp);
        if (error)
                return error;
index 62474d0557c41a970b3a8db14810895b0e7217d9..bf9199e8df633fa891d5ec160381491eefb31927 100644 (file)
@@ -808,7 +808,8 @@ xchk_directory_blocks(
        free_lblk = XFS_B_TO_FSB(mp, XFS_DIR2_FREE_OFFSET);
 
        /* Is this a block dir? */
-       error = xfs_dir2_isblock(&args, &is_block);
+       if (xfs_dir2_format(&args, &error) == XFS_DIR2_FMT_BLOCK)
+               is_block = true;
        if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
                goto out;
 
index 0ac77359d8e9f8f06a9f7b12d5731ab9522abb07..01c9a2dc0f2c48357b9a53f4cdb8442d6f284ff9 100644 (file)
@@ -276,7 +276,6 @@ xchk_dir_walk(
                .trans          = sc->tp,
                .owner          = dp->i_ino,
        };
-       bool                    isblock;
        int                     error;
 
        if (xfs_is_shutdown(dp->i_mount))
@@ -285,22 +284,17 @@ xchk_dir_walk(
        ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
        xfs_assert_ilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL);
 
-       if (dp->i_df.if_format == XFS_DINODE_FMT_LOCAL)
+       switch (xfs_dir2_format(&args, &error)) {
+       case XFS_DIR2_FMT_SF:
                return xchk_dir_walk_sf(sc, dp, dirent_fn, priv);
-
-       /* dir2 functions require that the data fork is loaded */
-       error = xfs_iread_extents(sc->tp, dp, XFS_DATA_FORK);
-       if (error)
-               return error;
-
-       error = xfs_dir2_isblock(&args, &isblock);
-       if (error)
-               return error;
-
-       if (isblock)
+       case XFS_DIR2_FMT_BLOCK:
                return xchk_dir_walk_block(sc, dp, dirent_fn, priv);
-
-       return xchk_dir_walk_leaf(sc, dp, dirent_fn, priv);
+       case XFS_DIR2_FMT_LEAF:
+       case XFS_DIR2_FMT_NODE:
+               return xchk_dir_walk_leaf(sc, dp, dirent_fn, priv);
+       default:
+               return error;
+       }
 }
 
 /*
index b3abad5a6cd800f9003b3908fbd0068500a0ac9b..06ac5a7de60a0497950801a66de31d2f059fb341 100644 (file)
@@ -516,7 +516,6 @@ xfs_readdir(
 {
        struct xfs_da_args      args = { NULL };
        unsigned int            lock_mode;
-       bool                    isblock;
        int                     error;
 
        trace_xfs_readdir(dp);
@@ -539,18 +538,18 @@ xfs_readdir(
                return xfs_dir2_sf_getdents(&args, ctx);
 
        lock_mode = xfs_ilock_data_map_shared(dp);
-       error = xfs_dir2_isblock(&args, &isblock);
-       if (error)
-               goto out_unlock;
-
-       if (isblock) {
+       switch (xfs_dir2_format(&args, &error)) {
+       case XFS_DIR2_FMT_BLOCK:
                error = xfs_dir2_block_getdents(&args, ctx, &lock_mode);
-               goto out_unlock;
+               break;
+       case XFS_DIR2_FMT_LEAF:
+       case XFS_DIR2_FMT_NODE:
+               error = xfs_dir2_leaf_getdents(&args, ctx, bufsize, &lock_mode);
+               break;
+       default:
+               break;
        }
 
-       error = xfs_dir2_leaf_getdents(&args, ctx, bufsize, &lock_mode);
-
-out_unlock:
        if (lock_mode)
                xfs_iunlock(dp, lock_mode);
        return error;