summaryrefslogtreecommitdiff
path: root/fs/xfs/libxfs/xfs_attr.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2022-05-12 15:12:52 +1000
committerDave Chinner <david@fromorbit.com>2022-05-12 15:12:52 +1000
commite0c41089b998f5a54dabd7a34ab24108e192d2ee (patch)
treebd2cccf8615f708c0df25c69b77171a7cd7becc7 /fs/xfs/libxfs/xfs_attr.c
parent709c8632597c3276cd21324b0256628f1a7fd4df (diff)
xfs: separate out initial attr_set states
We current use XFS_DAS_UNINIT for several steps in the attr_set state machine. We use it for setting shortform xattrs, converting from shortform to leaf, leaf add, leaf-to-node and leaf add. All of these things are essentially known before we start the state machine iterating, so we really should separate them out: XFS_DAS_SF_ADD: - tries to do a shortform add - on success -> done - on ENOSPC converts to leaf, -> XFS_DAS_LEAF_ADD - on error, dies. XFS_DAS_LEAF_ADD: - tries to do leaf add - on success: - inline attr -> done - remote xattr || REPLACE -> XFS_DAS_FOUND_LBLK - on ENOSPC converts to node, -> XFS_DAS_NODE_ADD - on error, dies XFS_DAS_NODE_ADD: - tries to do node add - on success: - inline attr -> done - remote xattr || REPLACE -> XFS_DAS_FOUND_NBLK - on error, dies This makes it easier to understand how the state machine starts up and sets us up on the path to further state machine simplifications. This also converts the DAS state tracepoints to use strings rather than numbers, as converting between enums and numbers requires manual counting rather than just reading the name. This also introduces a XFS_DAS_DONE state so that we can trace successful operation completions easily. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Allison Henderson<allison.henderson@oracle.com> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs/libxfs/xfs_attr.c')
-rw-r--r--fs/xfs/libxfs/xfs_attr.c161
1 files changed, 79 insertions, 82 deletions
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 54f90d66b206..7c11fe8b7b26 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -58,7 +58,7 @@ STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args, struct xfs_buf *bp);
*/
STATIC int xfs_attr_node_get(xfs_da_args_t *args);
STATIC void xfs_attr_restore_rmt_blk(struct xfs_da_args *args);
-STATIC int xfs_attr_node_addname(struct xfs_attr_item *attr);
+static int xfs_attr_node_try_addname(struct xfs_attr_item *attr);
STATIC int xfs_attr_node_addname_find_attr(struct xfs_attr_item *attr);
STATIC int xfs_attr_node_addname_clear_incomplete(struct xfs_attr_item *attr);
STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
@@ -223,6 +223,11 @@ xfs_init_attr_trans(
}
}
+/*
+ * Add an attr to a shortform fork. If there is no space,
+ * xfs_attr_shortform_addname() will convert to leaf format and return -ENOSPC.
+ * to use.
+ */
STATIC int
xfs_attr_try_sf_addname(
struct xfs_inode *dp,
@@ -254,20 +259,7 @@ xfs_attr_try_sf_addname(
return error;
}
-/*
- * Check to see if the attr should be upgraded from non-existent or shortform to
- * single-leaf-block attribute list.
- */
-static inline bool
-xfs_attr_is_shortform(
- struct xfs_inode *ip)
-{
- return ip->i_afp->if_format == XFS_DINODE_FMT_LOCAL ||
- (ip->i_afp->if_format == XFS_DINODE_FMT_EXTENTS &&
- ip->i_afp->if_nextents == 0);
-}
-
-STATIC int
+static int
xfs_attr_sf_addname(
struct xfs_attr_item *attr)
{
@@ -275,14 +267,12 @@ xfs_attr_sf_addname(
struct xfs_inode *dp = args->dp;
int error = 0;
- /*
- * Try to add the attr to the attribute list in the inode.
- */
error = xfs_attr_try_sf_addname(dp, args);
-
- /* Should only be 0, -EEXIST or -ENOSPC */
- if (error != -ENOSPC)
- return error;
+ if (error != -ENOSPC) {
+ ASSERT(!error || error == -EEXIST);
+ attr->xattri_dela_state = XFS_DAS_DONE;
+ goto out;
+ }
/*
* It won't fit in the shortform, transform to a leaf block. GROT:
@@ -298,64 +288,42 @@ xfs_attr_sf_addname(
* with the write verifier.
*/
xfs_trans_bhold(args->trans, attr->xattri_leaf_bp);
-
- /*
- * We're still in XFS_DAS_UNINIT state here. We've converted
- * the attr fork to leaf format and will restart with the leaf
- * add.
- */
- trace_xfs_attr_sf_addname_return(XFS_DAS_UNINIT, args->dp);
- return -EAGAIN;
+ attr->xattri_dela_state = XFS_DAS_LEAF_ADD;
+ error = -EAGAIN;
+out:
+ trace_xfs_attr_sf_addname_return(attr->xattri_dela_state, args->dp);
+ return error;
}
-STATIC int
+static int
xfs_attr_leaf_addname(
struct xfs_attr_item *attr)
{
struct xfs_da_args *args = attr->xattri_da_args;
- struct xfs_inode *dp = args->dp;
- enum xfs_delattr_state next_state = XFS_DAS_UNINIT;
int error;
- if (xfs_attr_is_leaf(dp)) {
-
- /*
- * Use the leaf buffer we may already hold locked as a result of
- * a sf-to-leaf conversion. The held buffer is no longer valid
- * after this call, regardless of the result.
- */
- error = xfs_attr_leaf_try_add(args, attr->xattri_leaf_bp);
- attr->xattri_leaf_bp = NULL;
+ ASSERT(xfs_attr_is_leaf(args->dp));
- if (error == -ENOSPC) {
- error = xfs_attr3_leaf_to_node(args);
- if (error)
- return error;
-
- /*
- * Finish any deferred work items and roll the
- * transaction once more. The goal here is to call
- * node_addname with the inode and transaction in the
- * same state (inode locked and joined, transaction
- * clean) no matter how we got to this step.
- *
- * At this point, we are still in XFS_DAS_UNINIT, but
- * when we come back, we'll be a node, so we'll fall
- * down into the node handling code below
- */
- error = -EAGAIN;
- goto out;
- }
- next_state = XFS_DAS_FOUND_LBLK;
- } else {
- ASSERT(!attr->xattri_leaf_bp);
+ /*
+ * Use the leaf buffer we may already hold locked as a result of
+ * a sf-to-leaf conversion. The held buffer is no longer valid
+ * after this call, regardless of the result.
+ */
+ error = xfs_attr_leaf_try_add(args, attr->xattri_leaf_bp);
+ attr->xattri_leaf_bp = NULL;
- error = xfs_attr_node_addname_find_attr(attr);
+ if (error == -ENOSPC) {
+ error = xfs_attr3_leaf_to_node(args);
if (error)
return error;
- next_state = XFS_DAS_FOUND_NBLK;
- error = xfs_attr_node_addname(attr);
+ /*
+ * We're not in leaf format anymore, so roll the transaction and
+ * retry the add to the newly allocated node block.
+ */
+ attr->xattri_dela_state = XFS_DAS_NODE_ADD;
+ error = -EAGAIN;
+ goto out;
}
if (error)
return error;
@@ -367,15 +335,46 @@ xfs_attr_leaf_addname(
*/
if (args->rmtblkno ||
(args->op_flags & XFS_DA_OP_RENAME)) {
- attr->xattri_dela_state = next_state;
+ attr->xattri_dela_state = XFS_DAS_FOUND_LBLK;
error = -EAGAIN;
+ } else {
+ attr->xattri_dela_state = XFS_DAS_DONE;
}
-
out:
trace_xfs_attr_leaf_addname_return(attr->xattri_dela_state, args->dp);
return error;
}
+static int
+xfs_attr_node_addname(
+ struct xfs_attr_item *attr)
+{
+ struct xfs_da_args *args = attr->xattri_da_args;
+ int error;
+
+ ASSERT(!attr->xattri_leaf_bp);
+
+ error = xfs_attr_node_addname_find_attr(attr);
+ if (error)
+ return error;
+
+ error = xfs_attr_node_try_addname(attr);
+ if (error)
+ return error;
+
+ if (args->rmtblkno ||
+ (args->op_flags & XFS_DA_OP_RENAME)) {
+ attr->xattri_dela_state = XFS_DAS_FOUND_NBLK;
+ error = -EAGAIN;
+ } else {
+ attr->xattri_dela_state = XFS_DAS_DONE;
+ }
+
+ trace_xfs_attr_node_addname_return(attr->xattri_dela_state, args->dp);
+ return error;
+}
+
+
/*
* Set the attribute specified in @args.
* This routine is meant to function as a delayed operation, and may return
@@ -396,16 +395,14 @@ xfs_attr_set_iter(
/* State machine switch */
switch (attr->xattri_dela_state) {
case XFS_DAS_UNINIT:
- /*
- * If the fork is shortform, attempt to add the attr. If there
- * is no space, this converts to leaf format and returns
- * -EAGAIN with the leaf buffer held across the roll. The caller
- * will deal with a transaction roll error, but otherwise
- * release the hold once we return with a clean transaction.
- */
- if (xfs_attr_is_shortform(dp))
- return xfs_attr_sf_addname(attr);
+ ASSERT(0);
+ return -EFSCORRUPTED;
+ case XFS_DAS_SF_ADD:
+ return xfs_attr_sf_addname(attr);
+ case XFS_DAS_LEAF_ADD:
return xfs_attr_leaf_addname(attr);
+ case XFS_DAS_NODE_ADD:
+ return xfs_attr_node_addname(attr);
case XFS_DAS_FOUND_LBLK:
/*
@@ -699,7 +696,7 @@ xfs_attr_defer_add(
if (error)
return error;
- new->xattri_dela_state = XFS_DAS_UNINIT;
+ new->xattri_dela_state = xfs_attr_init_add_state(args);
xfs_defer_add(args->trans, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
trace_xfs_attr_defer_add(new->xattri_dela_state, args->dp);
@@ -718,7 +715,7 @@ xfs_attr_defer_replace(
if (error)
return error;
- new->xattri_dela_state = XFS_DAS_UNINIT;
+ new->xattri_dela_state = xfs_attr_init_replace_state(args);
xfs_defer_add(args->trans, XFS_DEFER_OPS_TYPE_ATTR, &new->xattri_list);
trace_xfs_attr_defer_replace(new->xattri_dela_state, args->dp);
@@ -1261,8 +1258,8 @@ error:
* to handle this, and recall the function until a successful error code is
*returned.
*/
-STATIC int
-xfs_attr_node_addname(
+static int
+xfs_attr_node_try_addname(
struct xfs_attr_item *attr)
{
struct xfs_da_args *args = attr->xattri_da_args;