]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - libxfs/xfs_attr.c
libxfs: refactor manage_zones()
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_attr.c
index 0002c3ed82dd9badf588c422ac64d8f359459251..95f040b8d61f723fc9e64a659ca14bebce87bf01 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"
@@ -198,6 +186,128 @@ xfs_attr_calc_size(
        return nblks;
 }
 
+STATIC int
+xfs_attr_try_sf_addname(
+       struct xfs_inode        *dp,
+       struct xfs_da_args      *args)
+{
+
+       struct xfs_mount        *mp = dp->i_mount;
+       int                     error, error2;
+
+       error = xfs_attr_shortform_addname(args);
+       if (error == -ENOSPC)
+               return error;
+
+       /*
+        * Commit the shortform mods, and we're done.
+        * NOTE: this is also the error path (EEXIST, etc).
+        */
+       if (!error && (args->flags & ATTR_KERNOTIME) == 0)
+               xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
+
+       if (mp->m_flags & XFS_MOUNT_WSYNC)
+               xfs_trans_set_sync(args->trans);
+
+       error2 = xfs_trans_commit(args->trans);
+       args->trans = NULL;
+       return error ? error : error2;
+}
+
+/*
+ * Set the attribute specified in @args.
+ */
+int
+xfs_attr_set_args(
+       struct xfs_da_args      *args,
+       struct xfs_buf          **leaf_bp)
+{
+       struct xfs_inode        *dp = args->dp;
+       int                     error;
+
+       /*
+        * 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)) {
+
+               /*
+                * Build initial attribute list (if required).
+                */
+               if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
+                       xfs_attr_shortform_create(args);
+
+               /*
+                * Try to add the attr to the attribute list in the inode.
+                */
+               error = xfs_attr_try_sf_addname(dp, args);
+               if (error != -ENOSPC)
+                       return error;
+
+               /*
+                * It won't fit in the shortform, transform to a leaf block.
+                * GROT: another possible req'mt for a double-split btree op.
+                */
+               error = xfs_attr_shortform_to_leaf(args, leaf_bp);
+               if (error)
+                       return error;
+
+               /*
+                * 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);
+
+               error = xfs_defer_finish(&args->trans);
+               if (error)
+                       return error;
+
+               /*
+                * Commit the leaf transformation.  We'll need another
+                * (linked) transaction to add the new attribute to the
+                * leaf.
+                */
+               error = xfs_trans_roll_inode(&args->trans, dp);
+               if (error)
+                       return error;
+               xfs_trans_bjoin(args->trans, *leaf_bp);
+               *leaf_bp = NULL;
+       }
+
+       if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
+               error = xfs_attr_leaf_addname(args);
+       else
+               error = xfs_attr_node_addname(args);
+       return error;
+}
+
+/*
+ * Remove the attribute specified in @args.
+ */
+int
+xfs_attr_remove_args(
+       struct xfs_da_args      *args)
+{
+       struct xfs_inode        *dp = args->dp;
+       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_remove(args);
+       } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+               error = xfs_attr_leaf_removename(args);
+       } else {
+               error = xfs_attr_node_removename(args);
+       }
+
+       return error;
+}
+
 int
 xfs_attr_set(
        struct xfs_inode        *dp,
@@ -209,11 +319,9 @@ xfs_attr_set(
        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;
+       int                     error, local;
 
        XFS_STATS_INC(mp, xs_attr_set);
 
@@ -226,12 +334,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;
 
@@ -266,96 +372,17 @@ xfs_attr_set(
        error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0,
                                rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
                                       XFS_QMOPT_RES_REGBLKS);
-       if (error) {
-               xfs_iunlock(dp, XFS_ILOCK_EXCL);
-               xfs_trans_cancel(args.trans);
-               return error;
-       }
+       if (error)
+               goto out_trans_cancel;
 
        xfs_trans_ijoin(args.trans, dp, 0);
-
-       /*
-        * 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)) {
-
-               /*
-                * Build initial attribute list (if required).
-                */
-               if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
-                       xfs_attr_shortform_create(&args);
-
-               /*
-                * Try to add the attr to the attribute list in
-                * the inode.
-                */
-               error = xfs_attr_shortform_addname(&args);
-               if (error != -ENOSPC) {
-                       /*
-                        * Commit the shortform mods, and we're done.
-                        * NOTE: this is also the error path (EEXIST, etc).
-                        */
-                       ASSERT(args.trans != NULL);
-
-                       /*
-                        * 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)
-                               xfs_trans_set_sync(args.trans);
-
-                       if (!error && (flags & ATTR_KERNOTIME) == 0) {
-                               xfs_trans_ichgtime(args.trans, dp,
-                                                       XFS_ICHGTIME_CHG);
-                       }
-                       err2 = xfs_trans_commit(args.trans);
-                       xfs_iunlock(dp, XFS_ILOCK_EXCL);
-
-                       return error ? error : err2;
-               }
-
-               /*
-                * 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, &leaf_bp);
-               if (error)
-                       goto out_defer_cancel;
-               /*
-                * 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.dfops, leaf_bp);
-               xfs_defer_ijoin(args.dfops, dp);
-               error = xfs_defer_finish(&args.trans, args.dfops);
-               if (error)
-                       goto out_defer_cancel;
-
-               /*
-                * Commit the leaf transformation.  We'll need another (linked)
-                * 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_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))
-               error = xfs_attr_leaf_addname(&args);
-       else
-               error = xfs_attr_node_addname(&args);
+       error = xfs_attr_set_args(&args, &leaf_bp);
        if (error)
-               goto out;
+               goto out_release_leaf;
+       if (!args.trans) {
+               /* shortform attribute has already been committed */
+               goto out_unlock;
+       }
 
        /*
         * If this is a synchronous mount, make sure that the
@@ -372,19 +399,17 @@ xfs_attr_set(
         */
        xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
        error = xfs_trans_commit(args.trans);
+out_unlock:
        xfs_iunlock(dp, XFS_ILOCK_EXCL);
-
        return error;
 
-out_defer_cancel:
-       xfs_defer_cancel(&dfops);
-out:
+out_release_leaf:
        if (leaf_bp)
                xfs_trans_brelse(args.trans, leaf_bp);
+out_trans_cancel:
        if (args.trans)
                xfs_trans_cancel(args.trans);
-       xfs_iunlock(dp, XFS_ILOCK_EXCL);
-       return error;
+       goto out_unlock;
 }
 
 /*
@@ -399,8 +424,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);
@@ -412,9 +435,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
@@ -422,7 +442,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;
 
@@ -444,17 +464,7 @@ xfs_attr_remove(
         */
        xfs_trans_ijoin(args.trans, dp, 0);
 
-       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_remove(&args);
-       } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
-               error = xfs_attr_leaf_removename(&args);
-       } else {
-               error = xfs_attr_node_removename(&args);
-       }
-
+       error = xfs_attr_remove_args(&args);
        if (error)
                goto out;
 
