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