Btrfs: fix race setting block group back to RW mode during device replace
authorFilipe Manana <fdmanana@suse.com>
Sat, 14 May 2016 18:44:40 +0000 (19:44 +0100)
committerFilipe Manana <fdmanana@suse.com>
Mon, 30 May 2016 11:58:24 +0000 (12:58 +0100)
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>
fs/btrfs/scrub.c

index 19a1eda703611c8162498657d660ae7516b5b269..70427ef66b044db3baadd071e9b58b3fa9ce4bfd 100644 (file)
@@ -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);