@@ -543,11 +553,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);
 
@@ -605,14 +616,12 @@ 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)
-                       goto out_defer_cancel;
-               xfs_defer_ijoin(args->dfops, dp);
-               error = xfs_defer_finish(&args->trans, args->dfops);
+                       return error;
+               error = xfs_defer_finish(&args->trans);
                if (error)
-                       goto out_defer_cancel;
+                       return error;
 
                /*
                 * Commit the current trans (including the inode) and start
@@ -694,15 +703,13 @@ 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)
-                               goto out_defer_cancel;
-                       xfs_defer_ijoin(args->dfops, dp);
-                       error = xfs_defer_finish(&args->trans, args->dfops);
+                               return error;
+                       error = xfs_defer_finish(&args->trans);
                        if (error)
-                               goto out_defer_cancel;
+                               return error;
                }
 
                /*
@@ -717,9 +724,6 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
                error = xfs_attr3_leaf_clearflag(args);
        }
        return error;
-out_defer_cancel:
-       xfs_defer_cancel(args->dfops);
-       return error;
 }
 
 /*
@@ -729,11 +733,12 @@ out_defer_cancel:
  * 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);
 
@@ -758,20 +763,15 @@ 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)
-                       goto out_defer_cancel;
-               xfs_defer_ijoin(args->dfops, dp);
-               error = xfs_defer_finish(&args->trans, args->dfops);
+                       return error;
+               error = xfs_defer_finish(&args->trans);
                if (error)
-                       goto out_defer_cancel;
+                       return error;
        }
        return 0;
-out_defer_cancel:
-       xfs_defer_cancel(args->dfops);
-       return error;
 }
 
 /*
@@ -821,13 +821,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);
 
@@ -886,14 +887,12 @@ restart:
                         */
                        xfs_da_state_free(state);
                        state = NULL;
