From 01fbffad0ed6946c7c08c9aa2d6ac0cb6925507a Mon Sep 17 00:00:00 2001 From: Greg Lehey Date: Thu, 1 May 2003 01:30:59 +0000 Subject: [PATCH] Rewrite minor number decoding. Now we have only three types of object: subdisks, plexes and volumes. The encoding for plexes and subdisks no longer reflects the object to which they belong. The super devices are high-order volume numbers. This gives vastly more potential volumes (4 million instead of 256). As a result of the minor number changes, split out the superdevice handling into a separate function, vinum_super_ioctl. This was most of the code of vinumioctl. attachobject: Improve error checking. --- sys/dev/vinum/vinumioctl.c | 640 +++++++++++++++++++------------------ 1 file changed, 322 insertions(+), 318 deletions(-) diff --git a/sys/dev/vinum/vinumioctl.c b/sys/dev/vinum/vinumioctl.c index 3eac631fa9e..15e96c1da62 100644 --- a/sys/dev/vinum/vinumioctl.c +++ b/sys/dev/vinum/vinumioctl.c @@ -41,7 +41,7 @@ * otherwise) arising in any way out of the use of this software, even if * advised of the possibility of such damage. * - * $Id: vinumioctl.c,v 1.14 2000/10/27 03:07:53 grog Exp grog $ + * $Id: vinumioctl.c,v 1.20 2003/04/28 02:54:43 grog Exp $ * $FreeBSD$ */ @@ -69,345 +69,344 @@ vinumioctl(dev_t dev, struct thread *td) { unsigned int objno; - int error = 0; struct sd *sd; struct plex *plex; struct volume *vol; + + /* First, decide what we're looking at */ + if ((minor(dev) == VINUM_SUPERDEV_MINOR) + || (minor(dev) == VINUM_DAEMON_MINOR)) + return vinum_super_ioctl(dev, cmd, data); + else /* real device */ + switch (DEVTYPE(dev)) { + case VINUM_SD_TYPE: + case VINUM_SD2_TYPE: /* second half of sd namespace */ + objno = Sdno(dev); + + sd = &SD[objno]; + + switch (cmd) { + case DIOCGDINFO: /* get disk label */ + get_volume_label(sd->name, 1, sd->sectors, (struct disklabel *) data); + break; + + /* + * We don't have this stuff on hardware, + * so just pretend to do it so that + * utilities don't get upset. + */ + case DIOCWDINFO: /* write partition info */ + case DIOCSDINFO: /* set partition info */ + return 0; /* not a titty */ + + default: + return ENOTTY; /* not my kind of ioctl */ + } + + return 0; /* pretend we did it */ + + case VINUM_PLEX_TYPE: + objno = Plexno(dev); + + plex = &PLEX[objno]; + + switch (cmd) { + case DIOCGDINFO: /* get disk label */ + get_volume_label(plex->name, 1, plex->length, (struct disklabel *) data); + break; + + /* + * We don't have this stuff on hardware, + * so just pretend to do it so that + * utilities don't get upset. + */ + case DIOCWDINFO: /* write partition info */ + case DIOCSDINFO: /* set partition info */ + return 0; /* not a titty */ + + default: + return ENOTTY; /* not my kind of ioctl */ + } + + return 0; /* pretend we did it */ + + case VINUM_VOLUME_TYPE: + objno = Volno(dev); + + if ((unsigned) objno >= (unsigned) vinum_conf.volumes_allocated) /* not a valid volume */ + return ENXIO; + vol = &VOL[objno]; + if (vol->state != volume_up) /* not up, */ + return EIO; /* I/O error */ + + switch (cmd) { + case DIOCGDINFO: /* get disk label */ + get_volume_label(vol->name, vol->plexes, vol->size, (struct disklabel *) data); + break; + + /* + * We don't have this stuff on hardware, + * so just pretend to do it so that + * utilities don't get upset. + */ + case DIOCWDINFO: /* write partition info */ + case DIOCSDINFO: /* set partition info */ + return 0; /* not a titty */ + + default: + return ENOTTY; /* not my kind of ioctl */ + } + break; + } + return 0; /* XXX */ +} + +/* Handle ioctls for the super device */ +int +vinum_super_ioctl(dev_t dev, + u_long cmd, + caddr_t data) +{ + int error = 0; unsigned int index; /* for transferring config info */ unsigned int sdno; /* for transferring config info */ int fe; /* free list element number */ struct _ioctl_reply *ioctl_reply = (struct _ioctl_reply *) data; /* struct to return */ - /* First, decide what we're looking at */ - switch (DEVTYPE(dev)) { - case VINUM_SUPERDEV_TYPE: /* ordinary super device */ - ioctl_reply = (struct _ioctl_reply *) data; /* save the address to reply to */ - switch (cmd) { + ioctl_reply = (struct _ioctl_reply *) data; /* save the address to reply to */ + if (error) /* bombed out */ + return 0; /* the reply will contain meaningful info */ + switch (cmd) { #ifdef VINUMDEBUG - case VINUM_DEBUG: - if (((struct debuginfo *) data)->changeit) /* change debug settings */ - debug = (((struct debuginfo *) data)->param); - else { - if (debug & DEBUG_REMOTEGDB) - boothowto |= RB_GDB; /* serial debug line */ - else - boothowto &= ~RB_GDB; /* local ddb */ - Debugger("vinum debug"); - } - ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */ - ioctl_reply->error = 0; - return 0; + case VINUM_DEBUG: + if (((struct debuginfo *) data)->changeit) /* change debug settings */ + debug = (((struct debuginfo *) data)->param); + else { + if (debug & DEBUG_REMOTEGDB) + boothowto |= RB_GDB; /* serial debug line */ + else + boothowto &= ~RB_GDB; /* local ddb */ + Debugger("vinum debug"); + } + ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */ + ioctl_reply->error = 0; + return 0; #endif - case VINUM_CREATE: /* create a vinum object */ - error = lock_config(); /* get the config for us alone */ - if (error) /* can't do it, */ - return error; /* give up */ - error = setjmp(command_fail); /* come back here on error */ - if (error == 0) /* first time, */ - ioctl_reply->error = parse_user_config((char *) data, /* update the config */ - &keyword_set); - else if (ioctl_reply->error == 0) { /* longjmp, but no error status */ - ioctl_reply->error = EINVAL; /* note that something's up */ - ioctl_reply->msg[0] = '\0'; /* no message? */ - } - unlock_config(); - return 0; /* must be 0 to return the real error info */ + case VINUM_CREATE: /* create a vinum object */ + error = lock_config(); /* get the config for us alone */ + if (error) /* can't do it, */ + return error; /* give up */ + error = setjmp(command_fail); /* come back here on error */ + if (error == 0) /* first time, */ + ioctl_reply->error = parse_user_config((char *) data, /* update the config */ + &keyword_set); + else if (ioctl_reply->error == 0) { /* longjmp, but no error status */ + ioctl_reply->error = EINVAL; /* note that something's up */ + ioctl_reply->msg[0] = '\0'; /* no message? */ + } + unlock_config(); + return 0; /* must be 0 to return the real error info */ - case VINUM_GETCONFIG: /* get the configuration information */ - bcopy(&vinum_conf, data, sizeof(vinum_conf)); - return 0; + case VINUM_GETCONFIG: /* get the configuration information */ + bcopy(&vinum_conf, data, sizeof(vinum_conf)); + return 0; - /* start configuring the subsystem */ - case VINUM_STARTCONFIG: - return start_config(*(int *) data); /* just lock it. Parameter is 'force' */ + /* start configuring the subsystem */ + case VINUM_STARTCONFIG: + return start_config(*(int *) data); /* just lock it. Parameter is 'force' */ - /* - * Move the individual parts of the config to user space. - * - * Specify the index of the object in the first word of data, - * and return the object there - */ - case VINUM_DRIVECONFIG: - index = *(int *) data; /* get the index */ - if (index >= (unsigned) vinum_conf.drives_allocated) /* can't do it */ - return ENXIO; /* bang */ - bcopy(&DRIVE[index], data, sizeof(struct _drive)); /* copy the config item out */ - return 0; + /* + * Move the individual parts of the config to user space. + * + * Specify the index of the object in the first word of data, + * and return the object there + */ + case VINUM_DRIVECONFIG: + index = *(int *) data; /* get the index */ + if (index >= (unsigned) vinum_conf.drives_allocated) /* can't do it */ + return ENXIO; /* bang */ + bcopy(&DRIVE[index], data, sizeof(struct _drive)); /* copy the config item out */ + return 0; - case VINUM_SDCONFIG: - index = *(int *) data; /* get the index */ - if (index >= (unsigned) vinum_conf.subdisks_allocated) /* can't do it */ - return ENXIO; /* bang */ - bcopy(&SD[index], data, sizeof(struct _sd)); /* copy the config item out */ - return 0; + case VINUM_SDCONFIG: + index = *(int *) data; /* get the index */ + if (index >= (unsigned) vinum_conf.subdisks_allocated) /* can't do it */ + return ENXIO; /* bang */ + bcopy(&SD[index], data, sizeof(struct _sd)); /* copy the config item out */ + return 0; - case VINUM_PLEXCONFIG: - index = *(int *) data; /* get the index */ - if (index >= (unsigned) vinum_conf.plexes_allocated) /* can't do it */ - return ENXIO; /* bang */ - bcopy(&PLEX[index], data, sizeof(struct _plex)); /* copy the config item out */ - return 0; + case VINUM_PLEXCONFIG: + index = *(int *) data; /* get the index */ + if (index >= (unsigned) vinum_conf.plexes_allocated) /* can't do it */ + return ENXIO; /* bang */ + bcopy(&PLEX[index], data, sizeof(struct _plex)); /* copy the config item out */ + return 0; - case VINUM_VOLCONFIG: - index = *(int *) data; /* get the index */ - if (index >= (unsigned) vinum_conf.volumes_allocated) /* can't do it */ - return ENXIO; /* bang */ - bcopy(&VOL[index], data, sizeof(struct _volume)); /* copy the config item out */ - return 0; + case VINUM_VOLCONFIG: + index = *(int *) data; /* get the index */ + if (index >= (unsigned) vinum_conf.volumes_allocated) /* can't do it */ + return ENXIO; /* bang */ + bcopy(&VOL[index], data, sizeof(struct _volume)); /* copy the config item out */ + return 0; - case VINUM_PLEXSDCONFIG: - index = *(int *) data; /* get the plex index */ - sdno = ((int *) data)[1]; /* and the sd index */ - if ((index >= (unsigned) vinum_conf.plexes_allocated) /* plex doesn't exist */ - ||(sdno >= PLEX[index].subdisks)) /* or it doesn't have this many subdisks */ - return ENXIO; /* bang */ - bcopy(&SD[PLEX[index].sdnos[sdno]], /* copy the config item out */ - data, - sizeof(struct _sd)); - return 0; + case VINUM_PLEXSDCONFIG: + index = *(int *) data; /* get the plex index */ + sdno = ((int *) data)[1]; /* and the sd index */ + if ((index >= (unsigned) vinum_conf.plexes_allocated) /* plex doesn't exist */ + ||(sdno >= PLEX[index].subdisks)) /* or it doesn't have this many subdisks */ + return ENXIO; /* bang */ + bcopy(&SD[PLEX[index].sdnos[sdno]], /* copy the config item out */ + data, + sizeof(struct _sd)); + return 0; - /* - * We get called in two places: one from the - * userland config routines, which call us - * to complete the config and save it. This - * call supplies the value 0 as a parameter. - * - * The other place is from the user "saveconfig" - * routine, which can only work if we're *not* - * configuring. In this case, supply parameter 1. - */ - case VINUM_SAVECONFIG: - if (VFLAGS & VF_CONFIGURING) { /* must be us, the others are asleep */ - if (*(int *) data == 0) /* finish config */ - finish_config(1); /* finish the configuration and update it */ - else - return EBUSY; /* can't do it now */ - } + /* + * We get called in two places: one from the + * userland config routines, which call us + * to complete the config and save it. This + * call supplies the value 0 as a parameter. + * + * The other place is from the user "saveconfig" + * routine, which can only work if we're *not* + * configuring. In this case, supply parameter 1. + */ + case VINUM_SAVECONFIG: + if (VFLAGS & VF_CONFIGURING) { /* must be us, the others are asleep */ + if (*(int *) data == 0) /* finish config */ + finish_config(1); /* finish the configuration and update it */ + else + return EBUSY; /* can't do it now */ + } + save_config(); /* save configuration to disk */ + return 0; + + case VINUM_RELEASECONFIG: /* release the config */ + if (VFLAGS & VF_CONFIGURING) { /* must be us, the others are asleep */ + finish_config(0); /* finish the configuration, don't change it */ save_config(); /* save configuration to disk */ - return 0; + } else + error = EINVAL; /* release what config? */ + return error; - case VINUM_RELEASECONFIG: /* release the config */ - if (VFLAGS & VF_CONFIGURING) { /* must be us, the others are asleep */ - finish_config(0); /* finish the configuration, don't change it */ - save_config(); /* save configuration to disk */ - } else - error = EINVAL; /* release what config? */ - return error; + case VINUM_INIT: + ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */ + ioctl_reply->error = 0; + return 0; - case VINUM_INIT: + case VINUM_RESETCONFIG: + if (vinum_inactive(0)) { /* if the volumes are not active */ + /* + * Note the open count. We may be called from v, so we'll be open. + * Keep the count so we don't underflow + */ + free_vinum(1); /* clean up everything */ + log(LOG_NOTICE, "vinum: CONFIGURATION OBLITERATED\n"); ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */ ioctl_reply->error = 0; return 0; + } + return EBUSY; - case VINUM_RESETCONFIG: - if (vinum_inactive(0)) { /* if the volumes are not active */ - /* - * Note the open count. We may be called from v, so we'll be open. - * Keep the count so we don't underflow - */ - free_vinum(1); /* clean up everything */ - log(LOG_NOTICE, "vinum: CONFIGURATION OBLITERATED\n"); - ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */ - ioctl_reply->error = 0; - return 0; - } - return EBUSY; + case VINUM_SETSTATE: + setstate((struct vinum_ioctl_msg *) data); /* set an object state */ + return 0; - case VINUM_SETSTATE: - setstate((struct vinum_ioctl_msg *) data); /* set an object state */ - return 0; - - /* - * Set state by force, without changing - * anything else. - */ - case VINUM_SETSTATE_FORCE: - setstate_by_force((struct vinum_ioctl_msg *) data); /* set an object state */ - return 0; + /* + * Set state by force, without changing + * anything else. + */ + case VINUM_SETSTATE_FORCE: + setstate_by_force((struct vinum_ioctl_msg *) data); /* set an object state */ + return 0; #ifdef VINUMDEBUG - case VINUM_MEMINFO: - vinum_meminfo(data); - return 0; + case VINUM_MEMINFO: + vinum_meminfo(data); + return 0; - case VINUM_MALLOCINFO: - return vinum_mallocinfo(data); + case VINUM_MALLOCINFO: + return vinum_mallocinfo(data); - case VINUM_RQINFO: - return vinum_rqinfo(data); + case VINUM_RQINFO: + return vinum_rqinfo(data); #endif - case VINUM_LABEL: /* label a volume */ - ioctl_reply->error = write_volume_label(*(int *) data); /* index of the volume to label */ - ioctl_reply->msg[0] = '\0'; /* no message */ - return 0; + case VINUM_LABEL: /* label a volume */ + ioctl_reply->error = write_volume_label(*(int *) data); /* index of the volume to label */ + ioctl_reply->msg[0] = '\0'; /* no message */ + return 0; - case VINUM_REMOVE: - remove((struct vinum_ioctl_msg *) data); /* remove an object */ - return 0; + case VINUM_REMOVE: + remove((struct vinum_ioctl_msg *) data); /* remove an object */ + return 0; - case VINUM_GETFREELIST: /* get a drive free list element */ - index = *(int *) data; /* get the drive index */ - fe = ((int *) data)[1]; /* and the free list element */ - if ((index >= (unsigned) vinum_conf.drives_allocated) /* plex doesn't exist */ - ||(DRIVE[index].state == drive_unallocated)) - return ENODEV; - if (fe >= DRIVE[index].freelist_entries) /* no such entry */ - return ENOENT; - bcopy(&DRIVE[index].freelist[fe], - data, - sizeof(struct drive_freelist)); - return 0; + case VINUM_GETFREELIST: /* get a drive free list element */ + index = *(int *) data; /* get the drive index */ + fe = ((int *) data)[1]; /* and the free list element */ + if ((index >= (unsigned) vinum_conf.drives_allocated) /* plex doesn't exist */ + ||(DRIVE[index].state == drive_unallocated)) + return ENODEV; + if (fe >= DRIVE[index].freelist_entries) /* no such entry */ + return ENOENT; + bcopy(&DRIVE[index].freelist[fe], + data, + sizeof(struct drive_freelist)); + return 0; - case VINUM_RESETSTATS: - resetstats((struct vinum_ioctl_msg *) data); /* reset object stats */ - return 0; + case VINUM_RESETSTATS: + resetstats((struct vinum_ioctl_msg *) data); /* reset object stats */ + return 0; - /* attach an object to a superordinate object */ - case VINUM_ATTACH: - attachobject((struct vinum_ioctl_msg *) data); - return 0; + /* attach an object to a superordinate object */ + case VINUM_ATTACH: + attachobject((struct vinum_ioctl_msg *) data); + return 0; - /* detach an object from a superordinate object */ - case VINUM_DETACH: - detachobject((struct vinum_ioctl_msg *) data); - return 0; + /* detach an object from a superordinate object */ + case VINUM_DETACH: + detachobject((struct vinum_ioctl_msg *) data); + return 0; - /* rename an object */ - case VINUM_RENAME: - renameobject((struct vinum_rename_msg *) data); - return 0; + /* rename an object */ + case VINUM_RENAME: + renameobject((struct vinum_rename_msg *) data); + return 0; - /* replace an object */ - case VINUM_REPLACE: - replaceobject((struct vinum_ioctl_msg *) data); - return 0; + /* replace an object */ + case VINUM_REPLACE: + replaceobject((struct vinum_ioctl_msg *) data); + return 0; - case VINUM_DAEMON: - vinum_daemon(); /* perform the daemon */ - return 0; + case VINUM_DAEMON: + vinum_daemon(); /* perform the daemon */ + return 0; - case VINUM_FINDDAEMON: /* check for presence of daemon */ - return vinum_finddaemon(); - return 0; + case VINUM_FINDDAEMON: /* check for presence of daemon */ + return vinum_finddaemon(); + return 0; - case VINUM_SETDAEMON: /* set daemon flags */ - return vinum_setdaemonopts(*(int *) data); + case VINUM_SETDAEMON: /* set daemon flags */ + return vinum_setdaemonopts(*(int *) data); - case VINUM_GETDAEMON: /* get daemon flags */ - *(int *) data = daemon_options; - return 0; + case VINUM_GETDAEMON: /* get daemon flags */ + *(int *) data = daemon_options; + return 0; - case VINUM_PARITYOP: /* check/rebuild RAID-4/5 parity */ - parityops((struct vinum_ioctl_msg *) data); - return 0; + case VINUM_PARITYOP: /* check/rebuild RAID-4/5 parity */ + parityops((struct vinum_ioctl_msg *) data); + return 0; - /* move an object */ - case VINUM_MOVE: - moveobject((struct vinum_ioctl_msg *) data); - return 0; + /* move an object */ + case VINUM_MOVE: + moveobject((struct vinum_ioctl_msg *) data); + return 0; - default: - /* FALLTHROUGH */ - break; - } - - case VINUM_DRIVE_TYPE: default: - log(LOG_WARNING, - "vinumioctl: invalid ioctl from process %d (%s): %lx\n", - curthread->td_proc->p_pid, - curthread->td_proc->p_comm, - cmd); - return EINVAL; - - case VINUM_SD_TYPE: - case VINUM_RAWSD_TYPE: - objno = Sdno(dev); - - sd = &SD[objno]; - - switch (cmd) { - case DIOCGDINFO: /* get disk label */ - get_volume_label(sd->name, 1, sd->sectors, (struct disklabel *) data); - break; - - /* - * We don't have this stuff on hardware, - * so just pretend to do it so that - * utilities don't get upset. - */ - case DIOCWDINFO: /* write partition info */ - case DIOCSDINFO: /* set partition info */ - return 0; /* not a titty */ - - default: - return ENOTTY; /* not my kind of ioctl */ - } - - return 0; /* pretend we did it */ - - case VINUM_RAWPLEX_TYPE: - case VINUM_PLEX_TYPE: - objno = Plexno(dev); - - plex = &PLEX[objno]; - - switch (cmd) { - case DIOCGDINFO: /* get disk label */ - get_volume_label(plex->name, 1, plex->length, (struct disklabel *) data); - break; - - /* - * We don't have this stuff on hardware, - * so just pretend to do it so that - * utilities don't get upset. - */ - case DIOCWDINFO: /* write partition info */ - case DIOCSDINFO: /* set partition info */ - return 0; /* not a titty */ - - default: - return ENOTTY; /* not my kind of ioctl */ - } - - return 0; /* pretend we did it */ - - case VINUM_VOLUME_TYPE: - objno = Volno(dev); - - if ((unsigned) objno >= (unsigned) vinum_conf.volumes_allocated) /* not a valid volume */ - return ENXIO; - vol = &VOL[objno]; - if (vol->state != volume_up) /* not up, */ - return EIO; /* I/O error */ - - switch (cmd) { - - case DIOCGMEDIASIZE: - *(off_t *)data = vol->size << DEV_BSHIFT; - break; - - case DIOCGSECTORSIZE: - *(u_int *)data = DEV_BSIZE; - break; - - /* - * We don't have this stuff on hardware, - * so just pretend to do it so that - * utilities don't get upset. - */ - case DIOCWDINFO: /* write partition info */ - case DIOCSDINFO: /* set partition info */ - return 0; /* not a titty */ - - default: - return ENOTTY; /* not my kind of ioctl */ - } + /* FALLTHROUGH */ break; } - return 0; /* XXX */ + return 0; /* to keep the compiler happy */ } /* @@ -574,23 +573,24 @@ attachobject(struct vinum_ioctl_msg *msg) &&(!msg->force)) { /* without using force */ reply->error = EINVAL; /* no message, the user should check */ strcpy(reply->msg, "Can't attach to this plex organization"); - return; - } - if (sd->plexno >= 0) { /* already belong to a plex */ + } else if (sd->plexno >= 0) { /* already belong to a plex */ reply->error = EBUSY; /* no message, the user should check */ + sprintf(reply->msg, "%s is already attached to %s", + sd->name, + sd[sd->plexno].name); reply->msg[0] = '\0'; - return; + } else { + sd->plexoffset = msg->offset; /* this is where we want it */ + set_sd_state(sd->sdno, sd_stale, setstate_force); /* make sure it's stale */ + give_sd_to_plex(plex->plexno, sd->sdno); /* and give it to the plex */ + update_sd_config(sd->sdno, 0); + save_config(); + if (sd->state == sd_reviving) + reply->error = EAGAIN; /* need to revive it */ + else + reply->error = 0; } - sd->plexoffset = msg->offset; /* this is where we want it */ - set_sd_state(sd->sdno, sd_stale, setstate_force); /* make sure it's stale */ - give_sd_to_plex(plex->plexno, sd->sdno); /* and give it to the plex */ - update_sd_config(sd->sdno, 0); - save_config(); } - if (sd->state == sd_reviving) - reply->error = EAGAIN; /* need to revive it */ - else - reply->error = 0; break; case plex_object: @@ -599,23 +599,27 @@ attachobject(struct vinum_ioctl_msg *msg) return; vol = validvol(msg->otherobject, reply); /* and volume information */ if (vol) { - if ((vol->plexes == MAXPLEX) /* we have too many already */ - ||(plex->volno >= 0)) { /* or the plex has an owner */ - reply->error = EINVAL; /* no message, the user should check */ - reply->msg[0] = '\0'; - return; - } - for (sdno = 0; sdno < plex->subdisks; sdno++) { - sd = &SD[plex->sdnos[sdno]]; + if (vol->plexes == MAXPLEX) { /* we have too many already */ + reply->error = ENOSPC; /* nowhere to put it */ + strcpy(reply->msg, "Too many plexes"); + } else if (plex->volno >= 0) { /* the plex has an owner */ + reply->error = EBUSY; /* no message, the user should check */ + sprintf(reply->msg, "%s is already attached to %s", + plex->name, + VOL[plex->volno].name); + } else { + for (sdno = 0; sdno < plex->subdisks; sdno++) { + sd = &SD[plex->sdnos[sdno]]; - if (sd->state > sd_down) /* real subdisk, vaguely accessible */ - set_sd_state(plex->sdnos[sdno], sd_stale, setstate_force); /* make it stale */ + if (sd->state > sd_down) /* real subdisk, vaguely accessible */ + set_sd_state(plex->sdnos[sdno], sd_stale, setstate_force); /* make it stale */ + } + set_plex_state(plex->plexno, plex_up, setstate_none); /* update plex state */ + give_plex_to_volume(msg->otherobject, msg->index); /* and give it to the volume */ + update_plex_config(plex->plexno, 0); + save_config(); + reply->error = 0; /* all went well */ } - set_plex_state(plex->plexno, plex_up, setstate_none); /* update plex state */ - give_plex_to_volume(msg->otherobject, msg->index); /* and give it to the volume */ - update_plex_config(plex->plexno, 0); - save_config(); - reply->error = 0; /* all went well */ } } }