OSDN Git Service

xfs: allow merging ioends over append boundaries
authorChristoph Hellwig <hch@lst.de>
Sat, 29 Jun 2019 02:31:37 +0000 (19:31 -0700)
committerDarrick J. Wong <darrick.wong@oracle.com>
Sun, 30 Jun 2019 16:05:17 +0000 (09:05 -0700)
There is no real problem merging ioends that go beyond i_size into an
ioend that doesn't.  We just need to move the append transaction to the
base ioend.  Also use the opportunity to use a real error code instead
of the magic 1 to cancel the transactions, and write a comment
explaining the scheme.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
fs/xfs/xfs_aops.c

index 1d147ef..84fca91 100644 (file)
@@ -300,11 +300,28 @@ xfs_ioend_can_merge(
                return false;
        if (ioend->io_offset + ioend->io_size != next->io_offset)
                return false;
-       if (xfs_ioend_is_append(ioend) != xfs_ioend_is_append(next))
-               return false;
        return true;
 }
 
+/*
+ * If the to be merged ioend has a preallocated transaction for file
+ * size updates we need to ensure the ioend it is merged into also
+ * has one.  If it already has one we can simply cancel the transaction
+ * as it is guaranteed to be clean.
+ */
+static void
+xfs_ioend_merge_append_transactions(
+       struct xfs_ioend        *ioend,
+       struct xfs_ioend        *next)
+{
+       if (!ioend->io_append_trans) {
+               ioend->io_append_trans = next->io_append_trans;
+               next->io_append_trans = NULL;
+       } else {
+               xfs_setfilesize_ioend(next, -ECANCELED);
+       }
+}
+
 /* Try to merge adjacent completions. */
 STATIC void
 xfs_ioend_try_merge(
@@ -313,7 +330,6 @@ xfs_ioend_try_merge(
 {
        struct xfs_ioend        *next_ioend;
        int                     ioend_error;
-       int                     error;
 
        if (list_empty(more_ioends))
                return;
@@ -327,10 +343,8 @@ xfs_ioend_try_merge(
                        break;
                list_move_tail(&next_ioend->io_list, &ioend->io_list);
                ioend->io_size += next_ioend->io_size;
-               if (ioend->io_append_trans) {
-                       error = xfs_setfilesize_ioend(next_ioend, 1);
-                       ASSERT(error == 1);
-               }
+               if (next_ioend->io_append_trans)
+                       xfs_ioend_merge_append_transactions(ioend, next_ioend);
        }
 }