summaryrefslogtreecommitdiff
path: root/fs/xfs/libxfs/xfs_attr.c
diff options
context:
space:
mode:
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;