summaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2024-04-25 15:17:03 +0200
committerChandan Babu R <chandanbabu@kernel.org>2024-04-26 07:51:46 +0200
commite58ac1770ded2a316447ca7608bb7809af82eca6 (patch)
tree872ed3e02ec6d24782694ff4086f610bfdff87c3 /fs/xfs
parentxfs: factor out a xfs_dir_replace_args helper (diff)
downloadlinux-e58ac1770ded2a316447ca7608bb7809af82eca6.tar.xz
linux-e58ac1770ded2a316447ca7608bb7809af82eca6.zip
xfs: refactor dir format helpers
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>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/libxfs/xfs_dir2.c188
-rw-r--r--fs/xfs/libxfs/xfs_dir2.h12
-rw-r--r--fs/xfs/libxfs/xfs_exchmaps.c9
-rw-r--r--fs/xfs/scrub/dir.c3
-rw-r--r--fs/xfs/scrub/readdir.c24
-rw-r--r--fs/xfs/xfs_dir2_readdir.c19
6 files changed, 105 insertions, 150 deletions
diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
index d3d4d80c2098..457f9a38f850 100644
--- a/fs/xfs/libxfs/xfs_dir2.c
+++ b/fs/xfs/libxfs/xfs_dir2.c
@@ -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;
+ }
}
/*
@@ -634,57 +643,6 @@ xfs_dir2_grow_inode(
}
/*
- * 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
* by xfs_da_shrink_inode.
diff --git a/fs/xfs/libxfs/xfs_dir2.h b/fs/xfs/libxfs/xfs_dir2.h
index 6c00fe24a898..6dbe6e9ecb49 100644
--- a/fs/xfs/libxfs/xfs_dir2.h
+++ b/fs/xfs/libxfs/xfs_dir2.h
@@ -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);
diff --git a/fs/xfs/libxfs/xfs_exchmaps.c b/fs/xfs/libxfs/xfs_exchmaps.c
index 44ab6a9235c0..2021396651de 100644
--- a/fs/xfs/libxfs/xfs_exchmaps.c
+++ b/fs/xfs/libxfs/xfs_exchmaps.c
@@ -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;
diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c
index 62474d0557c4..bf9199e8df63 100644
--- a/fs/xfs/scrub/dir.c
+++ b/fs/xfs/scrub/dir.c
@@ -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;
diff --git a/fs/xfs/scrub/readdir.c b/fs/xfs/scrub/readdir.c
index 0ac77359d8e9..01c9a2dc0f2c 100644
--- a/fs/xfs/scrub/readdir.c
+++ b/fs/xfs/scrub/readdir.c
@@ -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;
+ }
}
/*
diff --git a/fs/xfs/xfs_dir2_readdir.c b/fs/xfs/xfs_dir2_readdir.c
index b3abad5a6cd8..06ac5a7de60a 100644
--- a/fs/xfs/xfs_dir2_readdir.c
+++ b/fs/xfs/xfs_dir2_readdir.c
@@ -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;