Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / sys / dev / raid / vinum / vinumioctl.c
1 /*
2  * XXX replace all the checks on object validity with
3  * calls to valid<object>
4  */
5 /*-
6  * Copyright (c) 1997, 1998, 1999
7  *      Nan Yang Computer Services Limited.  All rights reserved.
8  *
9  *  Parts copyright (c) 1997, 1998 Cybernet Corporation, NetMAX project.
10  *
11  *  Written by Greg Lehey
12  *
13  *  This software is distributed under the so-called ``Berkeley
14  *  License'':
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
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
27  *      Services Limited.
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.
31  *
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.
43  *
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.2 2003/06/17 04:28:33 dillon Exp $
47  */
48
49 #include <dev/vinum/vinumhdr.h>
50 #include <dev/vinum/request.h>
51
52 #ifdef VINUMDEBUG
53 #include <sys/reboot.h>
54 #endif
55
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 *);
61
62 jmp_buf command_fail;                                       /* return on a failed command */
63
64 /* ioctl routine */
65 int
66 vinumioctl(dev_t dev,
67     u_long cmd,
68     caddr_t data,
69     int flag,
70     struct proc *p)
71 {
72     unsigned int objno;
73     int error = 0;
74     struct sd *sd;
75     struct plex *plex;
76     struct volume *vol;
77     unsigned int index;                                     /* for transferring config info */
78     unsigned int sdno;                                      /* for transferring config info */
79     int fe;                                                 /* free list element number */
80     struct _ioctl_reply *ioctl_reply = (struct _ioctl_reply *) data; /* struct to return */
81
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 */
86         switch (cmd) {
87 #ifdef VINUMDEBUG
88         case VINUM_DEBUG:
89             if (((struct debuginfo *) data)->changeit)      /* change debug settings */
90                 debug = (((struct debuginfo *) data)->param);
91             else {
92                 if (debug & DEBUG_REMOTEGDB)
93                     boothowto |= RB_GDB;                    /* serial debug line */
94                 else
95                     boothowto &= ~RB_GDB;                   /* local ddb */
96                 Debugger("vinum debug");
97             }
98             ioctl_reply = (struct _ioctl_reply *) data;     /* reinstate the address to reply to */
99             ioctl_reply->error = 0;
100             return 0;
101 #endif
102
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, */
106                 return error;                               /* give up */
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 */
110                     &keyword_set);
111             else if (ioctl_reply->error == 0) {             /* longjmp, but no error status */
112                 ioctl_reply->error = EINVAL;                /* note that something's up */
113                 ioctl_reply->msg[0] = '\0';                 /* no message? */
114             }
115             unlock_config();
116             return 0;                                       /* must be 0 to return the real error info */
117
118         case VINUM_GETCONFIG:                               /* get the configuration information */
119             bcopy(&vinum_conf, data, sizeof(vinum_conf));
120             return 0;
121
122             /* start configuring the subsystem */
123         case VINUM_STARTCONFIG:
124             return start_config(*(int *) data);             /* just lock it.  Parameter is 'force' */
125
126             /*
127              * Move the individual parts of the config to user space.
128              *
129              * Specify the index of the object in the first word of data,
130              * and return the object there
131              */
132         case VINUM_DRIVECONFIG:
133             index = *(int *) data;                          /* get the index */
134             if (index >= (unsigned) vinum_conf.drives_allocated) /* can't do it */
135                 return ENXIO;                               /* bang */
136             bcopy(&DRIVE[index], data, sizeof(struct drive)); /* copy the config item out */
137             return 0;
138
139         case VINUM_SDCONFIG:
140             index = *(int *) data;                          /* get the index */
141             if (index >= (unsigned) vinum_conf.subdisks_allocated) /* can't do it */
142                 return ENXIO;                               /* bang */
143             bcopy(&SD[index], data, sizeof(struct sd));     /* copy the config item out */
144             return 0;
145
146         case VINUM_PLEXCONFIG:
147             index = *(int *) data;                          /* get the index */
148             if (index >= (unsigned) vinum_conf.plexes_allocated) /* can't do it */
149                 return ENXIO;                               /* bang */
150             bcopy(&PLEX[index], data, sizeof(struct plex)); /* copy the config item out */
151             return 0;
152
153         case VINUM_VOLCONFIG:
154             index = *(int *) data;                          /* get the index */
155             if (index >= (unsigned) vinum_conf.volumes_allocated) /* can't do it */
156                 return ENXIO;                               /* bang */
157             bcopy(&VOL[index], data, sizeof(struct volume)); /* copy the config item out */
158             return 0;
159
160         case VINUM_PLEXSDCONFIG:
161             index = *(int *) data;                          /* get the plex index */
162             sdno = ((int *) data)[1];                       /* and the sd index */
163             if ((index >= (unsigned) vinum_conf.plexes_allocated) /* plex doesn't exist */
164             ||(sdno >= PLEX[index].subdisks))               /* or it doesn't have this many subdisks */
165                 return ENXIO;                               /* bang */
166             bcopy(&SD[PLEX[index].sdnos[sdno]],             /* copy the config item out */
167                 data,
168                 sizeof(struct sd));
169             return 0;
170
171             /*
172              * We get called in two places: one from the
173              * userland config routines, which call us
174              * to complete the config and save it.  This
175              * call supplies the value 0 as a parameter.
176              *
177              * The other place is from the user "saveconfig"
178              * routine, which can only work if we're *not*
179              * configuring.  In this case, supply parameter 1.
180              */
181         case VINUM_SAVECONFIG:
182             if (VFLAGS & VF_CONFIGURING) {                  /* must be us, the others are asleep */
183                 if (*(int *) data == 0)                     /* finish config */
184                     finish_config(1);                       /* finish the configuration and update it */
185                 else
186                     return EBUSY;                           /* can't do it now */
187             }
188             save_config();                                  /* save configuration to disk */
189             return 0;
190
191         case VINUM_RELEASECONFIG:                           /* release the config */
192             if (VFLAGS & VF_CONFIGURING) {                  /* must be us, the others are asleep */
193                 finish_config(0);                           /* finish the configuration, don't change it */
194                 save_config();                              /* save configuration to disk */
195             } else
196                 error = EINVAL;                             /* release what config? */
197             return error;
198
199         case VINUM_INIT:
200             ioctl_reply = (struct _ioctl_reply *) data;     /* reinstate the address to reply to */
201             ioctl_reply->error = 0;
202             return 0;
203
204         case VINUM_RESETCONFIG:
205             if (vinum_inactive(0)) {                        /* if the volumes are not active */
206                 /*
207                  * Note the open count.  We may be called from v, so we'll be open.
208                  * Keep the count so we don't underflow
209                  */
210                 free_vinum(1);                              /* clean up everything */
211                 log(LOG_NOTICE, "vinum: CONFIGURATION OBLITERATED\n");
212                 ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */
213                 ioctl_reply->error = 0;
214                 return 0;
215             }
216             return EBUSY;
217
218         case VINUM_SETSTATE:
219             setstate((struct vinum_ioctl_msg *) data);      /* set an object state */
220             return 0;
221
222             /*
223              * Set state by force, without changing
224              * anything else.
225              */
226         case VINUM_SETSTATE_FORCE:
227             setstate_by_force((struct vinum_ioctl_msg *) data); /* set an object state */
228             return 0;
229
230 #ifdef VINUMDEBUG
231         case VINUM_MEMINFO:
232             vinum_meminfo(data);
233             return 0;
234
235         case VINUM_MALLOCINFO:
236             return vinum_mallocinfo(data);
237
238         case VINUM_RQINFO:
239             return vinum_rqinfo(data);
240 #endif
241
242         case VINUM_LABEL:                                   /* label a volume */
243             ioctl_reply->error = write_volume_label(*(int *) data); /* index of the volume to label */
244             ioctl_reply->msg[0] = '\0';                     /* no message */
245             return 0;
246
247         case VINUM_REMOVE:
248             remove((struct vinum_ioctl_msg *) data);        /* remove an object */
249             return 0;
250
251         case VINUM_GETFREELIST:                             /* get a drive free list element */
252             index = *(int *) data;                          /* get the drive index */
253             fe = ((int *) data)[1];                         /* and the free list element */
254             if ((index >= (unsigned) vinum_conf.drives_allocated) /* plex doesn't exist */
255             ||(DRIVE[index].state == drive_unallocated))
256                 return ENODEV;
257             if (fe >= DRIVE[index].freelist_entries)        /* no such entry */
258                 return ENOENT;
259             bcopy(&DRIVE[index].freelist[fe],
260                 data,
261                 sizeof(struct drive_freelist));
262             return 0;
263
264         case VINUM_RESETSTATS:
265             resetstats((struct vinum_ioctl_msg *) data);    /* reset object stats */
266             return 0;
267
268             /* attach an object to a superordinate object */
269         case VINUM_ATTACH:
270             attachobject((struct vinum_ioctl_msg *) data);
271             return 0;
272
273             /* detach an object from a superordinate object */
274         case VINUM_DETACH:
275             detachobject((struct vinum_ioctl_msg *) data);
276             return 0;
277
278             /* rename an object */
279         case VINUM_RENAME:
280             renameobject((struct vinum_rename_msg *) data);
281             return 0;
282
283             /* replace an object */
284         case VINUM_REPLACE:
285             replaceobject((struct vinum_ioctl_msg *) data);
286             return 0;
287
288         case VINUM_DAEMON:
289             vinum_daemon();                                 /* perform the daemon */
290             return 0;
291
292         case VINUM_FINDDAEMON:                              /* check for presence of daemon */
293             return vinum_finddaemon();
294             return 0;
295
296         case VINUM_SETDAEMON:                               /* set daemon flags */
297             return vinum_setdaemonopts(*(int *) data);
298
299         case VINUM_GETDAEMON:                               /* get daemon flags */
300             *(int *) data = daemon_options;
301             return 0;
302
303         case VINUM_PARITYOP:                                /* check/rebuild RAID-4/5 parity */
304             parityops((struct vinum_ioctl_msg *) data);
305             return 0;
306
307             /* move an object */
308         case VINUM_MOVE:
309             moveobject((struct vinum_ioctl_msg *) data);
310             return 0;
311
312         default:
313             /* FALLTHROUGH */
314         }
315
316     case VINUM_DRIVE_TYPE:
317     default:
318         log(LOG_WARNING,
319             "vinumioctl: invalid ioctl from process %d (%s): %lx\n",
320             curproc->p_pid,
321             curproc->p_comm,
322             cmd);
323         return EINVAL;
324
325     case VINUM_SD_TYPE:
326     case VINUM_RAWSD_TYPE:
327         objno = Sdno(dev);
328
329         sd = &SD[objno];
330
331         switch (cmd) {
332         case DIOCGDINFO:                                    /* get disk label */
333             get_volume_label(sd->name, 1, sd->sectors, (struct disklabel *) data);
334             break;
335
336             /*
337              * We don't have this stuff on hardware,
338              * so just pretend to do it so that
339              * utilities don't get upset.
340              */
341         case DIOCWDINFO:                                    /* write partition info */
342         case DIOCSDINFO:                                    /* set partition info */
343             return 0;                                       /* not a titty */
344
345         default:
346             return ENOTTY;                                  /* not my kind of ioctl */
347         }
348
349         return 0;                                           /* pretend we did it */
350
351     case VINUM_RAWPLEX_TYPE:
352     case VINUM_PLEX_TYPE:
353         objno = Plexno(dev);
354
355         plex = &PLEX[objno];
356
357         switch (cmd) {
358         case DIOCGDINFO:                                    /* get disk label */
359             get_volume_label(plex->name, 1, plex->length, (struct disklabel *) data);
360             break;
361
362             /*
363              * We don't have this stuff on hardware,
364              * so just pretend to do it so that
365              * utilities don't get upset.
366              */
367         case DIOCWDINFO:                                    /* write partition info */
368         case DIOCSDINFO:                                    /* set partition info */
369             return 0;                                       /* not a titty */
370
371         default:
372             return ENOTTY;                                  /* not my kind of ioctl */
373         }
374
375         return 0;                                           /* pretend we did it */
376
377     case VINUM_VOLUME_TYPE:
378         objno = Volno(dev);
379
380         if ((unsigned) objno >= (unsigned) vinum_conf.volumes_allocated) /* not a valid volume */
381             return ENXIO;
382         vol = &VOL[objno];
383         if (vol->state != volume_up)                        /* not up, */
384             return EIO;                                     /* I/O error */
385
386         switch (cmd) {
387         case DIOCGDINFO:                                    /* get disk label */
388             get_volume_label(vol->name, vol->plexes, vol->size, (struct disklabel *) data);
389             break;
390
391             /*
392              * Care!  DIOCGPART returns *pointers* to
393              * the caller, so we need to store this crap
394              * as well.  And yes, we need it.
395              */
396         case DIOCGPART:                                     /* get partition information */
397             get_volume_label(vol->name, vol->plexes, vol->size, &vol->label);
398             ((struct partinfo *) data)->disklab = &vol->label;
399             ((struct partinfo *) data)->part = &vol->label.d_partitions[0];
400             break;
401
402             /*
403              * We don't have this stuff on hardware,
404              * so just pretend to do it so that
405              * utilities don't get upset.
406              */
407         case DIOCWDINFO:                                    /* write partition info */
408         case DIOCSDINFO:                                    /* set partition info */
409             return 0;                                       /* not a titty */
410
411         case DIOCWLABEL:                                    /* set or reset label writeable */
412             if ((flag & FWRITE) == 0)                       /* not writeable? */
413                 return EACCES;                              /* no, die */
414             if (*(int *) data != 0)                         /* set it? */
415                 vol->flags |= VF_WLABEL;                    /* yes */
416             else
417                 vol->flags &= ~VF_WLABEL;                   /* no, reset */
418             break;
419
420         default:
421             return ENOTTY;                                  /* not my kind of ioctl */
422         }
423         break;
424     }
425     return 0;                                               /* XXX */
426 }
427
428 /*
429  * The following four functions check the supplied
430  * object index and return a pointer to the object
431  * if it exists.  Otherwise they longjump out via
432  * throw_rude_remark.
433  */
434 struct drive *
435 validdrive(int driveno, struct _ioctl_reply *reply)
436 {
437     if ((driveno < vinum_conf.drives_allocated)
438         && (DRIVE[driveno].state > drive_referenced))
439         return &DRIVE[driveno];
440     strcpy(reply->msg, "No such drive");
441     reply->error = ENOENT;
442     return NULL;
443 }
444
445 struct sd *
446 validsd(int sdno, struct _ioctl_reply *reply)
447 {
448     if ((sdno < vinum_conf.subdisks_allocated)
449         && (SD[sdno].state > sd_referenced))
450         return &SD[sdno];
451     strcpy(reply->msg, "No such subdisk");
452     reply->error = ENOENT;
453     return NULL;
454 }
455
456 struct plex *
457 validplex(int plexno, struct _ioctl_reply *reply)
458 {
459     if ((plexno < vinum_conf.plexes_allocated)
460         && (PLEX[plexno].state > plex_referenced))
461         return &PLEX[plexno];
462     strcpy(reply->msg, "No such plex");
463     reply->error = ENOENT;
464     return NULL;
465 }
466
467 struct volume *
468 validvol(int volno, struct _ioctl_reply *reply)
469 {
470     if ((volno < vinum_conf.volumes_allocated)
471         && (VOL[volno].state > volume_uninit))
472         return &VOL[volno];
473     strcpy(reply->msg, "No such volume");
474     reply->error = ENOENT;
475     return NULL;
476 }
477
478 /* reset an object's stats */
479 void
480 resetstats(struct vinum_ioctl_msg *msg)
481 {
482     struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
483
484     switch (msg->type) {
485     case drive_object:
486         if (msg->index < vinum_conf.drives_allocated) {
487             struct drive *drive = &DRIVE[msg->index];
488             if (drive->state > drive_referenced) {
489                 drive->reads = 0;                           /* number of reads on this drive */
490                 drive->writes = 0;                          /* number of writes on this drive */
491                 drive->bytes_read = 0;                      /* number of bytes read */
492                 drive->bytes_written = 0;                   /* number of bytes written */
493                 reply->error = 0;
494                 return;
495             }
496             reply->error = EINVAL;
497             return;
498         }
499     case sd_object:
500         if (msg->index < vinum_conf.subdisks_allocated) {
501             struct sd *sd = &SD[msg->index];
502             if (sd->state > sd_referenced) {
503                 sd->reads = 0;                              /* number of reads on this subdisk */
504                 sd->writes = 0;                             /* number of writes on this subdisk */
505                 sd->bytes_read = 0;                         /* number of bytes read */
506                 sd->bytes_written = 0;                      /* number of bytes written */
507                 reply->error = 0;
508                 return;
509             }
510             reply->error = EINVAL;
511             return;
512         }
513         break;
514
515     case plex_object:
516         if (msg->index < vinum_conf.plexes_allocated) {
517             struct plex *plex = &PLEX[msg->index];
518             if (plex->state > plex_referenced) {
519                 plex->reads = 0;
520                 plex->writes = 0;                           /* number of writes on this plex */
521                 plex->bytes_read = 0;                       /* number of bytes read */
522                 plex->bytes_written = 0;                    /* number of bytes written */
523                 plex->recovered_reads = 0;                  /* number of recovered read operations */
524                 plex->degraded_writes = 0;                  /* number of degraded writes */
525                 plex->parityless_writes = 0;                /* number of parityless writes */
526                 plex->multiblock = 0;                       /* requests that needed more than one block */
527                 plex->multistripe = 0;                      /* requests that needed more than one stripe */
528                 reply->error = 0;
529                 return;
530             }
531             reply->error = EINVAL;
532             return;
533         }
534         break;
535
536     case volume_object:
537         if (msg->index < vinum_conf.volumes_allocated) {
538             struct volume *vol = &VOL[msg->index];
539             if (vol->state > volume_uninit) {
540                 vol->bytes_read = 0;                        /* number of bytes read */
541                 vol->bytes_written = 0;                     /* number of bytes written */
542                 vol->reads = 0;                             /* number of reads on this volume */
543                 vol->writes = 0;                            /* number of writes on this volume */
544                 vol->recovered_reads = 0;                   /* reads recovered from another plex */
545                 reply->error = 0;
546                 return;
547             }
548             reply->error = EINVAL;
549             return;
550         }
551     case invalid_object:                                    /* can't get this */
552         reply->error = EINVAL;
553         return;
554     }
555 }
556
557 /* attach an object to a superior object */
558 void
559 attachobject(struct vinum_ioctl_msg *msg)
560 {
561     struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
562     int sdno;
563     struct sd *sd;
564     struct plex *plex;
565     struct volume *vol;
566
567     switch (msg->type) {
568     case drive_object:                                      /* you can't attach a drive to anything */
569     case volume_object:                                     /* nor a volume */
570     case invalid_object:                                    /* "this can't happen" */
571         reply->error = EINVAL;
572         reply->msg[0] = '\0';                               /* vinum(8) doesn't do this */
573         return;
574
575     case sd_object:
576         sd = validsd(msg->index, reply);
577         if (sd == NULL)                                     /* not a valid subdisk  */
578             return;
579         plex = validplex(msg->otherobject, reply);
580         if (plex) {
581             /*
582              * We should be more intelligent about this.
583              * We should be able to reattach a dead
584              * subdisk, but if we want to increase the total
585              * number of subdisks, we have a lot of reshuffling
586              * to do. XXX
587              */
588             if ((plex->organization != plex_concat)         /* can't attach to striped and RAID-4/5 */
589             &&(!msg->force)) {                              /* without using force */
590                 reply->error = EINVAL;                      /* no message, the user should check */
591                 strcpy(reply->msg, "Can't attach to this plex organization");
592                 return;
593             }
594             if (sd->plexno >= 0) {                          /* already belong to a plex */
595                 reply->error = EBUSY;                       /* no message, the user should check */
596                 reply->msg[0] = '\0';
597                 return;
598             }
599             sd->plexoffset = msg->offset;                   /* this is where we want it */
600             set_sd_state(sd->sdno, sd_stale, setstate_force); /* make sure it's stale */
601             give_sd_to_plex(plex->plexno, sd->sdno);        /* and give it to the plex */
602             update_sd_config(sd->sdno, 0);
603             save_config();
604         }
605         if (sd->state == sd_reviving)
606             reply->error = EAGAIN;                          /* need to revive it */
607         else
608             reply->error = 0;
609         break;
610
611     case plex_object:
612         plex = validplex(msg->index, reply);                /* get plex */
613         if (plex == NULL)
614             return;
615         vol = validvol(msg->otherobject, reply);            /* and volume information */
616         if (vol) {
617             if ((vol->plexes == MAXPLEX)                    /* we have too many already */
618             ||(plex->volno >= 0)) {                         /* or the plex has an owner */
619                 reply->error = EINVAL;                      /* no message, the user should check */
620                 reply->msg[0] = '\0';
621                 return;
622             }
623             for (sdno = 0; sdno < plex->subdisks; sdno++) {
624                 sd = &SD[plex->sdnos[sdno]];
625
626                 if (sd->state > sd_down)                    /* real subdisk, vaguely accessible */
627                     set_sd_state(plex->sdnos[sdno], sd_stale, setstate_force); /* make it stale */
628             }
629             set_plex_state(plex->plexno, plex_up, setstate_none); /* update plex state */
630             give_plex_to_volume(msg->otherobject, msg->index); /* and give it to the volume */
631             update_plex_config(plex->plexno, 0);
632             save_config();
633         }
634     }
635 }
636
637 /* detach an object from a superior object */
638 void
639 detachobject(struct vinum_ioctl_msg *msg)
640 {
641     struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
642     struct sd *sd;
643     struct plex *plex;
644     struct volume *vol;
645     int sdno;
646     int plexno;
647
648     switch (msg->type) {
649     case drive_object:                                      /* you can't detach a drive from anything */
650     case volume_object:                                     /* nor a volume */
651     case invalid_object:                                    /* "this can't happen" */
652         reply->error = EINVAL;
653         reply->msg[0] = '\0';                               /* vinum(8) doesn't do this */
654         return;
655
656     case sd_object:
657         sd = validsd(msg->index, reply);
658         if (sd == NULL)
659             return;
660         if (sd->plexno < 0) {                               /* doesn't belong to a plex */
661             reply->error = ENOENT;
662             strcpy(reply->msg, "Subdisk is not attached");
663             return;
664         } else {                                            /* valid plex number */
665             plex = &PLEX[sd->plexno];
666             if ((!msg->force)                               /* don't force things */
667             &&((plex->state == plex_up)                     /* and the plex is up */
668             ||((plex->state == plex_flaky) && sd->state == sd_up))) { /* or flaky with this sd up */
669                 reply->error = EBUSY;                       /* we need this sd */
670                 reply->msg[0] = '\0';
671                 return;
672             }
673             sd->plexno = -1;                                /* anonymous sd */
674             if (plex->subdisks == 1) {                      /* this was the only subdisk */
675                 Free(plex->sdnos);                          /* free the subdisk array */
676                 plex->sdnos = NULL;                         /* and note the fact */
677                 plex->subdisks_allocated = 0;               /* no subdisk space */
678             } else {
679                 for (sdno = 0; sdno < plex->subdisks; sdno++) {
680                     if (plex->sdnos[sdno] == msg->index)    /* found our subdisk */
681                         break;
682                 }
683                 if (sdno < (plex->subdisks - 1))            /* not the last one, compact */
684                     bcopy(&plex->sdnos[sdno + 1],
685                         &plex->sdnos[sdno],
686                         (plex->subdisks - 1 - sdno) * sizeof(int));
687             }
688             plex->subdisks--;
689             if (!bcmp(plex->name, sd->name, strlen(plex->name) + 1))
690                 /* this subdisk is named after the plex */
691             {
692                 bcopy(sd->name,
693                     &sd->name[3],
694                     min(strlen(sd->name) + 1, MAXSDNAME - 3));
695                 bcopy("ex-", sd->name, 3);
696                 sd->name[MAXSDNAME - 1] = '\0';
697             }
698             update_plex_config(plex->plexno, 0);
699             if (isstriped(plex))                            /* we've just mutilated our plex, */
700                 set_plex_state(plex->plexno,
701                     plex_down,
702                     setstate_force | setstate_configuring);
703             save_config();
704             reply->error = 0;
705         }
706         return;
707
708     case plex_object:
709         plex = validplex(msg->index, reply);                /* get plex */
710         if (plex == NULL)
711             return;
712         if (plex->volno >= 0) {
713             int volno = plex->volno;
714
715             vol = &VOL[volno];
716             if ((!msg->force)                               /* don't force things */
717             &&((vol->state == volume_up)                    /* and the volume is up */
718             &&(vol->plexes == 1))) {                        /* and this is the last plex */
719                 /*
720                    * XXX As elsewhere, check whether we will lose
721                    * mapping by removing this plex
722                  */
723                 reply->error = EBUSY;                       /* we need this plex */
724                 reply->msg[0] = '\0';
725                 return;
726             }
727             plex->volno = -1;                               /* anonymous plex */
728             for (plexno = 0; plexno < vol->plexes; plexno++) {
729                 if (vol->plex[plexno] == msg->index)        /* found our plex */
730                     break;
731             }
732             if (plexno < (vol->plexes - 1))                 /* not the last one, compact */
733                 bcopy(&vol->plex[plexno + 1],
734                     &vol->plex[plexno],
735                     (vol->plexes - 1 - plexno) * sizeof(int));
736             vol->plexes--;
737             vol->last_plex_read = 0;                        /* don't go beyond the end */
738             if (!bcmp(vol->name, plex->name, strlen(vol->name) + 1))
739                 /* this plex is named after the volume */
740             {
741                 /* First, check if the subdisks are the same */
742                 if (msg->recurse) {
743                     int sdno;
744
745                     for (sdno = 0; sdno < plex->subdisks; sdno++) {
746                         struct sd *sd = &SD[plex->sdnos[sdno]];
747
748                         if (!bcmp(plex->name, sd->name, strlen(plex->name) + 1))
749                                                             /* subdisk is named after the plex */
750                         {
751                             bcopy(sd->name,
752                                 &sd->name[3],
753                                 min(strlen(sd->name) + 1, MAXSDNAME - 3));
754                             bcopy("ex-", sd->name, 3);
755                             sd->name[MAXSDNAME - 1] = '\0';
756                         }
757                     }
758                 }
759                 bcopy(plex->name,
760                     &plex->name[3],
761                     min(strlen(plex->name) + 1, MAXPLEXNAME - 3));
762                 bcopy("ex-", plex->name, 3);
763                 plex->name[MAXPLEXNAME - 1] = '\0';
764             }
765             update_volume_config(volno, 0);
766             save_config();
767             reply->error = 0;
768         } else {
769             reply->error = ENOENT;
770             strcpy(reply->msg, "Plex is not attached");
771         }
772     }
773 }
774
775 void
776 renameobject(struct vinum_rename_msg *msg)
777 {
778     struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
779     struct drive *drive;
780     struct sd *sd;
781     struct plex *plex;
782     struct volume *vol;
783
784     switch (msg->type) {
785     case drive_object:                                      /* you can't attach a drive to anything */
786         if (find_drive(msg->newname, 0) >= 0) {             /* we have that name already, */
787             reply->error = EEXIST;
788             reply->msg[0] = '\0';
789             return;
790         }
791         drive = validdrive(msg->index, reply);
792         if (drive) {
793             bcopy(msg->newname, drive->label.name, MAXDRIVENAME);
794             save_config();
795             reply->error = 0;
796         }
797         return;
798
799     case sd_object:                                         /* you can't attach a subdisk to anything */
800         if (find_subdisk(msg->newname, 0) >= 0) {           /* we have that name already, */
801             reply->error = EEXIST;
802             reply->msg[0] = '\0';
803             return;
804         }
805         sd = validsd(msg->index, reply);
806         if (sd) {
807             bcopy(msg->newname, sd->name, MAXSDNAME);
808             update_sd_config(sd->sdno, 0);
809             save_config();
810             reply->error = 0;
811         }
812         return;
813
814     case plex_object:                                       /* you can't attach a plex to anything */
815         if (find_plex(msg->newname, 0) >= 0) {              /* we have that name already, */
816             reply->error = EEXIST;
817             reply->msg[0] = '\0';
818             return;
819         }
820         plex = validplex(msg->index, reply);
821         if (plex) {
822             bcopy(msg->newname, plex->name, MAXPLEXNAME);
823             update_plex_config(plex->plexno, 0);
824             save_config();
825             reply->error = 0;
826         }
827         return;
828
829     case volume_object:                                     /* you can't attach a volume to anything */
830         if (find_volume(msg->newname, 0) >= 0) {            /* we have that name already, */
831             reply->error = EEXIST;
832             reply->msg[0] = '\0';
833             return;
834         }
835         vol = validvol(msg->index, reply);
836         if (vol) {
837             bcopy(msg->newname, vol->name, MAXVOLNAME);
838             update_volume_config(msg->index, 0);
839             save_config();
840             reply->error = 0;
841         }
842         return;
843
844     case invalid_object:
845         reply->error = EINVAL;
846         reply->msg[0] = '\0';
847     }
848 }
849
850 /*
851  * Replace one object with another.
852  * Currently only for drives.
853  * message->index is the drive number of the old drive
854  * message->otherobject is the drive number of the new drive
855  */
856 void
857 replaceobject(struct vinum_ioctl_msg *msg)
858 {
859     struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
860
861     reply->error = ENODEV;                                  /* until I know how to do this */
862     strcpy(reply->msg, "replace not implemented yet");
863 /*      save_config (); */
864 }
865
866 void
867 moveobject(struct vinum_ioctl_msg *msg)
868 {
869     struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
870     struct drive *drive;
871     struct sd *sd;
872
873     /* Check that our objects are valid (i.e. they exist) */
874     drive = validdrive(msg->index, (struct _ioctl_reply *) msg);
875     if (drive == NULL)
876         return;
877     sd = validsd(msg->otherobject, (struct _ioctl_reply *) msg);
878     if (sd == NULL)
879         return;
880     if (sd->driveno == msg->index)                          /* sd already belongs to drive */
881         return;
882
883     if (sd->state > sd_stale)
884         set_sd_state(sd->sdno, sd_stale, setstate_force);   /* make the subdisk stale */
885     else
886         sd->state = sd_empty;
887     if (sd->plexno >= 0)                                    /* part of a plex, */
888         update_plex_state(sd->plexno);                      /* update its state */
889
890     /* Return the space on the old drive */
891     if ((sd->driveno >= 0)                                  /* we have a drive, */
892     &&(sd->sectors > 0))                                    /* and some space on it */
893         return_drive_space(sd->driveno,                     /* return the space */
894             sd->driveoffset,
895             sd->sectors);
896
897     /* Reassign the old subdisk */
898     sd->driveno = msg->index;
899     sd->driveoffset = -1;                                   /* let the drive decide where to put us */
900     give_sd_to_drive(sd->sdno);
901     reply->error = 0;
902 }
903
904 /* Local Variables: */
905 /* fill-column: 50 */
906 /* End: */