xfs: Add helpers xfs_attr_is_shortform and xfs_attr_set_shortform
authorAllison Collins <allison.henderson@oracle.com>
Tue, 21 Jul 2020 04:47:28 +0000 (21:47 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Wed, 29 Jul 2020 03:28:12 +0000 (20:28 -0700)
In this patch, we hoist code from xfs_attr_set_args into two new helpers
xfs_attr_is_shortform and xfs_attr_set_shortform.  These two will help
to simplify xfs_attr_set_args when we get into delayed attrs later.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Acked-by: Dave Chinner <dchinner@redhat.com>
fs/xfs/libxfs/xfs_attr.c

index 780af0ef6bc643ea454176923024cf768cf7647a..93a1c55cceb296491fcdfcd542509108e05f90f0 100644 (file)
@@ -203,6 +203,66 @@ xfs_attr_try_sf_addname(
        return error;
 }
 
+/*
+ * Check to see if the attr should be upgraded from non-existent or shortform to
+ * single-leaf-block attribute list.
+ */
+static inline bool
+xfs_attr_is_shortform(
+       struct xfs_inode    *ip)
+{
+       return ip->i_afp->if_format == XFS_DINODE_FMT_LOCAL ||
+              (ip->i_afp->if_format == XFS_DINODE_FMT_EXTENTS &&
+               ip->i_afp->if_nextents == 0);
+}
+
+/*
+ * Attempts to set an attr in shortform, or converts short form to leaf form if
+ * there is not enough room.  If the attr is set, the transaction is committed
+ * and set to NULL.
+ */
+STATIC int
+xfs_attr_set_shortform(
+       struct xfs_da_args      *args,
+       struct xfs_buf          **leaf_bp)
+{
+       struct xfs_inode        *dp = args->dp;
+       int                     error, error2 = 0;
+
+       /*
+        * Try to add the attr to the attribute list in the inode.
+        */
+       error = xfs_attr_try_sf_addname(dp, args);
+       if (error != -ENOSPC) {
+               error2 = xfs_trans_commit(args->trans);
+               args->trans = NULL;
+               return error ? error : error2;
+       }
+       /*
+        * 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. Once we're done rolling the transaction we
+        * can release the hold and add the attr to the leaf.
+        */
+       xfs_trans_bhold(args->trans, *leaf_bp);
+       error = xfs_defer_finish(&args->trans);
+       xfs_trans_bhold_release(args->trans, *leaf_bp);
+       if (error) {
+               xfs_trans_brelse(args->trans, *leaf_bp);
+               return error;
+       }
+
+       return 0;
+}
+
 /*
  * Set the attribute specified in @args.
  */
@@ -212,48 +272,25 @@ xfs_attr_set_args(
 {
        struct xfs_inode        *dp = args->dp;
        struct xfs_buf          *leaf_bp = NULL;
-       int                     error, error2 = 0;
+       int                     error = 0;
 
        /*
-        * If the attribute list is non-existent or a shortform list,
-        * upgrade it to a single-leaf-block attribute list.
+        * If the attribute list is already in leaf format, jump straight to
+        * leaf handling.  Otherwise, try to add the attribute to the shortform
+        * list; if there's no room then convert the list to leaf format and try
+        * again.
         */
-       if (dp->i_afp->if_format == XFS_DINODE_FMT_LOCAL ||
-           (dp->i_afp->if_format == XFS_DINODE_FMT_EXTENTS &&
-            dp->i_afp->if_nextents == 0)) {
+       if (xfs_attr_is_shortform(dp)) {
 
                /*
-                * Try to add the attr to the attribute list in the inode.
+                * If the attr was successfully set in shortform, the
+                * transaction is committed and set to NULL.  Otherwise, is it
+                * converted from shortform to leaf, and the transaction is
+                * retained.
                 */
-               error = xfs_attr_try_sf_addname(dp, args);
-               if (error != -ENOSPC) {
-                       error2 = xfs_trans_commit(args->trans);
-                       args->trans = NULL;
-                       return error ? error : error2;
-               }
-
-               /*
-                * 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.
-                * Once we're done rolling the transaction we can release
-                * the hold and add the attr to the leaf.
-                */
-               xfs_trans_bhold(args->trans, leaf_bp);
-               error = xfs_defer_finish(&args->trans);
-               xfs_trans_bhold_release(args->trans, leaf_bp);
-               if (error) {
-                       xfs_trans_brelse(args->trans, leaf_bp);
+               error = xfs_attr_set_shortform(args, &leaf_bp);
+               if (error || !args->trans)
                        return error;
-               }
        }
 
        if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {