+{
+ struct xfs_inode *dp = args->dp;
+ struct xfs_buf *bp;
+ int error;
+
+ if (!xfs_inode_hasattr(dp)) {
+ error = -ENOATTR;
+ } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
+ ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
+ error = xfs_attr_shortform_hasname(args, NULL, NULL);
+ } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+ error = xfs_attr_leaf_hasname(args, &bp);
+ if (error != -ENOATTR && error != -EEXIST)
+ goto out;
+ xfs_trans_brelse(args->trans, bp);
+ } else {
+ error = xfs_attr_node_hasname(args, NULL);
+ }
+out:
+ return error;
+}
+
+/*
* Remove the attribute specified in @args.
*/
int
@@ -580,27 +611,20 @@ STATIC int
xfs_attr_leaf_addname(
struct xfs_da_args *args)
{
- struct xfs_inode *dp;
struct xfs_buf *bp;
int retval, error, forkoff;
+ struct xfs_inode *dp = args->dp;
trace_xfs_attr_leaf_addname(args);
/*
- * Read the (only) block in the attribute list in.
- */
- dp = args->dp;
- args->blkno = 0;
- error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
- XFS_DABUF_MAP_NOMAPPING, &bp);
- if (error)
- return error;
-
- /*
* Look up the given attribute in the leaf block. Figure out if
* the given flags produce an error or call for an atomic rename.
*/
- retval = xfs_attr3_leaf_lookup_int(bp, args);
+ retval = xfs_attr_leaf_hasname(args, &bp);
+ if (retval != -ENOATTR && retval != -EEXIST)
+ return retval;
+
if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
xfs_trans_brelse(args->trans, bp);
return retval;
@@ -752,6 +776,24 @@ xfs_attr_leaf_addname(
}
/*
+ * Return EEXIST if attr is found, or ENOATTR if not
+ */
+STATIC int
+xfs_attr_leaf_hasname(
+ struct xfs_da_args *args,
+ struct xfs_buf **bp)
+{
+ int error = 0;
+
+ error = xfs_attr3_leaf_read(args->trans, args->dp, 0,
+ XFS_DABUF_MAP_NOMAPPING, bp);
+ if (error)
+ return error;
+
+ return xfs_attr3_leaf_lookup_int(*bp, args);
+}
+
+/*
* Remove a name from the leaf attribute list structure
*
* This leaf block cannot have a "remote" value, we only call this routine
@@ -771,13 +813,11 @@ xfs_attr_leaf_removename(
* Remove the attribute.
*/
dp = args->dp;
- args->blkno = 0;
- error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
- XFS_DABUF_MAP_NOMAPPING, &bp);
- if (error)
+
+ error = xfs_attr_leaf_hasname(args, &bp);
+ if (error != -ENOATTR && error != -EEXIST)
return error;
- error = xfs_attr3_leaf_lookup_int(bp, args);
if (error == -ENOATTR) {
xfs_trans_brelse(args->trans, bp);
return error;
@@ -816,13 +856,10 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
trace_xfs_attr_leaf_get(args);
- args->blkno = 0;
- error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
- XFS_DABUF_MAP_NOMAPPING, &bp);
- if (error)
+ error = xfs_attr_leaf_hasname(args, &bp);
+ if (error != -ENOATTR && error != -EEXIST)
return error;
- error = xfs_attr3_leaf_lookup_int(bp, args);
if (error != -EEXIST) {
xfs_trans_brelse(args->trans, bp);
return error;
@@ -832,6 +869,38 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
return error;
}
+/*
+ * Return EEXIST if attr is found, or ENOATTR if not
+ * statep: If not null is set to point at the found state. Caller will
+ * be responsible for freeing the state in this case.
+ */
+STATIC int
+xfs_attr_node_hasname(
+ struct xfs_da_args *args,
+ struct xfs_da_state **statep)
+{
+ struct xfs_da_state *state;
+ int retval, error;
+
+ state = xfs_da_state_alloc();
+ state->args = args;
+ state->mp = args->dp->i_mount;
+
+ /*
+ * Search to see if name exists, and get back a pointer to it.
+ */
+ error = xfs_da3_node_lookup_int(state, &retval);
+ if (error == 0)
+ error = retval;
+
+ if (statep != NULL)
+ *statep = state;
+ else
+ xfs_da_state_free(state);
+
+ return error;
+}
+
/*========================================================================
* External routines when attribute list size > geo->blksize
*========================================================================*/
@@ -864,20 +933,17 @@ xfs_attr_node_addname(
dp = args->dp;
mp = dp->i_mount;
restart:
- state = xfs_da_state_alloc();
- state->args = args;
- state->mp = mp;
-
/*
* Search to see if name already exists, and get back a pointer
* to where it should go.
*/
- error = xfs_da3_node_lookup_int(state, &retval);
- if (error)
+ retval = xfs_attr_node_hasname(args, &state);
+ if (retval != -ENOATTR)
goto out;
+
blk = &state->path.blk[ state->path.active-1 ];
ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
- if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
+ if (args->name.type & ATTR_REPLACE) {
goto out;
} else if (retval == -EEXIST) {
if (args->name.type & ATTR_CREATE)
@@ -1079,29 +1145,15 @@ xfs_attr_node_removename(
{
struct xfs_da_state *state;
struct xfs_da_state_blk *blk;
- struct xfs_inode *dp;
struct xfs_buf *bp;
int retval, error, forkoff;
+ struct xfs_inode *dp = args->dp;
trace_xfs_attr_node_removename(args);
- /*
- * Tie a string around our finger to remind us where we are.
- */
- dp = args->dp;
- state = xfs_da_state_alloc();
- state->args = args;
- state->mp = dp->i_mount;
-
- /*
- * Search to see if name exists, and get back a pointer to it.
- */
- error = xfs_da3_node_lookup_int(state, &retval);
- if (error || (retval != -EEXIST)) {
- if (error == 0)
- error = retval;
+ error = xfs_attr_node_hasname(args, &state);
+ if (error != -EEXIST)
goto out;
- }
/*
* If there is an out-of-line value, de-allocate the blocks.
@@ -1324,20 +1376,14 @@ xfs_attr_node_get(xfs_da_args_t *args)
trace_xfs_attr_node_get(args);
- state = xfs_da_state_alloc();
- state->args = args;
- state->mp = args->dp->i_mount;
-
/*
* Search to see if name exists, and get back a pointer to it.
*/
- error = xfs_da3_node_lookup_int(state, &retval);
- if (error) {
+ error = xfs_attr_node_hasname(args, &state);
+ if (error != -EEXIST) {
retval = error;
goto out_release;
}
- if (retval != -EEXIST)
- goto out_release;
/*
* Get the value, local or "remote"
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 44dd07a..3b5dad4 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -150,6 +150,7 @@ int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
unsigned char *value, int valuelen, int flags);
int xfs_attr_set_args(struct xfs_da_args *args);
int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
+int xfs_has_attr(struct xfs_da_args *args);
int xfs_attr_remove_args(struct xfs_da_args *args);
int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
int flags, struct attrlist_cursor_kern *cursor);
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 93c3496..d06cfd6 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -655,18 +655,67 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
}
/*
+ * Return -EEXIST if attr is found, or -ENOATTR if not
+ * args: args containing attribute name and namelen
+ * sfep: If not null, pointer will be set to the last attr entry found on
+ -EEXIST. On -ENOATTR pointer is left at the last entry in the list
+ * basep: If not null, pointer is set to the byte offset of the entry in the
+ * list on -EEXIST. On -ENOATTR, pointer is left at the byte offset of
+ * the last entry in the list
+ */
+int
+xfs_attr_shortform_hasname(
+ struct xfs_da_args *args,
+ struct xfs_attr_sf_entry **sfep,
+ int *basep)