aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2006-01-06 03:20:37 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-06 11:34:06 -0500
commit097426f689f179747f3cd6b4749eb2a6b605702d (patch)
tree92b0a78f8aebedd4afdb52dfa23b311a4468719d /drivers/md
parent2604b703b6b3db80e3c75ce472a54dfd0b7bf9f4 (diff)
[PATCH] md: fix possible problem in raid1/raid10 error overwriting
The code to overwrite/reread for addressing read errors in raid1/raid10 currently assumes that the read will not alter the buffer which could be used to write to the next device. This is not a safe assumption to make. So we split the loops into a overwrite loop and a separate re-read loop, so that the writing is complete before reading is attempted. Cc: Paul Clements <paul.clements@steeleye.com> Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/raid1.c38
-rw-r--r--drivers/md/raid10.c22
2 files changed, 48 insertions, 12 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 6e0f59ed3d80..39c10a65683d 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1253,6 +1253,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
1253 } while (!success && d != r1_bio->read_disk); 1253 } while (!success && d != r1_bio->read_disk);
1254 1254
1255 if (success) { 1255 if (success) {
1256 int start = d;
1256 /* write it back and re-read */ 1257 /* write it back and re-read */
1257 set_bit(R1BIO_Uptodate, &r1_bio->state); 1258 set_bit(R1BIO_Uptodate, &r1_bio->state);
1258 while (d != r1_bio->read_disk) { 1259 while (d != r1_bio->read_disk) {
@@ -1266,14 +1267,23 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
1266 sect + rdev->data_offset, 1267 sect + rdev->data_offset,
1267 s<<9, 1268 s<<9,
1268 bio->bi_io_vec[idx].bv_page, 1269 bio->bi_io_vec[idx].bv_page,
1269 WRITE) == 0 || 1270 WRITE) == 0)
1270 sync_page_io(rdev->bdev, 1271 md_error(mddev, rdev);
1272 }
1273 d = start;
1274 while (d != r1_bio->read_disk) {
1275 if (d == 0)
1276 d = conf->raid_disks;
1277 d--;
1278 if (r1_bio->bios[d]->bi_end_io != end_sync_read)
1279 continue;
1280 rdev = conf->mirrors[d].rdev;
1281 if (sync_page_io(rdev->bdev,
1271 sect + rdev->data_offset, 1282 sect + rdev->data_offset,
1272 s<<9, 1283 s<<9,
1273 bio->bi_io_vec[idx].bv_page, 1284 bio->bi_io_vec[idx].bv_page,
1274 READ) == 0) { 1285 READ) == 0)
1275 md_error(mddev, rdev); 1286 md_error(mddev, rdev);
1276 }
1277 } 1287 }
1278 } else { 1288 } else {
1279 char b[BDEVNAME_SIZE]; 1289 char b[BDEVNAME_SIZE];
@@ -1445,6 +1455,7 @@ static void raid1d(mddev_t *mddev)
1445 1455
1446 if (success) { 1456 if (success) {
1447 /* write it back and re-read */ 1457 /* write it back and re-read */
1458 int start = d;
1448 while (d != r1_bio->read_disk) { 1459 while (d != r1_bio->read_disk) {
1449 if (d==0) 1460 if (d==0)
1450 d = conf->raid_disks; 1461 d = conf->raid_disks;
@@ -1454,13 +1465,24 @@ static void raid1d(mddev_t *mddev)
1454 test_bit(In_sync, &rdev->flags)) { 1465 test_bit(In_sync, &rdev->flags)) {
1455 if (sync_page_io(rdev->bdev, 1466 if (sync_page_io(rdev->bdev,
1456 sect + rdev->data_offset, 1467 sect + rdev->data_offset,
1457 s<<9, conf->tmppage, WRITE) == 0 || 1468 s<<9, conf->tmppage, WRITE) == 0)
1458 sync_page_io(rdev->bdev, 1469 /* Well, this device is dead */
1470 md_error(mddev, rdev);
1471 }
1472 }
1473 d = start;
1474 while (d != r1_bio->read_disk) {
1475 if (d==0)
1476 d = conf->raid_disks;
1477 d--;
1478 rdev = conf->mirrors[d].rdev;
1479 if (rdev &&
1480 test_bit(In_sync, &rdev->flags)) {
1481 if (sync_page_io(rdev->bdev,
1459 sect + rdev->data_offset, 1482 sect + rdev->data_offset,
1460 s<<9, conf->tmppage, READ) == 0) { 1483 s<<9, conf->tmppage, READ) == 0)
1461 /* Well, this device is dead */ 1484 /* Well, this device is dead */
1462 md_error(mddev, rdev); 1485 md_error(mddev, rdev);
1463 }
1464 } 1486 }
1465 } 1487 }
1466 } else { 1488 } else {
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index f23d52c5df94..9647ebb0983a 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1421,6 +1421,7 @@ static void raid10d(mddev_t *mddev)
1421 } while (!success && sl != r10_bio->read_slot); 1421 } while (!success && sl != r10_bio->read_slot);
1422 1422
1423 if (success) { 1423 if (success) {
1424 int start = sl;
1424 /* write it back and re-read */ 1425 /* write it back and re-read */
1425 while (sl != r10_bio->read_slot) { 1426 while (sl != r10_bio->read_slot) {
1426 int d; 1427 int d;
@@ -1434,14 +1435,27 @@ static void raid10d(mddev_t *mddev)
1434 if (sync_page_io(rdev->bdev, 1435 if (sync_page_io(rdev->bdev,
1435 r10_bio->devs[sl].addr + 1436 r10_bio->devs[sl].addr +
1436 sect + rdev->data_offset, 1437 sect + rdev->data_offset,
1437 s<<9, conf->tmppage, WRITE) == 0 || 1438 s<<9, conf->tmppage, WRITE) == 0)
1438 sync_page_io(rdev->bdev, 1439 /* Well, this device is dead */
1440 md_error(mddev, rdev);
1441 }
1442 }
1443 sl = start;
1444 while (sl != r10_bio->read_slot) {
1445 int d;
1446 if (sl==0)
1447 sl = conf->copies;
1448 sl--;
1449 d = r10_bio->devs[sl].devnum;
1450 rdev = conf->mirrors[d].rdev;
1451 if (rdev &&
1452 test_bit(In_sync, &rdev->flags)) {
1453 if (sync_page_io(rdev->bdev,
1439 r10_bio->devs[sl].addr + 1454 r10_bio->devs[sl].addr +
1440 sect + rdev->data_offset, 1455 sect + rdev->data_offset,
1441 s<<9, conf->tmppage, READ) == 0) { 1456 s<<9, conf->tmppage, READ) == 0)
1442 /* Well, this device is dead */ 1457 /* Well, this device is dead */
1443 md_error(mddev, rdev); 1458 md_error(mddev, rdev);
1444 }
1445 } 1459 }
1446 } 1460 }
1447 } else { 1461 } else {