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: releng/5.0/sys/dev/vinum/vinumioctl.c 108907 2003-01-07 22:59:50Z grog $
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 thread *td)
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 break;
314 }
315
316 case VINUM_DRIVE_TYPE:
317 default:
318 log(LOG_WARNING,
319 "vinumioctl: invalid ioctl from process %d (%s): %lx\n",
320 curthread->td_proc->p_pid,
321 curthread->td_proc->p_comm,
322 cmd);
323 return EINVAL;
324
325 case VINUM_SD_TYPE:
326 case VINUM_RAWSD_TYPE:
327 objno = Sdno(dev);
328
329 sd = &SD[objno];
330
331 switch (cmd) {
332 case DIOCGDINFO: /* get disk label */
333 get_volume_label(sd->name, 1, sd->sectors, (struct disklabel *) data);
334 break;
335
336 /*
337 * We don't have this stuff on hardware,
338 * so just pretend to do it so that
339 * utilities don't get upset.
340 */
341 case DIOCWDINFO: /* write partition info */
342 case DIOCSDINFO: /* set partition info */
343 return 0; /* not a titty */
344
345 default:
346 return ENOTTY; /* not my kind of ioctl */
347 }
348
349 return 0; /* pretend we did it */
350
351 case VINUM_RAWPLEX_TYPE:
352 case VINUM_PLEX_TYPE:
353 objno = Plexno(dev);
354
355 plex = &PLEX[objno];
356
357 switch (cmd) {
358 case DIOCGDINFO: /* get disk label */
359 get_volume_label(plex->name, 1, plex->length, (struct disklabel *) data);
360 break;
361
362 /*
363 * We don't have this stuff on hardware,
364 * so just pretend to do it so that
365 * utilities don't get upset.
366 */
367 case DIOCWDINFO: /* write partition info */
368 case DIOCSDINFO: /* set partition info */
369 return 0; /* not a titty */
370
371 default:
372 return ENOTTY; /* not my kind of ioctl */
373 }
374
375 return 0; /* pretend we did it */
376
377 case VINUM_VOLUME_TYPE:
378 objno = Volno(dev);
379
380 if ((unsigned) objno >= (unsigned) vinum_conf.volumes_allocated) /* not a valid volume */
381 return ENXIO;
382 vol = &VOL[objno];
383 if (vol->state != volume_up) /* not up, */
384 return EIO; /* I/O error */
385
386 switch (cmd) {
387
388 case DIOCGMEDIASIZE:
389 *(off_t *)data = vol->size << DEV_BSHIFT;
390 break;
391
392 case DIOCGSECTORSIZE:
393 *(u_int *)data = DEV_BSIZE;
394 break;
395
396 /*
397 * We don't have this stuff on hardware,
398 * so just pretend to do it so that
399 * utilities don't get upset.
400 */
401 case DIOCWDINFO: /* write partition info */
402 case DIOCSDINFO: /* set partition info */
403 return 0; /* not a titty */
404
405 case DIOCWLABEL: /* set or reset label writeable */
406 if ((flag & FWRITE) == 0) /* not writeable? */
407 return EACCES; /* no, die */
408 if (*(int *) data != 0) /* set it? */
409 vol->flags |= VF_WLABEL; /* yes */
410 else
411 vol->flags &= ~VF_WLABEL; /* no, reset */
412 break;
413
414 default:
415 return ENOTTY; /* not my kind of ioctl */
416 }
417 break;
418 }
419 return 0; /* XXX */
420 }
421
422 /*
423 * The following four functions check the supplied
424 * object index and return a pointer to the object
425 * if it exists. Otherwise they longjump out via
426 * throw_rude_remark.
427 */
428 struct drive *
429 validdrive(int driveno, struct _ioctl_reply *reply)
430 {
431 if ((driveno < vinum_conf.drives_allocated)
432 && (DRIVE[driveno].state > drive_referenced))
433 return &DRIVE[driveno];
434 strcpy(reply->msg, "No such drive");
435 reply->error = ENOENT;
436 return NULL;
437 }
438
439 struct sd *
440 validsd(int sdno, struct _ioctl_reply *reply)
441 {
442 if ((sdno < vinum_conf.subdisks_allocated)
443 && (SD[sdno].state > sd_referenced))
444 return &SD[sdno];
445 strcpy(reply->msg, "No such subdisk");
446 reply->error = ENOENT;
447 return NULL;
448 }
449
450 struct plex *
451 validplex(int plexno, struct _ioctl_reply *reply)
452 {
453 if ((plexno < vinum_conf.plexes_allocated)
454 && (PLEX[plexno].state > plex_referenced))
455 return &PLEX[plexno];
456 strcpy(reply->msg, "No such plex");
457 reply->error = ENOENT;
458 return NULL;
459 }
460
461 struct volume *
462 validvol(int volno, struct _ioctl_reply *reply)
463 {
464 if ((volno < vinum_conf.volumes_allocated)
465 && (VOL[volno].state > volume_uninit))
466 return &VOL[volno];
467 strcpy(reply->msg, "No such volume");
468 reply->error = ENOENT;
469 return NULL;
470 }
471
472 /* reset an object's stats */
473 void
474 resetstats(struct vinum_ioctl_msg *msg)
475 {
476 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
477
478 switch (msg->type) {
479 case drive_object:
480 if (msg->index < vinum_conf.drives_allocated) {
481 struct drive *drive = &DRIVE[msg->index];
482 if (drive->state > drive_referenced) {
483 drive->reads = 0; /* number of reads on this drive */
484 drive->writes = 0; /* number of writes on this drive */
485 drive->bytes_read = 0; /* number of bytes read */
486 drive->bytes_written = 0; /* number of bytes written */
487 reply->error = 0;
488 return;
489 }
490 reply->error = EINVAL;
491 return;
492 }
493 case sd_object:
494 if (msg->index < vinum_conf.subdisks_allocated) {
495 struct sd *sd = &SD[msg->index];
496 if (sd->state > sd_referenced) {
497 sd->reads = 0; /* number of reads on this subdisk */
498 sd->writes = 0; /* number of writes on this subdisk */
499 sd->bytes_read = 0; /* number of bytes read */
500 sd->bytes_written = 0; /* number of bytes written */
501 reply->error = 0;
502 return;
503 }
504 reply->error = EINVAL;
505 return;
506 }
507 break;
508
509 case plex_object:
510 if (msg->index < vinum_conf.plexes_allocated) {
511 struct plex *plex = &PLEX[msg->index];
512 if (plex->state > plex_referenced) {
513 plex->reads = 0;
514 plex->writes = 0; /* number of writes on this plex */
515 plex->bytes_read = 0; /* number of bytes read */
516 plex->bytes_written = 0; /* number of bytes written */
517 plex->recovered_reads = 0; /* number of recovered read operations */
518 plex->degraded_writes = 0; /* number of degraded writes */
519 plex->parityless_writes = 0; /* number of parityless writes */
520 plex->multiblock = 0; /* requests that needed more than one block */
521 plex->multistripe = 0; /* requests that needed more than one stripe */
522 reply->error = 0;
523 return;
524 }
525 reply->error = EINVAL;
526 return;
527 }
528 break;
529
530 case volume_object:
531 if (msg->index < vinum_conf.volumes_allocated) {
532 struct volume *vol = &VOL[msg->index];
533 if (vol->state > volume_uninit) {
534 vol->bytes_read = 0; /* number of bytes read */
535 vol->bytes_written = 0; /* number of bytes written */
536 vol->reads = 0; /* number of reads on this volume */
537 vol->writes = 0; /* number of writes on this volume */
538 vol->recovered_reads = 0; /* reads recovered from another plex */
539 reply->error = 0;
540 return;
541 }
542 reply->error = EINVAL;
543 return;
544 }
545 case invalid_object: /* can't get this */
546 reply->error = EINVAL;
547 return;
548 }
549 }
550
551 /* attach an object to a superior object */
552 void
553 attachobject(struct vinum_ioctl_msg *msg)
554 {
555 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
556 int sdno;
557 struct sd *sd;
558 struct plex *plex;
559 struct volume *vol;
560
561 switch (msg->type) {
562 case drive_object: /* you can't attach a drive to anything */
563 case volume_object: /* nor a volume */
564 case invalid_object: /* "this can't happen" */
565 reply->error = EINVAL;
566 reply->msg[0] = '\0'; /* vinum(8) doesn't do this */
567 return;
568
569 case sd_object:
570 sd = validsd(msg->index, reply);
571 if (sd == NULL) /* not a valid subdisk */
572 return;
573 plex = validplex(msg->otherobject, reply);
574 if (plex) {
575 /*
576 * We should be more intelligent about this.
577 * We should be able to reattach a dead
578 * subdisk, but if we want to increase the total
579 * number of subdisks, we have a lot of reshuffling
580 * to do. XXX
581 */
582 if ((plex->organization != plex_concat) /* can't attach to striped and RAID-4/5 */
583 &&(!msg->force)) { /* without using force */
584 reply->error = EINVAL; /* no message, the user should check */
585 strcpy(reply->msg, "Can't attach to this plex organization");
586 return;
587 }
588 if (sd->plexno >= 0) { /* already belong to a plex */
589 reply->error = EBUSY; /* no message, the user should check */
590 reply->msg[0] = '\0';
591 return;
592 }
593 sd->plexoffset = msg->offset; /* this is where we want it */
594 set_sd_state(sd->sdno, sd_stale, setstate_force); /* make sure it's stale */
595 give_sd_to_plex(plex->plexno, sd->sdno); /* and give it to the plex */
596 update_sd_config(sd->sdno, 0);
597 save_config();
598 }
599 if (sd->state == sd_reviving)
600 reply->error = EAGAIN; /* need to revive it */
601 else
602 reply->error = 0;
603 break;
604
605 case plex_object:
606 plex = validplex(msg->index, reply); /* get plex */
607 if (plex == NULL)
608 return;
609 vol = validvol(msg->otherobject, reply); /* and volume information */
610 if (vol) {
611 if ((vol->plexes == MAXPLEX) /* we have too many already */
612 ||(plex->volno >= 0)) { /* or the plex has an owner */
613 reply->error = EINVAL; /* no message, the user should check */
614 reply->msg[0] = '\0';
615 return;
616 }
617 for (sdno = 0; sdno < plex->subdisks; sdno++) {
618 sd = &SD[plex->sdnos[sdno]];
619
620 if (sd->state > sd_down) /* real subdisk, vaguely accessible */
621 set_sd_state(plex->sdnos[sdno], sd_stale, setstate_force); /* make it stale */
622 }
623 set_plex_state(plex->plexno, plex_up, setstate_none); /* update plex state */
624 give_plex_to_volume(msg->otherobject, msg->index); /* and give it to the volume */
625 update_plex_config(plex->plexno, 0);
626 save_config();
627 reply->error = 0; /* all went well */
628 }
629 }
630 }
631
632 /* detach an object from a superior object */
633 void
634 detachobject(struct vinum_ioctl_msg *msg)
635 {
636 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
637 struct sd *sd;
638 struct plex *plex;
639 struct volume *vol;
640 int sdno;
641 int plexno;
642
643 switch (msg->type) {
644 case drive_object: /* you can't detach a drive from anything */
645 case volume_object: /* nor a volume */
646 case invalid_object: /* "this can't happen" */
647 reply->error = EINVAL;
648 reply->msg[0] = '\0'; /* vinum(8) doesn't do this */
649 return;
650
651 case sd_object:
652 sd = validsd(msg->index, reply);
653 if (sd == NULL)
654 return;
655 if (sd->plexno < 0) { /* doesn't belong to a plex */
656 reply->error = ENOENT;
657 strcpy(reply->msg, "Subdisk is not attached");
658 return;
659 } else { /* valid plex number */
660 plex = &PLEX[sd->plexno];
661 if ((!msg->force) /* don't force things */
662 &&((plex->state == plex_up) /* and the plex is up */
663 ||((plex->state == plex_flaky) && sd->state == sd_up))) { /* or flaky with this sd up */
664 reply->error = EBUSY; /* we need this sd */
665 reply->msg[0] = '\0';
666 return;
667 }
668 sd->plexno = -1; /* anonymous sd */
669 if (plex->subdisks == 1) { /* this was the only subdisk */
670 Free(plex->sdnos); /* free the subdisk array */
671 plex->sdnos = NULL; /* and note the fact */
672 plex->subdisks_allocated = 0; /* no subdisk space */
673 } else {
674 for (sdno = 0; sdno < plex->subdisks; sdno++) {
675 if (plex->sdnos[sdno] == msg->index) /* found our subdisk */
676 break;
677 }
678 if (sdno < (plex->subdisks - 1)) /* not the last one, compact */
679 bcopy(&plex->sdnos[sdno + 1],
680 &plex->sdnos[sdno],
681 (plex->subdisks - 1 - sdno) * sizeof(int));
682 }
683 plex->subdisks--;
684 if (!bcmp(plex->name, sd->name, strlen(plex->name) + 1))
685 /* this subdisk is named after the plex */
686 {
687 bcopy(sd->name,
688 &sd->name[3],
689 min(strlen(sd->name) + 1, MAXSDNAME - 3));
690 bcopy("ex-", sd->name, 3);
691 sd->name[MAXSDNAME - 1] = '\0';
692 }
693 update_plex_config(plex->plexno, 0);
694 if (isstriped(plex)) /* we've just mutilated our plex, */
695 set_plex_state(plex->plexno,
696 plex_down,
697 setstate_force | setstate_configuring);
698 save_config();
699 reply->error = 0;
700 }
701 return;
702
703 case plex_object:
704 plex = validplex(msg->index, reply); /* get plex */
705 if (plex == NULL)
706 return;
707 if (plex->volno >= 0) {
708 int volno = plex->volno;
709
710 vol = &VOL[volno];
711 if ((!msg->force) /* don't force things */
712 &&((vol->state == volume_up) /* and the volume is up */
713 &&(vol->plexes == 1))) { /* and this is the last plex */
714 /*
715 * XXX As elsewhere, check whether we will lose
716 * mapping by removing this plex
717 */
718 reply->error = EBUSY; /* we need this plex */
719 reply->msg[0] = '\0';
720 return;
721 }
722 plex->volno = -1; /* anonymous plex */
723 for (plexno = 0; plexno < vol->plexes; plexno++) {
724 if (vol->plex[plexno] == msg->index) /* found our plex */
725 break;
726 }
727 if (plexno < (vol->plexes - 1)) /* not the last one, compact */
728 bcopy(&vol->plex[plexno + 1],
729 &vol->plex[plexno],
730 (vol->plexes - 1 - plexno) * sizeof(int));
731 vol->plexes--;
732 vol->last_plex_read = 0; /* don't go beyond the end */
733 if (!bcmp(vol->name, plex->name, strlen(vol->name) + 1))
734 /* this plex is named after the volume */
735 {
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) + 1))
744 /* subdisk is named after the plex */
745 {
746 bcopy(sd->name,
747 &sd->name[3],
748 min(strlen(sd->name) + 1, MAXSDNAME - 3));
749 bcopy("ex-", sd->name, 3);
750 sd->name[MAXSDNAME - 1] = '\0';
751 }
752 }
753 }
754 bcopy(plex->name,
755 &plex->name[3],
756 min(strlen(plex->name) + 1, MAXPLEXNAME - 3));
757 bcopy("ex-", plex->name, 3);
758 plex->name[MAXPLEXNAME - 1] = '\0';
759 }
760 update_volume_config(volno, 0);
761 save_config();
762 reply->error = 0;
763 } else {
764 reply->error = ENOENT;
765 strcpy(reply->msg, "Plex is not attached");
766 }
767 }
768 }
769
770 void
771 renameobject(struct vinum_rename_msg *msg)
772 {
773 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
774 struct drive *drive;
775 struct sd *sd;
776 struct plex *plex;
777 struct volume *vol;
778
779 switch (msg->type) {
780 case drive_object: /* you can't attach a drive to anything */
781 if (find_drive(msg->newname, 0) >= 0) { /* we have that name already, */
782 reply->error = EEXIST;
783 reply->msg[0] = '\0';
784 return;
785 }
786 drive = validdrive(msg->index, reply);
787 if (drive) {
788 bcopy(msg->newname, drive->label.name, MAXDRIVENAME);
789 save_config();
790 reply->error = 0;
791 }
792 return;
793
794 case sd_object: /* you can't attach a subdisk to anything */
795 if (find_subdisk(msg->newname, 0) >= 0) { /* we have that name already, */
796 reply->error = EEXIST;
797 reply->msg[0] = '\0';
798 return;
799 }
800 sd = validsd(msg->index, reply);
801 if (sd) {
802 bcopy(msg->newname, sd->name, MAXSDNAME);
803 update_sd_config(sd->sdno, 0);
804 save_config();
805 reply->error = 0;
806 }
807 return;
808
809 case plex_object: /* you can't attach a plex to anything */
810 if (find_plex(msg->newname, 0) >= 0) { /* we have that name already, */
811 reply->error = EEXIST;
812 reply->msg[0] = '\0';
813 return;
814 }
815 plex = validplex(msg->index, reply);
816 if (plex) {
817 bcopy(msg->newname, plex->name, MAXPLEXNAME);
818 update_plex_config(plex->plexno, 0);
819 save_config();
820 reply->error = 0;
821 }
822 return;
823
824 case volume_object: /* you can't attach a volume to anything */
825 if (find_volume(msg->newname, 0) >= 0) { /* we have that name already, */
826 reply->error = EEXIST;
827 reply->msg[0] = '\0';
828 return;
829 }
830 vol = validvol(msg->index, reply);
831 if (vol) {
832 bcopy(msg->newname, vol->name, MAXVOLNAME);
833 update_volume_config(msg->index, 0);
834 save_config();
835 reply->error = 0;
836 }
837 return;
838
839 case invalid_object:
840 reply->error = EINVAL;
841 reply->msg[0] = '\0';
842 }
843 }
844
845 /*
846 * Replace one object with another.
847 * Currently only for drives.
848 * message->index is the drive number of the old drive
849 * message->otherobject is the drive number of the new drive
850 */
851 void
852 replaceobject(struct vinum_ioctl_msg *msg)
853 {
854 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
855
856 reply->error = ENODEV; /* until I know how to do this */
857 strcpy(reply->msg, "replace not implemented yet");
858 /* save_config (); */
859 }
860
861 void
862 moveobject(struct vinum_ioctl_msg *msg)
863 {
864 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg;
865 struct drive *drive;
866 struct sd *sd;
867
868 /* Check that our objects are valid (i.e. they exist) */
869 drive = validdrive(msg->index, (struct _ioctl_reply *) msg);
870 if (drive == NULL)
871 return;
872 sd = validsd(msg->otherobject, (struct _ioctl_reply *) msg);
873 if (sd == NULL)
874 return;
875 if (sd->driveno == msg->index) /* sd already belongs to drive */
876 return;
877
878 if (sd->state > sd_stale)
879 set_sd_state(sd->sdno, sd_stale, setstate_force); /* make the subdisk stale */
880 else
881 sd->state = sd_empty;
882 if (sd->plexno >= 0) /* part of a plex, */
883 update_plex_state(sd->plexno); /* update its state */
884
885 /* Return the space on the old drive */
886 if ((sd->driveno >= 0) /* we have a drive, */
887 &&(sd->sectors > 0)) /* and some space on it */
888 return_drive_space(sd->driveno, /* return the space */
889 sd->driveoffset,
890 sd->sectors);
891
892 /* Reassign the old subdisk */
893 sd->driveno = msg->index;
894 sd->driveoffset = -1; /* let the drive decide where to put us */
895 give_sd_to_drive(sd->sdno);
896 reply->error = 0;
897 }
898
899 /* Local Variables: */
900 /* fill-column: 50 */
901 /* End: */
Cache object: 4d3129d88167ff87d74c3bb001877792
|