summaryrefslogtreecommitdiff
path: root/drivers/md/multipath.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md/multipath.c')
-rw-r--r--drivers/md/multipath.c440
1 files changed, 211 insertions, 229 deletions
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 32dc200aee66..ac08a9a90611 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -55,9 +55,8 @@ static mdk_personality_t multipath_personality;
static spinlock_t retry_list_lock = SPIN_LOCK_UNLOCKED;
struct multipath_bh *multipath_retry_list = NULL, **multipath_retry_tail;
-static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state);
-
-
+static int multipath_spare_write(mddev_t *, int);
+static int multipath_spare_active(mddev_t *mddev, mdp_disk_t **d);
static struct multipath_bh *multipath_alloc_mpbh(multipath_conf_t *conf)
{
@@ -313,14 +312,14 @@ static void mark_disk_bad (mddev_t *mddev, int failed)
mddev->sb_dirty = 1;
md_wakeup_thread(conf->thread);
conf->working_disks--;
- printk (DISK_FAILED, partition_name (multipath->dev),
+ printk (DISK_FAILED, bdev_partition_name (multipath->bdev),
conf->working_disks);
}
/*
* Careful, this can execute in IRQ contexts as well!
*/
-static int multipath_error (mddev_t *mddev, kdev_t dev)
+static int multipath_error (mddev_t *mddev, struct block_device *bdev)
{
multipath_conf_t *conf = mddev_to_conf(mddev);
struct multipath_info * multipaths = conf->multipaths;
@@ -345,7 +344,7 @@ static int multipath_error (mddev_t *mddev, kdev_t dev)
* which has just failed.
*/
for (i = 0; i < disks; i++) {
- if (kdev_same(multipaths[i].dev, dev) && !multipaths[i].operational)
+ if (multipaths[i].bdev == bdev && !multipaths[i].operational)
return 0;
}
printk (LAST_DISK);
@@ -354,7 +353,7 @@ static int multipath_error (mddev_t *mddev, kdev_t dev)
* Mark disk as unusable
*/
for (i = 0; i < disks; i++) {
- if (kdev_same(multipaths[i].dev,dev) && multipaths[i].operational) {
+ if (multipaths[i].bdev == bdev && multipaths[i].operational) {
mark_disk_bad(mddev, i);
break;
}
@@ -366,11 +365,11 @@ static int multipath_error (mddev_t *mddev, kdev_t dev)
spare = get_spare(mddev);
if (spare) {
- err = multipath_diskop(mddev, &spare, DISKOP_SPARE_WRITE);
+ err = multipath_spare_write(mddev, spare->number);
printk("got DISKOP_SPARE_WRITE err: %d. (spare_faulty(): %d)\n", err, disk_faulty(spare));
}
if (!err && !disk_faulty(spare)) {
- multipath_diskop(mddev, &spare, DISKOP_SPARE_ACTIVE);
+ multipath_spare_active(mddev, &spare);
mark_disk_sync(spare);
mark_disk_active(spare);
sb->active_disks++;
@@ -406,259 +405,240 @@ static void print_multipath_conf (multipath_conf_t *conf)
printk(" disk%d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n",
i, tmp->spare,tmp->operational,
tmp->number,tmp->raid_disk,tmp->used_slot,
- partition_name(tmp->dev));
+ bdev_partition_name(tmp->bdev));
}
}
-static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state)
+/*
+ * Find the spare disk ... (can only be in the 'high' area of the array)
+ */
+static struct multipath_info *find_spare(mddev_t *mddev, int number)
{
- int err = 0;
- int i, failed_disk=-1, spare_disk=-1, removed_disk=-1, added_disk=-1;
multipath_conf_t *conf = mddev->private;
- struct multipath_info *tmp, *sdisk, *fdisk, *rdisk, *adisk;
- mdp_super_t *sb = mddev->sb;
- mdp_disk_t *failed_desc, *spare_desc, *added_desc;
- mdk_rdev_t *spare_rdev, *failed_rdev;
- struct block_device *bdev;
+ int i;
+ for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
+ struct multipath_info *p = conf->multipaths + i;
+ if (p->spare && p->number == number)
+ return p;
+ }
+ return NULL;
+}
+
+static int multipath_spare_inactive(mddev_t *mddev)
+{
+ multipath_conf_t *conf = mddev->private;
+ struct multipath_info *p;
+ int err = 0;
print_multipath_conf(conf);
spin_lock_irq(&conf->device_lock);
- /*
- * find the disk ...
- */
- switch (state) {
-
- case DISKOP_SPARE_ACTIVE:
+ p = find_spare(mddev, mddev->spare->number);
+ if (p) {
+ p->operational = 0;
+ } else {
+ MD_BUG();
+ err = 1;
+ }
+ spin_unlock_irq(&conf->device_lock);
- /*
- * Find the failed disk within the MULTIPATH configuration ...
- * (this can only be in the first conf->working_disks part)
- */
- for (i = 0; i < conf->raid_disks; i++) {
- tmp = conf->multipaths + i;
- if ((!tmp->operational && !tmp->spare) ||
- !tmp->used_slot) {
- failed_disk = i;
- break;
- }
- }
- /*
- * When we activate a spare disk we _must_ have a disk in
- * the lower (active) part of the array to replace.
- */
- if ((failed_disk == -1) || (failed_disk >= conf->raid_disks)) {
- MD_BUG();
- err = 1;
- goto abort;
- }
- /* fall through */
+ print_multipath_conf(conf);
+ return err;
+}
- case DISKOP_SPARE_WRITE:
- case DISKOP_SPARE_INACTIVE:
+static int multipath_spare_write(mddev_t *mddev, int number)
+{
+ multipath_conf_t *conf = mddev->private;
+ struct multipath_info *p;
+ int err = 0;
- /*
- * Find the spare disk ... (can only be in the 'high'
- * area of the array)
- */
- for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
- tmp = conf->multipaths + i;
- if (tmp->spare && tmp->number == (*d)->number) {
- spare_disk = i;
- break;
- }
- }
- if (spare_disk == -1) {
- MD_BUG();
- err = 1;
- goto abort;
- }
- break;
-
- case DISKOP_HOT_REMOVE_DISK:
-
- for (i = 0; i < MD_SB_DISKS; i++) {
- tmp = conf->multipaths + i;
- if (tmp->used_slot && (tmp->number == (*d)->number)) {
- if (tmp->operational) {
- printk(KERN_ERR "hot-remove-disk, slot %d is identified to be the requested disk (number %d), but is still operational!\n", i, (*d)->number);
- err = -EBUSY;
- goto abort;
- }
- removed_disk = i;
- break;
- }
- }
- if (removed_disk == -1) {
- MD_BUG();
- err = 1;
- goto abort;
- }
- break;
+ print_multipath_conf(conf);
+ spin_lock_irq(&conf->device_lock);
+ p = find_spare(mddev, number);
+ if (p) {
+ p->operational = 1;
+ } else {
+ MD_BUG();
+ err = 1;
+ }
+ spin_unlock_irq(&conf->device_lock);
- case DISKOP_HOT_ADD_DISK:
+ print_multipath_conf(conf);
+ return err;
+}
- for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
- tmp = conf->multipaths + i;
- if (!tmp->used_slot) {
- added_disk = i;
- break;
- }
- }
- if (added_disk == -1) {
- MD_BUG();
- err = 1;
- goto abort;
- }
- break;
- }
+static int multipath_spare_active(mddev_t *mddev, mdp_disk_t **d)
+{
+ int err = 0;
+ int i, failed_disk=-1, spare_disk=-1;
+ multipath_conf_t *conf = mddev->private;
+ struct multipath_info *tmp, *sdisk, *fdisk;
+ mdp_super_t *sb = mddev->sb;
+ mdp_disk_t *failed_desc, *spare_desc;
+ mdk_rdev_t *spare_rdev, *failed_rdev;
- switch (state) {
+ print_multipath_conf(conf);
+ spin_lock_irq(&conf->device_lock);
/*
- * Switch the spare disk to write-only mode:
+ * Find the failed disk within the MULTIPATH configuration ...
+ * (this can only be in the first conf->working_disks part)
*/
- case DISKOP_SPARE_WRITE:
- sdisk = conf->multipaths + spare_disk;
- sdisk->operational = 1;
- break;
+ for (i = 0; i < conf->raid_disks; i++) {
+ tmp = conf->multipaths + i;
+ if ((!tmp->operational && !tmp->spare) ||
+ !tmp->used_slot) {
+ failed_disk = i;
+ break;
+ }
+ }
/*
- * Deactivate a spare disk:
+ * When we activate a spare disk we _must_ have a disk in
+ * the lower (active) part of the array to replace.
*/
- case DISKOP_SPARE_INACTIVE:
- sdisk = conf->multipaths + spare_disk;
- sdisk->operational = 0;
- break;
+ if (failed_disk == -1) {
+ MD_BUG();
+ err = 1;
+ goto abort;
+ }
/*
- * Activate (mark read-write) the (now sync) spare disk,
- * which means we switch it's 'raid position' (->raid_disk)
- * with the failed disk. (only the first 'conf->nr_disks'
- * slots are used for 'real' disks and we must preserve this
- * property)
+ * Find the spare disk ... (can only be in the 'high'
+ * area of the array)
*/
- case DISKOP_SPARE_ACTIVE:
- sdisk = conf->multipaths + spare_disk;
- fdisk = conf->multipaths + failed_disk;
-
- spare_desc = &sb->disks[sdisk->number];
- failed_desc = &sb->disks[fdisk->number];
-
- if (spare_desc != *d) {
- MD_BUG();
- err = 1;
- goto abort;
+ for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
+ tmp = conf->multipaths + i;
+ if (tmp->spare && tmp->number == (*d)->number) {
+ spare_disk = i;
+ break;
}
+ }
+ if (spare_disk == -1) {
+ MD_BUG();
+ err = 1;
+ goto abort;
+ }
- if (spare_desc->raid_disk != sdisk->raid_disk) {
- MD_BUG();
- err = 1;
- goto abort;
- }
-
- if (sdisk->raid_disk != spare_disk) {
- MD_BUG();
- err = 1;
- goto abort;
- }
+ sdisk = conf->multipaths + spare_disk;
+ fdisk = conf->multipaths + failed_disk;
- if (failed_desc->raid_disk != fdisk->raid_disk) {
- MD_BUG();
- err = 1;
- goto abort;
- }
+ spare_desc = &sb->disks[sdisk->number];
+ failed_desc = &sb->disks[fdisk->number];
- if (fdisk->raid_disk != failed_disk) {
- MD_BUG();
- err = 1;
- goto abort;
- }
+ if (spare_desc != *d || spare_desc->raid_disk != sdisk->raid_disk ||
+ sdisk->raid_disk != spare_disk || fdisk->raid_disk != failed_disk ||
+ failed_desc->raid_disk != fdisk->raid_disk) {
+ MD_BUG();
+ err = 1;
+ goto abort;
+ }
- /*
- * do the switch finally
- */
- spare_rdev = find_rdev_nr(mddev, spare_desc->number);
- failed_rdev = find_rdev_nr(mddev, failed_desc->number);
- xchg_values(spare_rdev->desc_nr, failed_rdev->desc_nr);
- spare_rdev->alias_device = 0;
- failed_rdev->alias_device = 1;
+ /*
+ * do the switch finally
+ */
+ spare_rdev = find_rdev_nr(mddev, spare_desc->number);
+ failed_rdev = find_rdev_nr(mddev, failed_desc->number);
+ xchg_values(spare_rdev->desc_nr, failed_rdev->desc_nr);
+ spare_rdev->alias_device = 0;
+ failed_rdev->alias_device = 1;
- xchg_values(*spare_desc, *failed_desc);
- xchg_values(*fdisk, *sdisk);
+ xchg_values(*spare_desc, *failed_desc);
+ xchg_values(*fdisk, *sdisk);
- /*
- * (careful, 'failed' and 'spare' are switched from now on)
- *
- * we want to preserve linear numbering and we want to
- * give the proper raid_disk number to the now activated
- * disk. (this means we switch back these values)
- */
-
- xchg_values(spare_desc->raid_disk, failed_desc->raid_disk);
- xchg_values(sdisk->raid_disk, fdisk->raid_disk);
- xchg_values(spare_desc->number, failed_desc->number);
- xchg_values(sdisk->number, fdisk->number);
+ /*
+ * (careful, 'failed' and 'spare' are switched from now on)
+ *
+ * we want to preserve linear numbering and we want to
+ * give the proper raid_disk number to the now activated
+ * disk. (this means we switch back these values)
+ */
- *d = failed_desc;
+ xchg_values(spare_desc->raid_disk, failed_desc->raid_disk);
+ xchg_values(sdisk->raid_disk, fdisk->raid_disk);
+ xchg_values(spare_desc->number, failed_desc->number);
+ xchg_values(sdisk->number, fdisk->number);
- if (!sdisk->bdev)
- sdisk->used_slot = 0;
- /*
- * this really activates the spare.
- */
- fdisk->spare = 0;
+ *d = failed_desc;
- /*
- * if we activate a spare, we definitely replace a
- * non-operational disk slot in the 'low' area of
- * the disk array.
- */
+ if (!sdisk->bdev)
+ sdisk->used_slot = 0;
+ /*
+ * this really activates the spare.
+ */
+ fdisk->spare = 0;
- conf->working_disks++;
+ /*
+ * if we activate a spare, we definitely replace a
+ * non-operational disk slot in the 'low' area of
+ * the disk array.
+ */
- break;
+ conf->working_disks++;
+abort:
+ spin_unlock_irq(&conf->device_lock);
- case DISKOP_HOT_REMOVE_DISK:
- rdisk = conf->multipaths + removed_disk;
+ print_multipath_conf(conf);
+ return err;
+}
- if (rdisk->spare && (removed_disk < conf->raid_disks)) {
- MD_BUG();
- err = 1;
- goto abort;
- }
- bdev = rdisk->bdev;
- rdisk->dev = NODEV;
- rdisk->bdev = NULL;
- rdisk->used_slot = 0;
- conf->nr_disks--;
- bdput(bdev);
- break;
-
- case DISKOP_HOT_ADD_DISK:
- adisk = conf->multipaths + added_disk;
- added_desc = *d;
-
- if (added_disk != added_desc->number) {
- MD_BUG();
- err = 1;
- goto abort;
+static int multipath_add_disk(mddev_t *mddev, mdp_disk_t *added_desc,
+ mdk_rdev_t *rdev)
+{
+ multipath_conf_t *conf = mddev->private;
+ int err = 1;
+ int i;
+
+ print_multipath_conf(conf);
+ spin_lock_irq(&conf->device_lock);
+ for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
+ struct multipath_info *p = conf->multipaths + i;
+ if (!p->used_slot) {
+ if (added_desc->number != i)
+ break;
+ p->number = added_desc->number;
+ p->raid_disk = added_desc->raid_disk;
+ p->bdev = rdev->bdev;
+ p->operational = 0;
+ p->spare = 1;
+ p->used_slot = 1;
+ conf->nr_disks++;
+ err = 0;
+ break;
}
+ }
+ if (err)
+ MD_BUG();
+ spin_unlock_irq(&conf->device_lock);
- adisk->number = added_desc->number;
- adisk->raid_disk = added_desc->raid_disk;
- adisk->dev = mk_kdev(added_desc->major,added_desc->minor);
- /* it will be held open by rdev */
- adisk->bdev = bdget(kdev_t_to_nr(adisk->dev));
+ print_multipath_conf(conf);
+ return err;
+}
- adisk->operational = 0;
- adisk->spare = 1;
- adisk->used_slot = 1;
- conf->nr_disks++;
+static int multipath_remove_disk(mddev_t *mddev, int number)
+{
+ multipath_conf_t *conf = mddev->private;
+ int err = 1;
+ int i;
- break;
+ print_multipath_conf(conf);
+ spin_lock_irq(&conf->device_lock);
- default:
- MD_BUG();
- err = 1;
- goto abort;
+ for (i = 0; i < MD_SB_DISKS; i++) {
+ struct multipath_info *p = conf->multipaths + i;
+ if (p->used_slot && (p->number == number)) {
+ if (p->operational) {
+ printk(KERN_ERR "hot-remove-disk, slot %d is identified to be the requested disk (number %d), but is still operational!\n", i, number);
+ err = -EBUSY;
+ goto abort;
+ }
+ if (p->spare && i < conf->raid_disks)
+ break;
+ p->bdev = NULL;
+ p->used_slot = 0;
+ conf->nr_disks--;
+ err = 0;
+ break;
+ }
}
+ if (err)
+ MD_BUG();
abort:
spin_unlock_irq(&conf->device_lock);
@@ -666,7 +646,6 @@ abort:
return err;
}
-
#define IO_ERROR KERN_ALERT \
"multipath: %s: unrecoverable IO read error for block %lu\n"
@@ -872,7 +851,7 @@ static int multipath_run (mddev_t *mddev)
if (rdev->faulty) {
/* this is a "should never happen" case and if it */
/* ever does happen, a continue; won't help */
- printk(ERRORS, partition_name(rdev->dev));
+ printk(ERRORS, bdev_partition_name(rdev->bdev));
continue;
} else {
/* this is a "should never happen" case and if it */
@@ -892,7 +871,7 @@ static int multipath_run (mddev_t *mddev)
disk = conf->multipaths + disk_idx;
if (!disk_sync(desc))
- printk(NOT_IN_SYNC, partition_name(rdev->dev));
+ printk(NOT_IN_SYNC, bdev_partition_name(rdev->bdev));
/*
* Mark all disks as spare to start with, then pick our
@@ -901,7 +880,6 @@ static int multipath_run (mddev_t *mddev)
*/
disk->number = desc->number;
disk->raid_disk = desc->raid_disk;
- disk->dev = rdev->dev;
disk->bdev = rdev->bdev;
atomic_inc(&rdev->bdev->bd_count);
disk->operational = 0;
@@ -911,7 +889,7 @@ static int multipath_run (mddev_t *mddev)
if (disk_active(desc)) {
if(!conf->working_disks) {
- printk(OPERATIONAL, partition_name(rdev->dev),
+ printk(OPERATIONAL, bdev_partition_name(rdev->bdev),
desc->raid_disk);
disk->operational = 1;
disk->spare = 0;
@@ -928,7 +906,7 @@ static int multipath_run (mddev_t *mddev)
if(!conf->working_disks && num_rdevs) {
desc = &sb->disks[def_rdev->desc_nr];
disk = conf->multipaths + desc->raid_disk;
- printk(OPERATIONAL, partition_name(def_rdev->dev),
+ printk(OPERATIONAL, bdev_partition_name(def_rdev->bdev),
disk->raid_disk);
disk->operational = 1;
disk->spare = 0;
@@ -1074,7 +1052,11 @@ static mdk_personality_t multipath_personality=
stop: multipath_stop,
status: multipath_status,
error_handler: multipath_error,
- diskop: multipath_diskop,
+ hot_add_disk: multipath_add_disk,
+ hot_remove_disk:multipath_remove_disk,
+ spare_inactive: multipath_spare_inactive,
+ spare_active: multipath_spare_active,
+ spare_write: multipath_spare_write,
};
static int __init multipath_init (void)