Commit 2dc04d33 authored by NeilBrown's avatar NeilBrown Committed by Greg Kroah-Hartman

md/raid10: fix two problems with RAID10 resync.

commit 7bb23c49 upstream.

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 8be185f2 "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.
Reported-by: default avatarBrassow Jonathan <jbrassow@redhat.com>
Signed-off-by: default avatarNeilBrown <neilb@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4b5c1451
...@@ -2075,11 +2075,17 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) ...@@ -2075,11 +2075,17 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
* both 'first' and 'i', so we just compare them. * both 'first' and 'i', so we just compare them.
* All vec entries are PAGE_SIZE; * All vec entries are PAGE_SIZE;
*/ */
for (j = 0; j < vcnt; j++) int sectors = r10_bio->sectors;
for (j = 0; j < vcnt; j++) {
int len = PAGE_SIZE;
if (sectors < (len / 512))
len = sectors * 512;
if (memcmp(page_address(fbio->bi_io_vec[j].bv_page), if (memcmp(page_address(fbio->bi_io_vec[j].bv_page),
page_address(tbio->bi_io_vec[j].bv_page), page_address(tbio->bi_io_vec[j].bv_page),
fbio->bi_io_vec[j].bv_len)) len))
break; break;
sectors -= len/512;
}
if (j == vcnt) if (j == vcnt)
continue; continue;
atomic64_add(r10_bio->sectors, &mddev->resync_mismatches); atomic64_add(r10_bio->sectors, &mddev->resync_mismatches);
...@@ -3385,6 +3391,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, ...@@ -3385,6 +3391,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
if (bio->bi_end_io == end_sync_read) { if (bio->bi_end_io == end_sync_read) {
md_sync_acct(bio->bi_bdev, nr_sectors); md_sync_acct(bio->bi_bdev, nr_sectors);
set_bit(BIO_UPTODATE, &bio->bi_flags);
generic_make_request(bio); generic_make_request(bio);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment