summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2006-01-06 11:20:23 +0300
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-06 19:34:04 +0300
commitcf30a473a02901fe4db37abc0b0fa26dd5ba3f72 (patch)
tree3fa967963e174913826943f0f98e63c60032d07d
parent69382e85371c232df71524137a806b9c210ec021 (diff)
downloadlinux-cf30a473a02901fe4db37abc0b0fa26dd5ba3f72.tar.xz
[PATCH] md: handle errors when read-only
Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/md/raid1.c18
-rw-r--r--include/linux/raid/raid1.h7
2 files changed, 18 insertions, 7 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 14a8fe0349c7..a8bc93d6ff63 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -154,7 +154,7 @@ static void put_all_bios(conf_t *conf, r1bio_t *r1_bio)
for (i = 0; i < conf->raid_disks; i++) {
struct bio **bio = r1_bio->bios + i;
- if (*bio)
+ if (*bio && *bio != IO_BLOCKED)
bio_put(*bio);
*bio = NULL;
}
@@ -419,11 +419,13 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
new_disk = 0;
for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev);
+ r1_bio->bios[new_disk] == IO_BLOCKED ||
!rdev || !test_bit(In_sync, &rdev->flags)
|| test_bit(WriteMostly, &rdev->flags);
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;
if (new_disk == conf->raid_disks - 1) {
@@ -437,11 +439,13 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
/* make sure the disk is operational */
for (rdev = rcu_dereference(conf->mirrors[new_disk].rdev);
+ r1_bio->bios[new_disk] == IO_BLOCKED ||
!rdev || !test_bit(In_sync, &rdev->flags) ||
test_bit(WriteMostly, &rdev->flags);
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;
if (new_disk <= 0)
@@ -478,7 +482,7 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio)
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(WriteMostly, &rdev->flags))
continue;
@@ -1335,7 +1339,7 @@ static void raid1d(mddev_t *mddev)
sector_t sect = r1_bio->sector;
int sectors = r1_bio->sectors;
freeze_array(conf);
- while(sectors) {
+ if (mddev->ro == 0) while(sectors) {
int s = sectors;
int d = r1_bio->read_disk;
int success = 0;
@@ -1388,7 +1392,6 @@ static void raid1d(mddev_t *mddev)
sect += s;
}
-
unfreeze_array(conf);
bio = r1_bio->bios[r1_bio->read_disk];
@@ -1399,7 +1402,8 @@ static void raid1d(mddev_t *mddev)
(unsigned long long)r1_bio->sector);
raid_end_bio_io(r1_bio);
} 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;
bio_put(bio);
bio = bio_clone(r1_bio->master_bio, GFP_NOIO);
diff --git a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h
index cbe4238d3f9f..9d5494aaac0f 100644
--- a/include/linux/raid/raid1.h
+++ b/include/linux/raid/raid1.h
@@ -109,6 +109,13 @@ struct r1bio_s {
/* 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 */
#define R1BIO_Uptodate 0
#define R1BIO_IsSync 1