aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2008-05-23 16:04:35 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-05-24 12:56:10 -0400
commit698b18c1e8bddf39cbf1ba50792b0fe302dbe6d6 (patch)
tree9a65cf296b2b37654e30a1f2f9f6f13468259345
parent6be9d4940134b36f9ed020aead36f831f19b49f1 (diff)
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>
-rw-r--r--drivers/md/raid1.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 21629ae46682..d0f4021bbc2e 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1284,6 +1284,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
1284 rdev_dec_pending(conf->mirrors[i].rdev, mddev); 1284 rdev_dec_pending(conf->mirrors[i].rdev, mddev);
1285 } else { 1285 } else {
1286 /* fixup the bio for reuse */ 1286 /* fixup the bio for reuse */
1287 int size;
1287 sbio->bi_vcnt = vcnt; 1288 sbio->bi_vcnt = vcnt;
1288 sbio->bi_size = r1_bio->sectors << 9; 1289 sbio->bi_size = r1_bio->sectors << 9;
1289 sbio->bi_idx = 0; 1290 sbio->bi_idx = 0;
@@ -1297,10 +1298,20 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
1297 sbio->bi_sector = r1_bio->sector + 1298 sbio->bi_sector = r1_bio->sector +
1298 conf->mirrors[i].rdev->data_offset; 1299 conf->mirrors[i].rdev->data_offset;
1299 sbio->bi_bdev = conf->mirrors[i].rdev->bdev; 1300 sbio->bi_bdev = conf->mirrors[i].rdev->bdev;
1300 for (j = 0; j < vcnt ; j++) 1301 size = sbio->bi_size;
1301 memcpy(page_address(sbio->bi_io_vec[j].bv_page), 1302 for (j = 0; j < vcnt ; j++) {
1303 struct bio_vec *bi;
1304 bi = &sbio->bi_io_vec[j];
1305 bi->bv_offset = 0;
1306 if (size > PAGE_SIZE)
1307 bi->bv_len = PAGE_SIZE;
1308 else
1309 bi->bv_len = size;
1310 size -= PAGE_SIZE;
1311 memcpy(page_address(bi->bv_page),
1302 page_address(pbio->bi_io_vec[j].bv_page), 1312 page_address(pbio->bi_io_vec[j].bv_page),
1303 PAGE_SIZE); 1313 PAGE_SIZE);
1314 }
1304 1315
1305 } 1316 }
1306 } 1317 }