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.12 2000/02/29 02:20:31 grog Exp grog $
45 * $FreeBSD$
46 */
47
48 #include <dev/vinum/vinumhdr.h>
49 #include <dev/vinum/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
65 vinumioctl(dev_t dev,
66 u_long cmd,
67 caddr_t data,
68 int flag,
69 struct proc *p)
70 {
71 unsigned int objno;
72 int error = 0;
73 struct sd *sd;
74 struct plex *plex;
75 struct volume *vol;
76 unsigned int index; /* for transferring config info */
77 unsigned int sdno; /* for transferring config info */
78 int fe; /* free list element number */
79 struct _ioctl_reply *ioctl_reply = (struct _ioctl_reply *) data; /* struct to return */
80
81 /* First, decide what we're looking at */
82 switch (DEVTYPE(dev)) {
83 case VINUM_SUPERDEV_TYPE: /* ordinary super device */
84 ioctl_reply = (struct _ioctl_reply *) data; /* save the address to reply to */
85 switch (cmd) {
86 #ifdef VINUMDEBUG
87 case VINUM_DEBUG:
88 if (((struct debuginfo *) data)->changeit) /* change debug settings */
89 debug = (((struct debuginfo *) data)->param);
90 else {
91 if (debug & DEBUG_REMOTEGDB)
92 boothowto |= RB_GDB; /* serial debug line */
93 else
94 boothowto &= ~RB_GDB; /* local ddb */
95 Debugger("vinum debug");
96 }
97 ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */
98 ioctl_reply->error = 0;
99 return 0;
100 #endif
101
102 case VINUM_CREATE: /* create a vinum object */
103 error = lock_config(); /* get the config for us alone */
104 if (error) /* can't do it, */
105 return error; /* give up */
106 error = setjmp(command_fail); /* come back here on error */
107 if (error == 0) /* first time, */
108 ioctl_reply->error = parse_user_config((char *) data, /* update the config */
109 &keyword_set);
110 else if (ioctl_reply->error == 0) { /* longjmp, but no error status */
111 ioctl_reply->error = EINVAL; /* note that something's up */
112 ioctl_reply->msg[0] = '\0'; /* no message? */
113 }
114 unlock_config();
115 return 0; /* must be 0 to return the real error info */
116
117 case VINUM_GETCONFIG: /* get the configuration information */
118 bcopy(&vinum_conf, data, sizeof(vinum_conf));
119 return 0;
120
121 /* start configuring the subsystem */
122 case VINUM_STARTCONFIG:
123 return start_config(*(int *) data); /* just lock it. Parameter is 'force' */
124
125 /*
126 * Move the individual parts of the config to user space.
127 *
128 * Specify the index of the object in the first word of data,
129 * and return the object there
130 */
131 case VINUM_DRIVECONFIG:
132 index = *(int *) data; /* get the index */
133 if (index >= (unsigned) vinum_conf.drives_allocated) /* can't do it */
134 return ENXIO; /* bang */
135 bcopy(&DRIVE[index], data, sizeof(struct drive)); /* copy the config item out */
136 return 0;
137
138 case VINUM_SDCONFIG:
139 index = *(int *) data; /* get the index */
140 if (index >= (unsigned) vinum_conf.subdisks_allocated) /* can't do it */
141 return ENXIO; /* bang */
142 bcopy(&SD[index], data, sizeof(struct sd)); /* copy the config item out */
143 return 0;
144
145 case VINUM_PLEXCONFIG:
146 index = *(int *) data; /* get the index */
147 if (index >= (unsigned) vinum_conf.plexes_allocated) /* can't do it */
148 return ENXIO; /* bang */
149 bcopy(&PLEX[index], data, sizeof(struct plex)); /* copy the config item out */
150 return 0;
151
152 case VINUM_VOLCONFIG:
153 index = *(int *) data; /* get the index */
154 if (index >= (unsigned) vinum_conf.volumes_allocated) /* can't do it */
155 return ENXIO; /* bang */
156 bcopy(&VOL[index], data, sizeof(struct volume)); /* copy the config item out */
157 return 0;
158
159 case VINUM_PLEXSDCONFIG:
160 index = *(int *) data; /* get the plex index */
161 sdno = ((int *) data)[1]; /* and the sd index */
162 if ((index >= (unsigned) vinum_conf.plexes_allocated) /* plex doesn't exist */
163 ||(sdno >= PLEX[index].subdisks)) /* or it doesn't have this many subdisks */
164 return ENXIO; /* bang */
165 bcopy(&SD[PLEX[index].sdnos[sdno]], /* copy the config item out */
166 data,
167 sizeof(struct sd));
168 return 0;
169
170 /*
171 * We get called in two places: one from the
172 * userland config routines, which call us
173 * to complete the config and save it. This
174 * call supplies the value 0 as a parameter.
175 *
176 * The other place is from the user "saveconfig"
177 * routine, which can only work if we're *not*
178 * configuring. In this case, supply parameter 1.
179 */
180 case VINUM_SAVECONFIG:
181 if (VFLAGS & VF_CONFIGURING) { /* must be us, the others are asleep */
182 if (*(int *) data == 0) /* finish config */
183 finish_config(1); /* finish the configuration and update it */
184 else
185 return EBUSY; /* can't do it now */
186 }
187 save_config(); /* save configuration to disk */
188 return 0;
189
190 case VINUM_RELEASECONFIG: /* release the config */
191 if (VFLAGS & VF_CONFIGURING) { /* must be us, the others are asleep */
192 finish_config(0); /* finish the configuration, don't change it */
193 save_config(); /* save configuration to disk */
194 } else
195 error = EINVAL; /* release what config? */
196 return error;
197
198 case VINUM_INIT:
199 ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */
200 ioctl_reply->error = 0;
201 return 0;
202
203 case VINUM_RESETCONFIG:
204 if (vinum_inactive(0)) { /* if the volumes are not active */
205 /*
206 * Note the open count. We may be called from v, so we'll be open.
207 * Keep the count so we don't underflow
208 */
209 free_vinum(1); /* clean up everything */
210 log(LOG_NOTICE, "vinum: CONFIGURATION OBLITERATED\n");
211 ioctl_reply = (struct _ioctl_reply *) data; /* reinstate the address to reply to */
212 ioctl_reply->error = 0;
213 return 0;
214 }
215 return EBUSY;
216
217 case VINUM_SETSTATE:
218 setstate((struct vinum_ioctl_msg *) data); /* set an object state */
219 return 0;
220
221 /*
222 * Set state by force, without changing
223 * anything else.
224 */
225 case VINUM_SETSTATE_FORCE:
226 setstate_by_force((struct vinum_ioctl_msg *) data); /* set an object state */
227 return 0;
228
229 #ifdef VINUMDEBUG
230 case VINUM_MEMINFO:
231 vinum_meminfo(data);
232 return 0;
233
234 case VINUM_MALLOCINFO:
235 return vinum_mallocinfo(data);
236
237 case VINUM_RQINFO:
238 return vinum_rqinfo(data);
239 #endif
240
241 case VINUM_LABEL: /* label a volume */
242 ioctl_reply->error = write_volume_label(*(int *) data); /* index of the volume to label */
243 ioctl_reply->msg[0] = '\0'; /* no message */
244 return 0;
245
246 case VINUM_REMOVE:
247 remove((struct vinum_ioctl_msg *) data); /* remove an object */
248 return 0;
249
250 case VINUM_GETFREELIST: /* get a drive free list element */
251 index = *(int *) data; /* get the drive index */
252 fe = ((int *) data)[1]; /* and the free list element */
253 if ((index >= (unsigned) vinum_conf.drives_allocated) /* plex doesn't exist */
254 ||(DRIVE[index].state == drive_unallocated))
255 return ENODEV;
256 if (fe >= DRIVE[index].freelist_entries) /* no such entry */
257 return ENOENT;
258 bcopy(&DRIVE[index].freelist[fe],
259 data,
260 sizeof(struct drive_freelist));
261 return 0;
262
263 case VINUM_RESETSTATS:
264 resetstats((struct vinum_ioctl_msg *) data); /* reset object stats */
265 return 0;
266
267 /* attach an object to a superordinate object */
268 case VINUM_ATTACH:
269 attachobject((struct vinum_ioctl_msg *) data);
270 return 0;
271
272 /* detach an object from a superordinate object */
273 case VINUM_DETACH:
274 detachobject((struct vinum_ioctl_msg *) data);
275 return 0;
276
277 /* rename an object */
278 case VINUM_RENAME:
279 renameobject((struct vinum_rename_msg *) data);
280 return 0;
281
282 /* replace an object */
283 case VINUM_REPLACE:
284 replaceobject((struct vinum_ioctl_msg *) data);
285 return 0;
286
287 case VINUM_DAEMON:
288 vinum_daemon(); /* perform the daemon */
289 return 0;
290
291 case VINUM_FINDDAEMON: /* check for presence of daemon */
292 return vinum_finddaemon();
293 return 0;
294
295 case VINUM_SETDAEMON: /* set daemon flags */
296 return vinum_setdaemonopts(*(int *) data);
297
298 case VINUM_GETDAEMON: /* get daemon flags */
299 *(int *) data = daemon_options;
300 return 0;
301
302 case VINUM_PARITYOP: /* check/rebuild RAID-4/5 parity */
303 parityops((struct vinum_ioctl_msg *) data);
304 return 0;
305
306 /* move an object */
307 case VINUM_MOVE:
308 moveobject((struct vinum_ioctl_msg *) data);
309 return 0;
310
311 default:
312 /* FALLTHROUGH */
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 */
411 if ((flag & FWRITE) == 0) /* not writeable? */
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 */
433 struct drive *
434 validdrive(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
444 struct sd *
445 validsd(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
455 struct plex *
456 validplex(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
466 struct volume *
467 validvol(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 */
478 void
479 resetstats(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 */
557 void
558 attachobject(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 */
637 void
638 detachobject(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))) { /* this subdisk is named after the plex */
689 bcopy(sd->name,
690 &sd->name[3],
691 min(strlen(sd->name), MAXSDNAME - 3));
692 bcopy("ex-", sd->name, 3);
693 sd->name[MAXSDNAME - 1] = '\0';
694 }
695 update_plex_config(plex->plexno, 0);
696 if (isstriped(plex)) /* we've just mutilated our plex, */
697 set_plex_state(plex->plexno,
698 plex_down,
699 setstate_force | setstate_configuring);
700 save_config();
701 reply->error = 0;
702 }
703 return;
704
705 case plex_object:
706 plex = validplex(msg->index, reply); /* get plex */
707 if (plex == NULL)
708 return;
709 if (plex->volno >= 0) {
710 int volno = plex->volno;
711
712 vol = &VOL[volno];
713 if ((!msg->force) /* don't force things */
714 &&((vol->state == volume_up) /* and the volume is up */
715 &&(vol->plexes == 1))) { /* and this is the last plex */
716 /*
717 * XXX As elsewhere, check whether we will lose
718 * mapping by removing this plex
719 */
720 reply->error = EBUSY; /* we need this plex */
721 reply->msg[0] = '\0';
722 return;
723 }
724 plex->volno = -1; /* anonymous plex */
725 for (plexno = 0; plexno < vol->plexes; plexno++) {
726 if (vol->plex[plexno] == msg->index) /* found our plex */
727 break;
728 }
729 if (plexno < (vol->plexes - 1)) /* not the last one, compact */
730 bcopy(&vol->plex[plexno + 1],
731 &vol->plex[plexno],
732 (vol->plexes - 1 - plexno) * sizeof(int));
733 vol->plexes--;
734 vol->last_plex_read = 0; /* don't go beyond the end */
735 if (!bcmp(vol->name, plex->name, strlen(vol->name))) { /* this plex is named after the volume */
736 /* First, check if the subdisks are the same */
737 if (msg->recurse) {
738 int sdno;
739
740 for (sdno = 0; sdno < plex->subdisks; sdno++) {
741 struct sd *sd = &SD[plex->sdnos[sdno]];
742
743 if (!bcmp(plex->name, sd->name, strlen(plex->name))) { /* subdisk is named after the plex */
744 bcopy(sd->name, &sd->name[3], min(strlen(sd->name), MAXSDNAME - 3));
745 bcopy("ex-", sd->name, 3);
746 sd->name[MAXSDNAME - 1] = '\0';
747 }
748 }
749 }
750 bcopy(plex->name, &plex->name[3], min(strlen(plex->name), MAXPLEXNAME - 3));
751 bcopy("ex-", plex->name, 3);
752 plex->name[MAXPLEXNAME - 1] = '\0';
753 }
754 update_volume_config(volno, 0);
755 save_config();
756 reply->error = 0;
757 } else {
758 reply->error = ENOENT;
759 strcpy(reply->msg, "Plex is not attached");
760 }
761 }
762 }
763
764 void
765 renameobject(struct vinum_rename_msg *msg)
766 {
767 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
768 struct drive *drive;
769 struct sd *sd;
770 struct plex *plex;
771 struct volume *vol;
772
773 switch (msg->type) {
774 case drive_object: /* you can't attach a drive to anything */
775 if (find_drive(msg->newname, 0) >= 0) { /* we have that name already, */
776 reply->error = EEXIST;
777 reply->msg[0] = '\0';
778 return;
779 }
780 drive = validdrive(msg->index, reply);
781 if (drive) {
782 bcopy(msg->newname, drive->label.name, MAXDRIVENAME);
783 save_config();
784 reply->error = 0;
785 }
786 return;
787
788 case sd_object: /* you can't attach a subdisk to anything */
789 if (find_subdisk(msg->newname, 0) >= 0) { /* we have that name already, */
790 reply->error = EEXIST;
791 reply->msg[0] = '\0';
792 return;
793 }
794 sd = validsd(msg->index, reply);
795 if (sd) {
796 bcopy(msg->newname, sd->name, MAXSDNAME);
797 update_sd_config(sd->sdno, 0);
798 save_config();
799 reply->error = 0;
800 }
801 return;
802
803 case plex_object: /* you can't attach a plex to anything */
804 if (find_plex(msg->newname, 0) >= 0) { /* we have that name already, */
805 reply->error = EEXIST;
806 reply->msg[0] = '\0';
807 return;
808 }
809 plex = validplex(msg->index, reply);
810 if (plex) {
811 bcopy(msg->newname, plex->name, MAXPLEXNAME);
812 update_plex_config(plex->plexno, 0);
813 save_config();
814 reply->error = 0;
815 }
816 return;
817
818 case volume_object: /* you can't attach a volume to anything */
819 if (find_volume(msg->newname, 0) >= 0) { /* we have that name already, */
820 reply->error = EEXIST;
821 reply->msg[0] = '\0';
822 return;
823 }
824 vol = validvol(msg->index, reply);
825 if (vol) {
826 bcopy(msg->newname, vol->name, MAXVOLNAME);
827 update_volume_config(msg->index, 0);
828 save_config();
829 reply->error = 0;
830 }
831 return;
832
833 case invalid_object:
834 reply->error = EINVAL;
835 reply->msg[0] = '\0';
836 }
837 }
838
839 /*
840 * Replace one object with another.
841 * Currently only for drives.
842 * message->index is the drive number of the old drive
843 * message->otherobject is the drive number of the new drive
844 */
845 void
846 replaceobject(struct vinum_ioctl_msg *msg)
847 {
848 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
849
850 reply->error = ENODEV; /* until I know how to do this */
851 strcpy(reply->msg, "replace not implemented yet");
852 /* save_config (); */
853 }
854
855 void
856 moveobject(struct vinum_ioctl_msg *msg)
857 {
858 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
859 struct drive *drive;
860 struct sd *sd;
861
862 /* Check that our objects are valid (i.e. they exist) */
863 drive = validdrive(msg->index, (struct _ioctl_reply *) msg);
864 if (drive == NULL)
865 return;
866 sd = validsd(msg->otherobject, (struct _ioctl_reply *) msg);
867 if (sd == NULL)
868 return;
869 if (sd->driveno == msg->index) /* sd already belongs to drive */
870 return;
871
872 if (sd->state > sd_stale)
873 set_sd_state(sd->sdno, sd_stale, setstate_force); /* make the subdisk stale */
874 else
875 sd->state = sd_empty;
876 if (sd->plexno >= 0) /* part of a plex, */
877 update_plex_state(sd->plexno); /* update its state */
878
879 /* Return the space on the old drive */
880 if ((sd->driveno >= 0) /* we have a drive, */
881 &&(sd->sectors > 0)) /* and some space on it */
882 return_drive_space(sd->driveno, /* return the space */
883 sd->driveoffset,
884 sd->sectors);
885
886 /* Reassign the old subdisk */
887 sd->driveno = msg->index;
888 sd->driveoffset = -1; /* let the drive decide where to put us */
889 give_sd_to_drive(sd->sdno);
890 reply->error = 0;
891 }
892
893 /* Local Variables: */
894 /* fill-column: 50 */
895 /* End: */
Cache object: e77adbcef6ff31f8770c6e239783deb2
|