Commit cf30a473 authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds

[PATCH] md: handle errors when read-only

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 69382e85
...@@ -154,7 +154,7 @@ static void put_all_bios(conf_t *conf, r1bio_t *r1_bio) ...@@ -154,7 +154,7 @@ static void put_all_bios(conf_t *conf, r1bio_t *r1_bio)
for (i = 0; i < conf->raid_disks; i++) { for (i = 0; i < conf->raid_disks; i++) {
struct bio **bio = r1_bio->bios + i; struct bio **bio = r1_bio->bios + i;
if (*bio) if (*bio && *bio != IO_BLOCKED)
bio_put(*bio); bio_put(*bio);
*bio = NULL; *bio = NULL;
} }
...@@ -419,11 +419,13 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) ...@@ -419,11 +419,13 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
new_disk = 0; new_disk = 0;
for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev); for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev);
r1_bio->bios[new_disk] == IO_BLOCKED ||
!rdev || !test_bit(In_sync, &rdev->flags) !rdev || !test_bit(In_sync, &rdev->flags)
|| test_bit(WriteMostly, &rdev->flags); || test_bit(WriteMostly, &rdev->flags);
rdev = rcu_dereference(conf->mirrors[++new_disk].rdev)) { rdev = rcu_dereference(conf->mirrors[++new_disk].rdev)) {
if (rdev && test_bit(In_sync, &rdev->flags)) if (rdev && test_bit(In_sync, &rdev->flags) &&
r1_bio->bios[new_disk] != IO_BLOCKED)
wonly_disk = new_disk; wonly_disk = new_disk;
if (new_disk == conf->raid_disks - 1) { if (new_disk == conf->raid_disks - 1) {
...@@ -437,11 +439,13 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) ...@@ -437,11 +439,13 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
/* make sure the disk is operational */ /* make sure the disk is operational */
for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev); for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev);
r1_bio->bios[new_disk] == IO_BLOCKED ||
!rdev || !test_bit(In_sync, &rdev->flags) || !rdev || !test_bit(In_sync, &rdev->flags) ||
test_bit(WriteMostly, &rdev->flags); test_bit(WriteMostly, &rdev->flags);
rdev = rcu_dereference(conf->mirrors[new_disk].rdev)) { rdev = rcu_dereference(conf->mirrors[new_disk].rdev)) {
if (rdev && test_bit(In_sync, &rdev->flags)) if (rdev && test_bit(In_sync, &rdev->flags) &&
r1_bio->bios[new_disk] != IO_BLOCKED)
wonly_disk = new_disk; wonly_disk = new_disk;
if (new_disk <= 0) if (new_disk <= 0)
...@@ -478,7 +482,7 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) ...@@ -478,7 +482,7 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
rdev = rcu_dereference(conf->mirrors[disk].rdev); rdev = rcu_dereference(conf->mirrors[disk].rdev);
if (!rdev || if (!rdev || r1_bio->bios[disk] == IO_BLOCKED ||
!test_bit(In_sync, &rdev->flags) || !test_bit(In_sync, &rdev->flags) ||
test_bit(WriteMostly, &rdev->flags)) test_bit(WriteMostly, &rdev->flags))
continue; continue;
...@@ -1335,7 +1339,7 @@ static void raid1d(mddev_t *mddev) ...@@ -1335,7 +1339,7 @@ static void raid1d(mddev_t *mddev)
sector_t sect = r1_bio->sector; sector_t sect = r1_bio->sector;
int sectors = r1_bio->sectors; int sectors = r1_bio->sectors;
freeze_array(conf); freeze_array(conf);
while(sectors) { if (mddev->ro == 0) while(sectors) {
int s = sectors; int s = sectors;
int d = r1_bio->read_disk; int d = r1_bio->read_disk;
int success = 0; int success = 0;
...@@ -1388,7 +1392,6 @@ static void raid1d(mddev_t *mddev) ...@@ -1388,7 +1392,6 @@ static void raid1d(mddev_t *mddev)
sect += s; sect += s;
} }
unfreeze_array(conf); unfreeze_array(conf);
bio = r1_bio->bios[r1_bio->read_disk]; bio = r1_bio->bios[r1_bio->read_disk];
...@@ -1399,7 +1402,8 @@ static void raid1d(mddev_t *mddev) ...@@ -1399,7 +1402,8 @@ static void raid1d(mddev_t *mddev)
(unsigned long long)r1_bio->sector); (unsigned long long)r1_bio->sector);
raid_end_bio_io(r1_bio); raid_end_bio_io(r1_bio);
} else { } else {
r1_bio->bios[r1_bio->read_disk] = NULL; r1_bio->bios[r1_bio->read_disk] =
mddev->ro ? IO_BLOCKED : NULL;
r1_bio->read_disk = disk; r1_bio->read_disk = disk;
bio_put(bio); bio_put(bio);
bio = bio_clone(r1_bio->master_bio, GFP_NOIO); bio = bio_clone(r1_bio->master_bio, GFP_NOIO);
......
...@@ -109,6 +109,13 @@ struct r1bio_s { ...@@ -109,6 +109,13 @@ struct r1bio_s {
/* DO NOT PUT ANY NEW FIELDS HERE - bios array is contiguously alloced*/ /* DO NOT PUT ANY NEW FIELDS HERE - bios array is contiguously alloced*/
}; };
/* when we get a read error on a read-only array, we redirect to another
* device without failing the first device, or trying to over-write to
* correct the read error. To keep track of bad blocks on a per-bio
* level, we store IO_BLOCKED in the appropriate 'bios' pointer
*/
#define IO_BLOCKED ((struct bio*)1)
/* bits for r1bio.state */ /* bits for r1bio.state */
#define R1BIO_Uptodate 0 #define R1BIO_Uptodate 0
#define R1BIO_IsSync 1 #define R1BIO_IsSync 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment