From: Brian Foster Date: Wed, 18 Oct 2017 18:39:01 +0000 (-0500) Subject: xfs: relog dirty buffers during swapext bmbt owner change X-Git-Tag: v4.14.0-rc1~36 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=38fa71a753bea4226273e80ad1dff16027ef7591;p=thirdparty%2Fxfsprogs-dev.git xfs: relog dirty buffers during swapext bmbt owner change 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 Reviewed-by: Darrick J. Wong Reviewed-by: Christoph Hellwig [darrick: fix the xfs_trans_roll call] Signed-off-by: Darrick J. Wong [dchinner: proper userspace libxfs_trans_ordered_buf] Signed-off-by: Eric Sandeen --- diff --git a/include/xfs_trans.h b/include/xfs_trans.h index 59659843a..22931cd3f 100644 --- a/include/xfs_trans.h +++ b/include/xfs_trans.h @@ -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, diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h index 9c1279b1e..84a4fc25e 100644 --- a/libxfs/libxfs_api_defs.h +++ b/libxfs/libxfs_api_defs.h @@ -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 diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h index 812ce88c9..cba213a79 100644 --- a/libxfs/libxfs_priv.h +++ b/libxfs/libxfs_priv.h @@ -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) diff --git a/libxfs/trans.c b/libxfs/trans.c index bc708c276..3d6de982e 100644 --- a/libxfs/trans.c +++ b/libxfs/trans.c @@ -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, diff --git a/libxfs/xfs_btree.c b/libxfs/xfs_btree.c index 5244bf1c0..5f96020ef 100644 --- a/libxfs/xfs_btree.c +++ b/libxfs/xfs_btree.c @@ -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;