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