]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: relog dirty buffers during swapext bmbt owner change
authorBrian Foster <bfoster@redhat.com>
Wed, 18 Oct 2017 18:39:01 +0000 (13:39 -0500)
committerEric Sandeen <sandeen@redhat.com>
Wed, 18 Oct 2017 18:39:01 +0000 (13:39 -0500)
Source kernel commit: 2dd3d709fc4338681a3aa61658122fa8faa5a437

The owner change bmbt scan that occurs during extent swap operations
does not handle ordered buffer failures. Buffers that cannot be
marked ordered must be physically logged so previously dirty ranges
of the buffer can be relogged in the transaction.

Since the bmbt scan may need to process and potentially log a large
number of blocks, we can't expect to complete this operation in a
single transaction. Update extent swap to use a permanent
transaction with enough log reservation to physically log a buffer.
Update the bmbt scan to physically log any buffers that cannot be
ordered and to terminate the scan with -EAGAIN. On -EAGAIN, the
caller rolls the transaction and restarts the scan. Finally, update
the bmbt scan helper function to skip bmbt blocks that already match
the expected owner so they are not reprocessed after scan restarts.

Signed-off-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
[darrick: fix the xfs_trans_roll call]
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
[dchinner: proper userspace libxfs_trans_ordered_buf]
Signed-off-by: Eric Sandeen <sandeen@sandeen.net>
include/xfs_trans.h
libxfs/libxfs_api_defs.h
libxfs/libxfs_priv.h
libxfs/trans.c
libxfs/xfs_btree.c

index 59659843a04191f0742ca6059725fc2bb0d5ddfe..22931cd3f3a0d871ab880ff9001201a0f8d3b67c 100644 (file)
@@ -109,6 +109,7 @@ void        libxfs_trans_bjoin(struct xfs_trans *, struct xfs_buf *);
 void   libxfs_trans_bhold(struct xfs_trans *, struct xfs_buf *);
 void   libxfs_trans_log_buf(struct xfs_trans *, struct xfs_buf *,
                                uint, uint);
+bool   libxfs_trans_ordered_buf(xfs_trans_t *, struct xfs_buf *);
 
 struct xfs_buf *libxfs_trans_get_buf_map(struct xfs_trans *tp,
                                        struct xfs_buftarg *btp,
index 9c1279b1e76700c60814ed8479d01c73f0fcef45..84a4fc25ec1d741a1fe4748fbbf28b6920344b0b 100644 (file)
@@ -50,6 +50,7 @@
 #define xfs_trans_init                 libxfs_trans_init
 #define xfs_trans_inode_alloc_buf      libxfs_trans_inode_alloc_buf
 #define xfs_trans_log_buf              libxfs_trans_log_buf
+#define xfs_trans_ordered_buf          libxfs_trans_ordered_buf
 #define xfs_trans_log_inode            libxfs_trans_log_inode
 #define xfs_trans_roll_inode           libxfs_trans_roll_inode
 #define xfs_trans_mod_sb               libxfs_trans_mod_sb
index 812ce88c93f5e8dfdd4490e229568bc61f7f35d3..cba213a79d1340fab6d08b8e287971f03bde0768 100644 (file)
@@ -342,7 +342,6 @@ roundup_64(uint64_t x, uint32_t y)
 
 
 #define xfs_trans_set_sync(tp)         ((void) 0)
-#define xfs_trans_ordered_buf(tp, bp)  ((void) 0)
 #define        xfs_trans_agblocks_delta(tp, d)
 #define        xfs_trans_agflist_delta(tp, d)
 #define        xfs_trans_agbtree_delta(tp, d)
index bc708c2765da1dff64b289f1a7f0a734e64d9f35..3d6de982efe543eddb3c916efae29d0893691e58 100644 (file)
@@ -388,6 +388,26 @@ libxfs_trans_log_buf(
        xfs_buf_item_log(bip, first, last);
 }
 
+/*
+ * For userspace, ordered buffers just need to be marked dirty so
+ * the transaction commit will write them and mark them up-to-date.
+ * In essence, they are just like any other logged buffer in userspace.
+ *
+ * If the buffer is already dirty, trigger the "already logged" return condition.
+ */
+bool
+libxfs_trans_ordered_buf(
+       struct xfs_trans        *tp,
+       struct xfs_buf          *bp)
+{
+       struct xfs_buf_log_item *bip = bp->b_fspriv;
+       bool                    ret;
+
+       ret = (bip->bli_item.li_desc->lid_flags & XFS_LID_DIRTY);
+       libxfs_trans_log_buf(tp, bp, 0, bp->b_bcount);
+       return ret;
+}
+
 void
 libxfs_trans_brelse(
        xfs_trans_t             *tp,
index 5244bf1c07b8018b0702b87eb7651c55251be43d..5f96020efc919d1b3d3e63f97918c2238ef4f8ba 100644 (file)
@@ -4452,10 +4452,15 @@ xfs_btree_block_change_owner(
 
        /* modify the owner */
        block = xfs_btree_get_block(cur, level, &bp);
-       if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
+       if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
+               if (block->bb_u.l.bb_owner == cpu_to_be64(bbcoi->new_owner))
+                       return 0;
                block->bb_u.l.bb_owner = cpu_to_be64(bbcoi->new_owner);
-       else
+       } else {
+               if (block->bb_u.s.bb_owner == cpu_to_be32(bbcoi->new_owner))
+                       return 0;
                block->bb_u.s.bb_owner = cpu_to_be32(bbcoi->new_owner);
+       }
 
        /*
         * If the block is a root block hosted in an inode, we might not have a
@@ -4464,14 +4469,19 @@ xfs_btree_block_change_owner(
         * block is formatted into the on-disk inode fork. We still change it,
         * though, so everything is consistent in memory.
         */
-       if (bp) {
-               if (cur->bc_tp)
-                       xfs_trans_ordered_buf(cur->bc_tp, bp);
-               else
-                       xfs_buf_delwri_queue(bp, bbcoi->buffer_list);
-       } else {
+       if (!bp) {
                ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
                ASSERT(level == cur->bc_nlevels - 1);
+               return 0;
+       }
+
+       if (cur->bc_tp) {
+               if (!xfs_trans_ordered_buf(cur->bc_tp, bp)) {
+                       xfs_btree_log_block(cur, bp, XFS_BB_OWNER);
+                       return -EAGAIN;
+               }
+       } else {
+               xfs_buf_delwri_queue(bp, bbcoi->buffer_list);
        }
 
        return 0;