Clean up the ioctl switch and add support for DIOCGPART which is
[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.11 2007/07/13 18:55:45 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     int error;
72     unsigned int index;                                     /* for transferring config info */
73     unsigned int sdno;                                      /* for transferring config info */
74     unsigned int objno;
75     struct volume *vol;
76     struct partinfo *dpart;
77     int fe;                                                 /* free list element number */
78     struct _ioctl_reply *ioctl_reply = (struct _ioctl_reply *) data; /* struct to return */
79
80     error = 0;
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             break;
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                 break;
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                 error = 0;
113                 ioctl_reply->error = EINVAL;                /* note that something's up */
114                 ioctl_reply->msg[0] = '\0';                 /* no message? */
115             }
116             unlock_config();
117             break;
118
119         case VINUM_GETCONFIG:                               /* get the configuration information */
120             bcopy(&vinum_conf, data, sizeof(vinum_conf));
121             break;
122
123             /* start configuring the subsystem */
124         case VINUM_STARTCONFIG:
125             error = start_config(*(int *) data);            /* just lock it.  Parameter is 'force' */
126             break;
127
128         case VINUM_DRIVECONFIG:
129             /*
130              * Move the individual parts of the config to user space.
131              *
132              * Specify the index of the object in the first word of data,
133              * and return the object there
134              */
135             index = *(int *) data;
136             if (index >= (unsigned)vinum_conf.drives_allocated) {
137                 error = ENXIO;
138             } else {
139                 bcopy(&DRIVE[index], data, sizeof(struct drive));
140             }
141             break;
142
143         case VINUM_SDCONFIG:
144             index = *(int *) data;
145             if (index >= (unsigned) vinum_conf.subdisks_allocated) {
146                 error = ENXIO;
147             } else {
148                 bcopy(&SD[index], data, sizeof(struct sd));
149             }
150             break;
151
152         case VINUM_PLEXCONFIG:
153             index = *(int *) data;
154             if (index >= (unsigned) vinum_conf.plexes_allocated) {
155                 error = ENXIO;
156             } else {
157                 bcopy(&PLEX[index], data, sizeof(struct plex));
158             }
159             break;
160
161         case VINUM_VOLCONFIG:
162             index = *(int *) data;
163             if (index >= (unsigned) vinum_conf.volumes_allocated) {
164                 error = ENXIO;
165             } else {
166                 bcopy(&VOL[index], data, sizeof(struct volume));
167             }
168             break;
169
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)) {
175                 error = ENXIO;
176             } else {
177                 bcopy(&SD[PLEX[index].sdnos[sdno]], data, sizeof(struct sd));
178             }
179             break;
180         case VINUM_SAVECONFIG:
181             /*
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.
186              *
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.
190              */
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 */
194                 else
195                     error = EBUSY;
196             }
197             if (error == 0)
198                 save_config();                              /* save configuration to disk */
199             break;
200
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 */
205             } else {
206                 error = EINVAL;                             /* release what config? */
207             }
208             break;
209
210         case VINUM_INIT:
211             ioctl_reply = (struct _ioctl_reply *) data;     /* reinstate the address to reply to */
212             ioctl_reply->error = 0;
213             break;
214
215         case VINUM_RESETCONFIG:
216             if (vinum_inactive(0)) {                        /* if the volumes are not active */
217                 /*
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
220                  */
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;
225             } else {
226                 error = EBUSY;
227             }
228
229         case VINUM_SETSTATE:
230             setstate((struct vinum_ioctl_msg *) data);      /* set an object state */
231             break;
232
233             /*
234              * Set state by force, without changing
235              * anything else.
236              */
237         case VINUM_SETSTATE_FORCE:
238             setstate_by_force((struct vinum_ioctl_msg *) data); /* set an object state */
239             break;
240
241 #ifdef VINUMDEBUG
242         case VINUM_MEMINFO:
243             vinum_meminfo(data);
244             break;
245
246         case VINUM_MALLOCINFO:
247             error = vinum_mallocinfo(data);
248             break;
249
250         case VINUM_RQINFO:
251             error = vinum_rqinfo(data);
252             break;
253 #endif
254
255         case VINUM_REMOVE:
256             remove((struct vinum_ioctl_msg *) data);        /* remove an object */
257             break;
258
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)) {
264                 error = ENODEV;
265             } else if (fe >= DRIVE[index].freelist_entries) {
266                 error = ENOENT;
267             } else {
268                 bcopy(&DRIVE[index].freelist[fe], data,
269                       sizeof(struct drive_freelist));
270             }
271             break;
272
273         case VINUM_RESETSTATS:
274             resetstats((struct vinum_ioctl_msg *) data);    /* reset object stats */
275             break;
276
277             /* attach an object to a superordinate object */
278         case VINUM_ATTACH:
279             attachobject((struct vinum_ioctl_msg *) data);
280             break;
281
282             /* detach an object from a superordinate object */
283         case VINUM_DETACH:
284             detachobject((struct vinum_ioctl_msg *) data);
285             break;
286
287             /* rename an object */
288         case VINUM_RENAME:
289             renameobject((struct vinum_rename_msg *) data);
290             break;
291
292             /* replace an object */
293         case VINUM_REPLACE:
294             replaceobject((struct vinum_ioctl_msg *) data);
295             break;
296
297         case VINUM_DAEMON:
298             vinum_daemon();                                 /* perform the daemon */
299             break;
300
301         case VINUM_FINDDAEMON:                              /* check for presence of daemon */
302             error = vinum_finddaemon();
303             break;
304
305         case VINUM_SETDAEMON:                               /* set daemon flags */
306             error = vinum_setdaemonopts(*(int *) data);
307             break;
308
309         case VINUM_GETDAEMON:                               /* get daemon flags */
310             *(int *) data = daemon_options;
311             break;
312
313         case VINUM_PARITYOP:                                /* check/rebuild RAID-4/5 parity */
314             parityops((struct vinum_ioctl_msg *) data);
315             break;
316
317             /* move an object */
318         case VINUM_MOVE:
319             moveobject((struct vinum_ioctl_msg *) data);
320             break;
321         default:
322             error = EINVAL;
323             break;
324         }
325         break;
326     case VINUM_LABEL:
327     case VINUM_DRIVE_TYPE:
328     case VINUM_SD_TYPE:
329     case VINUM_RAWSD_TYPE:
330     case VINUM_RAWPLEX_TYPE:
331     case VINUM_PLEX_TYPE:
332         error = EINVAL;
333         break;
334     case VINUM_VOLUME_TYPE:
335         objno = Volno(dev);
336
337         if ((unsigned)objno >= (unsigned)vinum_conf.volumes_allocated) {
338             error = ENXIO;
339             break;
340         }
341         vol = &VOL[objno];
342         if (vol->state != volume_up) {
343             error = EIO;
344             break;
345         }
346
347         switch(cmd) {
348         case DIOCGPART:
349             dpart = (void *)data;
350
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;
357             break;
358         default:
359             error = EINVAL;
360         }
361         break;
362     default:
363         error = EINVAL;
364         break;
365     }
366     if (error) {
367         log(LOG_WARNING,
368             "vinumioctl: invalid ioctl from process %d (%s): %lx\n",
369             curproc->p_pid,
370             curproc->p_comm,
371             cmd);
372     }
373     return error;
374 }
375
376 /*
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
380  * throw_rude_remark.
381  */
382 struct drive *
383 validdrive(int driveno, struct _ioctl_reply *reply)
384 {
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;
390     return NULL;
391 }
392
393 struct sd *
394 validsd(int sdno, struct _ioctl_reply *reply)
395 {
396     if ((sdno < vinum_conf.subdisks_allocated)
397         && (SD[sdno].state > sd_referenced))
398         return &SD[sdno];
399     strcpy(reply->msg, "No such subdisk");
400     reply->error = ENOENT;
401     return NULL;
402 }
403
404 struct plex *
405 validplex(int plexno, struct _ioctl_reply *reply)
406 {
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;
412     return NULL;
413 }
414
415 struct volume *
416 validvol(int volno, struct _ioctl_reply *reply)
417 {
418     if ((volno < vinum_conf.volumes_allocated)
419         && (VOL[volno].state > volume_uninit))
420         return &VOL[volno];
421     strcpy(reply->msg, "No such volume");
422     reply->error = ENOENT;
423     return NULL;
424 }
425
426 /* reset an object's stats */
427 void
428 resetstats(struct vinum_ioctl_msg *msg)
429 {
430     struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
431
432     switch (msg->type) {
433     case drive_object:
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 */
441                 reply->error = 0;
442                 return;
443             }
444             reply->error = EINVAL;
445             return;
446         }
447     case sd_object:
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 */
455                 reply->error = 0;
456                 return;
457             }
458             reply->error = EINVAL;
459             return;
460         }
461         break;
462
463     case plex_object:
464         if (msg->index < vinum_conf.plexes_allocated) {
465             struct plex *plex = &PLEX[msg->index];
466             if (plex->state > plex_referenced) {
467                 plex->reads = 0;
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 */
476                 reply->error = 0;
477                 return;
478             }
479             reply->error = EINVAL;
480             return;
481         }
482         break;
483
484     case volume_object:
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 */
493                 reply->error = 0;
494                 return;
495             }
496             reply->error = EINVAL;
497             return;
498         }
499     case invalid_object:                                    /* can't get this */
500         reply->error = EINVAL;
501         return;
502     }
503 }
504
505 /* attach an object to a superior object */
506 void
507 attachobject(struct vinum_ioctl_msg *msg)
508 {
509     struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
510     int sdno;
511     struct sd *sd;
512     struct plex *plex;
513     struct volume *vol;
514
515     switch (msg->type) {
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 */
521         return;
522
523     case sd_object:
524         sd = validsd(msg->index, reply);
525         if (sd == NULL)                                     /* not a valid subdisk  */
526             return;
527         plex = validplex(msg->otherobject, reply);
528         if (plex) {
529             /*
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
534              * to do. XXX
535              */
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");
540                 return;
541             }
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';
545                 return;
546             }
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);
551             save_config();
552         }
553         if (sd->state == sd_reviving)
554             reply->error = EAGAIN;                          /* need to revive it */
555         else
556             reply->error = 0;
557         break;
558
559     case plex_object:
560         plex = validplex(msg->index, reply);                /* get plex */
561         if (plex == NULL)
562             return;
563         vol = validvol(msg->otherobject, reply);            /* and volume information */
564         if (vol) {
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';
569                 return;
570             }
571             for (sdno = 0; sdno < plex->subdisks; sdno++) {
572                 sd = &SD[plex->sdnos[sdno]];
573
574                 if (sd->state > sd_down)                    /* real subdisk, vaguely accessible */
575                     set_sd_state(plex->sdnos[sdno], sd_stale, setstate_force); /* make it stale */
576             }
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);
580             save_config();
581         }
582     }
583 }
584
585 /* detach an object from a superior object */
586 void
587 detachobject(struct vinum_ioctl_msg *msg)
588 {
589     struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
590     struct sd *sd;
591     struct plex *plex;
592     struct volume *vol;
593     int sdno;
594     int plexno;
595
596     switch (msg->type) {
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 */
602         return;
603
604     case sd_object:
605         sd = validsd(msg->index, reply);
606         if (sd == NULL)
607             return;
608         if (sd->plexno < 0) {                               /* doesn't belong to a plex */
609             reply->error = ENOENT;
610             strcpy(reply->msg, "Subdisk is not attached");
611             return;
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';
619                 return;
620             }
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 */
626             } else {
627                 for (sdno = 0; sdno < plex->subdisks; sdno++) {
628                     if (plex->sdnos[sdno] == msg->index)    /* found our subdisk */
629                         break;
630                 }
631                 if (sdno < (plex->subdisks - 1))            /* not the last one, compact */
632                     bcopy(&plex->sdnos[sdno + 1],
633                         &plex->sdnos[sdno],
634                         (plex->subdisks - 1 - sdno) * sizeof(int));
635             }
636             plex->subdisks--;
637             if (!bcmp(plex->name, sd->name, strlen(plex->name) + 1))
638                 /* this subdisk is named after the plex */
639             {
640                 bcopy(sd->name,
641                     &sd->name[3],
642                     min(strlen(sd->name) + 1, MAXSDNAME - 3));
643                 bcopy("ex-", sd->name, 3);
644                 sd->name[MAXSDNAME - 1] = '\0';
645             }
646             update_plex_config(plex->plexno, 0);
647             if (isstriped(plex))                            /* we've just mutilated our plex, */
648                 set_plex_state(plex->plexno,
649                     plex_down,
650                     setstate_force | setstate_configuring);
651             save_config();
652             reply->error = 0;
653         }
654         return;
655
656     case plex_object:
657         plex = validplex(msg->index, reply);                /* get plex */
658         if (plex == NULL)
659             return;
660         if (plex->volno >= 0) {
661             int volno = plex->volno;
662
663             vol = &VOL[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 */
667                 /*
668                    * XXX As elsewhere, check whether we will lose
669                    * mapping by removing this plex
670                  */
671                 reply->error = EBUSY;                       /* we need this plex */
672                 reply->msg[0] = '\0';
673                 return;
674             }
675             plex->volno = -1;                               /* anonymous plex */
676             for (plexno = 0; plexno < vol->plexes; plexno++) {
677                 if (vol->plex[plexno] == msg->index)        /* found our plex */
678                     break;
679             }
680             if (plexno < (vol->plexes - 1))                 /* not the last one, compact */
681                 bcopy(&vol->plex[plexno + 1],
682                     &vol->plex[plexno],
683                     (vol->plexes - 1 - plexno) * sizeof(int));
684             vol->plexes--;
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 */
688             {
689                 /* First, check if the subdisks are the same */
690                 if (msg->recurse) {
691                     int sdno;
692
693                     for (sdno = 0; sdno < plex->subdisks; sdno++) {
694                         struct sd *sd = &SD[plex->sdnos[sdno]];
695
696                         if (!bcmp(plex->name, sd->name, strlen(plex->name) + 1))
697                                                             /* subdisk is named after the plex */
698                         {
699                             bcopy(sd->name,
700                                 &sd->name[3],
701                                 min(strlen(sd->name) + 1, MAXSDNAME - 3));
702                             bcopy("ex-", sd->name, 3);
703                             sd->name[MAXSDNAME - 1] = '\0';
704                         }
705                     }
706                 }
707                 bcopy(plex->name,
708                     &plex->name[3],
709                     min(strlen(plex->name) + 1, MAXPLEXNAME - 3));
710                 bcopy("ex-", plex->name, 3);
711                 plex->name[MAXPLEXNAME - 1] = '\0';
712             }
713             update_volume_config(volno, 0);
714             save_config();
715             reply->error = 0;
716         } else {
717             reply->error = ENOENT;
718             strcpy(reply->msg, "Plex is not attached");
719         }
720     }
721 }
722
723 void
724 renameobject(struct vinum_rename_msg *msg)
725 {
726     struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
727     struct drive *drive;
728     struct sd *sd;
729     struct plex *plex;
730     struct volume *vol;
731
732     switch (msg->type) {
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';
737             return;
738         }
739         drive = validdrive(msg->index, reply);
740         if (drive) {
741             bcopy(msg->newname, drive->label.name, MAXDRIVENAME);
742             save_config();
743             reply->error = 0;
744         }
745         return;
746
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';
751             return;
752         }
753         sd = validsd(msg->index, reply);
754         if (sd) {
755             bcopy(msg->newname, sd->name, MAXSDNAME);
756             update_sd_config(sd->sdno, 0);
757             save_config();
758             reply->error = 0;
759         }
760         return;
761
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';
766             return;
767         }
768         plex = validplex(msg->index, reply);
769         if (plex) {
770             bcopy(msg->newname, plex->name, MAXPLEXNAME);
771             update_plex_config(plex->plexno, 0);
772             save_config();
773             reply->error = 0;
774         }
775         return;
776
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';
781             return;
782         }
783         vol = validvol(msg->index, reply);
784         if (vol) {
785             bcopy(msg->newname, vol->name, MAXVOLNAME);
786             update_volume_config(msg->index, 0);
787             save_config();
788             reply->error = 0;
789         }
790         return;
791
792     case invalid_object:
793         reply->error = EINVAL;
794         reply->msg[0] = '\0';
795     }
796 }
797
798 /*
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
803  */
804 void
805 replaceobject(struct vinum_ioctl_msg *msg)
806 {
807     struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
808
809     reply->error = ENODEV;                                  /* until I know how to do this */
810     strcpy(reply->msg, "replace not implemented yet");
811 /*      save_config (); */
812 }
813
814 void
815 moveobject(struct vinum_ioctl_msg *msg)
816 {
817     struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
818     struct drive *drive;
819     struct sd *sd;
820
821     /* Check that our objects are valid (i.e. they exist) */
822     drive = validdrive(msg->index, (struct _ioctl_reply *) msg);
823     if (drive == NULL)
824         return;
825     sd = validsd(msg->otherobject, (struct _ioctl_reply *) msg);
826     if (sd == NULL)
827         return;
828     if (sd->driveno == msg->index)                          /* sd already belongs to drive */
829         return;
830
831     if (sd->state > sd_stale)
832         set_sd_state(sd->sdno, sd_stale, setstate_force);   /* make the subdisk stale */
833     else
834         sd->state = sd_empty;
835     if (sd->plexno >= 0)                                    /* part of a plex, */
836         update_plex_state(sd->plexno);                      /* update its state */
837
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 */
842             sd->driveoffset,
843             sd->sectors);
844
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);
849     reply->error = 0;
850 }
851
852 /* Local Variables: */
853 /* fill-column: 50 */
854 /* End: */