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