diff options
author | NeilBrown <neilb@suse.de> | 2013-07-16 02:50:47 -0400 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2013-07-18 00:18:01 -0400 |
commit | 7bb23c4934059c64cbee2e41d5d24ce122285176 (patch) | |
tree | e457c9dc9bfbc502f8a739749a6d6d287f2ec144 /drivers/md | |
parent | 47188d39b5deeebf41f87a02af1b3935866364cf (diff) |
md/raid10: fix two problems with RAID10 resync.
1/ When an different between blocks is found, data is copied from
one bio to the other. However bv_len is used as the length to
copy and this could be zero. So use r10_bio->sectors to calculate
length instead.
Using bv_len was probably always a bit dubious, but the introduction
of bio_advance made it much more likely to be a problem.
2/ When preparing some blocks for sync, we don't set BIO_UPTODATE
except on bios that we schedule for a read. This ensures that
missing/failed devices don't confuse the loop at the top of
sync_request write.
Commit 8be185f2c9d54d6 "raid10: Use bio_reset()"
removed a loop which set BIO_UPTDATE on all appropriate bios.
So we need to re-add that flag.
These bugs were introduced in 3.10, so this patch is suitable for
3.10-stable, and can remove a potential for data corruption.
Cc: stable@vger.kernel.org (3.10)
Reported-by: Brassow Jonathan <jbrassow@redhat.com>
Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/raid10.c | 11 |
1 files changed, 9 insertions, 2 deletions
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index cd066b63bdaf..957a719e8c2f 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c | |||
@@ -2097,11 +2097,17 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) | |||
2097 | * both 'first' and 'i', so we just compare them. | 2097 | * both 'first' and 'i', so we just compare them. |
2098 | * All vec entries are PAGE_SIZE; | 2098 | * All vec entries are PAGE_SIZE; |
2099 | */ | 2099 | */ |
2100 | for (j = 0; j < vcnt; j++) | 2100 | int sectors = r10_bio->sectors; |
2101 | for (j = 0; j < vcnt; j++) { | ||
2102 | int len = PAGE_SIZE; | ||
2103 | if (sectors < (len / 512)) | ||
2104 | len = sectors * 512; | ||
2101 | if (memcmp(page_address(fbio->bi_io_vec[j].bv_page), | 2105 | if (memcmp(page_address(fbio->bi_io_vec[j].bv_page), |
2102 | page_address(tbio->bi_io_vec[j].bv_page), | 2106 | page_address(tbio->bi_io_vec[j].bv_page), |
2103 | fbio->bi_io_vec[j].bv_len)) | 2107 | len)) |
2104 | break; | 2108 | break; |
2109 | sectors -= len/512; | ||
2110 | } | ||
2105 | if (j == vcnt) | 2111 | if (j == vcnt) |
2106 | continue; | 2112 | continue; |
2107 | atomic64_add(r10_bio->sectors, &mddev->resync_mismatches); | 2113 | atomic64_add(r10_bio->sectors, &mddev->resync_mismatches); |
@@ -3407,6 +3413,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, | |||
3407 | 3413 | ||
3408 | if (bio->bi_end_io == end_sync_read) { | 3414 | if (bio->bi_end_io == end_sync_read) { |
3409 | md_sync_acct(bio->bi_bdev, nr_sectors); | 3415 | md_sync_acct(bio->bi_bdev, nr_sectors); |
3416 | set_bit(BIO_UPTODATE, &bio->bi_flags); | ||
3410 | generic_make_request(bio); | 3417 | generic_make_request(bio); |
3411 | } | 3418 | } |
3412 | } | 3419 | } |