summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFilipe Manana <fdmanana@suse.com>2016-05-14 20:44:40 +0200
committerFilipe Manana <fdmanana@suse.com>2016-05-30 13:58:24 +0200
commit1a1a8b732c7e958e6eba0680439e814efde2362d (patch)
tree1028ed1d30fbc490a1b40abbea9b35e9f364be1c
parentBtrfs: fix unprotected assignment of the left cursor for device replace (diff)
downloadlinux-1a1a8b732c7e958e6eba0680439e814efde2362d.tar.xz
linux-1a1a8b732c7e958e6eba0680439e814efde2362d.zip
Btrfs: fix race setting block group back to RW mode during device replace
After it finishes processing a device extent, the device replace code sets back the block group to RW mode and then after that it sets the left cursor to match the logical end address of the block group, so that future writes into extents belonging to the block group go both the source (old) and target (new) devices. However from the moment we turn the block group back to RW mode we have a short time window, that lasts until we update the left cursor's value, where extents can be allocated from the block group and written to, in which case they will not be copied/written to the target (new) device. Fix this by updating the left cursor's value before turning the block group back to RW mode. Signed-off-by: Filipe Manana <fdmanana@suse.com> Reviewed-by: Josef Bacik <jbacik@fb.com>
-rw-r--r--fs/btrfs/scrub.c10
1 files changed, 5 insertions, 5 deletions
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 19a1eda70361..70427ef66b04 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -3682,6 +3682,11 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
scrub_pause_off(fs_info);
+ btrfs_dev_replace_lock(&fs_info->dev_replace, 1);
+ dev_replace->cursor_left = dev_replace->cursor_right;
+ dev_replace->item_needs_writeback = 1;
+ btrfs_dev_replace_unlock(&fs_info->dev_replace, 1);
+
if (ro_set)
btrfs_dec_block_group_ro(root, cache);
@@ -3719,11 +3724,6 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
ret = -ENOMEM;
break;
}
-
- btrfs_dev_replace_lock(&fs_info->dev_replace, 1);
- dev_replace->cursor_left = dev_replace->cursor_right;
- dev_replace->item_needs_writeback = 1;
- btrfs_dev_replace_unlock(&fs_info->dev_replace, 1);
skip:
key.offset = found_key.offset + length;
btrfs_release_path(path);