Change the kernel dev_t, representing a pointer to a specinfo structure,
[dragonfly.git] / sys / dev / raid / vinum / vinumioctl.c
CommitLineData
984263bc
MD
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 $
b13267a5 46 * $DragonFly: src/sys/dev/raid/vinum/vinumioctl.c,v 1.7 2006/09/10 01:26:36 dillon Exp $
984263bc
MD
47 */
48
1f2de5d4
MD
49#include "vinumhdr.h"
50#include "request.h"
984263bc
MD
51
52#ifdef VINUMDEBUG
53#include <sys/reboot.h>
54#endif
55
56void attachobject(struct vinum_ioctl_msg *);
57void detachobject(struct vinum_ioctl_msg *);
58void renameobject(struct vinum_rename_msg *);
59void replaceobject(struct vinum_ioctl_msg *);
60void moveobject(struct vinum_ioctl_msg *);
61
62jmp_buf command_fail; /* return on a failed command */
63
64/* ioctl routine */
65int
fef8985e 66vinumioctl(struct dev_ioctl_args *ap)
984263bc 67{
b13267a5 68 cdev_t dev = ap->a_head.a_dev;
fef8985e
MD
69 u_long cmd = ap->a_cmd;
70 caddr_t data = ap->a_data;
984263bc
MD
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;
984263bc
MD
310 default:
311 /* FALLTHROUGH */
6b08710e 312 break;
984263bc
MD
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 /*
391 * Care! DIOCGPART returns *pointers* to
392 * the caller, so we need to store this crap
393 * as well. And yes, we need it.
394 */
395 case DIOCGPART: /* get partition information */
396 get_volume_label(vol->name, vol->plexes, vol->size, &vol->label);
397 ((struct partinfo *) data)->disklab = &vol->label;
398 ((struct partinfo *) data)->part = &vol->label.d_partitions[0];
399 break;
400
401 /*
402 * We don't have this stuff on hardware,
403 * so just pretend to do it so that
404 * utilities don't get upset.
405 */
406 case DIOCWDINFO: /* write partition info */
407 case DIOCSDINFO: /* set partition info */
408 return 0; /* not a titty */
409
410 case DIOCWLABEL: /* set or reset label writeable */
fef8985e 411 if ((ap->a_fflag & FWRITE) == 0) /* not writeable? */
984263bc
MD
412 return EACCES; /* no, die */
413 if (*(int *) data != 0) /* set it? */
414 vol->flags |= VF_WLABEL; /* yes */
415 else
416 vol->flags &= ~VF_WLABEL; /* no, reset */
417 break;
418
419 default:
420 return ENOTTY; /* not my kind of ioctl */
421 }
422 break;
423 }
424 return 0; /* XXX */
425}
426
427/*
428 * The following four functions check the supplied
429 * object index and return a pointer to the object
430 * if it exists. Otherwise they longjump out via
431 * throw_rude_remark.
432 */
433struct drive *
434validdrive(int driveno, struct _ioctl_reply *reply)
435{
436 if ((driveno < vinum_conf.drives_allocated)
437 && (DRIVE[driveno].state > drive_referenced))
438 return &DRIVE[driveno];
439 strcpy(reply->msg, "No such drive");
440 reply->error = ENOENT;
441 return NULL;
442}
443
444struct sd *
445validsd(int sdno, struct _ioctl_reply *reply)
446{
447 if ((sdno < vinum_conf.subdisks_allocated)
448 && (SD[sdno].state > sd_referenced))
449 return &SD[sdno];
450 strcpy(reply->msg, "No such subdisk");
451 reply->error = ENOENT;
452 return NULL;
453}
454
455struct plex *
456validplex(int plexno, struct _ioctl_reply *reply)
457{
458 if ((plexno < vinum_conf.plexes_allocated)
459 && (PLEX[plexno].state > plex_referenced))
460 return &PLEX[plexno];
461 strcpy(reply->msg, "No such plex");
462 reply->error = ENOENT;
463 return NULL;
464}
465
466struct volume *
467validvol(int volno, struct _ioctl_reply *reply)
468{
469 if ((volno < vinum_conf.volumes_allocated)
470 && (VOL[volno].state > volume_uninit))
471 return &VOL[volno];
472 strcpy(reply->msg, "No such volume");
473 reply->error = ENOENT;
474 return NULL;
475}
476
477/* reset an object's stats */
478void
479resetstats(struct vinum_ioctl_msg *msg)
480{
481 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
482
483 switch (msg->type) {
484 case drive_object:
485 if (msg->index < vinum_conf.drives_allocated) {
486 struct drive *drive = &DRIVE[msg->index];
487 if (drive->state > drive_referenced) {
488 drive->reads = 0; /* number of reads on this drive */
489 drive->writes = 0; /* number of writes on this drive */
490 drive->bytes_read = 0; /* number of bytes read */
491 drive->bytes_written = 0; /* number of bytes written */
492 reply->error = 0;
493 return;
494 }
495 reply->error = EINVAL;
496 return;
497 }
498 case sd_object:
499 if (msg->index < vinum_conf.subdisks_allocated) {
500 struct sd *sd = &SD[msg->index];
501 if (sd->state > sd_referenced) {
502 sd->reads = 0; /* number of reads on this subdisk */
503 sd->writes = 0; /* number of writes on this subdisk */
504 sd->bytes_read = 0; /* number of bytes read */
505 sd->bytes_written = 0; /* number of bytes written */
506 reply->error = 0;
507 return;
508 }
509 reply->error = EINVAL;
510 return;
511 }
512 break;
513
514 case plex_object:
515 if (msg->index < vinum_conf.plexes_allocated) {
516 struct plex *plex = &PLEX[msg->index];
517 if (plex->state > plex_referenced) {
518 plex->reads = 0;
519 plex->writes = 0; /* number of writes on this plex */
520 plex->bytes_read = 0; /* number of bytes read */
521 plex->bytes_written = 0; /* number of bytes written */
522 plex->recovered_reads = 0; /* number of recovered read operations */
523 plex->degraded_writes = 0; /* number of degraded writes */
524 plex->parityless_writes = 0; /* number of parityless writes */
525 plex->multiblock = 0; /* requests that needed more than one block */
526 plex->multistripe = 0; /* requests that needed more than one stripe */
527 reply->error = 0;
528 return;
529 }
530 reply->error = EINVAL;
531 return;
532 }
533 break;
534
535 case volume_object:
536 if (msg->index < vinum_conf.volumes_allocated) {
537 struct volume *vol = &VOL[msg->index];
538 if (vol->state > volume_uninit) {
539 vol->bytes_read = 0; /* number of bytes read */
540 vol->bytes_written = 0; /* number of bytes written */
541 vol->reads = 0; /* number of reads on this volume */
542 vol->writes = 0; /* number of writes on this volume */
543 vol->recovered_reads = 0; /* reads recovered from another plex */
544 reply->error = 0;
545 return;
546 }
547 reply->error = EINVAL;
548 return;
549 }
550 case invalid_object: /* can't get this */
551 reply->error = EINVAL;
552 return;
553 }
554}
555
556/* attach an object to a superior object */
557void
558attachobject(struct vinum_ioctl_msg *msg)
559{
560 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
561 int sdno;
562 struct sd *sd;
563 struct plex *plex;
564 struct volume *vol;
565
566 switch (msg->type) {
567 case drive_object: /* you can't attach a drive to anything */
568 case volume_object: /* nor a volume */
569 case invalid_object: /* "this can't happen" */
570 reply->error = EINVAL;
571 reply->msg[0] = '\0'; /* vinum(8) doesn't do this */
572 return;
573
574 case sd_object:
575 sd = validsd(msg->index, reply);
576 if (sd == NULL) /* not a valid subdisk */
577 return;
578 plex = validplex(msg->otherobject, reply);
579 if (plex) {
580 /*
581 * We should be more intelligent about this.
582 * We should be able to reattach a dead
583 * subdisk, but if we want to increase the total
584 * number of subdisks, we have a lot of reshuffling
585 * to do. XXX
586 */
587 if ((plex->organization != plex_concat) /* can't attach to striped and RAID-4/5 */
588 &&(!msg->force)) { /* without using force */
589 reply->error = EINVAL; /* no message, the user should check */
590 strcpy(reply->msg, "Can't attach to this plex organization");
591 return;
592 }
593 if (sd->plexno >= 0) { /* already belong to a plex */
594 reply->error = EBUSY; /* no message, the user should check */
595 reply->msg[0] = '\0';
596 return;
597 }
598 sd->plexoffset = msg->offset; /* this is where we want it */
599 set_sd_state(sd->sdno, sd_stale, setstate_force); /* make sure it's stale */
600 give_sd_to_plex(plex->plexno, sd->sdno); /* and give it to the plex */
601 update_sd_config(sd->sdno, 0);
602 save_config();
603 }
604 if (sd->state == sd_reviving)
605 reply->error = EAGAIN; /* need to revive it */
606 else
607 reply->error = 0;
608 break;
609
610 case plex_object:
611 plex = validplex(msg->index, reply); /* get plex */
612 if (plex == NULL)
613 return;
614 vol = validvol(msg->otherobject, reply); /* and volume information */
615 if (vol) {
616 if ((vol->plexes == MAXPLEX) /* we have too many already */
617 ||(plex->volno >= 0)) { /* or the plex has an owner */
618 reply->error = EINVAL; /* no message, the user should check */
619 reply->msg[0] = '\0';
620 return;
621 }
622 for (sdno = 0; sdno < plex->subdisks; sdno++) {
623 sd = &SD[plex->sdnos[sdno]];
624
625 if (sd->state > sd_down) /* real subdisk, vaguely accessible */
626 set_sd_state(plex->sdnos[sdno], sd_stale, setstate_force); /* make it stale */
627 }
628 set_plex_state(plex->plexno, plex_up, setstate_none); /* update plex state */
629 give_plex_to_volume(msg->otherobject, msg->index); /* and give it to the volume */
630 update_plex_config(plex->plexno, 0);
631 save_config();
632 }
633 }
634}
635
636/* detach an object from a superior object */
637void
638detachobject(struct vinum_ioctl_msg *msg)
639{
640 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
641 struct sd *sd;
642 struct plex *plex;
643 struct volume *vol;
644 int sdno;
645 int plexno;
646
647 switch (msg->type) {
648 case drive_object: /* you can't detach a drive from anything */
649 case volume_object: /* nor a volume */
650 case invalid_object: /* "this can't happen" */
651 reply->error = EINVAL;
652 reply->msg[0] = '\0'; /* vinum(8) doesn't do this */
653 return;
654
655 case sd_object:
656 sd = validsd(msg->index, reply);
657 if (sd == NULL)
658 return;
659 if (sd->plexno < 0) { /* doesn't belong to a plex */
660 reply->error = ENOENT;
661 strcpy(reply->msg, "Subdisk is not attached");
662 return;
663 } else { /* valid plex number */
664 plex = &PLEX[sd->plexno];
665 if ((!msg->force) /* don't force things */
666 &&((plex->state == plex_up) /* and the plex is up */
667 ||((plex->state == plex_flaky) && sd->state == sd_up))) { /* or flaky with this sd up */
668 reply->error = EBUSY; /* we need this sd */
669 reply->msg[0] = '\0';
670 return;
671 }
672 sd->plexno = -1; /* anonymous sd */
673 if (plex->subdisks == 1) { /* this was the only subdisk */
674 Free(plex->sdnos); /* free the subdisk array */
675 plex->sdnos = NULL; /* and note the fact */
676 plex->subdisks_allocated = 0; /* no subdisk space */
677 } else {
678 for (sdno = 0; sdno < plex->subdisks; sdno++) {
679 if (plex->sdnos[sdno] == msg->index) /* found our subdisk */
680 break;
681 }
682 if (sdno < (plex->subdisks - 1)) /* not the last one, compact */
683 bcopy(&plex->sdnos[sdno + 1],
684 &plex->sdnos[sdno],
685 (plex->subdisks - 1 - sdno) * sizeof(int));
686 }
687 plex->subdisks--;
688 if (!bcmp(plex->name, sd->name, strlen(plex->name) + 1))
689 /* this subdisk is named after the plex */
690 {
691 bcopy(sd->name,
692 &sd->name[3],
693 min(strlen(sd->name) + 1, MAXSDNAME - 3));
694 bcopy("ex-", sd->name, 3);
695 sd->name[MAXSDNAME - 1] = '\0';
696 }
697 update_plex_config(plex->plexno, 0);
698 if (isstriped(plex)) /* we've just mutilated our plex, */
699 set_plex_state(plex->plexno,
700 plex_down,
701 setstate_force | setstate_configuring);
702 save_config();
703 reply->error = 0;
704 }
705 return;
706
707 case plex_object:
708 plex = validplex(msg->index, reply); /* get plex */
709 if (plex == NULL)
710 return;
711 if (plex->volno >= 0) {
712 int volno = plex->volno;
713
714 vol = &VOL[volno];
715 if ((!msg->force) /* don't force things */
716 &&((vol->state == volume_up) /* and the volume is up */
717 &&(vol->plexes == 1))) { /* and this is the last plex */
718 /*
719 * XXX As elsewhere, check whether we will lose
720 * mapping by removing this plex
721 */
722 reply->error = EBUSY; /* we need this plex */
723 reply->msg[0] = '\0';
724 return;
725 }
726 plex->volno = -1; /* anonymous plex */
727 for (plexno = 0; plexno < vol->plexes; plexno++) {
728 if (vol->plex[plexno] == msg->index) /* found our plex */
729 break;
730 }
731 if (plexno < (vol->plexes - 1)) /* not the last one, compact */
732 bcopy(&vol->plex[plexno + 1],
733 &vol->plex[plexno],
734 (vol->plexes - 1 - plexno) * sizeof(int));
735 vol->plexes--;
736 vol->last_plex_read = 0; /* don't go beyond the end */
737 if (!bcmp(vol->name, plex->name, strlen(vol->name) + 1))
738 /* this plex is named after the volume */
739 {
740 /* First, check if the subdisks are the same */
741 if (msg->recurse) {
742 int sdno;
743
744 for (sdno = 0; sdno < plex->subdisks; sdno++) {
745 struct sd *sd = &SD[plex->sdnos[sdno]];
746
747 if (!bcmp(plex->name, sd->name, strlen(plex->name) + 1))
748 /* subdisk is named after the plex */
749 {
750 bcopy(sd->name,
751 &sd->name[3],
752 min(strlen(sd->name) + 1, MAXSDNAME - 3));
753 bcopy("ex-", sd->name, 3);
754 sd->name[MAXSDNAME - 1] = '\0';
755 }
756 }
757 }
758 bcopy(plex->name,
759 &plex->name[3],
760 min(strlen(plex->name) + 1, MAXPLEXNAME - 3));
761 bcopy("ex-", plex->name, 3);
762 plex->name[MAXPLEXNAME - 1] = '\0';
763 }
764 update_volume_config(volno, 0);
765 save_config();
766 reply->error = 0;
767 } else {
768 reply->error = ENOENT;
769 strcpy(reply->msg, "Plex is not attached");
770 }
771 }
772}
773
774void
775renameobject(struct vinum_rename_msg *msg)
776{
777 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
778 struct drive *drive;
779 struct sd *sd;
780 struct plex *plex;
781 struct volume *vol;
782
783 switch (msg->type) {
784 case drive_object: /* you can't attach a drive to anything */
785 if (find_drive(msg->newname, 0) >= 0) { /* we have that name already, */
786 reply->error = EEXIST;
787 reply->msg[0] = '\0';
788 return;
789 }
790 drive = validdrive(msg->index, reply);
791 if (drive) {
792 bcopy(msg->newname, drive->label.name, MAXDRIVENAME);
793 save_config();
794 reply->error = 0;
795 }
796 return;
797
798 case sd_object: /* you can't attach a subdisk to anything */
799 if (find_subdisk(msg->newname, 0) >= 0) { /* we have that name already, */
800 reply->error = EEXIST;
801 reply->msg[0] = '\0';
802 return;
803 }
804 sd = validsd(msg->index, reply);
805 if (sd) {
806 bcopy(msg->newname, sd->name, MAXSDNAME);
807 update_sd_config(sd->sdno, 0);
808 save_config();
809 reply->error = 0;
810 }
811 return;
812
813 case plex_object: /* you can't attach a plex to anything */
814 if (find_plex(msg->newname, 0) >= 0) { /* we have that name already, */
815 reply->error = EEXIST;
816 reply->msg[0] = '\0';
817 return;
818 }
819 plex = validplex(msg->index, reply);
820 if (plex) {
821 bcopy(msg->newname, plex->name, MAXPLEXNAME);
822 update_plex_config(plex->plexno, 0);
823 save_config();
824 reply->error = 0;
825 }
826 return;
827
828 case volume_object: /* you can't attach a volume to anything */
829 if (find_volume(msg->newname, 0) >= 0) { /* we have that name already, */
830 reply->error = EEXIST;
831 reply->msg[0] = '\0';
832 return;
833 }
834 vol = validvol(msg->index, reply);
835 if (vol) {
836 bcopy(msg->newname, vol->name, MAXVOLNAME);
837 update_volume_config(msg->index, 0);
838 save_config();
839 reply->error = 0;
840 }
841 return;
842
843 case invalid_object:
844 reply->error = EINVAL;
845 reply->msg[0] = '\0';
846 }
847}
848
849/*
850 * Replace one object with another.
851 * Currently only for drives.
852 * message->index is the drive number of the old drive
853 * message->otherobject is the drive number of the new drive
854 */
855void
856replaceobject(struct vinum_ioctl_msg *msg)
857{
858 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
859
860 reply->error = ENODEV; /* until I know how to do this */
861 strcpy(reply->msg, "replace not implemented yet");
862/* save_config (); */
863}
864
865void
866moveobject(struct vinum_ioctl_msg *msg)
867{
868 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
869 struct drive *drive;
870 struct sd *sd;
871
872 /* Check that our objects are valid (i.e. they exist) */
873 drive = validdrive(msg->index, (struct _ioctl_reply *) msg);
874 if (drive == NULL)
875 return;
876 sd = validsd(msg->otherobject, (struct _ioctl_reply *) msg);
877 if (sd == NULL)
878 return;
879 if (sd->driveno == msg->index) /* sd already belongs to drive */
880 return;
881
882 if (sd->state > sd_stale)
883 set_sd_state(sd->sdno, sd_stale, setstate_force); /* make the subdisk stale */
884 else
885 sd->state = sd_empty;
886 if (sd->plexno >= 0) /* part of a plex, */
887 update_plex_state(sd->plexno); /* update its state */
888
889 /* Return the space on the old drive */
890 if ((sd->driveno >= 0) /* we have a drive, */
891 &&(sd->sectors > 0)) /* and some space on it */
892 return_drive_space(sd->driveno, /* return the space */
893 sd->driveoffset,
894 sd->sectors);
895
896 /* Reassign the old subdisk */
897 sd->driveno = msg->index;
898 sd->driveoffset = -1; /* let the drive decide where to put us */
899 give_sd_to_drive(sd->sdno);
900 reply->error = 0;
901}
902
903/* Local Variables: */
904/* fill-column: 50 */
905/* End: */