xfs: pass xfs_da_args to xfs_attr_leaf_newentsize
[firefly-linux-kernel-4.4.55.git] / fs / xfs / xfs_attr.c
index 01b6a0102fbdd4d153612740d95c4f00fda691f7..3d8c03edf657d745b15fd8ea62a1a02bd7d24fc2 100644 (file)
@@ -77,17 +77,27 @@ STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
 
 
 STATIC int
-xfs_attr_name_to_xname(
-       struct xfs_name *xname,
-       const unsigned char *aname)
+xfs_attr_args_init(
+       struct xfs_da_args      *args,
+       struct xfs_inode        *dp,
+       const unsigned char     *name,
+       int                     flags)
 {
-       if (!aname)
+
+       if (!name)
                return EINVAL;
-       xname->name = aname;
-       xname->len = strlen((char *)aname);
-       if (xname->len >= MAXNAMELEN)
+
+       memset(args, 0, sizeof(*args));
+       args->geo = dp->i_mount->m_attr_geo;
+       args->whichfork = XFS_ATTR_FORK;
+       args->dp = dp;
+       args->flags = flags;
+       args->name = name;
+       args->namelen = strlen((const char *)name);
+       if (args->namelen >= MAXNAMELEN)
                return EFAULT;          /* match IRIX behaviour */
 
+       args->hashval = xfs_da_hashname(args->name, args->namelen);
        return 0;
 }
 
@@ -106,79 +116,46 @@ xfs_inode_hasattr(
  * Overall external interface routines.
  *========================================================================*/
 
-STATIC int
-xfs_attr_get_int(
+int
+xfs_attr_get(
        struct xfs_inode        *ip,
-       struct xfs_name         *name,
+       const unsigned char     *name,
        unsigned char           *value,
        int                     *valuelenp,
        int                     flags)
 {
-       xfs_da_args_t   args;
-       int             error;
+       struct xfs_da_args      args;
+       uint                    lock_mode;
+       int                     error;
+
+       XFS_STATS_INC(xs_attr_get);
+
+       if (XFS_FORCED_SHUTDOWN(ip->i_mount))
+               return EIO;
 
        if (!xfs_inode_hasattr(ip))
                return ENOATTR;
 
-       /*
-        * Fill in the arg structure for this request.
-        */
-       memset((char *)&args, 0, sizeof(args));
-       args.name = name->name;
-       args.namelen = name->len;
+       error = xfs_attr_args_init(&args, ip, name, flags);
+       if (error)
+               return error;
+
        args.value = value;
        args.valuelen = *valuelenp;
-       args.flags = flags;
-       args.hashval = xfs_da_hashname(args.name, args.namelen);
-       args.dp = ip;
-       args.whichfork = XFS_ATTR_FORK;
 
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
-       if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
+       lock_mode = xfs_ilock_attr_map_shared(ip);
+       if (!xfs_inode_hasattr(ip))
+               error = ENOATTR;
+       else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
                error = xfs_attr_shortform_getvalue(&args);
-       } else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) {
+       else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK))
                error = xfs_attr_leaf_get(&args);
-       } else {
+       else
                error = xfs_attr_node_get(&args);
-       }
+       xfs_iunlock(ip, lock_mode);
 
-       /*
-        * Return the number of bytes in the value to the caller.
-        */
        *valuelenp = args.valuelen;
