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