summaryrefslogtreecommitdiffstats
path: root/fs/xfs/libxfs/xfs_btree.c
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2017-08-29 19:08:40 +0200
committerDarrick J. Wong <darrick.wong@oracle.com>2017-09-01 19:55:30 +0200
commit2dd3d709fc4338681a3aa61658122fa8faa5a437 (patch)
tree3f93d0d040996d5042ec3735df553c038b065ee4 /fs/xfs/libxfs/xfs_btree.c
parentxfs: disallow marking previously dirty buffers as ordered (diff)
downloadlinux-2dd3d709fc4338681a3aa61658122fa8faa5a437.tar.xz
linux-2dd3d709fc4338681a3aa61658122fa8faa5a437.zip
xfs: relog dirty buffers during swapext bmbt owner change
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>
Diffstat (limited to 'fs/xfs/libxfs/xfs_btree.c')
-rw-r--r--fs/xfs/libxfs/xfs_btree.c26
1 files changed, 18 insertions, 8 deletions
diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
index 1d15d04e29a5..5bfb88261c7e 100644
--- a/fs/xfs/libxfs/xfs_btree.c
+++ b/fs/xfs/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;