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