summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeil Brown <neilb@cse.unsw.edu.au>2003-06-04 09:29:59 -0700
committerBen Collins <bcollins@debian.org>2003-06-04 09:29:59 -0700
commit1e23fe7dc8d5a883cf6fc4ec6737eca05b9e8571 (patch)
tree3a857157534b47aabf933969e61626d153c801a6
parentb6d201a6b5f0386bcea5a0a909084a9090cdba3c (diff)
[PATCH] Fix raid1 handling of writing to multiple devices.
When raid1 writes, it needs to schedule writes to some number of devices, and when all writes have completed, the r1_bio structure that holds it all together must be freed. However we must make sure not to free it before all devices have been considered for submitting writes to. This happens in two places: when submitting a normal write request and when submiting a write as part of resync. This patch makes both these places: the same simpler more correct.
-rw-r--r--drivers/md/raid1.c68
1 files changed, 12 insertions, 56 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 79cd5e4ca138..1c1ef07c83b2 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -462,7 +462,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
mirror_info_t *mirror;
r1bio_t *r1_bio;
struct bio *read_bio;
- int i, sum_bios = 0, disks = conf->raid_disks;
+ int i, disks = conf->raid_disks;
/*
* Register the new request and wait if the reconstruction
@@ -525,6 +525,9 @@ static int make_request(request_queue_t *q, struct bio * bio)
r1_bio->write_bios[i] = NULL;
}
spin_unlock_irq(&conf->device_lock);
+
+ atomic_set(&r1_bio->remaining, 1);
+ md_write_start(mddev);
for (i = 0; i < disks; i++) {
struct bio *mbio;
if (!r1_bio->write_bios[i])
@@ -539,37 +542,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
mbio->bi_rw = r1_bio->cmd;
mbio->bi_private = r1_bio;
- sum_bios++;
- }
- if (!sum_bios) {
- /*
- * If all mirrors are non-operational
- * then return an IO error:
- */
- md_write_end(mddev);
- raid_end_bio_io(r1_bio);
- return 0;
- }
- atomic_set(&r1_bio->remaining, sum_bios+1);
-
- /*
- * We have to be a bit careful about the semaphore above, thats
- * why we start the requests separately. Since generic_make_request()
- * can sleep, this is the safer solution. Imagine, raid1_end_request
- * decreasing the semaphore before we could have set it up ...
- * We could play tricks with the semaphore (presetting it and
- * correcting at the end if sum_bios is not 'n' but we have to
- * do raid1_end_request by hand if all requests finish until we had a
- * chance to set up the semaphore correctly ... lots of races).
- */
-
- md_write_start(mddev);
- for (i=disks; i--; ) {
- struct bio *mbio;
- mbio = r1_bio->write_bios[i];
- if (!mbio)
- continue;
-
+ atomic_inc(&r1_bio->remaining);
generic_make_request(mbio);
}
@@ -802,7 +775,7 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
{
conf_t *conf = mddev_to_conf(mddev);
- int i, sum_bios = 0;
+ int i;
int disks = conf->raid_disks;
struct bio *bio, *mbio;
@@ -849,7 +822,8 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
}
spin_unlock_irq(&conf->device_lock);
- for (i = 0; i < disks ; i++) {
+ atomic_set(&r1_bio->remaining, 1);
+ for (i = disks; i-- ; ) {
if (!r1_bio->write_bios[i])
continue;
mbio = bio_clone(bio, GFP_NOIO);
@@ -860,32 +834,14 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
mbio->bi_rw = WRITE;
mbio->bi_private = r1_bio;
- sum_bios++;
+ atomic_inc(&r1_bio->remaining);
+ md_sync_acct(conf->mirrors[i].rdev, mbio->bi_size >> 9);
+ generic_make_request(mbio);
}
- if (i != disks)
- BUG();
- atomic_set(&r1_bio->remaining, sum_bios);
-
- if (!sum_bios) {
- /*
- * Nowhere to write this to... I guess we
- * must be done
- */
- printk(KERN_ALERT "raid1: sync aborting as there is nowhere"
- " to write sector %llu\n",
- (unsigned long long)r1_bio->sector);
+ if (atomic_dec_and_test(&r1_bio->remaining)) {
md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0);
put_buf(r1_bio);
- return;
- }
- for (i = 0; i < disks ; i++) {
- mbio = r1_bio->write_bios[i];
- if (!mbio)
- continue;
-
- md_sync_acct(conf->mirrors[i].rdev, mbio->bi_size >> 9);
- generic_make_request(mbio);
}
}