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