* Internal routines when attribute list is more than one block.
*/
STATIC int xfs_attr_node_get(xfs_da_args_t *args);
-STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
+STATIC int xfs_attr_node_addname(struct xfs_da_args *args,
+ struct xfs_da_state *state);
+STATIC int xfs_attr_node_addname_find_attr(struct xfs_da_args *args,
+ struct xfs_da_state **state);
STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
STATIC int xfs_attr_node_addname_clear_incomplete(struct xfs_da_args *args);
STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
struct xfs_da_args *args)
{
struct xfs_inode *dp = args->dp;
+ struct xfs_da_state *state;
int error;
/*
return error;
}
- return xfs_attr_node_addname(args);
+ do {
+ error = xfs_attr_node_addname_find_attr(args, &state);
+ if (error)
+ return error;
+ error = xfs_attr_node_addname(args, state);
+ } while (error == -EAGAIN);
+
+ return error;
}
/*
* External routines when attribute list size > geo->blksize
*========================================================================*/
-/*
- * Add a name to a Btree-format attribute list.
- *
- * This will involve walking down the Btree, and may involve splitting
- * leaf nodes and even splitting intermediate nodes up to and including
- * the root node (a special case of an intermediate node).
- *
- * "Remote" attribute values confuse the issue and atomic rename operations
- * add a whole extra layer of confusion on top of that.
- */
STATIC int
-xfs_attr_node_addname(
- struct xfs_da_args *args)
+xfs_attr_node_addname_find_attr(
+ struct xfs_da_args *args,
+ struct xfs_da_state **state)
{
- struct xfs_da_state *state;
- struct xfs_da_state_blk *blk;
- struct xfs_inode *dp;
- int retval, error;
-
- trace_xfs_attr_node_addname(args);
+ int retval;
/*
- * Fill in bucket of arguments/results/context to carry around.
- */
- dp = args->dp;
-restart:
- /*
* Search to see if name already exists, and get back a pointer
* to where it should go.
*/
- error = 0;
- retval = xfs_attr_node_hasname(args, &state);
+ retval = xfs_attr_node_hasname(args, state);
if (retval != -ENOATTR && retval != -EEXIST)
- goto out;
+ goto error;
- blk = &state->path.blk[ state->path.active-1 ];
- ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
if (retval == -ENOATTR && (args->attr_flags & XATTR_REPLACE))
- goto out;
+ goto error;
if (retval == -EEXIST) {
if (args->attr_flags & XATTR_CREATE)
- goto out;
+ goto error;
trace_xfs_attr_node_replace(args);
args->rmtvaluelen = 0;
}
+ return 0;
+error:
+ if (*state)
+ xfs_da_state_free(*state);
+ return retval;
+}
+
+/*
+ * Add a name to a Btree-format attribute list.
+ *
+ * This will involve walking down the Btree, and may involve splitting
+ * leaf nodes and even splitting intermediate nodes up to and including
+ * the root node (a special case of an intermediate node).
+ *
+ * "Remote" attribute values confuse the issue and atomic rename operations
+ * add a whole extra layer of confusion on top of that.
+ */
+STATIC int
+xfs_attr_node_addname(
+ struct xfs_da_args *args,
+ struct xfs_da_state *state)
+{
+ struct xfs_da_state_blk *blk;
+ struct xfs_inode *dp;
+ int retval, error;
+
+ trace_xfs_attr_node_addname(args);
+
+ dp = args->dp;
+ blk = &state->path.blk[state->path.active-1];
+ ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
+
retval = xfs_attr3_leaf_add(blk->bp, state->args);
if (retval == -ENOSPC) {
if (state->path.active == 1) {
if (error)
goto out;
- goto restart;
+ return -EAGAIN;
}
/*