2 * XXX replace all the checks on object validity with
3 * calls to valid<object>
6 * Copyright (c) 1997, 1998, 1999
7 * Nan Yang Computer Services Limited. All rights reserved.
9 * Parts copyright (c) 1997, 1998 Cybernet Corporation, NetMAX project.
11 * Written by Greg Lehey
13 * This software is distributed under the so-called ``Berkeley
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. All advertising materials mentioning features or use of this software
25 * must display the following acknowledgement:
26 * This product includes software developed by Nan Yang Computer
28 * 4. Neither the name of the Company nor the names of its contributors
29 * may be used to endorse or promote products derived from this software
30 * without specific prior written permission.
32 * This software is provided ``as is'', and any express or implied
33 * warranties, including, but not limited to, the implied warranties of
34 * merchantability and fitness for a particular purpose are disclaimed.
35 * In no event shall the company or contributors be liable for any
36 * direct, indirect, incidental, special, exemplary, or consequential
37 * damages (including, but not limited to, procurement of substitute
38 * goods or services; loss of use, data, or profits; or business
39 * interruption) however caused and on any theory of liability, whether
40 * in contract, strict liability, or tort (including negligence or
41 * otherwise) arising in any way out of the use of this software, even if
42 * advised of the possibility of such damage.
44 * $Id: vinumioctl.c,v 1.14 2000/10/27 03:07:53 grog Exp grog $
45 * $FreeBSD: src/sys/dev/vinum/vinumioctl.c,v 1.25.2.4 2002/02/03 00:44:19 grog Exp $
46 * $DragonFly: src/sys/dev/raid/vinum/vinumioctl.c,v 1.11 2007/07/13 18:55:45 dillon Exp $
53 #include <sys/reboot.h>
56 void attachobject(struct vinum_ioctl_msg *);
57 void detachobject(struct vinum_ioctl_msg *);
58 void renameobject(struct vinum_rename_msg *);
59 void replaceobject(struct vinum_ioctl_msg *);
60 void moveobject(struct vinum_ioctl_msg *);
62 jmp_buf command_fail; /* return on a failed command */
66 vinumioctl(struct dev_ioctl_args *ap)
68 cdev_t dev = ap->a_head.a_dev;
69 u_long cmd = ap->a_cmd;
70 caddr_t data = ap->a_data;
72 unsigned int index; /* for transferring config info */
73 unsigned int sdno; /* for transferring config info */
76 struct partinfo *dpart;
77 int fe; /* free list element number */
78 struct _ioctl_reply *ioctl_reply; /* struct to return */
82 /* First, decide what we're looking at */
83 switch (DEVTYPE(dev)) {
84 case VINUM_SUPERDEV_TYPE: /* ordinary super device */
85 ioctl_reply = (struct _ioctl_reply *) data; /* save the address to reply to */
89 if (((struct debuginfo *) data)->changeit) /* change debug settings */
90 debug = (((struct debuginfo *) data)->param);
92 if (debug & DEBUG_REMOTEGDB)
93 boothowto |= RB_GDB; /* serial debug line */
95 boothowto &= ~RB_GDB; /* local ddb */
96 Debugger("vinum debug");
98 ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */
99 ioctl_reply->error = 0;
103 case VINUM_CREATE: /* create a vinum object */
104 error = lock_config(); /* get the config for us alone */
105 if (error) /* can't do it, */
107 error = setjmp(command_fail); /* come back here on error */
108 if (error == 0) /* first time, */
109 ioctl_reply->error = parse_user_config((char *) data, /* update the config */
111 else if (ioctl_reply->error == 0) { /* longjmp, but no error status */
113 ioctl_reply->error = EINVAL; /* note that something's up */
114 ioctl_reply->msg[0] = '\0'; /* no message? */
119 case VINUM_GETCONFIG: /* get the configuration information */
120 bcopy(&vinum_conf, data, sizeof(vinum_conf));
123 /* start configuring the subsystem */
124 case VINUM_STARTCONFIG:
125 error = start_config(*(int *) data); /* just lock it. Parameter is 'force' */
128 case VINUM_DRIVECONFIG:
130 * Move the individual parts of the config to user space.
132 * Specify the index of the object in the first word of data,
133 * and return the object there
135 index = *(int *) data;
136 if (index >= (unsigned)vinum_conf.drives_allocated) {
139 bcopy(&DRIVE[index], data, sizeof(struct drive));
144 index = *(int *) data;
145 if (index >= (unsigned) vinum_conf.subdisks_allocated) {
148 bcopy(&SD[index], data, sizeof(struct sd));
152 case VINUM_PLEXCONFIG:
153 index = *(int *) data;
154 if (index >= (unsigned) vinum_conf.plexes_allocated) {
157 bcopy(&PLEX[index], data, sizeof(struct plex));
161 case VINUM_VOLCONFIG:
162 index = *(int *) data;
163 if (index >= (unsigned) vinum_conf.volumes_allocated) {
166 bcopy(&VOL[index], data, sizeof(struct volume));
170 case VINUM_PLEXSDCONFIG:
171 index = ((int *)data)[0]; /* get the plex index */
172 sdno = ((int *)data)[1]; /* and the sd index */
173 if ((index >= (unsigned) vinum_conf.plexes_allocated)
174 ||(sdno >= PLEX[index].subdisks)) {
177 bcopy(&SD[PLEX[index].sdnos[sdno]], data, sizeof(struct sd));
180 case VINUM_SAVECONFIG:
182 * We get called in two places: one from the
183 * userland config routines, which call us
184 * to complete the config and save it. This
185 * call supplies the value 0 as a parameter.
187 * The other place is from the user "saveconfig"
188 * routine, which can only work if we're *not*
189 * configuring. In this case, supply parameter 1.
191 if (VFLAGS & VF_CONFIGURING) { /* must be us, the others are asleep */
192 if (*(int *) data == 0) /* finish config */
193 finish_config(1); /* finish the configuration and update it */
198 save_config(); /* save configuration to disk */
201 case VINUM_RELEASECONFIG: /* release the config */
202 if (VFLAGS & VF_CONFIGURING) { /* must be us, the others are asleep */
203 finish_config(0); /* finish the configuration, don't change it */
204 save_config(); /* save configuration to disk */
206 error = EINVAL; /* release what config? */
211 ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */
212 ioctl_reply->error = 0;
215 case VINUM_RESETCONFIG:
216 if (vinum_inactive(0)) { /* if the volumes are not active */
218 * Note the open count. We may be called from v, so we'll be open.
219 * Keep the count so we don't underflow
221 free_vinum(1); /* clean up everything */
222 log(LOG_NOTICE, "vinum: CONFIGURATION OBLITERATED\n");
223 ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */
224 ioctl_reply->error = 0;
230 setstate((struct vinum_ioctl_msg *) data); /* set an object state */
234 * Set state by force, without changing
237 case VINUM_SETSTATE_FORCE:
238 setstate_by_force((struct vinum_ioctl_msg *) data); /* set an object state */
246 case VINUM_MALLOCINFO:
247 error = vinum_mallocinfo(data);
251 error = vinum_rqinfo(data);
256 remove((struct vinum_ioctl_msg *) data); /* remove an object */
259 case VINUM_GETFREELIST: /* get a drive free list element */
260 index = *(int *) data; /* get the drive index */
261 fe = ((int *) data)[1]; /* and the free list element */
262 if ((index >= (unsigned) vinum_conf.drives_allocated) /* plex doesn't exist */
263 ||(DRIVE[index].state == drive_unallocated)) {
265 } else if (fe >= DRIVE[index].freelist_entries) {
268 bcopy(&DRIVE[index].freelist[fe], data,
269 sizeof(struct drive_freelist));
273 case VINUM_RESETSTATS:
274 resetstats((struct vinum_ioctl_msg *) data); /* reset object stats */
277 /* attach an object to a superordinate object */
279 attachobject((struct vinum_ioctl_msg *) data);
282 /* detach an object from a superordinate object */
284 detachobject((struct vinum_ioctl_msg *) data);
287 /* rename an object */
289 renameobject((struct vinum_rename_msg *) data);
292 /* replace an object */
294 replaceobject((struct vinum_ioctl_msg *) data);
298 vinum_daemon(); /* perform the daemon */
301 case VINUM_FINDDAEMON: /* check for presence of daemon */
302 error = vinum_finddaemon();
305 case VINUM_SETDAEMON: /* set daemon flags */
306 error = vinum_setdaemonopts(*(int *) data);
309 case VINUM_GETDAEMON: /* get daemon flags */
310 *(int *) data = daemon_options;
313 case VINUM_PARITYOP: /* check/rebuild RAID-4/5 parity */
314 parityops((struct vinum_ioctl_msg *) data);
319 moveobject((struct vinum_ioctl_msg *) data);
327 case VINUM_DRIVE_TYPE:
329 case VINUM_RAWSD_TYPE:
330 case VINUM_RAWPLEX_TYPE:
331 case VINUM_PLEX_TYPE:
334 case VINUM_VOLUME_TYPE:
337 if ((unsigned)objno >= (unsigned)vinum_conf.volumes_allocated) {
342 if (vol->state != volume_up) {
349 dpart = (void *)data;
351 bzero(dpart, sizeof(*dpart));
352 dpart->media_offset = 0;
353 dpart->media_size = (u_int64_t)vol->size * DEV_BSIZE;
354 dpart->media_blocks = vol->size;
355 dpart->media_blksize = DEV_BSIZE;
356 dpart->fstype = FS_BSDFFS;
368 "vinumioctl: invalid ioctl from process %d (%s): %lx\n",
377 * The following four functions check the supplied
378 * object index and return a pointer to the object
379 * if it exists. Otherwise they longjump out via
383 validdrive(int driveno, struct _ioctl_reply *reply)
385 if ((driveno < vinum_conf.drives_allocated)
386 && (DRIVE[driveno].state > drive_referenced))
387 return &DRIVE[driveno];
388 strcpy(reply->msg, "No such drive");
389 reply->error = ENOENT;
394 validsd(int sdno, struct _ioctl_reply *reply)
396 if ((sdno < vinum_conf.subdisks_allocated)
397 && (SD[sdno].state > sd_referenced))
399 strcpy(reply->msg, "No such subdisk");
400 reply->error = ENOENT;
405 validplex(int plexno, struct _ioctl_reply *reply)
407 if ((plexno < vinum_conf.plexes_allocated)
408 && (PLEX[plexno].state > plex_referenced))
409 return &PLEX[plexno];
410 strcpy(reply->msg, "No such plex");
411 reply->error = ENOENT;
416 validvol(int volno, struct _ioctl_reply *reply)
418 if ((volno < vinum_conf.volumes_allocated)
419 && (VOL[volno].state > volume_uninit))
421 strcpy(reply->msg, "No such volume");
422 reply->error = ENOENT;
426 /* reset an object's stats */
428 resetstats(struct vinum_ioctl_msg *msg)
430 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
434 if (msg->index < vinum_conf.drives_allocated) {
435 struct drive *drive = &DRIVE[msg->index];
436 if (drive->state > drive_referenced) {
437 drive->reads = 0; /* number of reads on this drive */
438 drive->writes = 0; /* number of writes on this drive */
439 drive->bytes_read = 0; /* number of bytes read */
440 drive->bytes_written = 0; /* number of bytes written */
444 reply->error = EINVAL;
448 if (msg->index < vinum_conf.subdisks_allocated) {
449 struct sd *sd = &SD[msg->index];
450 if (sd->state > sd_referenced) {
451 sd->reads = 0; /* number of reads on this subdisk */
452 sd->writes = 0; /* number of writes on this subdisk */
453 sd->bytes_read = 0; /* number of bytes read */
454 sd->bytes_written = 0; /* number of bytes written */
458 reply->error = EINVAL;
464 if (msg->index < vinum_conf.plexes_allocated) {
465 struct plex *plex = &PLEX[msg->index];
466 if (plex->state > plex_referenced) {
468 plex->writes = 0; /* number of writes on this plex */
469 plex->bytes_read = 0; /* number of bytes read */
470 plex->bytes_written = 0; /* number of bytes written */
471 plex->recovered_reads = 0; /* number of recovered read operations */
472 plex->degraded_writes = 0; /* number of degraded writes */
473 plex->parityless_writes = 0; /* number of parityless writes */
474 plex->multiblock = 0; /* requests that needed more than one block */
475 plex->multistripe = 0; /* requests that needed more than one stripe */
479 reply->error = EINVAL;
485 if (msg->index < vinum_conf.volumes_allocated) {
486 struct volume *vol = &VOL[msg->index];
487 if (vol->state > volume_uninit) {
488 vol->bytes_read = 0; /* number of bytes read */
489 vol->bytes_written = 0; /* number of bytes written */
490 vol->reads = 0; /* number of reads on this volume */
491 vol->writes = 0; /* number of writes on this volume */
492 vol->recovered_reads = 0; /* reads recovered from another plex */
496 reply->error = EINVAL;
499 case invalid_object: /* can't get this */
500 reply->error = EINVAL;
505 /* attach an object to a superior object */
507 attachobject(struct vinum_ioctl_msg *msg)
509 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
516 case drive_object: /* you can't attach a drive to anything */
517 case volume_object: /* nor a volume */
518 case invalid_object: /* "this can't happen" */
519 reply->error = EINVAL;
520 reply->msg[0] = '\0'; /* vinum(8) doesn't do this */
524 sd = validsd(msg->index, reply);
525 if (sd == NULL) /* not a valid subdisk */
527 plex = validplex(msg->otherobject, reply);
530 * We should be more intelligent about this.
531 * We should be able to reattach a dead
532 * subdisk, but if we want to increase the total
533 * number of subdisks, we have a lot of reshuffling
536 if ((plex->organization != plex_concat) /* can't attach to striped and RAID-4/5 */
537 &&(!msg->force)) { /* without using force */
538 reply->error = EINVAL; /* no message, the user should check */
539 strcpy(reply->msg, "Can't attach to this plex organization");
542 if (sd->plexno >= 0) { /* already belong to a plex */
543 reply->error = EBUSY; /* no message, the user should check */
544 reply->msg[0] = '\0';
547 sd->plexoffset = msg->offset; /* this is where we want it */
548 set_sd_state(sd->sdno, sd_stale, setstate_force); /* make sure it's stale */
549 give_sd_to_plex(plex->plexno, sd->sdno); /* and give it to the plex */
550 update_sd_config(sd->sdno, 0);
553 if (sd->state == sd_reviving)
554 reply->error = EAGAIN; /* need to revive it */
560 plex = validplex(msg->index, reply); /* get plex */
563 vol = validvol(msg->otherobject, reply); /* and volume information */
565 if ((vol->plexes == MAXPLEX) /* we have too many already */
566 ||(plex->volno >= 0)) { /* or the plex has an owner */
567 reply->error = EINVAL; /* no message, the user should check */
568 reply->msg[0] = '\0';
571 for (sdno = 0; sdno < plex->subdisks; sdno++) {
572 sd = &SD[plex->sdnos[sdno]];
574 if (sd->state > sd_down) /* real subdisk, vaguely accessible */
575 set_sd_state(plex->sdnos[sdno], sd_stale, setstate_force); /* make it stale */
577 set_plex_state(plex->plexno, plex_up, setstate_none); /* update plex state */
578 give_plex_to_volume(msg->otherobject, msg->index); /* and give it to the volume */
579 update_plex_config(plex->plexno, 0);
585 /* detach an object from a superior object */
587 detachobject(struct vinum_ioctl_msg *msg)
589 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
597 case drive_object: /* you can't detach a drive from anything */
598 case volume_object: /* nor a volume */
599 case invalid_object: /* "this can't happen" */
600 reply->error = EINVAL;
601 reply->msg[0] = '\0'; /* vinum(8) doesn't do this */
605 sd = validsd(msg->index, reply);
608 if (sd->plexno < 0) { /* doesn't belong to a plex */
609 reply->error = ENOENT;
610 strcpy(reply->msg, "Subdisk is not attached");
612 } else { /* valid plex number */
613 plex = &PLEX[sd->plexno];
614 if ((!msg->force) /* don't force things */
615 &&((plex->state == plex_up) /* and the plex is up */
616 ||((plex->state == plex_flaky) && sd->state == sd_up))) { /* or flaky with this sd up */
617 reply->error = EBUSY; /* we need this sd */
618 reply->msg[0] = '\0';
621 sd->plexno = -1; /* anonymous sd */
622 if (plex->subdisks == 1) { /* this was the only subdisk */
623 Free(plex->sdnos); /* free the subdisk array */
624 plex->sdnos = NULL; /* and note the fact */
625 plex->subdisks_allocated = 0; /* no subdisk space */
627 for (sdno = 0; sdno < plex->subdisks; sdno++) {
628 if (plex->sdnos[sdno] == msg->index) /* found our subdisk */
631 if (sdno < (plex->subdisks - 1)) /* not the last one, compact */
632 bcopy(&plex->sdnos[sdno + 1],
634 (plex->subdisks - 1 - sdno) * sizeof(int));
637 if (!bcmp(plex->name, sd->name, strlen(plex->name) + 1))
638 /* this subdisk is named after the plex */
642 imin(strlen(sd->name) + 1, MAXSDNAME - 3));
643 bcopy("ex-", sd->name, 3);
644 sd->name[MAXSDNAME - 1] = '\0';
646 update_plex_config(plex->plexno, 0);
647 if (isstriped(plex)) /* we've just mutilated our plex, */
648 set_plex_state(plex->plexno,
650 setstate_force | setstate_configuring);
657 plex = validplex(msg->index, reply); /* get plex */
660 if (plex->volno >= 0) {
661 int volno = plex->volno;
664 if ((!msg->force) /* don't force things */
665 &&((vol->state == volume_up) /* and the volume is up */
666 &&(vol->plexes == 1))) { /* and this is the last plex */
668 * XXX As elsewhere, check whether we will lose
669 * mapping by removing this plex
671 reply->error = EBUSY; /* we need this plex */
672 reply->msg[0] = '\0';
675 plex->volno = -1; /* anonymous plex */
676 for (plexno = 0; plexno < vol->plexes; plexno++) {
677 if (vol->plex[plexno] == msg->index) /* found our plex */
680 if (plexno < (vol->plexes - 1)) /* not the last one, compact */
681 bcopy(&vol->plex[plexno + 1],
683 (vol->plexes - 1 - plexno) * sizeof(int));
685 vol->last_plex_read = 0; /* don't go beyond the end */
686 if (!bcmp(vol->name, plex->name, strlen(vol->name) + 1))
687 /* this plex is named after the volume */
689 /* First, check if the subdisks are the same */
693 for (sdno = 0; sdno < plex->subdisks; sdno++) {
694 struct sd *sd = &SD[plex->sdnos[sdno]];
696 if (!bcmp(plex->name, sd->name, strlen(plex->name) + 1))
697 /* subdisk is named after the plex */
701 imin(strlen(sd->name) + 1, MAXSDNAME - 3));
702 bcopy("ex-", sd->name, 3);
703 sd->name[MAXSDNAME - 1] = '\0';
709 imin(strlen(plex->name) + 1, MAXPLEXNAME - 3));
710 bcopy("ex-", plex->name, 3);
711 plex->name[MAXPLEXNAME - 1] = '\0';
713 update_volume_config(volno, 0);
717 reply->error = ENOENT;
718 strcpy(reply->msg, "Plex is not attached");
724 renameobject(struct vinum_rename_msg *msg)
726 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
733 case drive_object: /* you can't attach a drive to anything */
734 if (find_drive(msg->newname, 0) >= 0) { /* we have that name already, */
735 reply->error = EEXIST;
736 reply->msg[0] = '\0';
739 drive = validdrive(msg->index, reply);
741 bcopy(msg->newname, drive->label.name, MAXDRIVENAME);
747 case sd_object: /* you can't attach a subdisk to anything */
748 if (find_subdisk(msg->newname, 0) >= 0) { /* we have that name already, */
749 reply->error = EEXIST;
750 reply->msg[0] = '\0';
753 sd = validsd(msg->index, reply);
755 bcopy(msg->newname, sd->name, MAXSDNAME);
756 update_sd_config(sd->sdno, 0);
762 case plex_object: /* you can't attach a plex to anything */
763 if (find_plex(msg->newname, 0) >= 0) { /* we have that name already, */
764 reply->error = EEXIST;
765 reply->msg[0] = '\0';
768 plex = validplex(msg->index, reply);
770 bcopy(msg->newname, plex->name, MAXPLEXNAME);
771 update_plex_config(plex->plexno, 0);
777 case volume_object: /* you can't attach a volume to anything */
778 if (find_volume(msg->newname, 0) >= 0) { /* we have that name already, */
779 reply->error = EEXIST;
780 reply->msg[0] = '\0';
783 vol = validvol(msg->index, reply);
785 bcopy(msg->newname, vol->name, MAXVOLNAME);
786 update_volume_config(msg->index, 0);
793 reply->error = EINVAL;
794 reply->msg[0] = '\0';
799 * Replace one object with another.
800 * Currently only for drives.
801 * message->index is the drive number of the old drive
802 * message->otherobject is the drive number of the new drive
805 replaceobject(struct vinum_ioctl_msg *msg)
807 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
809 reply->error = ENODEV; /* until I know how to do this */
810 strcpy(reply->msg, "replace not implemented yet");
811 /* save_config (); */
815 moveobject(struct vinum_ioctl_msg *msg)
817 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
821 /* Check that our objects are valid (i.e. they exist) */
822 drive = validdrive(msg->index, (struct _ioctl_reply *) msg);
825 sd = validsd(msg->otherobject, (struct _ioctl_reply *) msg);
828 if (sd->driveno == msg->index) /* sd already belongs to drive */
831 if (sd->state > sd_stale)
832 set_sd_state(sd->sdno, sd_stale, setstate_force); /* make the subdisk stale */
834 sd->state = sd_empty;
835 if (sd->plexno >= 0) /* part of a plex, */
836 update_plex_state(sd->plexno); /* update its state */
838 /* Return the space on the old drive */
839 if ((sd->driveno >= 0) /* we have a drive, */
840 &&(sd->sectors > 0)) /* and some space on it */
841 return_drive_space(sd->driveno, /* return the space */
845 /* Reassign the old subdisk */
846 sd->driveno = msg->index;
847 sd->driveoffset = -1; /* let the drive decide where to put us */
848 give_sd_to_drive(sd->sdno);
852 /* Local Variables: */
853 /* fill-column: 50 */