Commit f3ddcd6b authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] raid ->diskop() splitup

	* ->diskop() split into individual methods; prototypes cleaned
up.  In particular, handling of hot_add_disk() gets mdk_rdev_t * of
the component we are adding as an argument instead of playing the games
with major/minor.  Code cleaned up.
parent 480f4106
...@@ -1741,8 +1741,7 @@ static int do_md_stop(mddev_t * mddev, int ro) ...@@ -1741,8 +1741,7 @@ static int do_md_stop(mddev_t * mddev, int ro)
md_unregister_thread(mddev->sync_thread); md_unregister_thread(mddev->sync_thread);
mddev->sync_thread = NULL; mddev->sync_thread = NULL;
if (mddev->spare) { if (mddev->spare) {
mddev->pers->diskop(mddev, &mddev->spare, mddev->pers->spare_inactive(mddev);
DISKOP_SPARE_INACTIVE);
mddev->spare = NULL; mddev->spare = NULL;
} }
} }
...@@ -2250,7 +2249,7 @@ static int hot_remove_disk(mddev_t * mddev, kdev_t dev) ...@@ -2250,7 +2249,7 @@ static int hot_remove_disk(mddev_t * mddev, kdev_t dev)
printk(KERN_INFO "md: trying to remove %s from md%d ... \n", printk(KERN_INFO "md: trying to remove %s from md%d ... \n",
partition_name(dev), mdidx(mddev)); partition_name(dev), mdidx(mddev));
if (!mddev->pers->diskop) { if (!mddev->pers->hot_remove_disk) {
printk(KERN_WARNING "md%d: personality does not support diskops!\n", printk(KERN_WARNING "md%d: personality does not support diskops!\n",
mdidx(mddev)); mdidx(mddev));
return -EINVAL; return -EINVAL;
...@@ -2274,7 +2273,7 @@ static int hot_remove_disk(mddev_t * mddev, kdev_t dev) ...@@ -2274,7 +2273,7 @@ static int hot_remove_disk(mddev_t * mddev, kdev_t dev)
return -EINVAL; return -EINVAL;
} }
err = mddev->pers->diskop(mddev, &disk, DISKOP_HOT_REMOVE_DISK); err = mddev->pers->hot_remove_disk(mddev, disk->number);
if (err == -EBUSY) { if (err == -EBUSY) {
MD_BUG(); MD_BUG();
goto busy; goto busy;
...@@ -2308,7 +2307,7 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev) ...@@ -2308,7 +2307,7 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev)
printk(KERN_INFO "md: trying to hot-add %s to md%d ... \n", printk(KERN_INFO "md: trying to hot-add %s to md%d ... \n",
partition_name(dev), mdidx(mddev)); partition_name(dev), mdidx(mddev));
if (!mddev->pers->diskop) { if (!mddev->pers->hot_add_disk) {
printk(KERN_WARNING "md%d: personality does not support diskops!\n", printk(KERN_WARNING "md%d: personality does not support diskops!\n",
mdidx(mddev)); mdidx(mddev));
return -EINVAL; return -EINVAL;
...@@ -2388,7 +2387,7 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev) ...@@ -2388,7 +2387,7 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev)
disk->major = major(dev); disk->major = major(dev);
disk->minor = minor(dev); disk->minor = minor(dev);
if (mddev->pers->diskop(mddev, &disk, DISKOP_HOT_ADD_DISK)) { if (mddev->pers->hot_add_disk(mddev, disk, rdev)) {
MD_BUG(); MD_BUG();
err = -EINVAL; err = -EINVAL;
goto abort_unbind_export; goto abort_unbind_export;
...@@ -3370,7 +3369,7 @@ void md_do_recovery(void *data) ...@@ -3370,7 +3369,7 @@ void md_do_recovery(void *data)
ITERATE_MDDEV(mddev,tmp) if (mddev_lock(mddev)==0) { ITERATE_MDDEV(mddev,tmp) if (mddev_lock(mddev)==0) {
sb = mddev->sb; sb = mddev->sb;
if (!sb || !mddev->pers || !mddev->pers->diskop || mddev->ro) if (!sb || !mddev->pers || mddev->ro)
goto unlock; goto unlock;
if (mddev->recovery_running > 0) if (mddev->recovery_running > 0)
/* resync/recovery still happening */ /* resync/recovery still happening */
...@@ -3384,16 +3383,19 @@ void md_do_recovery(void *data) ...@@ -3384,16 +3383,19 @@ void md_do_recovery(void *data)
* If we were doing a reconstruction, * If we were doing a reconstruction,
* we need to retrieve the spare * we need to retrieve the spare
*/ */
if (!mddev->pers->spare_inactive)
goto unlock;
if (mddev->spare) { if (mddev->spare) {
mddev->pers->diskop(mddev, &mddev->spare, mddev->pers->spare_inactive(mddev);
DISKOP_SPARE_INACTIVE);
mddev->spare = NULL; mddev->spare = NULL;
} }
} else { } else {
if (!mddev->pers->spare_active)
goto unlock;
/* success...*/ /* success...*/
if (mddev->spare) { if (mddev->spare) {
mddev->pers->diskop(mddev, &mddev->spare, mddev->pers->spare_active(mddev,
DISKOP_SPARE_ACTIVE); &mddev->spare);
mark_disk_sync(mddev->spare); mark_disk_sync(mddev->spare);
mark_disk_active(mddev->spare); mark_disk_active(mddev->spare);
sb->active_disks++; sb->active_disks++;
...@@ -3432,12 +3434,13 @@ void md_do_recovery(void *data) ...@@ -3432,12 +3434,13 @@ void md_do_recovery(void *data)
if (!mddev->sync_thread) { if (!mddev->sync_thread) {
printk(KERN_ERR "md%d: could not start resync thread...\n", mdidx(mddev)); printk(KERN_ERR "md%d: could not start resync thread...\n", mdidx(mddev));
if (mddev->spare) if (mddev->spare)
mddev->pers->diskop(mddev, &mddev->spare, DISKOP_SPARE_INACTIVE); mddev->pers->spare_inactive(mddev);
mddev->spare = NULL; mddev->spare = NULL;
mddev->recovery_running = 0; mddev->recovery_running = 0;
} else { } else {
if (mddev->spare) if (mddev->spare)
mddev->pers->diskop(mddev, &mddev->spare, DISKOP_SPARE_WRITE); mddev->pers->spare_write(mddev,
mddev->spare->number);
mddev->recovery_running = 1; mddev->recovery_running = 1;
md_wakeup_thread(mddev->sync_thread); md_wakeup_thread(mddev->sync_thread);
} }
......
...@@ -55,9 +55,8 @@ static mdk_personality_t multipath_personality; ...@@ -55,9 +55,8 @@ static mdk_personality_t multipath_personality;
static spinlock_t retry_list_lock = SPIN_LOCK_UNLOCKED; static spinlock_t retry_list_lock = SPIN_LOCK_UNLOCKED;
struct multipath_bh *multipath_retry_list = NULL, **multipath_retry_tail; 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) static struct multipath_bh *multipath_alloc_mpbh(multipath_conf_t *conf)
{ {
...@@ -366,11 +365,11 @@ static int multipath_error (mddev_t *mddev, struct block_device *bdev) ...@@ -366,11 +365,11 @@ static int multipath_error (mddev_t *mddev, struct block_device *bdev)
spare = get_spare(mddev); spare = get_spare(mddev);
if (spare) { 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)); printk("got DISKOP_SPARE_WRITE err: %d. (spare_faulty(): %d)\n", err, disk_faulty(spare));
} }
if (!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_sync(spare);
mark_disk_active(spare); mark_disk_active(spare);
sb->active_disks++; sb->active_disks++;
...@@ -410,26 +409,75 @@ static void print_multipath_conf (multipath_conf_t *conf) ...@@ -410,26 +409,75 @@ static void print_multipath_conf (multipath_conf_t *conf)
} }
} }
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)
{
multipath_conf_t *conf = mddev->private;
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; int err = 0;
int i, failed_disk=-1, spare_disk=-1, removed_disk=-1, added_disk=-1;
print_multipath_conf(conf);
spin_lock_irq(&conf->device_lock);
p = find_spare(mddev, mddev->spare->number);
if (p) {
p->operational = 0;
} else {
MD_BUG();
err = 1;
}
spin_unlock_irq(&conf->device_lock);
print_multipath_conf(conf);
return err;
}
static int multipath_spare_write(mddev_t *mddev, int number)
{
multipath_conf_t *conf = mddev->private; multipath_conf_t *conf = mddev->private;
struct multipath_info *tmp, *sdisk, *fdisk, *rdisk, *adisk; struct multipath_info *p;
mdp_super_t *sb = mddev->sb; int err = 0;
mdp_disk_t *failed_desc, *spare_desc, *added_desc;
mdk_rdev_t *spare_rdev, *failed_rdev;
struct block_device *bdev;
print_multipath_conf(conf); print_multipath_conf(conf);
spin_lock_irq(&conf->device_lock); spin_lock_irq(&conf->device_lock);
/* p = find_spare(mddev, number);
* find the disk ... if (p) {
*/ p->operational = 1;
switch (state) { } else {
MD_BUG();
err = 1;
}
spin_unlock_irq(&conf->device_lock);
print_multipath_conf(conf);
return err;
}
case DISKOP_SPARE_ACTIVE: 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;
print_multipath_conf(conf);
spin_lock_irq(&conf->device_lock);
/* /*
* Find the failed disk within the MULTIPATH configuration ... * Find the failed disk within the MULTIPATH configuration ...
* (this can only be in the first conf->working_disks part) * (this can only be in the first conf->working_disks part)
...@@ -446,16 +494,11 @@ static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state) ...@@ -446,16 +494,11 @@ static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state)
* When we activate a spare disk we _must_ have a disk in * When we activate a spare disk we _must_ have a disk in
* the lower (active) part of the array to replace. * the lower (active) part of the array to replace.
*/ */
if ((failed_disk == -1) || (failed_disk >= conf->raid_disks)) { if (failed_disk == -1) {
MD_BUG(); MD_BUG();
err = 1; err = 1;
goto abort; goto abort;
} }
/* fall through */
case DISKOP_SPARE_WRITE:
case DISKOP_SPARE_INACTIVE:
/* /*
* Find the spare disk ... (can only be in the 'high' * Find the spare disk ... (can only be in the 'high'
* area of the array) * area of the array)
...@@ -472,100 +515,16 @@ static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state) ...@@ -472,100 +515,16 @@ static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state)
err = 1; err = 1;
goto abort; 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;
case DISKOP_HOT_ADD_DISK:
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;
}
switch (state) {
/*
* Switch the spare disk to write-only mode:
*/
case DISKOP_SPARE_WRITE:
sdisk = conf->multipaths + spare_disk;
sdisk->operational = 1;
break;
/*
* Deactivate a spare disk:
*/
case DISKOP_SPARE_INACTIVE:
sdisk = conf->multipaths + spare_disk;
sdisk->operational = 0;
break;
/*
* 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)
*/
case DISKOP_SPARE_ACTIVE:
sdisk = conf->multipaths + spare_disk; sdisk = conf->multipaths + spare_disk;
fdisk = conf->multipaths + failed_disk; fdisk = conf->multipaths + failed_disk;
spare_desc = &sb->disks[sdisk->number]; spare_desc = &sb->disks[sdisk->number];
failed_desc = &sb->disks[fdisk->number]; failed_desc = &sb->disks[fdisk->number];
if (spare_desc != *d) { if (spare_desc != *d || spare_desc->raid_disk != sdisk->raid_disk ||
MD_BUG(); sdisk->raid_disk != spare_disk || fdisk->raid_disk != failed_disk ||
err = 1; failed_desc->raid_disk != fdisk->raid_disk) {
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;
}
if (failed_desc->raid_disk != fdisk->raid_disk) {
MD_BUG();
err = 1;
goto abort;
}
if (fdisk->raid_disk != failed_disk) {
MD_BUG(); MD_BUG();
err = 1; err = 1;
goto abort; goto abort;
...@@ -612,53 +571,76 @@ static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state) ...@@ -612,53 +571,76 @@ static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state)
*/ */
conf->working_disks++; conf->working_disks++;
abort:
spin_unlock_irq(&conf->device_lock);
break; print_multipath_conf(conf);
return err;
}
case DISKOP_HOT_REMOVE_DISK: static int multipath_add_disk(mddev_t *mddev, mdp_disk_t *added_desc,
rdisk = conf->multipaths + removed_disk; mdk_rdev_t *rdev)
{
multipath_conf_t *conf = mddev->private;
int err = 1;
int i;
if (rdisk->spare && (removed_disk < conf->raid_disks)) { print_multipath_conf(conf);
MD_BUG(); spin_lock_irq(&conf->device_lock);
err = 1; for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
goto abort; struct multipath_info *p = conf->multipaths + i;
} if (!p->used_slot) {
bdev = rdisk->bdev; if (added_desc->number != i)
rdisk->dev = NODEV;
rdisk->bdev = NULL;
rdisk->used_slot = 0;
conf->nr_disks--;
bdput(bdev);
break; break;
p->number = added_desc->number;
case DISKOP_HOT_ADD_DISK: p->raid_disk = added_desc->raid_disk;
adisk = conf->multipaths + added_disk; p->dev = rdev->dev;
added_desc = *d; p->bdev = rdev->bdev;
p->operational = 0;
if (added_disk != added_desc->number) { p->spare = 1;
MD_BUG(); p->used_slot = 1;
err = 1; conf->nr_disks++;
goto abort; err = 0;
break;
}
} }
if (err)
MD_BUG();
spin_unlock_irq(&conf->device_lock);
adisk->number = added_desc->number; print_multipath_conf(conf);
adisk->raid_disk = added_desc->raid_disk; return err;
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));
adisk->operational = 0; static int multipath_remove_disk(mddev_t *mddev, int number)
adisk->spare = 1; {
adisk->used_slot = 1; multipath_conf_t *conf = mddev->private;
conf->nr_disks++; int err = 1;
int i;
break; print_multipath_conf(conf);
spin_lock_irq(&conf->device_lock);
default: for (i = 0; i < MD_SB_DISKS; i++) {
MD_BUG(); struct multipath_info *p = conf->multipaths + i;
err = 1; 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; goto abort;
} }
if (p->spare && i < conf->raid_disks)
break;
p->dev = NODEV;
p->bdev = NULL;
p->used_slot = 0;
conf->nr_disks--;
err = 0;
break;
}
}
if (err)
MD_BUG();
abort: abort:
spin_unlock_irq(&conf->device_lock); spin_unlock_irq(&conf->device_lock);
...@@ -666,7 +648,6 @@ static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state) ...@@ -666,7 +648,6 @@ static int multipath_diskop(mddev_t *mddev, mdp_disk_t **d, int state)
return err; return err;
} }
#define IO_ERROR KERN_ALERT \ #define IO_ERROR KERN_ALERT \
"multipath: %s: unrecoverable IO read error for block %lu\n" "multipath: %s: unrecoverable IO read error for block %lu\n"
...@@ -1074,7 +1055,11 @@ static mdk_personality_t multipath_personality= ...@@ -1074,7 +1055,11 @@ static mdk_personality_t multipath_personality=
stop: multipath_stop, stop: multipath_stop,
status: multipath_status, status: multipath_status,
error_handler: multipath_error, 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) static int __init multipath_init (void)
......
...@@ -658,26 +658,30 @@ static void close_sync(conf_t *conf) ...@@ -658,26 +658,30 @@ static void close_sync(conf_t *conf)
conf->r1buf_pool = NULL; conf->r1buf_pool = NULL;
} }
static int diskop(mddev_t *mddev, mdp_disk_t **d, int state) static mirror_info_t *find_spare(mddev_t *mddev, int number)
{
conf_t *conf = mddev->private;
int i;
for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
mirror_info_t *p = conf->mirrors + i;
if (p->spare && p->number == number)
return p;
}
return NULL;
}
static int raid1_spare_active(mddev_t *mddev, mdp_disk_t **d)
{ {
int err = 0; int err = 0;
int i, failed_disk = -1, spare_disk = -1, removed_disk = -1, added_disk = -1; int i, failed_disk = -1, spare_disk = -1;
conf_t *conf = mddev->private; conf_t *conf = mddev->private;
mirror_info_t *tmp, *sdisk, *fdisk, *rdisk, *adisk; mirror_info_t *tmp, *sdisk, *fdisk;
mdp_super_t *sb = mddev->sb; mdp_super_t *sb = mddev->sb;
mdp_disk_t *failed_desc, *spare_desc, *added_desc; mdp_disk_t *failed_desc, *spare_desc;
mdk_rdev_t *spare_rdev, *failed_rdev; mdk_rdev_t *spare_rdev, *failed_rdev;
struct block_device *bdev;
print_conf(conf); print_conf(conf);
spin_lock_irq(&conf->device_lock); spin_lock_irq(&conf->device_lock);
/*
* find the disk ...
*/
switch (state) {
case DISKOP_SPARE_ACTIVE:
/* /*
* Find the failed disk within the RAID1 configuration ... * Find the failed disk within the RAID1 configuration ...
* (this can only be in the first conf->working_disks part) * (this can only be in the first conf->working_disks part)
...@@ -694,16 +698,11 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state) ...@@ -694,16 +698,11 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state)
* When we activate a spare disk we _must_ have a disk in * When we activate a spare disk we _must_ have a disk in
* the lower (active) part of the array to replace. * the lower (active) part of the array to replace.
*/ */
if ((failed_disk == -1) || (failed_disk >= conf->raid_disks)) { if (failed_disk == -1) {
MD_BUG(); MD_BUG();
err = 1; err = 1;
goto abort; goto abort;
} }
/* fall through */
case DISKOP_SPARE_WRITE:
case DISKOP_SPARE_INACTIVE:
/* /*
* Find the spare disk ... (can only be in the 'high' * Find the spare disk ... (can only be in the 'high'
* area of the array) * area of the array)
...@@ -720,101 +719,16 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state) ...@@ -720,101 +719,16 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state)
err = 1; err = 1;
goto abort; goto abort;
} }
break;
case DISKOP_HOT_REMOVE_DISK:
for (i = 0; i < MD_SB_DISKS; i++) {
tmp = conf->mirrors + i;
if (tmp->used_slot && (tmp->number == (*d)->number)) {
if (tmp->operational) {
err = -EBUSY;
goto abort;
}
removed_disk = i;
break;
}
}
if (removed_disk == -1) {
MD_BUG();
err = 1;
goto abort;
}
break;
case DISKOP_HOT_ADD_DISK:
for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
tmp = conf->mirrors + i;
if (!tmp->used_slot) {
added_disk = i;
break;
}
}
if (added_disk == -1) {
MD_BUG();
err = 1;
goto abort;
}
break;
}
switch (state) {
/*
* Switch the spare disk to write-only mode:
*/
case DISKOP_SPARE_WRITE:
sdisk = conf->mirrors + spare_disk;
sdisk->operational = 1;
sdisk->write_only = 1;
break;
/*
* Deactivate a spare disk:
*/
case DISKOP_SPARE_INACTIVE:
sdisk = conf->mirrors + spare_disk;
sdisk->operational = 0;
sdisk->write_only = 0;
break;
/*
* 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)
*/
case DISKOP_SPARE_ACTIVE:
sdisk = conf->mirrors + spare_disk; sdisk = conf->mirrors + spare_disk;
fdisk = conf->mirrors + failed_disk; fdisk = conf->mirrors + failed_disk;
spare_desc = &sb->disks[sdisk->number]; spare_desc = &sb->disks[sdisk->number];
failed_desc = &sb->disks[fdisk->number]; failed_desc = &sb->disks[fdisk->number];
if (spare_desc != *d) { if (spare_desc != *d || spare_desc->raid_disk != sdisk->raid_disk ||
MD_BUG(); sdisk->raid_disk != spare_disk || fdisk->raid_disk != failed_disk ||
err = 1; failed_desc->raid_disk != fdisk->raid_disk) {
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;
}
if (failed_desc->raid_disk != fdisk->raid_disk) {
MD_BUG();
err = 1;
goto abort;
}
if (fdisk->raid_disk != failed_disk) {
MD_BUG(); MD_BUG();
err = 1; err = 1;
goto abort; goto abort;
...@@ -866,55 +780,122 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state) ...@@ -866,55 +780,122 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state)
*/ */
conf->working_disks++; conf->working_disks++;
abort:
spin_unlock_irq(&conf->device_lock);
break; print_conf(conf);
return err;
}
case DISKOP_HOT_REMOVE_DISK: static int raid1_spare_inactive(mddev_t *mddev)
rdisk = conf->mirrors + removed_disk; {
conf_t *conf = mddev->private;
mirror_info_t *p;
int err = 0;
if (rdisk->spare && (removed_disk < conf->raid_disks)) { print_conf(conf);
spin_lock_irq(&conf->device_lock);
p = find_spare(mddev, mddev->spare->number);
if (p) {
p->operational = 0;
p->write_only = 0;
} else {
MD_BUG(); MD_BUG();
err = 1; err = 1;
goto abort;
} }
bdev = rdisk->bdev; spin_unlock_irq(&conf->device_lock);
rdisk->dev = NODEV; print_conf(conf);
rdisk->bdev = NULL; return err;
rdisk->used_slot = 0; }
conf->nr_disks--;
bdput(bdev);
break;
case DISKOP_HOT_ADD_DISK: static int raid1_spare_write(mddev_t *mddev, int number)
adisk = conf->mirrors + added_disk; {
added_desc = *d; conf_t *conf = mddev->private;
mirror_info_t *p;
int err = 0;
if (added_disk != added_desc->number) { print_conf(conf);
spin_lock_irq(&conf->device_lock);
p = find_spare(mddev, number);
if (p) {
p->operational = 1;
p->write_only = 1;
} else {
MD_BUG(); MD_BUG();
err = 1; err = 1;
goto abort;
} }
spin_unlock_irq(&conf->device_lock);
print_conf(conf);
return err;
}
adisk->number = added_desc->number; static int raid1_add_disk(mddev_t *mddev, mdp_disk_t *added_desc,
adisk->raid_disk = added_desc->raid_disk; mdk_rdev_t *rdev)
adisk->dev = mk_kdev(added_desc->major, added_desc->minor); {
/* it will be held open by rdev */ conf_t *conf = mddev->private;
adisk->bdev = bdget(kdev_t_to_nr(adisk->dev)); int err = 1;
int i;
adisk->operational = 0; print_conf(conf);
adisk->write_only = 0; spin_lock_irq(&conf->device_lock);
adisk->spare = 1; /*
adisk->used_slot = 1; * find the disk ...
adisk->head_position = 0; */
for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
mirror_info_t *p = conf->mirrors + i;
if (!p->used_slot) {
if (added_desc->number != i)
break;
p->number = added_desc->number;
p->raid_disk = added_desc->raid_disk;
p->dev = rdev->dev;
/* it will be held open by rdev */
p->bdev = rdev->bdev;
p->operational = 0;
p->write_only = 0;
p->spare = 1;
p->used_slot = 1;
p->head_position = 0;
conf->nr_disks++; conf->nr_disks++;
err = 0;
break; break;
}
default: }
if (err)
MD_BUG(); MD_BUG();
err = 1; spin_unlock_irq(&conf->device_lock);
print_conf(conf);
return err;
}
static int raid1_remove_disk(mddev_t *mddev, int number)
{
conf_t *conf = mddev->private;
int err = 1;
int i;
print_conf(conf);
spin_lock_irq(&conf->device_lock);
for (i = 0; i < MD_SB_DISKS; i++) {
mirror_info_t *p = conf->mirrors + i;
if (p->used_slot && (p->number == number)) {
if (p->operational) {
err = -EBUSY;
goto abort; goto abort;
} }
if (p->spare && (i < conf->raid_disks))
break;
p->dev = NODEV;
p->bdev = NULL;
p->used_slot = 0;
conf->nr_disks--;
err = 0;
break;
}
}
if (err)
MD_BUG();
abort: abort:
spin_unlock_irq(&conf->device_lock); spin_unlock_irq(&conf->device_lock);
...@@ -922,7 +903,6 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state) ...@@ -922,7 +903,6 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state)
return err; return err;
} }
#define IO_ERROR KERN_ALERT \ #define IO_ERROR KERN_ALERT \
"raid1: %s: unrecoverable I/O read error for block %lu\n" "raid1: %s: unrecoverable I/O read error for block %lu\n"
...@@ -1495,7 +1475,11 @@ static mdk_personality_t raid1_personality = ...@@ -1495,7 +1475,11 @@ static mdk_personality_t raid1_personality =
stop: stop, stop: stop,
status: status, status: status,
error_handler: error, error_handler: error,
diskop: diskop, hot_add_disk: raid1_add_disk,
hot_remove_disk:raid1_remove_disk,
spare_write: raid1_spare_write,
spare_inactive: raid1_spare_inactive,
spare_active: raid1_spare_active,
sync_request: sync_request sync_request: sync_request
}; };
......
...@@ -1694,29 +1694,30 @@ static void print_raid5_conf (raid5_conf_t *conf) ...@@ -1694,29 +1694,30 @@ static void print_raid5_conf (raid5_conf_t *conf)
} }
} }
static int diskop(mddev_t *mddev, mdp_disk_t **d, int state) static struct disk_info *find_spare(mddev_t *mddev, int number)
{
raid5_conf_t *conf = mddev->private;
int i;
for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
struct disk_info *p = conf->disks + i;
if (p->spare && p->number == number)
return p;
}
return NULL;
}
static int raid5_spare_active(mddev_t *mddev, mdp_disk_t **d)
{ {
int err = 0; int err = 0;
int i, failed_disk=-1, spare_disk=-1, removed_disk=-1, added_disk=-1; int i, failed_disk=-1, spare_disk=-1;
raid5_conf_t *conf = mddev->private; raid5_conf_t *conf = mddev->private;
struct disk_info *tmp, *sdisk, *fdisk, *rdisk, *adisk; struct disk_info *tmp, *sdisk, *fdisk;
mdp_super_t *sb = mddev->sb; mdp_super_t *sb = mddev->sb;
mdp_disk_t *failed_desc, *spare_desc, *added_desc; mdp_disk_t *failed_desc, *spare_desc;
mdk_rdev_t *spare_rdev, *failed_rdev; mdk_rdev_t *spare_rdev, *failed_rdev;
print_raid5_conf(conf); print_raid5_conf(conf);
spin_lock_irq(&conf->device_lock); spin_lock_irq(&conf->device_lock);
/*
* find the disk ...
*/
switch (state) {
case DISKOP_SPARE_ACTIVE:
/*
* Find the failed disk within the RAID5 configuration ...
* (this can only be in the first conf->raid_disks part)
*/
for (i = 0; i < conf->raid_disks; i++) { for (i = 0; i < conf->raid_disks; i++) {
tmp = conf->disks + i; tmp = conf->disks + i;
if ((!tmp->operational && !tmp->spare) || if ((!tmp->operational && !tmp->spare) ||
...@@ -1725,20 +1726,11 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state) ...@@ -1725,20 +1726,11 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state)
break; break;
} }
} }
/* if (failed_disk == -1) {
* 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(); MD_BUG();
err = 1; err = 1;
goto abort; goto abort;
} }
/* fall through */
case DISKOP_SPARE_WRITE:
case DISKOP_SPARE_INACTIVE:
/* /*
* Find the spare disk ... (can only be in the 'high' * Find the spare disk ... (can only be in the 'high'
* area of the array) * area of the array)
...@@ -1755,81 +1747,7 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state) ...@@ -1755,81 +1747,7 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state)
err = 1; err = 1;
goto abort; goto abort;
} }
break;
case DISKOP_HOT_REMOVE_DISK:
for (i = 0; i < MD_SB_DISKS; i++) {
tmp = conf->disks + i;
if (tmp->used_slot && (tmp->number == (*d)->number)) {
if (tmp->operational) {
err = -EBUSY;
goto abort;
}
removed_disk = i;
break;
}
}
if (removed_disk == -1) {
MD_BUG();
err = 1;
goto abort;
}
break;
case DISKOP_HOT_ADD_DISK:
for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
tmp = conf->disks + i;
if (!tmp->used_slot) {
added_disk = i;
break;
}
}
if (added_disk == -1) {
MD_BUG();
err = 1;
goto abort;
}
break;
}
switch (state) {
/*
* Switch the spare disk to write-only mode:
*/
case DISKOP_SPARE_WRITE:
if (conf->spare) {
MD_BUG();
err = 1;
goto abort;
}
sdisk = conf->disks + spare_disk;
sdisk->operational = 1;
sdisk->write_only = 1;
conf->spare = sdisk;
break;
/*
* Deactivate a spare disk:
*/
case DISKOP_SPARE_INACTIVE:
sdisk = conf->disks + spare_disk;
sdisk->operational = 0;
sdisk->write_only = 0;
/*
* Was the spare being resynced?
*/
if (conf->spare == sdisk)
conf->spare = NULL;
break;
/*
* 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->raid_disks'
* slots are used for 'real' disks and we must preserve this
* property)
*/
case DISKOP_SPARE_ACTIVE:
if (!conf->spare) { if (!conf->spare) {
MD_BUG(); MD_BUG();
err = 1; err = 1;
...@@ -1841,31 +1759,9 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state) ...@@ -1841,31 +1759,9 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state)
spare_desc = &sb->disks[sdisk->number]; spare_desc = &sb->disks[sdisk->number];
failed_desc = &sb->disks[fdisk->number]; failed_desc = &sb->disks[fdisk->number];
if (spare_desc != *d) { if (spare_desc != *d || spare_desc->raid_disk != sdisk->raid_disk ||
MD_BUG(); sdisk->raid_disk != spare_disk || fdisk->raid_disk != failed_disk ||
err = 1; failed_desc->raid_disk != fdisk->raid_disk) {
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;
}
if (failed_desc->raid_disk != fdisk->raid_disk) {
MD_BUG();
err = 1;
goto abort;
}
if (fdisk->raid_disk != failed_disk) {
MD_BUG(); MD_BUG();
err = 1; err = 1;
goto abort; goto abort;
...@@ -1919,56 +1815,126 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state) ...@@ -1919,56 +1815,126 @@ static int diskop(mddev_t *mddev, mdp_disk_t **d, int state)
conf->failed_disks--; conf->failed_disks--;
conf->working_disks++; conf->working_disks++;
conf->spare = NULL; conf->spare = NULL;
abort:
spin_unlock_irq(&conf->device_lock);
print_raid5_conf(conf);
return err;
}
break; static int raid5_spare_inactive(mddev_t *mddev)
{
case DISKOP_HOT_REMOVE_DISK: raid5_conf_t *conf = mddev->private;
rdisk = conf->disks + removed_disk; struct disk_info *p;
int err = 0;
if (rdisk->spare && (removed_disk < conf->raid_disks)) { print_raid5_conf(conf);
spin_lock_irq(&conf->device_lock);
p = find_spare(mddev, mddev->spare->number);
if (p) {
p->operational = 0;
p->write_only = 0;
if (conf->spare == p)
conf->spare = NULL;
} else {
MD_BUG(); MD_BUG();
err = 1; err = 1;
goto abort;
} }
rdisk->bdev = NULL; spin_unlock_irq(&conf->device_lock);
rdisk->used_slot = 0; print_raid5_conf(conf);
return err;
break; }
case DISKOP_HOT_ADD_DISK: static int raid5_spare_write(mddev_t *mddev, int number)
adisk = conf->disks + added_disk; {
added_desc = *d; raid5_conf_t *conf = mddev->private;
struct disk_info *p;
int err = 0;
if (added_disk != added_desc->number) { print_raid5_conf(conf);
spin_lock_irq(&conf->device_lock);
p = find_spare(mddev, number);
if (p && !conf->spare) {
p->operational = 1;
p->write_only = 1;
conf->spare = p;
} else {
MD_BUG(); MD_BUG();
err = 1; err = 1;
goto abort;
} }
spin_unlock_irq(&conf->device_lock);
print_raid5_conf(conf);
return err;
}
adisk->number = added_desc->number; static int raid5_remove_disk(mddev_t *mddev, int number)
adisk->raid_disk = added_desc->raid_disk; {
/* it will be held open by rdev */ raid5_conf_t *conf = mddev->private;
adisk->bdev = bdget(MKDEV(added_desc->major,added_desc->minor)); int err = 1;
int i;
adisk->operational = 0;
adisk->write_only = 0;
adisk->spare = 1;
adisk->used_slot = 1;
break; print_raid5_conf(conf);
spin_lock_irq(&conf->device_lock);
default: for (i = 0; i < MD_SB_DISKS; i++) {
MD_BUG(); struct disk_info *p = conf->disks + i;
err = 1; if (p->used_slot && p->number == number) {
if (p->operational) {
err = -EBUSY;
goto abort; goto abort;
} }
if (p->spare && i < conf->raid_disks)
break;
p->bdev = NULL;
p->used_slot = 0;
err = 0;
break;
}
}
if (err)
MD_BUG();
abort: abort:
spin_unlock_irq(&conf->device_lock); spin_unlock_irq(&conf->device_lock);
print_raid5_conf(conf); print_raid5_conf(conf);
return err; return err;
} }
static int raid5_add_disk(mddev_t *mddev, mdp_disk_t *added_desc,
mdk_rdev_t *rdev)
{
raid5_conf_t *conf = mddev->private;
int err = 1;
int i;
print_raid5_conf(conf);
spin_lock_irq(&conf->device_lock);
/*
* find the disk ...
*/
for (i = conf->raid_disks; i < MD_SB_DISKS; i++) {
struct disk_info *p = conf->disks + i;
if (!p->used_slot) {
if (added_desc->number != i)
break;
p->number = added_desc->number;
p->raid_disk = added_desc->raid_disk;
/* it will be held open by rdev */
p->bdev = rdev->bdev;
p->operational = 0;
p->write_only = 0;
p->spare = 1;
p->used_slot = 1;
err = 0;
break;
}
}
if (err)
MD_BUG();
spin_unlock_irq(&conf->device_lock);
print_raid5_conf(conf);
return err;
}
static mdk_personality_t raid5_personality= static mdk_personality_t raid5_personality=
{ {
name: "raid5", name: "raid5",
...@@ -1977,7 +1943,11 @@ static mdk_personality_t raid5_personality= ...@@ -1977,7 +1943,11 @@ static mdk_personality_t raid5_personality=
stop: stop, stop: stop,
status: status, status: status,
error_handler: error, error_handler: error,
diskop: diskop, hot_add_disk: raid5_add_disk,
hot_remove_disk:raid5_remove_disk,
spare_write: raid5_spare_write,
spare_inactive: raid5_spare_inactive,
spare_active: raid5_spare_active,
sync_request: sync_request sync_request: sync_request
}; };
......
...@@ -13,14 +13,9 @@ ...@@ -13,14 +13,9 @@
* Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl} * Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl}
*/ */
#include <linux/config.h> #include <linux/init.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/genhd.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/blk.h> #include <linux/blk.h>
#include <linux/init.h>
#include <linux/raid/md.h>
#include <linux/buffer_head.h> /* for invalidate_bdev() */ #include <linux/buffer_head.h> /* for invalidate_bdev() */
#include "check.h" #include "check.h"
......
...@@ -160,16 +160,6 @@ struct mdk_rdev_s ...@@ -160,16 +160,6 @@ struct mdk_rdev_s
int desc_nr; /* descriptor index in the superblock */ int desc_nr; /* descriptor index in the superblock */
}; };
/*
* disk operations in a working array:
*/
#define DISKOP_SPARE_INACTIVE 0
#define DISKOP_SPARE_WRITE 1
#define DISKOP_SPARE_ACTIVE 2
#define DISKOP_HOT_REMOVE_DISK 3
#define DISKOP_HOT_ADD_DISK 4
typedef struct mdk_personality_s mdk_personality_t; typedef struct mdk_personality_s mdk_personality_t;
struct mddev_s struct mddev_s
...@@ -214,18 +204,11 @@ struct mdk_personality_s ...@@ -214,18 +204,11 @@ struct mdk_personality_s
int (*stop)(mddev_t *mddev); int (*stop)(mddev_t *mddev);
int (*status)(char *page, mddev_t *mddev); int (*status)(char *page, mddev_t *mddev);
int (*error_handler)(mddev_t *mddev, struct block_device *bdev); int (*error_handler)(mddev_t *mddev, struct block_device *bdev);
int (*hot_add_disk) (mddev_t *mddev, mdp_disk_t *descriptor, mdk_rdev_t *rdev);
/* int (*hot_remove_disk) (mddev_t *mddev, int number);
* Some personalities (RAID-1, RAID-5) can have disks hot-added and int (*spare_write) (mddev_t *mddev, int number);
* hot-removed. Hot removal is different from failure. (failure marks int (*spare_inactive) (mddev_t *mddev);
* a disk inactive, but the disk is still part of the array) The interface int (*spare_active) (mddev_t *mddev, mdp_disk_t **descriptor);
* to such operations is the 'pers->diskop()' function, can be NULL.
*
* the diskop function can change the pointer pointing to the incoming
* descriptor, but must do so very carefully. (currently only
* SPARE_ACTIVE expects such a change)
*/
int (*diskop) (mddev_t *mddev, mdp_disk_t **descriptor, int state);
int (*sync_request)(mddev_t *mddev, sector_t sector_nr, int go_faster); int (*sync_request)(mddev_t *mddev, sector_t sector_nr, int go_faster);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment