md: raid1: Fix restoration of bio between failed read and write.
When performing a "recovery" or "check" pass on a RAID1 array, we read from each device and possible, if there is a difference or a read error, write back to some devices. We use the same 'bio' for both read and write, resetting various fields between the two operations. We forgot to reset bv_offset and bv_len however. These are often left unchanged, but in the case where there is an IO error one or two sectors into a page, they are changed. This results in correctable errors not being corrected properly. It does not result in any data corruption. Cc: "Fairbanks, David" <David.Fairbanks@stratus.com> Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
committed by
Linus Torvalds
parent
6be9d49401
commit
698b18c1e8
@@ -1284,6 +1284,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
|
|||||||
rdev_dec_pending(conf->mirrors[i].rdev, mddev);
|
rdev_dec_pending(conf->mirrors[i].rdev, mddev);
|
||||||
} else {
|
} else {
|
||||||
/* fixup the bio for reuse */
|
/* fixup the bio for reuse */
|
||||||
|
int size;
|
||||||
sbio->bi_vcnt = vcnt;
|
sbio->bi_vcnt = vcnt;
|
||||||
sbio->bi_size = r1_bio->sectors << 9;
|
sbio->bi_size = r1_bio->sectors << 9;
|
||||||
sbio->bi_idx = 0;
|
sbio->bi_idx = 0;
|
||||||
@@ -1297,10 +1298,20 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
|
|||||||
sbio->bi_sector = r1_bio->sector +
|
sbio->bi_sector = r1_bio->sector +
|
||||||
conf->mirrors[i].rdev->data_offset;
|
conf->mirrors[i].rdev->data_offset;
|
||||||
sbio->bi_bdev = conf->mirrors[i].rdev->bdev;
|
sbio->bi_bdev = conf->mirrors[i].rdev->bdev;
|
||||||
for (j = 0; j < vcnt ; j++)
|
size = sbio->bi_size;
|
||||||
memcpy(page_address(sbio->bi_io_vec[j].bv_page),
|
for (j = 0; j < vcnt ; j++) {
|
||||||
|
struct bio_vec *bi;
|
||||||
|
bi = &sbio->bi_io_vec[j];
|
||||||
|
bi->bv_offset = 0;
|
||||||
|
if (size > PAGE_SIZE)
|
||||||
|
bi->bv_len = PAGE_SIZE;
|
||||||
|
else
|
||||||
|
bi->bv_len = size;
|
||||||
|
size -= PAGE_SIZE;
|
||||||
|
memcpy(page_address(bi->bv_page),
|
||||||
page_address(pbio->bi_io_vec[j].bv_page),
|
page_address(pbio->bi_io_vec[j].bv_page),
|
||||||
PAGE_SIZE);
|
PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user