mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
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>
This commit is contained in:
parent
dfe5febe2b
commit
e58ac1770d
@ -256,31 +256,60 @@ xfs_dir_init(
|
|||||||
return error;
|
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
|
int
|
||||||
xfs_dir_createname_args(
|
xfs_dir_createname_args(
|
||||||
struct xfs_da_args *args)
|
struct xfs_da_args *args)
|
||||||
{
|
{
|
||||||
bool is_block, is_leaf;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (!args->inumber)
|
if (!args->inumber)
|
||||||
args->op_flags |= XFS_DA_OP_JUSTCHECK;
|
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);
|
return xfs_dir2_sf_addname(args);
|
||||||
|
case XFS_DIR2_FMT_BLOCK:
|
||||||
error = xfs_dir2_isblock(args, &is_block);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
if (is_block)
|
|
||||||
return xfs_dir2_block_addname(args);
|
return xfs_dir2_block_addname(args);
|
||||||
|
case XFS_DIR2_FMT_LEAF:
|
||||||
error = xfs_dir2_isleaf(args, &is_leaf);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
if (is_leaf)
|
|
||||||
return xfs_dir2_leaf_addname(args);
|
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(
|
xfs_dir_lookup_args(
|
||||||
struct xfs_da_args *args)
|
struct xfs_da_args *args)
|
||||||
{
|
{
|
||||||
bool is_block, is_leaf;
|
|
||||||
int error;
|
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);
|
error = xfs_dir2_sf_lookup(args);
|
||||||
goto out;
|
break;
|
||||||
}
|
case XFS_DIR2_FMT_BLOCK:
|
||||||
|
|
||||||
/* 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) {
|
|
||||||
error = xfs_dir2_block_lookup(args);
|
error = xfs_dir2_block_lookup(args);
|
||||||
goto out;
|
break;
|
||||||
|
case XFS_DIR2_FMT_LEAF:
|
||||||
|
error = xfs_dir2_leaf_lookup(args);
|
||||||
|
break;
|
||||||
|
case XFS_DIR2_FMT_NODE:
|
||||||
|
error = xfs_dir2_node_lookup(args);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
error = xfs_dir2_isleaf(args, &is_leaf);
|
|
||||||
if (error)
|
|
||||||
goto out;
|
|
||||||
if (is_leaf)
|
|
||||||
error = xfs_dir2_leaf_lookup(args);
|
|
||||||
else
|
|
||||||
error = xfs_dir2_node_lookup(args);
|
|
||||||
out:
|
|
||||||
if (error != -EEXIST)
|
if (error != -EEXIST)
|
||||||
return error;
|
return error;
|
||||||
return 0;
|
return 0;
|
||||||
@ -448,24 +466,20 @@ int
|
|||||||
xfs_dir_removename_args(
|
xfs_dir_removename_args(
|
||||||
struct xfs_da_args *args)
|
struct xfs_da_args *args)
|
||||||
{
|
{
|
||||||
bool is_block, is_leaf;
|
|
||||||
int error;
|
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);
|
return xfs_dir2_sf_removename(args);
|
||||||
|
case XFS_DIR2_FMT_BLOCK:
|
||||||
error = xfs_dir2_isblock(args, &is_block);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
if (is_block)
|
|
||||||
return xfs_dir2_block_removename(args);
|
return xfs_dir2_block_removename(args);
|
||||||
|
case XFS_DIR2_FMT_LEAF:
|
||||||
error = xfs_dir2_isleaf(args, &is_leaf);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
if (is_leaf)
|
|
||||||
return xfs_dir2_leaf_removename(args);
|
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(
|
xfs_dir_replace_args(
|
||||||
struct xfs_da_args *args)
|
struct xfs_da_args *args)
|
||||||
{
|
{
|
||||||
bool is_block, is_leaf;
|
|
||||||
int error;
|
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);
|
return xfs_dir2_sf_replace(args);
|
||||||
|
case XFS_DIR2_FMT_BLOCK:
|
||||||
error = xfs_dir2_isblock(args, &is_block);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
if (is_block)
|
|
||||||
return xfs_dir2_block_replace(args);
|
return xfs_dir2_block_replace(args);
|
||||||
|
case XFS_DIR2_FMT_LEAF:
|
||||||
error = xfs_dir2_isleaf(args, &is_leaf);
|
|
||||||
if (error)
|
|
||||||
return error;
|
|
||||||
if (is_leaf)
|
|
||||||
return xfs_dir2_leaf_replace(args);
|
return xfs_dir2_leaf_replace(args);
|
||||||
|
case XFS_DIR2_FMT_NODE:
|
||||||
return xfs_dir2_node_replace(args);
|
return xfs_dir2_node_replace(args);
|
||||||
|
default:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -633,57 +642,6 @@ xfs_dir2_grow_inode(
|
|||||||
return 0;
|
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.
|
* Remove the given block from the directory.
|
||||||
* This routine is used for data and free blocks, leaf/node are done
|
* This routine is used for data and free blocks, leaf/node are done
|
||||||
|
@ -36,6 +36,16 @@ xfs_dir2_samename(
|
|||||||
return !memcmp(n1->name, n2->name, n1->len);
|
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
|
* 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
|
* 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,
|
extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db,
|
||||||
struct xfs_buf *bp);
|
struct xfs_buf *bp);
|
||||||
|
|
||||||
|
@ -465,17 +465,12 @@ xfs_exchmaps_dir_to_sf(
|
|||||||
};
|
};
|
||||||
struct xfs_dir2_sf_hdr sfh;
|
struct xfs_dir2_sf_hdr sfh;
|
||||||
struct xfs_buf *bp;
|
struct xfs_buf *bp;
|
||||||
bool isblock;
|
|
||||||
int size;
|
int size;
|
||||||
int error;
|
int error = 0;
|
||||||
|
|
||||||
error = xfs_dir2_isblock(&args, &isblock);
|
if (xfs_dir2_format(&args, &error) != XFS_DIR2_FMT_BLOCK)
|
||||||
if (error)
|
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (!isblock)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error = xfs_dir3_block_read(tp, xmi->xmi_ip2, xmi->xmi_ip2->i_ino, &bp);
|
error = xfs_dir3_block_read(tp, xmi->xmi_ip2, xmi->xmi_ip2->i_ino, &bp);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
@ -808,7 +808,8 @@ xchk_directory_blocks(
|
|||||||
free_lblk = XFS_B_TO_FSB(mp, XFS_DIR2_FREE_OFFSET);
|
free_lblk = XFS_B_TO_FSB(mp, XFS_DIR2_FREE_OFFSET);
|
||||||
|
|
||||||
/* Is this a block dir? */
|
/* 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))
|
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -276,7 +276,6 @@ xchk_dir_walk(
|
|||||||
.trans = sc->tp,
|
.trans = sc->tp,
|
||||||
.owner = dp->i_ino,
|
.owner = dp->i_ino,
|
||||||
};
|
};
|
||||||
bool isblock;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (xfs_is_shutdown(dp->i_mount))
|
if (xfs_is_shutdown(dp->i_mount))
|
||||||
@ -285,22 +284,17 @@ xchk_dir_walk(
|
|||||||
ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
|
ASSERT(S_ISDIR(VFS_I(dp)->i_mode));
|
||||||
xfs_assert_ilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL);
|
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);
|
return xchk_dir_walk_sf(sc, dp, dirent_fn, priv);
|
||||||
|
case XFS_DIR2_FMT_BLOCK:
|
||||||
/* 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)
|
|
||||||
return xchk_dir_walk_block(sc, dp, dirent_fn, priv);
|
return xchk_dir_walk_block(sc, dp, dirent_fn, priv);
|
||||||
|
case XFS_DIR2_FMT_LEAF:
|
||||||
return xchk_dir_walk_leaf(sc, dp, dirent_fn, priv);
|
case XFS_DIR2_FMT_NODE:
|
||||||
|
return xchk_dir_walk_leaf(sc, dp, dirent_fn, priv);
|
||||||
|
default:
|
||||||
|
return error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -516,7 +516,6 @@ xfs_readdir(
|
|||||||
{
|
{
|
||||||
struct xfs_da_args args = { NULL };
|
struct xfs_da_args args = { NULL };
|
||||||
unsigned int lock_mode;
|
unsigned int lock_mode;
|
||||||
bool isblock;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
trace_xfs_readdir(dp);
|
trace_xfs_readdir(dp);
|
||||||
@ -539,18 +538,18 @@ xfs_readdir(
|
|||||||
return xfs_dir2_sf_getdents(&args, ctx);
|
return xfs_dir2_sf_getdents(&args, ctx);
|
||||||
|
|
||||||
lock_mode = xfs_ilock_data_map_shared(dp);
|
lock_mode = xfs_ilock_data_map_shared(dp);
|
||||||
error = xfs_dir2_isblock(&args, &isblock);
|
switch (xfs_dir2_format(&args, &error)) {
|
||||||
if (error)
|
case XFS_DIR2_FMT_BLOCK:
|
||||||
goto out_unlock;
|
|
||||||
|
|
||||||
if (isblock) {
|
|
||||||
error = xfs_dir2_block_getdents(&args, ctx, &lock_mode);
|
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)
|
if (lock_mode)
|
||||||
xfs_iunlock(dp, lock_mode);
|
xfs_iunlock(dp, lock_mode);
|
||||||
return error;
|
return error;
|
||||||
|
Loading…
Reference in New Issue
Block a user