]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - libxfs/xfs_attr.c
xfs: remove unnecessary dfops init calls in xattr code
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_attr.c
index a595fbf6c7d67eef8c2e3ae046ca12e2172cfc2e..c14e8a346fcea41da713123b422b54fed027af58 100644 (file)
@@ -1,19 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (c) 2000-2005 Silicon Graphics, Inc.
  * All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include "libxfs_priv.h"
 #include "xfs_fs.h"
@@ -207,10 +195,9 @@ xfs_attr_set(
        int                     flags)
 {
        struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_buf          *leaf_bp = NULL;
        struct xfs_da_args      args;
-       struct xfs_defer_ops    dfops;
        struct xfs_trans_res    tres;
-       xfs_fsblock_t           firstblock;
        int                     rsvd = (flags & ATTR_ROOT) != 0;
        int                     error, err2, local;
 
@@ -225,12 +212,10 @@ xfs_attr_set(
 
        args.value = value;
        args.valuelen = valuelen;
-       args.firstblock = &firstblock;
-       args.dfops = &dfops;
        args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
        args.total = xfs_attr_calc_size(&args, &local);
 
-       error = xfs_qm_dqattach(dp, 0);
+       error = xfs_qm_dqattach(dp);
        if (error)
                return error;
 
@@ -321,25 +306,31 @@ xfs_attr_set(
                 * It won't fit in the shortform, transform to a leaf block.
                 * GROT: another possible req'mt for a double-split btree op.
                 */
-               xfs_defer_init(args.dfops, args.firstblock);
-               error = xfs_attr_shortform_to_leaf(&args);
-               if (!error)
-                       error = xfs_defer_finish(&args.trans, args.dfops, dp);
-               if (error) {
-                       args.trans = NULL;
-                       xfs_defer_cancel(&dfops);
+               error = xfs_attr_shortform_to_leaf(&args, &leaf_bp);
+               if (error)
+                       goto out;
+               /*
+                * Prevent the leaf buffer from being unlocked so that a
+                * concurrent AIL push cannot grab the half-baked leaf
+                * buffer and run into problems with the write verifier.
+                */
+               xfs_trans_bhold(args.trans, leaf_bp);
+               xfs_defer_bjoin(args.trans->t_dfops, leaf_bp);
+               xfs_defer_ijoin(args.trans->t_dfops, dp);
+               error = xfs_defer_finish(&args.trans, args.trans->t_dfops);
+               if (error)
                        goto out;
-               }
 
                /*
                 * Commit the leaf transformation.  We'll need another (linked)
-                * transaction to add the new attribute to the leaf.
+                * transaction to add the new attribute to the leaf, which
+                * means that we have to hold & join the leaf buffer here too.
                 */
-
-               error = xfs_trans_roll(&args.trans, dp);
+               error = xfs_trans_roll_inode(&args.trans, dp);
                if (error)
                        goto out;
-
+               xfs_trans_bjoin(args.trans, leaf_bp);
+               leaf_bp = NULL;
        }
 
        if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
@@ -369,6 +360,8 @@ xfs_attr_set(
        return error;
 
 out:
+       if (leaf_bp)
+               xfs_trans_brelse(args.trans, leaf_bp);
        if (args.trans)
                xfs_trans_cancel(args.trans);
        xfs_iunlock(dp, XFS_ILOCK_EXCL);
@@ -387,8 +380,6 @@ xfs_attr_remove(
 {
        struct xfs_mount        *mp = dp->i_mount;
        struct xfs_da_args      args;
-       struct xfs_defer_ops    dfops;
-       xfs_fsblock_t           firstblock;
        int                     error;
 
        XFS_STATS_INC(mp, xs_attr_remove);
@@ -400,9 +391,6 @@ xfs_attr_remove(
        if (error)
                return error;
 
-       args.firstblock = &firstblock;
-       args.dfops = &dfops;
-
        /*
         * we have no control over the attribute names that userspace passes us
         * to remove, so we have to allow the name lookup prior to attribute
@@ -410,7 +398,7 @@ xfs_attr_remove(
         */
        args.op_flags = XFS_DA_OP_OKNOENT;
 
-       error = xfs_qm_dqattach(dp, 0);
+       error = xfs_qm_dqattach(dp);
        if (error)
                return error;
 
@@ -494,7 +482,14 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
                if (args->flags & ATTR_CREATE)
                        return retval;
                retval = xfs_attr_shortform_remove(args);
-               ASSERT(retval == 0);
+               if (retval)
+                       return retval;
+               /*
+                * Since we have removed the old attr, clear ATTR_REPLACE so
+                * that the leaf format add routine won't trip over the attr
+                * not being around.
+                */
+               args->flags &= ~ATTR_REPLACE;
        }
 
        if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
@@ -524,11 +519,12 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
  * if bmap_one_block() says there is only one block (ie: no remote blks).
  */
 STATIC int
-xfs_attr_leaf_addname(xfs_da_args_t *args)
+xfs_attr_leaf_addname(
+       struct xfs_da_args      *args)
 {
-       xfs_inode_t *dp;
-       struct xfs_buf *bp;
-       int retval, error, forkoff;
+       struct xfs_inode        *dp;
+       struct xfs_buf          *bp;
+       int                     retval, error, forkoff;
 
        trace_xfs_attr_leaf_addname(args);
 
@@ -586,21 +582,19 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
                 * Commit that transaction so that the node_addname() call
                 * can manage its own transactions.
                 */
-               xfs_defer_init(args->dfops, args->firstblock);
                error = xfs_attr3_leaf_to_node(args);
-               if (!error)
-                       error = xfs_defer_finish(&args->trans, args->dfops, dp);
-               if (error) {
-                       args->trans = NULL;
-                       xfs_defer_cancel(args->dfops);
-                       return error;
-               }
+               if (error)
+                       goto out_defer_cancel;
+               xfs_defer_ijoin(args->trans->t_dfops, dp);
+               error = xfs_defer_finish(&args->trans, args->trans->t_dfops);
+               if (error)
+                       goto out_defer_cancel;
 
                /*
                 * Commit the current trans (including the inode) and start
                 * a new one.
                 */
-               error = xfs_trans_roll(&args->trans, dp);
+               error = xfs_trans_roll_inode(&args->trans, dp);
                if (error)
                        return error;
 
@@ -615,7 +609,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
         * Commit the transaction that added the attr name so that
         * later routines can manage their own transactions.
         */
-       error = xfs_trans_roll(&args->trans, dp);
+       error = xfs_trans_roll_inode(&args->trans, dp);
        if (error)
                return error;
 
@@ -676,23 +670,20 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
                 * If the result is small enough, shrink it all into the inode.
                 */
                if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
-                       xfs_defer_init(args->dfops, args->firstblock);
                        error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
                        /* bp is gone due to xfs_da_shrink_inode */
-                       if (!error)
-                               error = xfs_defer_finish(&args->trans,
-                                                       args->dfops, dp);
-                       if (error) {
-                               args->trans = NULL;
-                               xfs_defer_cancel(args->dfops);
-                               return error;
-                       }
+                       if (error)
+                               goto out_defer_cancel;
+                       xfs_defer_ijoin(args->trans->t_dfops, dp);
+                       error = xfs_defer_finish(&args->trans, args->trans->t_dfops);
+                       if (error)
+                               goto out_defer_cancel;
                }
 
                /*
                 * Commit the remove and start the next trans in series.
                 */
-               error = xfs_trans_roll(&args->trans, dp);
+               error = xfs_trans_roll_inode(&args->trans, dp);
 
        } else if (args->rmtblkno > 0) {
                /*
@@ -701,6 +692,9 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
                error = xfs_attr3_leaf_clearflag(args);
        }
        return error;
+out_defer_cancel:
+       xfs_defer_cancel(args->trans->t_dfops);
+       return error;
 }
 
 /*
@@ -710,11 +704,12 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
  * if bmap_one_block() says there is only one block (ie: no remote blks).
  */
 STATIC int
-xfs_attr_leaf_removename(xfs_da_args_t *args)
+xfs_attr_leaf_removename(
+       struct xfs_da_args      *args)
 {
-       xfs_inode_t *dp;
-       struct xfs_buf *bp;
-       int error, forkoff;
+       struct xfs_inode        *dp;
+       struct xfs_buf          *bp;
+       int                     error, forkoff;
 
        trace_xfs_attr_leaf_removename(args);
 
@@ -739,18 +734,19 @@ xfs_attr_leaf_removename(xfs_da_args_t *args)
         * If the result is small enough, shrink it all into the inode.
         */
        if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
-               xfs_defer_init(args->dfops, args->firstblock);
                error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
                /* bp is gone due to xfs_da_shrink_inode */
-               if (!error)
-                       error = xfs_defer_finish(&args->trans, args->dfops, dp);
-               if (error) {
-                       args->trans = NULL;
-                       xfs_defer_cancel(args->dfops);
-                       return error;
-               }
+               if (error)
+                       goto out_defer_cancel;
+               xfs_defer_ijoin(args->trans->t_dfops, dp);
+               error = xfs_defer_finish(&args->trans, args->trans->t_dfops);
+               if (error)
+                       goto out_defer_cancel;
        }
        return 0;
+out_defer_cancel:
+       xfs_defer_cancel(args->trans->t_dfops);
+       return error;
 }
 
 /*
@@ -800,13 +796,14 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
  * add a whole extra layer of confusion on top of that.
  */
 STATIC int
-xfs_attr_node_addname(xfs_da_args_t *args)
+xfs_attr_node_addname(
+       struct xfs_da_args      *args)
 {
-       xfs_da_state_t *state;
-       xfs_da_state_blk_t *blk;
-       xfs_inode_t *dp;
-       xfs_mount_t *mp;
-       int retval, error;
+       struct xfs_da_state     *state;
+       struct xfs_da_state_blk *blk;
+       struct xfs_inode        *dp;
+       struct xfs_mount        *mp;
+       int                     retval, error;
 
        trace_xfs_attr_node_addname(args);
 
@@ -865,22 +862,20 @@ restart:
                         */
                        xfs_da_state_free(state);
                        state = NULL;
-                       xfs_defer_init(args->dfops, args->firstblock);
                        error = xfs_attr3_leaf_to_node(args);
-                       if (!error)
-                               error = xfs_defer_finish(&args->trans,
-                                                       args->dfops, dp);
-                       if (error) {
-                               args->trans = NULL;
-                               xfs_defer_cancel(args->dfops);
-                               goto out;
-                       }
+                       if (error)
+                               goto out_defer_cancel;
+                       xfs_defer_ijoin(args->trans->t_dfops, dp);
+                       error = xfs_defer_finish(&args->trans,
+                                                args->trans->t_dfops);
+                       if (error)
+                               goto out_defer_cancel;
 
                        /*
                         * Commit the node conversion and start the next
                         * trans in the chain.
                         */
-                       error = xfs_trans_roll(&args->trans, dp);
+                       error = xfs_trans_roll_inode(&args->trans, dp);
                        if (error)
                                goto out;
 
@@ -893,15 +888,13 @@ restart:
                 * in the index/blkno/rmtblkno/rmtblkcnt fields and
                 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
                 */
-               xfs_defer_init(args->dfops, args->firstblock);
                error = xfs_da3_split(state);
-               if (!error)
-                       error = xfs_defer_finish(&args->trans, args->dfops, dp);
-               if (error) {
-                       args->trans = NULL;
-                       xfs_defer_cancel(args->dfops);
-                       goto out;
-               }
+               if (error)
+                       goto out_defer_cancel;
+               xfs_defer_ijoin(args->trans->t_dfops, dp);
+               error = xfs_defer_finish(&args->trans, args->trans->t_dfops);
+               if (error)
+                       goto out_defer_cancel;
        } else {
                /*
                 * Addition succeeded, update Btree hashvals.
@@ -920,7 +913,7 @@ restart:
         * Commit the leaf addition or btree split and start the next
         * trans in the chain.
         */
-       error = xfs_trans_roll(&args->trans, dp);
+       error = xfs_trans_roll_inode(&args->trans, dp);
        if (error)
                goto out;
 
@@ -992,22 +985,19 @@ restart:
                 * Check to see if the tree needs to be collapsed.
                 */
                if (retval && (state->path.active > 1)) {
-                       xfs_defer_init(args->dfops, args->firstblock);
                        error = xfs_da3_join(state);
-                       if (!error)
-                               error = xfs_defer_finish(&args->trans,
-                                                       args->dfops, dp);
-                       if (error) {
-                               args->trans = NULL;
-                               xfs_defer_cancel(args->dfops);
-                               goto out;
-                       }
+                       if (error)
+                               goto out_defer_cancel;
+                       xfs_defer_ijoin(args->trans->t_dfops, dp);
+                       error = xfs_defer_finish(&args->trans, args->trans->t_dfops);
+                       if (error)
+                               goto out_defer_cancel;
                }
 
                /*
                 * Commit and start the next trans in the chain.
                 */
-               error = xfs_trans_roll(&args->trans, dp);
+               error = xfs_trans_roll_inode(&args->trans, dp);
                if (error)
                        goto out;
 
@@ -1027,6 +1017,9 @@ out:
        if (error)
                return error;
        return retval;
+out_defer_cancel:
+       xfs_defer_cancel(args->trans->t_dfops);
+       goto out;
 }
 
 /*
@@ -1037,13 +1030,14 @@ out:
  * the root node (a special case of an intermediate node).
  */
 STATIC int
-xfs_attr_node_removename(xfs_da_args_t *args)
+xfs_attr_node_removename(
+       struct xfs_da_args      *args)
 {
-       xfs_da_state_t *state;
-       xfs_da_state_blk_t *blk;
-       xfs_inode_t *dp;
-       struct xfs_buf *bp;
-       int retval, error, forkoff;
+       struct xfs_da_state     *state;
+       struct xfs_da_state_blk *blk;
+       struct xfs_inode        *dp;
+       struct xfs_buf          *bp;
+       int                     retval, error, forkoff;
 
        trace_xfs_attr_node_removename(args);
 
@@ -1115,19 +1109,17 @@ xfs_attr_node_removename(xfs_da_args_t *args)
         * Check to see if the tree needs to be collapsed.
         */
        if (retval && (state->path.active > 1)) {
-               xfs_defer_init(args->dfops, args->firstblock);
                error = xfs_da3_join(state);
-               if (!error)
-                       error = xfs_defer_finish(&args->trans, args->dfops, dp);
-               if (error) {
-                       args->trans = NULL;
-                       xfs_defer_cancel(args->dfops);
-                       goto out;
-               }
+               if (error)
+                       goto out_defer_cancel;
+               xfs_defer_ijoin(args->trans->t_dfops, dp);
+               error = xfs_defer_finish(&args->trans, args->trans->t_dfops);
+               if (error)
+                       goto out_defer_cancel;
                /*
                 * Commit the Btree join operation and start a new trans.
                 */
-               error = xfs_trans_roll(&args->trans, dp);
+               error = xfs_trans_roll_inode(&args->trans, dp);
                if (error)
                        goto out;
        }
@@ -1148,17 +1140,14 @@ xfs_attr_node_removename(xfs_da_args_t *args)
                        goto out;
 
                if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
-                       xfs_defer_init(args->dfops, args->firstblock);
                        error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
                        /* bp is gone due to xfs_da_shrink_inode */
-                       if (!error)
-                               error = xfs_defer_finish(&args->trans,
-                                                       args->dfops, dp);
-                       if (error) {
-                               args->trans = NULL;
-                               xfs_defer_cancel(args->dfops);
-                               goto out;
-                       }
+                       if (error)
+                               goto out_defer_cancel;
+                       xfs_defer_ijoin(args->trans->t_dfops, dp);
+                       error = xfs_defer_finish(&args->trans, args->trans->t_dfops);
+                       if (error)
+                               goto out_defer_cancel;
                } else
                        xfs_trans_brelse(args->trans, bp);
        }
@@ -1167,6 +1156,9 @@ xfs_attr_node_removename(xfs_da_args_t *args)
 out:
        xfs_da_state_free(state);
        return error;
+out_defer_cancel:
+       xfs_defer_cancel(args->trans->t_dfops);
+       goto out;
 }
 
 /*