diff options
author | NeilBrown <neilb@suse.de> | 2008-05-23 16:04:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-05-24 12:56:10 -0400 |
commit | 698b18c1e8bddf39cbf1ba50792b0fe302dbe6d6 (patch) | |
tree | 9a65cf296b2b37654e30a1f2f9f6f13468259345 /drivers/md | |
parent | 6be9d4940134b36f9ed020aead36f831f19b49f1 (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>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/raid1.c | 15 |
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 | } |