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