diff options
author | Qu Wenruo <quwenruo@cn.fujitsu.com> | 2017-03-28 21:33:20 -0400 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2017-04-18 08:07:26 -0400 |
commit | 9a33944bdf075ca93062cde206cb25e62044890e (patch) | |
tree | c5b05f1697cf4258ec12b3b993300639df6dd2e2 | |
parent | d51ea5dd222d13dc46c76b2446aa59c4183e3922 (diff) |
btrfs: scrub: Don't append on-disk pages for raid56 scrub
In the following situation, scrub will calculate wrong parity to
overwrite the correct one:
RAID5 full stripe:
Before
| Dev 1 | Dev 2 | Dev 3 |
| Data stripe 1 | Data stripe 2 | Parity Stripe |
--------------------------------------------------- 0
| 0x0000 (Bad) | 0xcdcd | 0x0000 |
--------------------------------------------------- 4K
| 0xcdcd | 0xcdcd | 0x0000 |
...
| 0xcdcd | 0xcdcd | 0x0000 |
--------------------------------------------------- 64K
After scrubbing dev3 only:
| Dev 1 | Dev 2 | Dev 3 |
| Data stripe 1 | Data stripe 2 | Parity Stripe |
--------------------------------------------------- 0
| 0xcdcd (Good) | 0xcdcd | 0xcdcd (Bad) |
--------------------------------------------------- 4K
| 0xcdcd | 0xcdcd | 0x0000 |
...
| 0xcdcd | 0xcdcd | 0x0000 |
--------------------------------------------------- 64K
The reason is that after raid56 read rebuild rbio->stripe_pages are all
correctly recovered (0xcd for data stripes).
However when we check and repair parity in
scrub_parity_check_and_repair(), we will append pages in sparity->spages
list to rbio->bio_pages[], which contains old on-disk data.
And when we submit parity data to disk, we calculate parity using
rbio->bio_pages[] first, if rbio->bio_pages[] not found, then fallback
to rbio->stripe_pages[].
The patch fix it by not appending pages from sparity->spages.
So finish_parity_scrub() will use rbio->stripe_pages[] which is correct.
Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Reviewed-by: Liu Bo <bo.li.liu@oracle.com>
Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r-- | fs/btrfs/scrub.c | 4 |
1 files changed, 0 insertions, 4 deletions
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index fe1c793877dd..26dbe563fed0 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c | |||
@@ -2769,7 +2769,6 @@ static void scrub_parity_check_and_repair(struct scrub_parity *sparity) | |||
2769 | struct btrfs_fs_info *fs_info = sctx->fs_info; | 2769 | struct btrfs_fs_info *fs_info = sctx->fs_info; |
2770 | struct bio *bio; | 2770 | struct bio *bio; |
2771 | struct btrfs_raid_bio *rbio; | 2771 | struct btrfs_raid_bio *rbio; |
2772 | struct scrub_page *spage; | ||
2773 | struct btrfs_bio *bbio = NULL; | 2772 | struct btrfs_bio *bbio = NULL; |
2774 | u64 length; | 2773 | u64 length; |
2775 | int ret; | 2774 | int ret; |
@@ -2799,9 +2798,6 @@ static void scrub_parity_check_and_repair(struct scrub_parity *sparity) | |||
2799 | if (!rbio) | 2798 | if (!rbio) |
2800 | goto rbio_out; | 2799 | goto rbio_out; |
2801 | 2800 | ||
2802 | list_for_each_entry(spage, &sparity->spages, list) | ||
2803 | raid56_add_scrub_pages(rbio, spage->page, spage->logical); | ||
2804 | |||
2805 | scrub_pending_bio_inc(sctx); | 2801 | scrub_pending_bio_inc(sctx); |
2806 | raid56_parity_submit_scrub_rbio(rbio); | 2802 | raid56_parity_submit_scrub_rbio(rbio); |
2807 | return; | 2803 | return; |