STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
+STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
 
 /*
  * 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_removename(xfs_da_args_t *args);
+STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
+                                struct xfs_da_state **state);
 STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
 STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
 
        return error;
 }
 
+/*
+ * Return EEXIST if attr is found, or ENOATTR if not
+ */
+int
+xfs_has_attr(
+       struct xfs_da_args      *args)
+{
+       struct xfs_inode        *dp = args->dp;
+       struct xfs_buf          *bp = NULL;
+       int                     error;
+
+       if (!xfs_inode_hasattr(dp))
+               return -ENOATTR;
+
+       if (dp->i_afp->if_format == XFS_DINODE_FMT_LOCAL) {
+               ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
+               return xfs_attr_sf_findname(args, NULL, NULL);
+       }
+
+       if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+               error = xfs_attr_leaf_hasname(args, &bp);
+
+               if (bp)
+                       xfs_trans_brelse(args->trans, bp);
+
+               return error;
+       }
+
+       return xfs_attr_node_hasname(args, NULL);
+}
+
 /*
  * Remove the attribute specified in @args.
  */
 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, &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 (retval == -ENOATTR && (args->attr_flags & XATTR_REPLACE))
                goto out_brelse;
        if (retval == -EEXIST) {
        return retval;
 }
 
+/*
+ * 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, bp);
+       if (error)
+               return error;
+
+       error = xfs_attr3_leaf_lookup_int(*bp, args);
+       if (error != -ENOATTR && error != -EEXIST)
+               xfs_trans_brelse(args->trans, *bp);
+
+       return error;
+}
+
 /*
  * Remove a name from the leaf attribute list structure
  *
         * Remove the attribute.
         */
        dp = args->dp;
-       args->blkno = 0;
-       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
-       if (error)
-               return error;
 
-       error = xfs_attr3_leaf_lookup_int(bp, args);
+       error = xfs_attr_leaf_hasname(args, &bp);
+
        if (error == -ENOATTR) {
                xfs_trans_brelse(args->trans, bp);
                return error;
-       }
+       } else if (error != -EEXIST)
+               return error;
 
        xfs_attr3_leaf_remove(bp, args);
 
 
        trace_xfs_attr_leaf_get(args);
 
-       args->blkno = 0;
-       error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
-       if (error)
-               return error;
+       error = xfs_attr_leaf_hasname(args, &bp);
 
-       error = xfs_attr3_leaf_lookup_int(bp, args);
-       if (error != -EEXIST)  {
+       if (error == -ENOATTR)  {
                xfs_trans_brelse(args->trans, bp);
                return error;
-       }
+       } else if (error != -EEXIST)
+               return error;
+
+
        error = xfs_attr3_leaf_getvalue(bp, args);
        xfs_trans_brelse(args->trans, bp);
        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(args);
+       if (statep != NULL)
+               *statep = NULL;
+
+       /*
+        * Search to see if name exists, and get back a pointer to it.
+        */
+       error = xfs_da3_node_lookup_int(state, &retval);
+       if (error) {
+               xfs_da_state_free(state);
+               return error;
+       }
+
+       if (statep != NULL)
+               *statep = state;
+       else
+               xfs_da_state_free(state);
+       return retval;
+}
+
 /*========================================================================
  * External routines when attribute list size > geo->blksize
  *========================================================================*/
         */
        dp = args->dp;
 restart:
-       state = xfs_da_state_alloc(args);
-
        /*
         * 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 && retval != -EEXIST)
                goto out;
+
        blk = &state->path.blk[ state->path.active-1 ];
        ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
        if (retval == -ENOATTR && (args->attr_flags & XATTR_REPLACE))
 {
        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(args);
-
-       /*
-        * 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.
        error = 0;
 
 out:
-       xfs_da_state_free(state);
+       if (state)
+               xfs_da_state_free(state);
        return error;
 }
 
  * Returns 0 on successful retrieval, otherwise an error.
  */
 STATIC int
