X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmd%2Fraid1.c;h=060c6a28c86c3ae5acb9325653886b63d73eae24;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=1ed82ea4be8ef3aff8205157bee0f7c1e517264c;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 1ed82ea4b..060c6a28c 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -30,8 +30,6 @@ #define NR_RAID1_BIOS 256 static mdk_personality_t raid1_personality; -static spinlock_t retry_list_lock = SPIN_LOCK_UNLOCKED; -static LIST_HEAD(retry_list_head); static void unplug_slaves(mddev_t *mddev); @@ -188,10 +186,11 @@ static void reschedule_retry(r1bio_t *r1_bio) { unsigned long flags; mddev_t *mddev = r1_bio->mddev; + conf_t *conf = mddev_to_conf(mddev); - spin_lock_irqsave(&retry_list_lock, flags); - list_add(&r1_bio->retry_list, &retry_list_head); - spin_unlock_irqrestore(&retry_list_lock, flags); + spin_lock_irqsave(&conf->device_lock, flags); + list_add(&r1_bio->retry_list, &conf->retry_list); + spin_unlock_irqrestore(&conf->device_lock, flags); md_wakeup_thread(mddev->thread); } @@ -340,7 +339,7 @@ static int read_balance(conf_t *conf, r1bio_t *r1_bio) const int sectors = r1_bio->sectors; sector_t new_distance, current_distance; - spin_lock_irq(&conf->device_lock); + rcu_read_lock(); /* * Check if it if we can balance. We can balance on the whole * device if no resync is going on, or below the resync window. @@ -417,7 +416,7 @@ rb_out: conf->last_used = new_disk; atomic_inc(&conf->mirrors[new_disk].rdev->nr_pending); } - spin_unlock_irq(&conf->device_lock); + rcu_read_unlock(); return new_disk; } @@ -426,26 +425,26 @@ static void unplug_slaves(mddev_t *mddev) { conf_t *conf = mddev_to_conf(mddev); int i; - unsigned long flags; - spin_lock_irqsave(&conf->device_lock, flags); + rcu_read_lock(); for (i=0; iraid_disks; i++) { mdk_rdev_t *rdev = conf->mirrors[i].rdev; - if (rdev && atomic_read(&rdev->nr_pending)) { + if (rdev && !rdev->faulty && atomic_read(&rdev->nr_pending)) { request_queue_t *r_queue = bdev_get_queue(rdev->bdev); atomic_inc(&rdev->nr_pending); - spin_unlock_irqrestore(&conf->device_lock, flags); + rcu_read_unlock(); if (r_queue->unplug_fn) r_queue->unplug_fn(r_queue); - spin_lock_irqsave(&conf->device_lock, flags); - atomic_dec(&rdev->nr_pending); + rdev_dec_pending(rdev, mddev); + rcu_read_lock(); } } - spin_unlock_irqrestore(&conf->device_lock, flags); + rcu_read_unlock(); } + static void raid1_unplug(request_queue_t *q) { unplug_slaves(q->queuedata); @@ -456,24 +455,28 @@ static int raid1_issue_flush(request_queue_t *q, struct gendisk *disk, { mddev_t *mddev = q->queuedata; conf_t *conf = mddev_to_conf(mddev); - unsigned long flags; int i, ret = 0; - spin_lock_irqsave(&conf->device_lock, flags); - for (i=0; iraid_disks; i++) { + rcu_read_lock(); + for (i=0; iraid_disks && ret == 0; i++) { mdk_rdev_t *rdev = conf->mirrors[i].rdev; if (rdev && !rdev->faulty) { struct block_device *bdev = rdev->bdev; request_queue_t *r_queue = bdev_get_queue(bdev); - if (r_queue->issue_flush_fn) { - ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, error_sector); - if (ret) - break; + if (!r_queue->issue_flush_fn) + ret = -EOPNOTSUPP; + else { + atomic_inc(&rdev->nr_pending); + rcu_read_unlock(); + ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk, + error_sector); + rdev_dec_pending(rdev, mddev); + rcu_read_lock(); } } } - spin_unlock_irqrestore(&conf->device_lock, flags); + rcu_read_unlock(); return ret; } @@ -580,7 +583,7 @@ static int make_request(request_queue_t *q, struct bio * bio) * bios[x] to bio */ disks = conf->raid_disks; - spin_lock_irq(&conf->device_lock); + rcu_read_lock(); for (i = 0; i < disks; i++) { if (conf->mirrors[i].rdev && !conf->mirrors[i].rdev->faulty) { @@ -589,7 +592,7 @@ static int make_request(request_queue_t *q, struct bio * bio) } else r1_bio->bios[i] = NULL; } - spin_unlock_irq(&conf->device_lock); + rcu_read_unlock(); atomic_set(&r1_bio->remaining, 1); md_write_start(mddev); @@ -711,7 +714,6 @@ static int raid1_spare_active(mddev_t *mddev) conf_t *conf = mddev->private; mirror_info_t *tmp; - spin_lock_irq(&conf->device_lock); /* * Find all failed disks within the RAID1 configuration * and mark them readable @@ -726,7 +728,6 @@ static int raid1_spare_active(mddev_t *mddev) tmp->rdev->in_sync = 1; } } - spin_unlock_irq(&conf->device_lock); print_conf(conf); return 0; @@ -740,10 +741,8 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) int mirror; mirror_info_t *p; - spin_lock_irq(&conf->device_lock); for (mirror=0; mirror < mddev->raid_disks; mirror++) if ( !(p=conf->mirrors+mirror)->rdev) { - p->rdev = rdev; blk_queue_stack_limits(mddev->queue, rdev->bdev->bd_disk->queue); @@ -758,9 +757,9 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) p->head_position = 0; rdev->raid_disk = mirror; found = 1; + p->rdev = rdev; break; } - spin_unlock_irq(&conf->device_lock); print_conf(conf); return found; @@ -769,24 +768,27 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) static int raid1_remove_disk(mddev_t *mddev, int number) { conf_t *conf = mddev->private; - int err = 1; + int err = 0; + mdk_rdev_t *rdev; mirror_info_t *p = conf->mirrors+ number; print_conf(conf); - spin_lock_irq(&conf->device_lock); - if (p->rdev) { - if (p->rdev->in_sync || - atomic_read(&p->rdev->nr_pending)) { + rdev = p->rdev; + if (rdev) { + if (rdev->in_sync || + atomic_read(&rdev->nr_pending)) { err = -EBUSY; goto abort; } p->rdev = NULL; - err = 0; + synchronize_kernel(); + if (atomic_read(&rdev->nr_pending)) { + /* lost the race, try later */ + err = -EBUSY; + p->rdev = rdev; + } } - if (err) - MD_BUG(); abort: - spin_unlock_irq(&conf->device_lock); print_conf(conf); return err; @@ -904,11 +906,11 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) static void raid1d(mddev_t *mddev) { - struct list_head *head = &retry_list_head; r1bio_t *r1_bio; struct bio *bio; unsigned long flags; conf_t *conf = mddev_to_conf(mddev); + struct list_head *head = &conf->retry_list; int unplug=0; mdk_rdev_t *rdev; @@ -917,12 +919,12 @@ static void raid1d(mddev_t *mddev) for (;;) { char b[BDEVNAME_SIZE]; - spin_lock_irqsave(&retry_list_lock, flags); + spin_lock_irqsave(&conf->device_lock, flags); if (list_empty(head)) break; r1_bio = list_entry(head->prev, r1bio_t, retry_list); list_del(head->prev); - spin_unlock_irqrestore(&retry_list_lock, flags); + spin_unlock_irqrestore(&conf->device_lock, flags); mddev = r1_bio->mddev; conf = mddev_to_conf(mddev); @@ -941,6 +943,8 @@ static void raid1d(mddev_t *mddev) } else { r1_bio->bios[r1_bio->read_disk] = NULL; r1_bio->read_disk = disk; + bio_put(bio); + bio = bio_clone(r1_bio->master_bio, GFP_NOIO); r1_bio->bios[r1_bio->read_disk] = bio; rdev = conf->mirrors[disk].rdev; if (printk_ratelimit()) @@ -948,15 +952,17 @@ static void raid1d(mddev_t *mddev) " another mirror\n", bdevname(rdev->bdev,b), (unsigned long long)r1_bio->sector); - bio->bi_bdev = rdev->bdev; bio->bi_sector = r1_bio->sector + rdev->data_offset; + bio->bi_bdev = rdev->bdev; + bio->bi_end_io = raid1_end_read_request; bio->bi_rw = READ; + bio->bi_private = r1_bio; unplug = 1; generic_make_request(bio); } } } - spin_unlock_irqrestore(&retry_list_lock, flags); + spin_unlock_irqrestore(&conf->device_lock, flags); if (unplug) unplug_slaves(mddev); } @@ -1013,7 +1019,7 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) * put in a delay to throttle resync. */ if (!go_faster && waitqueue_active(&conf->wait_resume)) - schedule_timeout(HZ); + msleep_interruptible(1000); device_barrier(conf, sector_nr + RESYNC_SECTORS); /* @@ -1023,7 +1029,7 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) */ disk = conf->last_used; /* make sure disk is operational */ - spin_lock_irq(&conf->device_lock); + while (conf->mirrors[disk].rdev == NULL || !conf->mirrors[disk].rdev->in_sync) { if (disk <= 0) @@ -1034,7 +1040,7 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) } conf->last_used = disk; atomic_inc(&conf->mirrors[disk].rdev->nr_pending); - spin_unlock_irq(&conf->device_lock); + mirror = conf->mirrors + disk; @@ -1087,7 +1093,7 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) int rv = max_sector - sector_nr; md_done_sync(mddev, rv, 1); put_buf(r1_bio); - atomic_dec(&conf->mirrors[disk].rdev->nr_pending); + rdev_dec_pending(conf->mirrors[disk].rdev, mddev); return rv; } @@ -1204,11 +1210,12 @@ static int run(mddev_t *mddev) } conf->raid_disks = mddev->raid_disks; conf->mddev = mddev; - conf->device_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&conf->device_lock); + INIT_LIST_HEAD(&conf->retry_list); if (conf->working_disks == 1) mddev->recovery_cp = MaxSector; - conf->resync_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&conf->resync_lock); init_waitqueue_head(&conf->wait_idle); init_waitqueue_head(&conf->wait_resume); @@ -1286,6 +1293,7 @@ static int stop(mddev_t *mddev) md_unregister_thread(mddev->thread); mddev->thread = NULL; + blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ if (conf->r1bio_pool) mempool_destroy(conf->r1bio_pool); if (conf->mirrors)