Merge tag 'for-v5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux...
[linux-2.6-microblaze.git] / fs / xfs / libxfs / xfs_attr_remote.c
index 01ad7f3..3f80ced 100644 (file)
@@ -440,32 +440,23 @@ xfs_attr_rmtval_get(
 }
 
 /*
- * Write the value associated with an attribute into the out-of-line buffer
- * that we have defined for it.
+ * Find a "hole" in the attribute address space large enough for us to drop the
+ * new attribute's value into
  */
-int
-xfs_attr_rmtval_set(
+STATIC int
+xfs_attr_rmt_find_hole(
        struct xfs_da_args      *args)
 {
        struct xfs_inode        *dp = args->dp;
        struct xfs_mount        *mp = dp->i_mount;
-       struct xfs_bmbt_irec    map;
-       xfs_dablk_t             lblkno;
-       xfs_fileoff_t           lfileoff = 0;
-       uint8_t                 *src = args->value;
-       int                     blkcnt;
-       int                     valuelen;
-       int                     nmap;
        int                     error;
-       int                     offset = 0;
-
-       trace_xfs_attr_rmtval_set(args);
+       int                     blkcnt;
+       xfs_fileoff_t           lfileoff = 0;
 
        /*
-        * Find a "hole" in the attribute address space large enough for
-        * us to drop the new attribute's value into. Because CRC enable
-        * attributes have headers, we can't just do a straight byte to FSB
-        * conversion and have to take the header space into account.
+        * Because CRC enable attributes have headers, we can't just do a
+        * straight byte to FSB conversion and have to take the header space
+        * into account.
         */
        blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
        error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
@@ -473,48 +464,26 @@ xfs_attr_rmtval_set(
        if (error)
                return error;
 
-       args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
+       args->rmtblkno = (xfs_dablk_t)lfileoff;
        args->rmtblkcnt = blkcnt;
 
-       /*
-        * Roll through the "value", allocating blocks on disk as required.
-        */
-       while (blkcnt > 0) {
-               /*
-                * Allocate a single extent, up to the size of the value.
-                *
-                * Note that we have to consider this a data allocation as we
-                * write the remote attribute without logging the contents.
-                * Hence we must ensure that we aren't using blocks that are on
-                * the busy list so that we don't overwrite blocks which have
-                * recently been freed but their transactions are not yet
-                * committed to disk. If we overwrite the contents of a busy
-                * extent and then crash then the block may not contain the
-                * correct metadata after log recovery occurs.
-                */
-               nmap = 1;
-               error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
-                                 blkcnt, XFS_BMAPI_ATTRFORK, args->total, &map,
-                                 &nmap);
-               if (error)
-                       return error;
-               error = xfs_defer_finish(&args->trans);
-               if (error)
-                       return error;
-
-               ASSERT(nmap == 1);
-               ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
-                      (map.br_startblock != HOLESTARTBLOCK));
-               lblkno += map.br_blockcount;
-               blkcnt -= map.br_blockcount;
+       return 0;
+}
 
-               /*
-                * Start the next trans in the chain.
-                */
-               error = xfs_trans_roll_inode(&args->trans, dp);
-               if (error)
-                       return error;
-       }
+STATIC int
+xfs_attr_rmtval_set_value(
+       struct xfs_da_args      *args)
+{
+       struct xfs_inode        *dp = args->dp;
+       struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_bmbt_irec    map;
+       xfs_dablk_t             lblkno;
+       uint8_t                 *src = args->value;
+       int                     blkcnt;
+       int                     valuelen;
+       int                     nmap;
+       int                     error;
+       int                     offset = 0;
 
        /*
         * Roll through the "value", copying the attribute value to the
@@ -594,20 +563,83 @@ xfs_attr_rmtval_stale(
        return 0;
 }
 
+/*
+ * Write the value associated with an attribute into the out-of-line buffer
+ * that we have defined for it.
+ */
+int
+xfs_attr_rmtval_set(
+       struct xfs_da_args      *args)
+{
+       struct xfs_inode        *dp = args->dp;
+       struct xfs_bmbt_irec    map;
+       xfs_dablk_t             lblkno;
+       int                     blkcnt;
+       int                     nmap;
+       int                     error;
+
+       trace_xfs_attr_rmtval_set(args);
+
+       error = xfs_attr_rmt_find_hole(args);
+       if (error)
+               return error;
+
+       blkcnt = args->rmtblkcnt;
+       lblkno = (xfs_dablk_t)args->rmtblkno;
+       /*
+        * Roll through the "value", allocating blocks on disk as required.
+        */
+       while (blkcnt > 0) {
+               /*
+                * Allocate a single extent, up to the size of the value.
+                *
+                * Note that we have to consider this a data allocation as we
+                * write the remote attribute without logging the contents.
+                * Hence we must ensure that we aren't using blocks that are on
+                * the busy list so that we don't overwrite blocks which have
+                * recently been freed but their transactions are not yet
+                * committed to disk. If we overwrite the contents of a busy
+                * extent and then crash then the block may not contain the
+                * correct metadata after log recovery occurs.
+                */
+               nmap = 1;
+               error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno,
+                                 blkcnt, XFS_BMAPI_ATTRFORK, args->total, &map,
+                                 &nmap);
+               if (error)
+                       return error;
+               error = xfs_defer_finish(&args->trans);
+               if (error)
+                       return error;
+
+               ASSERT(nmap == 1);
+               ASSERT((map.br_startblock != DELAYSTARTBLOCK) &&
+                      (map.br_startblock != HOLESTARTBLOCK));
+               lblkno += map.br_blockcount;
+               blkcnt -= map.br_blockcount;
+
+               /*
+                * Start the next trans in the chain.
+                */
+               error = xfs_trans_roll_inode(&args->trans, dp);
+               if (error)
+                       return error;
+       }
+
+       return xfs_attr_rmtval_set_value(args);
+}
+
 /*
  * Remove the value associated with an attribute by deleting the
  * out-of-line buffer that it is stored on.
  */
 int
