+}
+
+/*
* Remove a name from the leaf attribute list structure
*
* This leaf block cannot have a "remote" value, we only call this routine
@@ -806,12 +846,8 @@ xfs_attr_leaf_removename(
* Remove the attribute.
*/
dp = args->dp;
- args->blkno = 0;
- error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
- if (error)
- return error;
- error = xfs_attr3_leaf_lookup_int(bp, args);
+ error = xfs_leaf_has_attr(args, &bp);
if (error == -ENOATTR) {
xfs_trans_brelse(args->trans, bp);
return error;
@@ -848,12 +884,7 @@ 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, -1, &bp);
- if (error)
- return error;
-
- error = xfs_attr3_leaf_lookup_int(bp, args);
+ error = xfs_leaf_has_attr(args, &bp);
if (error != -EEXIST) {
xfs_trans_brelse(args->trans, bp);
return error;
@@ -866,6 +897,43 @@ 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;
+ struct xfs_inode *dp;
+ int retval, error;
+
+ /*
+ * 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 == 0)
+ error = retval;
+
+ if (statep != NULL)
+ *statep = state;
+ else
+ xfs_da_state_free(state);
+
+ return error;
+}
+
/*========================================================================
* External routines when attribute list size > geo->blksize
*========================================================================*/
@@ -898,17 +966,14 @@ 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)
+ error = xfs_attr_node_hasname(args, &state);
+ if (error == -EEXIST)
goto out;
+
blk = &state->path.blk[ state->path.active-1 ];
ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
@@ -1113,29 +1178,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.
@@ -1355,17 +1406,13 @@ 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;
- } else if (retval == -EEXIST) {
+ } else {
blk = &state->path.blk[ state->path.active-1 ];
ASSERT(blk->bp != NULL);
ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 0bade83..c082d34 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -170,6 +170,7 @@ int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
unsigned char *value, int valuelen);
int xfs_attr_set_args(struct xfs_da_args *args);
int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name);
+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 70eb941..8d2e11f 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -546,6 +546,53 @@ 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
+ * basep: If not null, pointer is set to the byte offset of the entry in the
+ * list
+ */
+int
+xfs_shortform_has_attr(
+ struct xfs_da_args *args,
+ struct xfs_attr_sf_entry **sfep,
+ int *basep)
+{
+ struct xfs_attr_shortform *sf;
+ struct xfs_attr_sf_entry *sfe;
+ int base = sizeof(struct xfs_attr_sf_hdr);
+ int size = 0;
+ int end;
+ int i;
+
+ base = sizeof(struct xfs_attr_sf_hdr);
+ sf = (struct xfs_attr_shortform *)args->dp->i_afp->if_u1.if_data;
+ sfe = &sf->list[0];
+ end = sf->hdr.count;
+ for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
+ base += size, i++) {
+ size = XFS_ATTR_SF_ENTSIZE(sfe);
+ if (sfe->namelen != args->namelen)
+ continue;
+ if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
+ continue;
+ if (!xfs_attr_namesp_match(args->flags, sfe->flags))
+ continue;
+ break;
+ }
+
+ if (sfep != NULL)
+ *sfep = sfe;
+
+ if (basep != NULL)
+ *basep = base;
+
+ if (i == end)
+ return -ENOATTR;
+ return -EEXIST;
+}
+
+/*
* Add a name/value pair to the shortform attribute list.
* Overflow from the inode has already been checked for.
*/
@@ -554,7 +601,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
{
xfs_attr_shortform_t *sf;
xfs_attr_sf_entry_t *sfe;
- int i, offset, size;
+ int offset, size, error;
xfs_mount_t *mp;
xfs_inode_t *dp;
struct xfs_ifork *ifp;
@@ -568,18 +615,11 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
ifp = dp->i_afp;
ASSERT(ifp->if_flags & XFS_IFINLINE);
sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
- sfe = &sf->list[0];
- for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
+ error = xfs_shortform_has_attr(args, &sfe, NULL);
#ifdef DEBUG
- if (sfe->namelen != args->namelen)
- continue;
- if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
- continue;
- if (!xfs_attr_namesp_match(args->flags, sfe->flags))
- continue;
+ if (error == -EEXIST)
ASSERT(0);
#endif
- }
offset = (char *)sfe - (char *)sf;
size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
@@ -626,7 +666,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
{
xfs_attr_shortform_t *sf;
xfs_attr_sf_entry_t *sfe;
- int base, size=0, end, totsize, i;
+ int base, size = 0, end, totsize, error;
xfs_mount_t *mp;
xfs_inode_t *dp;