Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 097426f6 authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds
Browse files

[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: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 2604b703
Loading
Loading
Loading
Loading
+30 −8
Original line number Diff line number Diff line
@@ -1253,6 +1253,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
			} while (!success && d != r1_bio->read_disk);

			if (success) {
				int start = d;
				/* write it back and re-read */
				set_bit(R1BIO_Uptodate, &r1_bio->state);
				while (d != r1_bio->read_disk) {
@@ -1266,15 +1267,24 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
							 sect + rdev->data_offset,
							 s<<9,
							 bio->bi_io_vec[idx].bv_page,
							 WRITE) == 0 ||
					    sync_page_io(rdev->bdev,
							 WRITE) == 0)
						md_error(mddev, rdev);
				}
				d = start;
				while (d != r1_bio->read_disk) {
					if (d == 0)
						d = conf->raid_disks;
					d--;
					if (r1_bio->bios[d]->bi_end_io != end_sync_read)
						continue;
					rdev = conf->mirrors[d].rdev;
					if (sync_page_io(rdev->bdev,
							 sect + rdev->data_offset,
							 s<<9,
							 bio->bi_io_vec[idx].bv_page,
							 READ) == 0) {
							 READ) == 0)
						md_error(mddev, rdev);
				}
				}
			} else {
				char b[BDEVNAME_SIZE];
				/* Cannot read from anywhere, array is toast */
@@ -1445,6 +1455,7 @@ static void raid1d(mddev_t *mddev)

				if (success) {
					/* write it back and re-read */
					int start = d;
					while (d != r1_bio->read_disk) {
						if (d==0)
							d = conf->raid_disks;
@@ -1454,14 +1465,25 @@ static void raid1d(mddev_t *mddev)
						    test_bit(In_sync, &rdev->flags)) {
							if (sync_page_io(rdev->bdev,
									 sect + rdev->data_offset,
									 s<<9, conf->tmppage, WRITE) == 0 ||
							    sync_page_io(rdev->bdev,
									 sect + rdev->data_offset,
									 s<<9, conf->tmppage, READ) == 0) {
									 s<<9, conf->tmppage, WRITE) == 0)
								/* Well, this device is dead */
								md_error(mddev, rdev);
						}
					}
					d = start;
					while (d != r1_bio->read_disk) {
						if (d==0)
							d = conf->raid_disks;
						d--;
						rdev = conf->mirrors[d].rdev;
						if (rdev &&
						    test_bit(In_sync, &rdev->flags)) {
							if (sync_page_io(rdev->bdev,
									 sect + rdev->data_offset,
									 s<<9, conf->tmppage, READ) == 0)
								/* Well, this device is dead */
								md_error(mddev, rdev);
						}
					}
				} else {
					/* Cannot read from anywhere -- bye bye array */
+18 −4
Original line number Diff line number Diff line
@@ -1421,6 +1421,7 @@ static void raid10d(mddev_t *mddev)
				} while (!success && sl != r10_bio->read_slot);

				if (success) {
					int start = sl;
					/* write it back and re-read */
					while (sl != r10_bio->read_slot) {
						int d;
@@ -1434,16 +1435,29 @@ static void raid10d(mddev_t *mddev)
							if (sync_page_io(rdev->bdev,
									 r10_bio->devs[sl].addr +
									 sect + rdev->data_offset,
									 s<<9, conf->tmppage, WRITE) == 0 ||
							    sync_page_io(rdev->bdev,
									 s<<9, conf->tmppage, WRITE) == 0)
								/* Well, this device is dead */
								md_error(mddev, rdev);
						}
					}
					sl = start;
					while (sl != r10_bio->read_slot) {
						int d;
						if (sl==0)
							sl = conf->copies;
						sl--;
						d = r10_bio->devs[sl].devnum;
						rdev = conf->mirrors[d].rdev;
						if (rdev &&
						    test_bit(In_sync, &rdev->flags)) {
							if (sync_page_io(rdev->bdev,
									 r10_bio->devs[sl].addr +
									 sect + rdev->data_offset,
									 s<<9, conf->tmppage, READ) == 0) {
									 s<<9, conf->tmppage, READ) == 0)
								/* Well, this device is dead */
								md_error(mddev, rdev);
						}
					}
					}
				} else {
					/* Cannot read from anywhere -- bye bye array */
					md_error(mddev, conf->mirrors[r10_bio->devs[r10_bio->read_slot].devnum].rdev);