diff options
author | Ilya Dryomov <idryomov@gmail.com> | 2013-10-07 06:42:57 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2013-11-11 21:55:36 -0500 |
commit | 539f358a30d5113bad81c41a2e7ba8770d6c9f6e (patch) | |
tree | 6b033dcb841d21d40a659196fba358437aa1b04d /fs | |
parent | 778ba82b1796e75e719a52679ae431371ca73988 (diff) |
Btrfs: fix the dev-replace suspend sequence
Replace progresses strictly from lower to higher offsets, and the
progress is tracked in chunks, by storing the physical offset of the
dev_extent which is being copied in the cursor_left field of
btrfs_dev_replace_item. When we are done copying the chunk,
left_cursor is updated to point one byte past the dev_extent, so that
on resume we can skip the dev_extents that have already been copied.
There is a major bug (which goes all the way back to the inception of
dev-replace in 3.8) in the way left_cursor is bumped: the bump is done
unconditionally, without any regard to the scrub_chunk return value.
On suspend (and also on any kind of error) scrub_chunk returns early,
i.e. without completing the copy. This leads to us skipping the chunk
that hasn't been fully copied yet when resuming.
Fix this by doing the cursor_left update only if scrub_chunk ret is 0.
(On suspend scrub_chunk returns with -ECANCELED, so this fix covers
both suspend and error cases.)
Cc: Stefan Behrens <sbehrens@giantdisaster.de>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/scrub.c | 5 |
1 files changed, 3 insertions, 2 deletions
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index a18e0e23f6a6..f21e2df89bc2 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c | |||
@@ -2717,8 +2717,6 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, | |||
2717 | mutex_unlock(&fs_info->scrub_lock); | 2717 | mutex_unlock(&fs_info->scrub_lock); |
2718 | wake_up(&fs_info->scrub_pause_wait); | 2718 | wake_up(&fs_info->scrub_pause_wait); |
2719 | 2719 | ||
2720 | dev_replace->cursor_left = dev_replace->cursor_right; | ||
2721 | dev_replace->item_needs_writeback = 1; | ||
2722 | btrfs_put_block_group(cache); | 2720 | btrfs_put_block_group(cache); |
2723 | if (ret) | 2721 | if (ret) |
2724 | break; | 2722 | break; |
@@ -2732,6 +2730,9 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, | |||
2732 | break; | 2730 | break; |
2733 | } | 2731 | } |
2734 | 2732 | ||
2733 | dev_replace->cursor_left = dev_replace->cursor_right; | ||
2734 | dev_replace->item_needs_writeback = 1; | ||
2735 | |||
2735 | key.offset = found_key.offset + length; | 2736 | key.offset = found_key.offset + length; |
2736 | btrfs_release_path(path); | 2737 | btrfs_release_path(path); |
2737 | } | 2738 | } |