diff options
Diffstat (limited to 'drivers/md/multipath.c')
| -rw-r--r-- | drivers/md/multipath.c | 156 |
1 files changed, 81 insertions, 75 deletions
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index c3589099098..849ad39f547 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -20,6 +20,7 @@ */ #include <linux/blkdev.h> +#include <linux/module.h> #include <linux/raid/md_u.h> #include <linux/seq_file.h> #include <linux/slab.h> @@ -31,7 +32,7 @@ #define NR_RESERVED_BUFS 32 -static int multipath_map (multipath_conf_t *conf) +static int multipath_map (struct mpconf *conf) { int i, disks = conf->raid_disks; @@ -42,7 +43,7 @@ static int multipath_map (multipath_conf_t *conf) rcu_read_lock(); for (i = 0; i < disks; i++) { - mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev); + struct md_rdev *rdev = rcu_dereference(conf->multipaths[i].rdev); if (rdev && test_bit(In_sync, &rdev->flags)) { atomic_inc(&rdev->nr_pending); rcu_read_unlock(); @@ -58,8 +59,8 @@ static int multipath_map (multipath_conf_t *conf) static void multipath_reschedule_retry (struct multipath_bh *mp_bh) { unsigned long flags; - mddev_t *mddev = mp_bh->mddev; - multipath_conf_t *conf = mddev->private; + struct mddev *mddev = mp_bh->mddev; + struct mpconf *conf = mddev->private; spin_lock_irqsave(&conf->device_lock, flags); list_add(&mp_bh->retry_list, &conf->retry_list); @@ -76,7 +77,7 @@ static void multipath_reschedule_retry (struct multipath_bh *mp_bh) static void multipath_end_bh_io (struct multipath_bh *mp_bh, int err) { struct bio *bio = mp_bh->master_bio; - multipath_conf_t *conf = mp_bh->mddev->private; + struct mpconf *conf = mp_bh->mddev->private; bio_endio(bio, err); mempool_free(mp_bh, conf->pool); @@ -86,8 +87,8 @@ static void multipath_end_request(struct bio *bio, int error) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct multipath_bh *mp_bh = bio->bi_private; - multipath_conf_t *conf = mp_bh->mddev->private; - mdk_rdev_t *rdev = conf->multipaths[mp_bh->path].rdev; + struct mpconf *conf = mp_bh->mddev->private; + struct md_rdev *rdev = conf->multipaths[mp_bh->path].rdev; if (uptodate) multipath_end_bh_io(mp_bh, 0); @@ -99,22 +100,22 @@ static void multipath_end_request(struct bio *bio, int error) md_error (mp_bh->mddev, rdev); printk(KERN_ERR "multipath: %s: rescheduling sector %llu\n", bdevname(rdev->bdev,b), - (unsigned long long)bio->bi_sector); + (unsigned long long)bio->bi_iter.bi_sector); multipath_reschedule_retry(mp_bh); } else multipath_end_bh_io(mp_bh, error); rdev_dec_pending(rdev, conf->mddev); } -static int multipath_make_request(mddev_t *mddev, struct bio * bio) +static void multipath_make_request(struct mddev *mddev, struct bio * bio) { - multipath_conf_t *conf = mddev->private; + struct mpconf *conf = mddev->private; struct multipath_bh * mp_bh; struct multipath_info *multipath; if (unlikely(bio->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bio); - return 0; + return; } mp_bh = mempool_alloc(conf->pool, GFP_NOIO); @@ -126,27 +127,27 @@ static int multipath_make_request(mddev_t *mddev, struct bio * bio) if (mp_bh->path < 0) { bio_endio(bio, -EIO); mempool_free(mp_bh, conf->pool); - return 0; + return; } multipath = conf->multipaths + mp_bh->path; mp_bh->bio = *bio; - mp_bh->bio.bi_sector += multipath->rdev->data_offset; + mp_bh->bio.bi_iter.bi_sector += multipath->rdev->data_offset; mp_bh->bio.bi_bdev = multipath->rdev->bdev; mp_bh->bio.bi_rw |= REQ_FAILFAST_TRANSPORT; mp_bh->bio.bi_end_io = multipath_end_request; mp_bh->bio.bi_private = mp_bh; generic_make_request(&mp_bh->bio); - return 0; + return; } -static void multipath_status (struct seq_file *seq, mddev_t *mddev) +static void multipath_status (struct seq_file *seq, struct mddev *mddev) { - multipath_conf_t *conf = mddev->private; + struct mpconf *conf = mddev->private; int i; seq_printf (seq, " [%d/%d] [", conf->raid_disks, - conf->working_disks); + conf->raid_disks - mddev->degraded); for (i = 0; i < conf->raid_disks; i++) seq_printf (seq, "%s", conf->multipaths[i].rdev && @@ -156,8 +157,8 @@ static void multipath_status (struct seq_file *seq, mddev_t *mddev) static int multipath_congested(void *data, int bits) { - mddev_t *mddev = data; - multipath_conf_t *conf = mddev->private; + struct mddev *mddev = data; + struct mpconf *conf = mddev->private; int i, ret = 0; if (mddev_congested(mddev, bits)) @@ -165,7 +166,7 @@ static int multipath_congested(void *data, int bits) rcu_read_lock(); for (i = 0; i < mddev->raid_disks ; i++) { - mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev); + struct md_rdev *rdev = rcu_dereference(conf->multipaths[i].rdev); if (rdev && !test_bit(Faulty, &rdev->flags)) { struct request_queue *q = bdev_get_queue(rdev->bdev); @@ -183,41 +184,42 @@ static int multipath_congested(void *data, int bits) /* * Careful, this can execute in IRQ contexts as well! */ -static void multipath_error (mddev_t *mddev, mdk_rdev_t *rdev) +static void multipath_error (struct mddev *mddev, struct md_rdev *rdev) { - multipath_conf_t *conf = mddev->private; + struct mpconf *conf = mddev->private; + char b[BDEVNAME_SIZE]; - if (conf->working_disks <= 1) { + if (conf->raid_disks - mddev->degraded <= 1) { /* * Uh oh, we can do nothing if this is our last path, but * first check if this is a queued request for a device * which has just failed. */ printk(KERN_ALERT - "multipath: only one IO path left and IO error.\n"); + "multipath: only one IO path left and IO error.\n"); /* leave it active... it's all we have */ - } else { - /* - * Mark disk as unusable - */ - if (!test_bit(Faulty, &rdev->flags)) { - char b[BDEVNAME_SIZE]; - clear_bit(In_sync, &rdev->flags); - set_bit(Faulty, &rdev->flags); - set_bit(MD_CHANGE_DEVS, &mddev->flags); - conf->working_disks--; - mddev->degraded++; - printk(KERN_ALERT "multipath: IO failure on %s," - " disabling IO path.\n" - "multipath: Operation continuing" - " on %d IO paths.\n", - bdevname (rdev->bdev,b), - conf->working_disks); - } + return; + } + /* + * Mark disk as unusable + */ + if (test_and_clear_bit(In_sync, &rdev->flags)) { + unsigned long flags; + spin_lock_irqsave(&conf->device_lock, flags); + mddev->degraded++; + spin_unlock_irqrestore(&conf->device_lock, flags); } + set_bit(Faulty, &rdev->flags); + set_bit(MD_CHANGE_DEVS, &mddev->flags); + printk(KERN_ALERT "multipath: IO failure on %s," + " disabling IO path.\n" + "multipath: Operation continuing" + " on %d IO paths.\n", + bdevname(rdev->bdev, b), + conf->raid_disks - mddev->degraded); } -static void print_multipath_conf (multipath_conf_t *conf) +static void print_multipath_conf (struct mpconf *conf) { int i; struct multipath_info *tmp; @@ -227,7 +229,7 @@ static void print_multipath_conf (multipath_conf_t *conf) printk("(conf==NULL)\n"); return; } - printk(" --- wd:%d rd:%d\n", conf->working_disks, + printk(" --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded, conf->raid_disks); for (i = 0; i < conf->raid_disks; i++) { @@ -241,9 +243,9 @@ static void print_multipath_conf (multipath_conf_t *conf) } -static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) +static int multipath_add_disk(struct mddev *mddev, struct md_rdev *rdev) { - multipath_conf_t *conf = mddev->private; + struct mpconf *conf = mddev->private; struct request_queue *q; int err = -EEXIST; int path; @@ -274,10 +276,11 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) PAGE_CACHE_SIZE - 1); } - conf->working_disks++; + spin_lock_irq(&conf->device_lock); mddev->degraded--; rdev->raid_disk = path; set_bit(In_sync, &rdev->flags); + spin_unlock_irq(&conf->device_lock); rcu_assign_pointer(p->rdev, rdev); err = 0; md_integrity_add_rdev(rdev, mddev); @@ -289,17 +292,16 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) return err; } -static int multipath_remove_disk(mddev_t *mddev, int number) +static int multipath_remove_disk(struct mddev *mddev, struct md_rdev *rdev) { - multipath_conf_t *conf = mddev->private; + struct mpconf *conf = mddev->private; int err = 0; - mdk_rdev_t *rdev; + int number = rdev->raid_disk; struct multipath_info *p = conf->multipaths + number; print_multipath_conf(conf); - rdev = p->rdev; - if (rdev) { + if (rdev == p->rdev) { if (test_bit(In_sync, &rdev->flags) || atomic_read(&rdev->nr_pending)) { printk(KERN_ERR "hot-remove-disk, slot %d is identified" @@ -333,12 +335,13 @@ abort: * 3. Performs writes following reads for array syncronising. */ -static void multipathd (mddev_t *mddev) +static void multipathd(struct md_thread *thread) { + struct mddev *mddev = thread->mddev; struct multipath_bh *mp_bh; struct bio *bio; unsigned long flags; - multipath_conf_t *conf = mddev->private; + struct mpconf *conf = mddev->private; struct list_head *head = &conf->retry_list; md_check_recovery(mddev); @@ -352,21 +355,22 @@ static void multipathd (mddev_t *mddev) spin_unlock_irqrestore(&conf->device_lock, flags); bio = &mp_bh->bio; - bio->bi_sector = mp_bh->master_bio->bi_sector; + bio->bi_iter.bi_sector = mp_bh->master_bio->bi_iter.bi_sector; if ((mp_bh->path = multipath_map (conf))<0) { printk(KERN_ALERT "multipath: %s: unrecoverable IO read" " error for block %llu\n", bdevname(bio->bi_bdev,b), - (unsigned long long)bio->bi_sector); + (unsigned long long)bio->bi_iter.bi_sector); multipath_end_bh_io(mp_bh, -EIO); } else { printk(KERN_ERR "multipath: %s: redirecting sector %llu" " to another IO path\n", bdevname(bio->bi_bdev,b), - (unsigned long long)bio->bi_sector); + (unsigned long long)bio->bi_iter.bi_sector); *bio = *(mp_bh->master_bio); - bio->bi_sector += conf->multipaths[mp_bh->path].rdev->data_offset; + bio->bi_iter.bi_sector += + conf->multipaths[mp_bh->path].rdev->data_offset; bio->bi_bdev = conf->multipaths[mp_bh->path].rdev->bdev; bio->bi_rw |= REQ_FAILFAST_TRANSPORT; bio->bi_end_io = multipath_end_request; @@ -377,7 +381,7 @@ static void multipathd (mddev_t *mddev) spin_unlock_irqrestore(&conf->device_lock, flags); } -static sector_t multipath_size(mddev_t *mddev, sector_t sectors, int raid_disks) +static sector_t multipath_size(struct mddev *mddev, sector_t sectors, int raid_disks) { WARN_ONCE(sectors || raid_disks, "%s does not support generic reshape\n", __func__); @@ -385,12 +389,13 @@ static sector_t multipath_size(mddev_t *mddev, sector_t sectors, int raid_disks) return mddev->dev_sectors; } -static int multipath_run (mddev_t *mddev) +static int multipath_run (struct mddev *mddev) { - multipath_conf_t *conf; + struct mpconf *conf; int disk_idx; struct multipath_info *disk; - mdk_rdev_t *rdev; + struct md_rdev *rdev; + int working_disks; if (md_check_no_bitmap(mddev)) return -EINVAL; @@ -406,7 +411,7 @@ static int multipath_run (mddev_t *mddev) * should be freed in multipath_stop()] */ - conf = kzalloc(sizeof(multipath_conf_t), GFP_KERNEL); + conf = kzalloc(sizeof(struct mpconf), GFP_KERNEL); mddev->private = conf; if (!conf) { printk(KERN_ERR @@ -424,8 +429,8 @@ static int multipath_run (mddev_t *mddev) goto out_free_conf; } - conf->working_disks = 0; - list_for_each_entry(rdev, &mddev->disks, same_set) { + working_disks = 0; + rdev_for_each(rdev, mddev) { disk_idx = rdev->raid_disk; if (disk_idx < 0 || disk_idx >= mddev->raid_disks) @@ -446,7 +451,7 @@ static int multipath_run (mddev_t *mddev) } if (!test_bit(Faulty, &rdev->flags)) - conf->working_disks++; + working_disks++; } conf->raid_disks = mddev->raid_disks; @@ -454,12 +459,12 @@ static int multipath_run (mddev_t *mddev) spin_lock_init(&conf->device_lock); INIT_LIST_HEAD(&conf->retry_list); - if (!conf->working_disks) { + if (!working_disks) { printk(KERN_ERR "multipath: no operational IO paths for %s\n", mdname(mddev)); goto out_free_conf; } - mddev->degraded = conf->raid_disks - conf->working_disks; + mddev->degraded = conf->raid_disks - working_disks; conf->pool = mempool_create_kmalloc_pool(NR_RESERVED_BUFS, sizeof(struct multipath_bh)); @@ -471,7 +476,8 @@ static int multipath_run (mddev_t *mddev) } { - mddev->thread = md_register_thread(multipathd, mddev, NULL); + mddev->thread = md_register_thread(multipathd, mddev, + "multipath"); if (!mddev->thread) { printk(KERN_ERR "multipath: couldn't allocate thread" " for %s\n", mdname(mddev)); @@ -481,7 +487,8 @@ static int multipath_run (mddev_t *mddev) printk(KERN_INFO "multipath: array %s active with %d out of %d IO paths\n", - mdname(mddev), conf->working_disks, mddev->raid_disks); + mdname(mddev), conf->raid_disks - mddev->degraded, + mddev->raid_disks); /* * Ok, everything is just fine now */ @@ -506,12 +513,11 @@ out: } -static int multipath_stop (mddev_t *mddev) +static int multipath_stop (struct mddev *mddev) { - multipath_conf_t *conf = mddev->private; + struct mpconf *conf = mddev->private; - md_unregister_thread(mddev->thread); - mddev->thread = NULL; + md_unregister_thread(&mddev->thread); blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ mempool_destroy(conf->pool); kfree(conf->multipaths); @@ -520,7 +526,7 @@ static int multipath_stop (mddev_t *mddev) return 0; } -static struct mdk_personality multipath_personality = +static struct md_personality multipath_personality = { .name = "multipath", .level = LEVEL_MULTIPATH, |
