aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorIlya Dryomov <idryomov@gmail.com>2013-10-07 06:42:57 -0400
committerChris Mason <chris.mason@fusionio.com>2013-11-11 21:55:36 -0500
commit539f358a30d5113bad81c41a2e7ba8770d6c9f6e (patch)
tree6b033dcb841d21d40a659196fba358437aa1b04d /fs
parent778ba82b1796e75e719a52679ae431371ca73988 (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.c5
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 }