-
-       if (error == EEXIST)
-               error = 0;
-       return(error);
-}
-
-int
-xfs_attr_get(
-       xfs_inode_t     *ip,
-       const unsigned char *name,
-       unsigned char   *value,
-       int             *valuelenp,
-       int             flags)
-{
-       int             error;
-       struct xfs_name xname;
-       uint            lock_mode;
-
-       XFS_STATS_INC(xs_attr_get);
-
-       if (XFS_FORCED_SHUTDOWN(ip->i_mount))
-               return(EIO);
-
-       error = xfs_attr_name_to_xname(&xname, name);
-       if (error)
-               return error;
-
-       lock_mode = xfs_ilock_attr_map_shared(ip);
-       error = xfs_attr_get_int(ip, &xname, value, valuelenp, flags);
-       xfs_iunlock(ip, lock_mode);
-       return(error);
+       return error == EEXIST ? 0 : error;
 }
 
 /*
@@ -186,12 +163,10 @@ xfs_attr_get(
  */
 STATIC int
 xfs_attr_calc_size(
-       struct xfs_inode        *ip,
-       int                     namelen,
-       int                     valuelen,
+       struct xfs_da_args      *args,
        int                     *local)
 {
-       struct xfs_mount        *mp = ip->i_mount;
+       struct xfs_mount        *mp = args->dp->i_mount;
        int                     size;
        int                     nblks;
 
@@ -199,12 +174,10 @@ xfs_attr_calc_size(
         * Determine space new attribute will use, and if it would be
         * "local" or "remote" (note: local != inline).
         */
-       size = xfs_attr_leaf_newentsize(namelen, valuelen,
-                                       mp->m_sb.sb_blocksize, local);
-
+       size = xfs_attr_leaf_newentsize(args, local);
        nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
        if (*local) {
-               if (size > (mp->m_sb.sb_blocksize >> 1)) {
+               if (size > (args->geo->blksize / 2)) {
                        /* Double split possible */
                        nblks *= 2;
                }
@@ -213,7 +186,7 @@ xfs_attr_calc_size(
                 * Out of line attribute, cannot double split, but
                 * make room for the attribute value itself.
                 */
-               uint    dblocks = XFS_B_TO_FSB(mp, valuelen);
+               uint    dblocks = xfs_attr3_rmt_blocks(mp, args->valuelen);
                nblks += dblocks;
                nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);
        }
@@ -221,26 +194,38 @@ xfs_attr_calc_size(
        return nblks;
 }
 
-STATIC int
-xfs_attr_set_int(
-       struct xfs_inode *dp,
-       struct xfs_name *name,
-       unsigned char   *value,
-       int             valuelen,
-       int             flags)
+int
+xfs_attr_set(
+       struct xfs_inode        *dp,
+       const unsigned char     *name,
+       unsigned char           *value,
+       int                     valuelen,
+       int                     flags)
 {
-       xfs_da_args_t           args;
-       xfs_fsblock_t           firstblock;
-       xfs_bmap_free_t         flist;
-       int                     error, err2, committed;
        struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_da_args      args;
+       struct xfs_bmap_free    flist;
        struct xfs_trans_res    tres;
+       xfs_fsblock_t           firstblock;
        int                     rsvd = (flags & ATTR_ROOT) != 0;
-       int                     local;
+       int                     error, err2, committed, local;
+
+       XFS_STATS_INC(xs_attr_set);
+
+       if (XFS_FORCED_SHUTDOWN(dp->i_mount))
+               return EIO;
+
+       error = xfs_attr_args_init(&args, dp, name, flags);
+       if (error)
+               return error;
+
+       args.value = value;
+       args.valuelen = valuelen;
+       args.firstblock = &firstblock;
+       args.flist = &flist;
+       args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
+       args.total = xfs_attr_calc_size(&args, &local);
 
-       /*
-        * Attach the dquots to the inode.
-        */
        error = xfs_qm_dqattach(dp, 0);
        if (error)
                return error;
@@ -251,31 +236,13 @@ xfs_attr_set_int(
         */
        if (XFS_IFORK_Q(dp) == 0) {
                int sf_size = sizeof(xfs_attr_sf_hdr_t) +
-                             XFS_ATTR_SF_ENTSIZE_BYNAME(name->len, valuelen);
+                       XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
 
-               if ((error = xfs_bmap_add_attrfork(dp, sf_size, rsvd)))
-                       return(error);
+               error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
+               if (error)
+                       return error;
        }
 
-       /*
-        * Fill in the arg structure for this request.
-        */
-       memset((char *)&args, 0, sizeof(args));
-       args.name = name->name;
-       args.namelen = name->len;
-       args.value = value;
-       args.valuelen = valuelen;
-       args.flags = flags;
-       args.hashval = xfs_da_hashname(args.name, args.namelen);
-       args.dp = dp;
-       args.firstblock = &firstblock;
-       args.flist = &flist;
-       args.whichfork = XFS_ATTR_FORK;
-       args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
-
-       /* Size is now blocks for attribute data */
-       args.total = xfs_attr_calc_size(dp, name->len, valuelen, &local);
-
        /*
         * Start our first transaction of the day.
         *
@@ -303,7 +270,7 @@ xfs_attr_set_int(
        error = xfs_trans_reserve(args.trans, &tres, args.total, 0);
        if (error) {
                xfs_trans_cancel(args.trans, 0);
-               return(error);
+               return error;
        }
        xfs_ilock(dp, XFS_ILOCK_EXCL);
 
@@ -313,7 +280,7 @@ xfs_attr_set_int(
        if (error) {
                xfs_iunlock(dp, XFS_ILOCK_EXCL);
                xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
-               return (error);
+               return error;
        }
 
        xfs_trans_ijoin(args.trans, dp, 0);
@@ -322,9 +289,9 @@ xfs_attr_set_int(
         * If the attribute list is non-existent or a shortform list,
         * upgrade it to a single-leaf-block attribute list.
         */
-       if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
-           ((dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) &&
-            (dp->i_d.di_anextents == 0))) {
+       if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
+           (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
+            dp->i_d.di_anextents == 0)) {
 
                /*
                 * Build initial attribute list (if required).
@@ -349,9 +316,8 @@ xfs_attr_set_int(
                         * the transaction goes to disk before returning
                         * to the user.
                         */
-                       if (mp->m_flags & XFS_MOUNT_WSYNC) {
+                       if (mp->m_flags & XFS_MOUNT_WSYNC)
                                xfs_trans_set_sync(args.trans);
-                       }
 
                        if (!error && (flags & ATTR_KERNOTIME) == 0) {
                                xfs_trans_ichgtime(args.trans, dp,
@@ -361,7 +327,7 @@ xfs_attr_set_int(
                                                 XFS_TRANS_RELEASE_LOG_RES);
                        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 
-                       return(error == 0 ? err2 : error);
+                       return error ? error : err2;
                }
 
                /*
@@ -399,22 +365,19 @@ xfs_attr_set_int(
 
        }
 
-       if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+       if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
                error = xfs_attr_leaf_addname(&args);
-       } else {
+       else
                error = xfs_attr_node_addname(&args);
-       }
-       if (error) {
+       if (error)
                goto out;
-       }
 
        /*
         * If this is a synchronous mount, make sure that the
         * transaction goes to disk before returning to the user.
         */
-       if (mp->m_flags & XFS_MOUNT_WSYNC) {
+       if (mp->m_flags & XFS_MOUNT_WSYNC)
                xfs_trans_set_sync(args.trans);
-       }
 
        if ((flags & ATTR_KERNOTIME) == 0)
                xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
@@ -426,65 +389,47 @@ xfs_attr_set_int(
        error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 
-       return(error);
+       return error;
 
 out:
-       if (args.trans)
+       if (args.trans) {
                xfs_trans_cancel(args.trans,
                        XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
+       }
        xfs_iunlock(dp, XFS_ILOCK_EXCL);
-       return(error);
+       return error;
 }
 
+/*
+ * Generic handler routine to remove a name from an attribute list.
+ * Transitions attribute list from Btree to shortform as necessary.
+ */
 int
-xfs_attr_set(
-       xfs_inode_t     *dp,
-       const unsigned char *name,
-       unsigned char   *value,
-       int             valuelen,
-       int             flags)
+xfs_attr_remove(
+       struct xfs_inode        *dp,
+       const unsigned char     *name,
+       int                     flags)
 {
-       int             error;
-       struct xfs_name xname;
+       struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_da_args      args;
+       struct xfs_bmap_free    flist;
+       xfs_fsblock_t           firstblock;
+       int                     error;
 
-       XFS_STATS_INC(xs_attr_set);
+       XFS_STATS_INC(xs_attr_remove);
 
        if (XFS_FORCED_SHUTDOWN(dp->i_mount))
-               return (EIO);
+               return EIO;
 
-       error = xfs_attr_name_to_xname(&xname, name);
+       if (!xfs_inode_hasattr(dp))
+               return ENOATTR;
+
+       error = xfs_attr_args_init(&args, dp, name, flags);
        if (error)
                return error;
 
-       return xfs_attr_set_int(dp, &xname, value, valuelen, flags);
-}
-
-/*
- * Generic handler routine to remove a name from an attribute list.
- * Transitions attribute list from Btree to shortform as necessary.
- */
-STATIC int
-xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
-{
-       xfs_da_args_t   args;
-       xfs_fsblock_t   firstblock;
-       xfs_bmap_free_t flist;
-       int             error;
-       xfs_mount_t     *mp = dp->i_mount;
-
-       /*
-        * Fill in the arg structure for this request.
-        */
-       memset((char *)&args, 0, sizeof(args));
-       args.name = name->name;
-       args.namelen = name->len;
-       args.flags = flags;
-       args.hashval = xfs_da_hashname(args.name, args.namelen);
-       args.dp = dp;
        args.firstblock = &firstblock;
        args.flist = &flist;
-       args.total = 0;
-       args.whichfork = XFS_ATTR_FORK;
 
        /*
         * we have no control over the attribute names that userspace passes us
@@ -493,9 +438,6 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
         */
        args.op_flags = XFS_DA_OP_OKNOENT;
 
-       /*
-        * Attach the dquots to the inode.
-        */
        error = xfs_qm_dqattach(dp, 0);
        if (error)
                return error;
@@ -524,7 +466,7 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
                                  XFS_ATTRRM_SPACE_RES(mp), 0);
        if (error) {
                xfs_trans_cancel(args.trans, 0);
-               return(error);
+               return error;
        }
 
        xfs_ilock(dp, XFS_ILOCK_EXCL);
@@ -534,35 +476,26 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
         */
        xfs_trans_ijoin(args.trans, dp, 0);
 
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
        if (!xfs_inode_hasattr(dp)) {
                error = XFS_ERROR(ENOATTR);
-               goto out;
-       }
-       if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
+       } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
                ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
                error = xfs_attr_shortform_remove(&args);
-               if (error) {
-                       goto out;
-               }
        } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
                error = xfs_attr_leaf_removename(&args);
        } else {
                error = xfs_attr_node_removename(&args);
        }
-       if (error) {
+
+       if (error)
                goto out;
-       }
 
        /*
         * If this is a synchronous mount, make sure that the
         * transaction goes to disk before returning to the user.
         */
-       if (mp->m_flags & XFS_MOUNT_WSYNC) {
+       if (mp->m_flags & XFS_MOUNT_WSYNC)
                xfs_trans_set_sync(args.trans);
-       }
 
        if ((flags & ATTR_KERNOTIME) == 0)
                xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
@@ -574,45 +507,17 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
        error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
        xfs_iunlock(dp, XFS_ILOCK_EXCL);
 
-       return(error);
+       return error;
 
 out:
-       if (args.trans)
+       if (args.trans) {
                xfs_trans_cancel(args.trans,
                        XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
-       xfs_iunlock(dp, XFS_ILOCK_EXCL);
-       return(error);
-}
-
-int
-xfs_attr_remove(
-       xfs_inode_t     *dp,
-       const unsigned char *name,
-       int             flags)
-{
-       int             error;
-       struct xfs_name xname;
-
-       XFS_STATS_INC(xs_attr_remove);
-
-       if (XFS_FORCED_SHUTDOWN(dp->i_mount))
-               return (EIO);
-
-       error = xfs_attr_name_to_xname(&xname, name);
-       if (error)
-               return error;
-
-       xfs_ilock(dp, XFS_ILOCK_SHARED);
-       if (!xfs_inode_hasattr(dp)) {
-               xfs_iunlock(dp, XFS_ILOCK_SHARED);
-               return XFS_ERROR(ENOATTR);
        }
-       xfs_iunlock(dp, XFS_ILOCK_SHARED);
-
-       return xfs_attr_remove_int(dp, &xname, flags);
+       xfs_iunlock(dp, XFS_ILOCK_EXCL);
+       return error;
 }
 
-
 /*========================================================================
  * External routines when attribute list is inside the inode
  *========================================================================*/
@@ -698,11 +603,22 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
 
                trace_xfs_attr_leaf_replace(args);
 
+               /* save the attribute state for later removal*/
                args->op_flags |= XFS_DA_OP_RENAME;     /* an atomic rename */
                args->blkno2 = args->blkno;             /* set 2nd entry info*/
                args->index2 = args->index;
                args->rmtblkno2 = args->rmtblkno;
                args->rmtblkcnt2 = args->rmtblkcnt;
+               args->rmtvaluelen2 = args->rmtvaluelen;
+
+               /*
+                * clear the remote attr state now that it is saved so that the
+                * values reflect the state of the attribute we are about to
+                * add, not the attribute we just found and will remove later.
+                */
+               args->rmtblkno = 0;
+               args->rmtblkcnt = 0;
+               args->rmtvaluelen = 0;
        }
 
        /*
@@ -794,6 +710,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
                args->blkno = args->blkno2;
                args->rmtblkno = args->rmtblkno2;
                args->rmtblkcnt = args->rmtblkcnt2;
+               args->rmtvaluelen = args->rmtvaluelen2;
                if (args->rmtblkno) {
                        error = xfs_attr_rmtval_remove(args);
                        if (error)
@@ -979,8 +896,8 @@ restart:
        state = xfs_da_state_alloc();
        state->args = args;
        state->mp = mp;
-       state->blocksize = state->mp->m_sb.sb_blocksize;
-       state->node_ents = state->mp->m_attr_node_ents;
+       state->blocksize = args->geo->blksize;
+       state->node_ents = args->geo->node_ents;
 
        /*
         * Search to see if name already exists, and get back a pointer
@@ -999,13 +916,22 @@ restart:
 
                trace_xfs_attr_node_replace(args);
 
+               /* save the attribute state for later removal*/
                args->op_flags |= XFS_DA_OP_RENAME;     /* atomic rename op */
                args->blkno2 = args->blkno;             /* set 2nd entry info*/
                args->index2 = args->index;
                args->rmtblkno2 = args->rmtblkno;
                args->rmtblkcnt2 = args->rmtblkcnt;
+               args->rmtvaluelen2 = args->rmtvaluelen;
+
+               /*
+                * clear the remote attr state now that it is saved so that the
+                * values reflect the state of the attribute we are about to
+                * add, not the attribute we just found and will remove later.
+                */
                args->rmtblkno = 0;
                args->rmtblkcnt = 0;
+               args->rmtvaluelen = 0;
        }
 
        retval = xfs_attr3_leaf_add(blk->bp, state->args);
@@ -1133,6 +1059,7 @@ restart:
                args->blkno = args->blkno2;
                args->rmtblkno = args->rmtblkno2;
                args->rmtblkcnt = args->rmtblkcnt2;
+               args->rmtvaluelen = args->rmtvaluelen2;
                if (args->rmtblkno) {
                        error = xfs_attr_rmtval_remove(args);
                        if (error)
@@ -1148,8 +1075,8 @@ restart:
                state = xfs_da_state_alloc();
                state->args = args;
                state->mp = mp;
-               state->blocksize = state->mp->m_sb.sb_blocksize;
-               state->node_ents = state->mp->m_attr_node_ents;
+               state->blocksize = args->geo->blksize;
+               state->node_ents = args->geo->node_ents;
                state->inleaf = 0;
                error = xfs_da3_node_lookup_int(state, &retval);
                if (error)
@@ -1240,8 +1167,8 @@ xfs_attr_node_removename(xfs_da_args_t *args)
        state = xfs_da_state_alloc();
        state->args = args;
        state->mp = dp->i_mount;
-       state->blocksize = state->mp->m_sb.sb_blocksize;
-       state->node_ents = state->mp->m_attr_node_ents;
+       state->blocksize = args->geo->blksize;
+       state->node_ents = args->geo->node_ents;
 
        /*
         * Search to see if name exists, and get back a pointer to it.
@@ -1503,8 +1430,8 @@ xfs_attr_node_get(xfs_da_args_t *args)
        state = xfs_da_state_alloc();
        state->args = args;
        state->mp = args->dp->i_mount;
-       state->blocksize = state->mp->m_sb.sb_blocksize;
-       state->node_ents = state->mp->m_attr_node_ents;
+       state->blocksize = args->geo->blksize;
+       state->node_ents = args->geo->node_ents;
 
        /*
         * Search to see if name exists, and get back a pointer to it.