-                       xfs_defer_init(args->dfops, args->firstblock);
                        error = xfs_attr3_leaf_to_node(args);
                        if (error)
-                               goto out_defer_cancel;
-                       xfs_defer_ijoin(args->dfops, dp);
-                       error = xfs_defer_finish(&args->trans, args->dfops);
+                               goto out;
+                       error = xfs_defer_finish(&args->trans);
                        if (error)
-                               goto out_defer_cancel;
+                               goto out;
 
                        /*
                         * Commit the node conversion and start the next
@@ -912,14 +911,12 @@ 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)
-                       goto out_defer_cancel;
-               xfs_defer_ijoin(args->dfops, dp);
-               error = xfs_defer_finish(&args->trans, args->dfops);
+                       goto out;
+               error = xfs_defer_finish(&args->trans);
                if (error)
-                       goto out_defer_cancel;
+                       goto out;
        } else {
                /*
                 * Addition succeeded, update Btree hashvals.
@@ -1010,14 +1007,12 @@ 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)
-                               goto out_defer_cancel;
-                       xfs_defer_ijoin(args->dfops, dp);
-                       error = xfs_defer_finish(&args->trans, args->dfops);
+                               goto out;
+                       error = xfs_defer_finish(&args->trans);
                        if (error)
-                               goto out_defer_cancel;
+                               goto out;
                }
 
                /*
@@ -1043,9 +1038,6 @@ out:
        if (error)
                return error;
        return retval;
-out_defer_cancel:
-       xfs_defer_cancel(args->dfops);
-       goto out;
 }
 
 /*
@@ -1056,13 +1048,14 @@ out_defer_cancel:
  * 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);
 
@@ -1134,14 +1127,12 @@ 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)
-                       goto out_defer_cancel;
-               xfs_defer_ijoin(args->dfops, dp);
-               error = xfs_defer_finish(&args->trans, args->dfops);
+                       goto out;
+               error = xfs_defer_finish(&args->trans);
                if (error)
-                       goto out_defer_cancel;
+                       goto out;
                /*
                 * Commit the Btree join operation and start a new trans.
                 */
@@ -1166,15 +1157,13 @@ 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)
-                               goto out_defer_cancel;
-                       xfs_defer_ijoin(args->dfops, dp);
-                       error = xfs_defer_finish(&args->trans, args->dfops);
+                               goto out;
+                       error = xfs_defer_finish(&args->trans);
                        if (error)
-                               goto out_defer_cancel;
+                               goto out;
                } else
                        xfs_trans_brelse(args->trans, bp);
        }
@@ -1183,9 +1172,6 @@ xfs_attr_node_removename(xfs_da_args_t *args)
 out:
        xfs_da_state_free(state);
        return error;
-out_defer_cancel:
-       xfs_defer_cancel(args->dfops);
-       goto out;
 }
 
 /*