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