-xfs_attr_node_get(xfs_da_args_t *args)
+xfs_attr_node_get(
+       struct xfs_da_args      *args)
 {
-       xfs_da_state_t *state;
-       xfs_da_state_blk_t *blk;
-       int error, retval;
-       int i;
+       struct xfs_da_state     *state;
+       struct xfs_da_state_blk *blk;
+       int                     i;
+       int                     error;
 
        trace_xfs_attr_node_get(args);
 
-       state = xfs_da_state_alloc(args);
-
        /*
         * Search to see if name exists, and get back a pointer to it.
         */
-       error = xfs_da3_node_lookup_int(state, &retval);
-       if (error) {
-               retval = error;
-               goto out_release;
-       }
-       if (retval != -EEXIST)
+       error = xfs_attr_node_hasname(args, &state);
+       if (error != -EEXIST)
                goto out_release;
 
        /*
         * Get the value, local or "remote"
         */
        blk = &state->path.blk[state->path.active - 1];
-       retval = xfs_attr3_leaf_getvalue(blk->bp, args);
+       error = xfs_attr3_leaf_getvalue(blk->bp, args);
 
        /*
         * If not in a transaction, we have to release all the buffers.
         */
 out_release:
-       for (i = 0; i < state->path.active; i++) {
+       for (i = 0; state != NULL && i < state->path.active; i++) {
                xfs_trans_brelse(args->trans, state->path.blk[i].bp);
                state->path.blk[i].bp = NULL;
        }
 
-       xfs_da_state_free(state);
-       return retval;
+       if (state)
+               xfs_da_state_free(state);
+       return error;
 }
 
 /* Returns true if the attribute entry name is valid. */
 
        xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
 }
 
+/*
+ * 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_sf_findname(
+       struct xfs_da_args       *args,
+       struct xfs_attr_sf_entry **sfep,
+       unsigned int             *basep)
+{
+       struct xfs_attr_shortform *sf;
+       struct xfs_attr_sf_entry *sfe;
+       unsigned int            base = sizeof(struct xfs_attr_sf_hdr);
+       int                     size = 0;
+       int                     end;
+       int                     i;
+
+       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 (!xfs_attr_match(args, sfe->namelen, sfe->nameval,
+                                   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.
  */
 void
-xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
+xfs_attr_shortform_add(
+       struct xfs_da_args              *args,
+       int                             forkoff)
 {
-       xfs_attr_shortform_t *sf;
-       xfs_attr_sf_entry_t *sfe;
-       int i, offset, size;
-       xfs_mount_t *mp;
-       xfs_inode_t *dp;
-       struct xfs_ifork *ifp;
+       struct xfs_attr_shortform       *sf;
+       struct xfs_attr_sf_entry        *sfe;
+       int                             offset, size;
+       struct xfs_mount                *mp;
+       struct xfs_inode                *dp;
+       struct xfs_ifork                *ifp;
 
        trace_xfs_attr_sf_add(args);
 
        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++) {
-               ASSERT(!xfs_attr_match(args, sfe->namelen, sfe->nameval,
-                       sfe->flags));
-       }
+       if (xfs_attr_sf_findname(args, &sfe, NULL) == -EEXIST)
+               ASSERT(0);
 
        offset = (char *)sfe - (char *)sf;
        size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
  * Remove an attribute from the shortform attribute list structure.
  */
 int
-xfs_attr_shortform_remove(xfs_da_args_t *args)
+xfs_attr_shortform_remove(
+       struct xfs_da_args              *args)
 {
-       xfs_attr_shortform_t *sf;
-       xfs_attr_sf_entry_t *sfe;
-       int base, size=0, end, totsize, i;
-       xfs_mount_t *mp;
-       xfs_inode_t *dp;
+       struct xfs_attr_shortform       *sf;
+       struct xfs_attr_sf_entry        *sfe;
+       int                             size = 0, end, totsize;
+       unsigned int                    base;
+       struct xfs_mount                *mp;
+       struct xfs_inode                *dp;
+       int                             error;
 
        trace_xfs_attr_sf_remove(args);
 
        dp = args->dp;
        mp = dp->i_mount;
-       base = sizeof(xfs_attr_sf_hdr_t);
        sf = (xfs_attr_shortform_t *)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 (xfs_attr_match(args, sfe->namelen, sfe->nameval,
-                               sfe->flags))
-                       break;
-       }
-       if (i == end)
-               return -ENOATTR;
+
+       error = xfs_attr_sf_findname(args, &sfe, &base);
+       if (error != -EEXIST)
+               return error;
+       size = XFS_ATTR_SF_ENTSIZE(sfe);
 
        /*
         * Fix up the attribute fork data, covering the hole