-xfs_attr_rmtval_remove(
+xfs_attr_rmtval_invalidate(
        struct xfs_da_args      *args)
 {
        xfs_dablk_t             lblkno;
        int                     blkcnt;
        int                     error;
-       int                     done;
-
-       trace_xfs_attr_rmtval_remove(args);
 
        /*
         * Roll through the "value", invalidating the attribute value's blocks.
@@ -635,21 +667,29 @@ xfs_attr_rmtval_remove(
                lblkno += map.br_blockcount;
                blkcnt -= map.br_blockcount;
        }
+       return 0;
+}
+
+/*
+ * Remove the value associated with an attribute by deleting the
+ * out-of-line buffer that it is stored on.
+ */
+int
+xfs_attr_rmtval_remove(
+       struct xfs_da_args      *args)
+{
+       int                     error;
+       int                     retval;
+
+       trace_xfs_attr_rmtval_remove(args);
 
        /*
         * Keep de-allocating extents until the remote-value region is gone.
         */
-       lblkno = args->rmtblkno;
-       blkcnt = args->rmtblkcnt;
-       done = 0;
-       while (!done) {
-               error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
-                                   XFS_BMAPI_ATTRFORK, 1, &done);
-               if (error)
-                       return error;
-               error = xfs_defer_finish(&args->trans);
-               if (error)
-                       return error;
+       do {
+               retval = __xfs_attr_rmtval_remove(args);
+               if (retval && retval != -EAGAIN)
+                       return retval;
 
                /*
                 * Close out trans and start the next one in the chain.
@@ -657,6 +697,36 @@ xfs_attr_rmtval_remove(
                error = xfs_trans_roll_inode(&args->trans, args->dp);
                if (error)
                        return error;
-       }
+       } while (retval == -EAGAIN);
+
        return 0;
 }
+
+/*
+ * Remove the value associated with an attribute by deleting the out-of-line
+ * buffer that it is stored on. Returns EAGAIN for the caller to refresh the
+ * transaction and re-call the function
+ */
+int
+__xfs_attr_rmtval_remove(
+       struct xfs_da_args      *args)
+{
+       int                     error, done;
+
+       /*
+        * Unmap value blocks for this attr.
+        */
+       error = xfs_bunmapi(args->trans, args->dp, args->rmtblkno,
+                           args->rmtblkcnt, XFS_BMAPI_ATTRFORK, 1, &done);
+       if (error)
+               return error;
+
+       error = xfs_defer_finish(&args->trans);
+       if (error)
+               return error;
+
+       if (!done)
+               return -EAGAIN;
+
+       return error;
+}