1 /* commands.c: vinum interface program, main commands */ 2 /*- 3 * Copyright (c) 1997, 1998 4 * Nan Yang Computer Services Limited. All rights reserved. 5 * 6 * Written by Greg Lehey 7 * 8 * This software is distributed under the so-called ``Berkeley 9 * License'': 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the Company nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * This software is provided ``as is'', and any express or implied 24 * warranties, including, but not limited to, the implied warranties of 25 * merchantability and fitness for a particular purpose are disclaimed. 26 * In no event shall the company or contributors be liable for any 27 * direct, indirect, incidental, special, exemplary, or consequential 28 * damages (including, but not limited to, procurement of substitute 29 * goods or services; loss of use, data, or profits; or business 30 * interruption) however caused and on any theory of liability, whether 31 * in contract, strict liability, or tort (including negligence or 32 * otherwise) arising in any way out of the use of this software, even if 33 * advised of the possibility of such damage. 34 * 35 * $Id: commands.c,v 1.14 2000/11/14 20:01:23 grog Exp grog $ 36 * $FreeBSD: src/sbin/vinum/commands.c,v 1.31.2.6 2003/06/06 05:13:29 grog Exp $ 37 * $DragonFly: src/sbin/vinum/commands.c,v 1.10 2008/06/05 18:06:31 swildner Exp $ 38 */ 39 40 #define _KERNEL_STRUCTURES 41 42 #include <ctype.h> 43 #include <errno.h> 44 #include <fcntl.h> 45 #include <sys/mman.h> 46 #include <netdb.h> 47 #include <paths.h> 48 #include <setjmp.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <syslog.h> 53 #include <unistd.h> 54 #include <sys/ioctl.h> 55 #include <dev/raid/vinum/vinumhdr.h> 56 #include <dev/raid/vinum/request.h> 57 #include "vext.h" 58 #include <sys/types.h> 59 #include <sys/linker.h> 60 #include <sys/module.h> 61 #include <sys/wait.h> 62 #include <readline/readline.h> 63 #include <devstat.h> 64 65 static void dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen); 66 67 void 68 vinum_create(int argc, char *argv[], char *arg0[]) 69 { 70 int error; 71 FILE *dfd; /* file descriptor for the config file */ 72 char buffer[BUFSIZE]; /* read config file in here */ 73 char commandline[BUFSIZE]; /* issue command from here */ 74 struct _ioctl_reply *reply; 75 int ioctltype; /* for ioctl call */ 76 char tempfile[PATH_MAX]; /* name of temp file for direct editing */ 77 char *file; /* file to read */ 78 FILE *tf; /* temp file */ 79 80 if (argc == 0) { /* no args, */ 81 char *editor; /* editor to start */ 82 int status; 83 84 editor = getenv("EDITOR"); 85 if (editor == NULL) 86 editor = "/usr/bin/vi"; 87 sprintf(tempfile, "/var/tmp/" VINUMMOD ".create.%d", getpid()); /* create a temp file */ 88 tf = fopen(tempfile, "w"); /* open it */ 89 if (tf == NULL) { 90 fprintf(stderr, "Can't open %s: %s\n", argv[0], strerror(errno)); 91 return; 92 } 93 printconfig(tf, "# "); /* and put the current config it */ 94 fclose(tf); 95 sprintf(commandline, "%s %s", editor, tempfile); /* create an edit command */ 96 status = system(commandline); /* do it */ 97 if (status != 0) { 98 fprintf(stderr, "Can't edit config: status %d\n", status); 99 return; 100 } 101 file = tempfile; 102 } else if (argc == 1) 103 file = argv[0]; 104 else { 105 fprintf(stderr, "Expecting 1 parameter, not %d\n", argc); 106 return; 107 } 108 reply = (struct _ioctl_reply *) &buffer; 109 dfd = fopen(file, "r"); 110 if (dfd == NULL) { /* no go */ 111 fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno)); 112 return; 113 } 114 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ 115 printf("Can't configure: %s (%d)\n", strerror(errno), errno); 116 return; 117 } 118 file_line = 0; /* start with line 1 */ 119 /* Parse the configuration, and add it to the global configuration */ 120 for (;;) { /* love this style(9) */ 121 char *configline; 122 123 configline = fgets(buffer, BUFSIZE, dfd); 124 125 if (configline == NULL) { 126 if (ferror(dfd)) 127 perror("Can't read config file"); 128 break; 129 } 130 if (hist) 131 fprintf(hist, "%s", buffer); 132 file_line++; /* count the lines */ 133 if (vflag) 134 printf("%4d: %s", file_line, buffer); 135 strcpy(commandline, buffer); /* make a copy */ 136 ioctl(superdev, VINUM_CREATE, buffer); 137 if (reply->error != 0) { /* error in config */ 138 if (!vflag) /* print this line anyway */ 139 printf("%4d: %s", file_line, commandline); 140 fprintf(stdout, "** %d %s: %s\n", 141 file_line, 142 reply->msg, 143 strerror(reply->error)); 144 145 /* 146 * XXX at the moment, we reset the config 147 * lock on error, so try to get it again. 148 * If we fail, don't cry again. 149 */ 150 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) /* can't get config? */ 151 return; 152 } 153 } 154 fclose(dfd); /* done with the config file */ 155 ioctltype = 0; /* saveconfig after update */ 156 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ 157 if (error != 0) 158 perror("Can't save Vinum config"); 159 make_devices(); 160 listconfig(); 161 checkupdates(); /* make sure we're updating */ 162 } 163 164 /* Read vinum config from a disk */ 165 void 166 vinum_read(int argc, char *argv[], char *arg0[]) 167 { 168 int error; 169 char buffer[BUFSIZE]; /* read config file in here */ 170 struct _ioctl_reply *reply; 171 int i; 172 173 reply = (struct _ioctl_reply *) &buffer; 174 if (argc < 1) { /* wrong arg count */ 175 fprintf(stderr, "Usage: read drive [drive ...]\n"); 176 return; 177 } 178 strcpy(buffer, "read "); 179 for (i = 0; i < argc; i++) { /* each drive name */ 180 strcat(buffer, argv[i]); 181 strcat(buffer, " "); 182 } 183 184 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ 185 fprintf(stderr, "Can't configure: %s (%d)\n", strerror(errno), errno); 186 return; 187 } 188 ioctl(superdev, VINUM_CREATE, &buffer); 189 if (reply->error != 0) { /* error in config */ 190 fprintf(stdout, "** %s: %s\n", reply->msg, strerror(reply->error)); 191 error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */ 192 if (error != 0) 193 perror("Can't save Vinum config"); 194 } else { 195 error = ioctl(superdev, VINUM_RELEASECONFIG, NULL); /* save the config to disk */ 196 if (error != 0) 197 perror("Can't save Vinum config"); 198 make_devices(); 199 } 200 checkupdates(); /* make sure we're updating */ 201 } 202 203 #ifdef VINUMDEBUG 204 void 205 vinum_debug(int argc, char *argv[], char *arg0[]) 206 { 207 struct debuginfo info; 208 209 if (argc > 0) { 210 info.param = atoi(argv[0]); 211 info.changeit = 1; 212 } else { 213 info.changeit = 0; 214 sleep(2); /* give a chance to leave the window */ 215 } 216 ioctl(superdev, VINUM_DEBUG, (caddr_t) & info); 217 } 218 #endif 219 220 void 221 vinum_modify(int argc, char *argv[], char *arg0[]) 222 { 223 fprintf(stderr, "Modify command is currently not implemented\n"); 224 checkupdates(); /* make sure we're updating */ 225 } 226 227 void 228 vinum_set(int argc, char *argv[], char *arg0[]) 229 { 230 fprintf(stderr, "set is not implemented yet\n"); 231 } 232 233 void 234 vinum_rm(int argc, char *argv[], char *arg0[]) 235 { 236 int object; 237 struct _ioctl_reply reply; 238 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; 239 240 if (argc == 0) /* start everything */ 241 fprintf(stderr, "Usage: rm object [object...]\n"); 242 else { /* start specified objects */ 243 int index; 244 enum objecttype type; 245 246 for (index = 0; index < argc; index++) { 247 object = find_object(argv[index], &type); /* look for it */ 248 if (type == invalid_object) 249 fprintf(stderr, "Can't find object: %s\n", argv[index]); 250 else { 251 message->index = object; /* pass object number */ 252 message->type = type; /* and type of object */ 253 message->force = force; /* do we want to force the operation? */ 254 message->recurse = recurse; /* do we want to remove subordinates? */ 255 ioctl(superdev, VINUM_REMOVE, message); 256 if (reply.error != 0) { 257 fprintf(stderr, 258 "Can't remove %s: %s (%d)\n", 259 argv[index], 260 reply.msg[0] ? reply.msg : strerror(reply.error), 261 reply.error); 262 } else if (vflag) 263 fprintf(stderr, "%s removed\n", argv[index]); 264 } 265 } 266 checkupdates(); /* make sure we're updating */ 267 } 268 } 269 270 void 271 vinum_resetconfig(int argc, char *argv[], char *arg0[]) 272 { 273 char reply[32]; 274 int error; 275 276 if (! isatty (STDIN_FILENO)) { 277 fprintf (stderr, "Please enter this command from a tty device\n"); 278 return; 279 } 280 printf(" WARNING! This command will completely wipe out your vinum configuration.\n" 281 " All data will be lost. If you really want to do this, enter the text\n\n" 282 " NO FUTURE\n" 283 " Enter text -> "); 284 fgets(reply, sizeof(reply), stdin); 285 if (strcmp(reply, "NO FUTURE\n")) /* changed his mind */ 286 printf("\n No change\n"); 287 else { 288 error = ioctl(superdev, VINUM_RESETCONFIG, NULL); /* trash config on disk */ 289 if (error) { 290 if (errno == EBUSY) 291 fprintf(stderr, "Can't reset configuration: objects are in use\n"); 292 else 293 perror("Can't find vinum config"); 294 } else { 295 make_devices(); /* recreate the /dev/vinum hierarchy */ 296 printf("\b Vinum configuration obliterated\n"); 297 start_daemon(); /* then restart the daemon */ 298 } 299 } 300 checkupdates(); /* make sure we're updating */ 301 } 302 303 /* Initialize subdisks */ 304 void 305 vinum_init(int argc, char *argv[], char *arg0[]) 306 { 307 if (argc > 0) { /* initialize plexes */ 308 int objindex; 309 int objno; 310 enum objecttype type; /* type returned */ 311 312 if (hist) 313 fflush(hist); /* don't let all the kids do it. */ 314 for (objindex = 0; objindex < argc; objindex++) { 315 objno = find_object(argv[objindex], &type); /* find the object */ 316 if (objno < 0) 317 printf("Can't find %s\n", argv[objindex]); 318 else { 319 switch (type) { 320 case volume_object: 321 initvol(objno); 322 break; 323 324 case plex_object: 325 initplex(objno, argv[objindex]); 326 break; 327 328 case sd_object: 329 initsd(objno, dowait); 330 break; 331 332 default: 333 printf("Can't initialize %s: wrong object type\n", argv[objindex]); 334 break; 335 } 336 } 337 } 338 } 339 checkupdates(); /* make sure we're updating */ 340 } 341 342 void 343 initvol(int volno) 344 { 345 printf("Initializing volumes is not implemented yet\n"); 346 } 347 348 void 349 initplex(int plexno, char *name) 350 { 351 int sdno; 352 int plexfh = 0; /* file handle for plex */ 353 pid_t pid; 354 char filename[MAXPATHLEN]; /* create a file name here */ 355 356 /* Variables for use by children */ 357 int failed = 0; /* set if a child dies badly */ 358 359 sprintf(filename, VINUM_DIR "/plex/%s", name); 360 if ((plexfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* got a plex, open it */ 361 /* 362 * We don't actually write anything to the 363 * plex. We open it to ensure that nobody 364 * else tries to open it while we initialize 365 * its subdisks. 366 */ 367 fprintf(stderr, "can't open plex %s: %s\n", filename, strerror(errno)); 368 return; 369 } 370 if (dowait == 0) { 371 pid = fork(); /* into the background with you */ 372 if (pid != 0) { /* I'm the parent, or we failed */ 373 if (pid < 0) /* failure */ 374 printf("Couldn't fork: %s", strerror(errno)); 375 close(plexfh); /* we don't need this any more */ 376 return; 377 } 378 } 379 /* 380 * If we get here, we're either the first-level 381 * child (if we're not waiting) or we're going 382 * to wait. 383 */ 384 for (sdno = 0; sdno < plex.subdisks; sdno++) { /* initialize each subdisk */ 385 get_plex_sd_info(&sd, plexno, sdno); 386 initsd(sd.sdno, 0); 387 } 388 /* Now wait for them to complete */ 389 while (1) { 390 int status; 391 pid = wait(&status); 392 if (((int) pid == -1) 393 && (errno == ECHILD)) /* all gone */ 394 break; 395 if (WEXITSTATUS(status) != 0) { /* oh, oh */ 396 printf("child %d exited with status 0x%x\n", pid, WEXITSTATUS(status)); 397 failed++; 398 } 399 } 400 if (failed == 0) { 401 #if 0 402 message->index = plexno; /* pass object number */ 403 message->type = plex_object; /* and type of object */ 404 message->state = object_up; 405 message->force = 1; /* insist */ 406 ioctl(superdev, VINUM_SETSTATE, message); 407 #endif 408 syslog(LOG_INFO | LOG_KERN, "plex %s initialized", plex.name); 409 } else 410 syslog(LOG_ERR | LOG_KERN, "couldn't initialize plex %s, %d processes died", 411 plex.name, 412 failed); 413 if (dowait == 0) /* we're the waiting child, */ 414 exit(0); /* we've done our dash */ 415 } 416 417 /* Initialize a subdisk. */ 418 void 419 initsd(int sdno, int dowait) 420 { 421 pid_t pid; 422 struct _ioctl_reply reply; 423 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; 424 char filename[MAXPATHLEN]; /* create a file name here */ 425 426 /* Variables for use by children */ 427 int sdfh; /* and for subdisk */ 428 int initsize; /* actual size to write */ 429 int64_t sdsize; /* size of subdisk */ 430 431 if (dowait == 0) { 432 pid = fork(); /* into the background with you */ 433 if (pid > 0) /* I'm the parent */ 434 return; 435 else if (pid < 0) { /* failure */ 436 printf("couldn't fork for subdisk %d: %s", sdno, strerror(errno)); 437 return; 438 } 439 } 440 if (SSize != 0) { /* specified a size for init */ 441 if (SSize < 512) 442 SSize <<= DEV_BSHIFT; 443 initsize = min(SSize, MAXPLEXINITSIZE); 444 } else 445 initsize = PLEXINITSIZE; 446 openlog("vinum", LOG_CONS | LOG_PERROR | LOG_PID, LOG_KERN); 447 get_sd_info(&sd, sdno); 448 sdsize = sd.sectors * DEV_BSIZE; /* size of subdisk in bytes */ 449 sprintf(filename, VINUM_DIR "/sd/%s", sd.name); 450 setproctitle("initializing %s", filename); /* show what we're doing */ 451 syslog(LOG_INFO | LOG_KERN, "initializing subdisk %s", filename); 452 if ((sdfh = open(filename, O_RDWR, S_IRWXU)) < 0) { /* no go */ 453 syslog(LOG_ERR | LOG_KERN, 454 "can't open subdisk %s: %s", 455 filename, 456 strerror(errno)); 457 exit(1); 458 } 459 /* Set the subdisk in initializing state */ 460 message->index = sd.sdno; /* pass object number */ 461 message->type = sd_object; /* and type of object */ 462 message->state = object_initializing; 463 message->verify = vflag; /* verify what we write? */ 464 message->force = 1; /* insist */ 465 ioctl(superdev, VINUM_SETSTATE, message); 466 if ((SSize > 0) /* specified a size for init */ 467 &&(SSize < 512)) 468 SSize <<= DEV_BSHIFT; 469 if (reply.error) { 470 fprintf(stderr, 471 "Can't initialize %s: %s (%d)\n", 472 filename, 473 strerror(reply.error), 474 reply.error); 475 exit(1); 476 } else { 477 do { 478 if (interval) /* pause between copies */ 479 usleep(interval * 1000); 480 message->index = sd.sdno; /* pass object number */ 481 message->type = sd_object; /* and type of object */ 482 message->state = object_up; 483 message->verify = vflag; /* verify what we write? */ 484 message->blocksize = SSize; 485 ioctl(superdev, VINUM_SETSTATE, message); 486 } 487 while (reply.error == EAGAIN); /* until we're done */ 488 if (reply.error) { 489 fprintf(stderr, 490 "Can't initialize %s: %s (%d)\n", 491 filename, 492 strerror(reply.error), 493 reply.error); 494 get_sd_info(&sd, sdno); 495 if (sd.state != sd_up) 496 /* Set the subdisk down */ 497 message->index = sd.sdno; /* pass object number */ 498 message->type = sd_object; /* and type of object */ 499 message->state = object_down; 500 message->verify = vflag; /* verify what we write? */ 501 message->force = 1; /* insist */ 502 ioctl(superdev, VINUM_SETSTATE, message); 503 } 504 } 505 printf("subdisk %s initialized\n", filename); 506 if (!dowait) 507 exit(0); 508 } 509 510 void 511 vinum_start(int argc, char *argv[], char *arg0[]) 512 { 513 int object; 514 struct _ioctl_reply reply; 515 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; 516 517 if (argc == 0) { /* start everything */ 518 int devs = getnumdevs(); 519 struct statinfo statinfo; 520 char *namelist; 521 char *enamelist; /* end of name list */ 522 int i; 523 char **token; /* list of tokens */ 524 int tokens; /* and their number */ 525 526 bzero(&statinfo, sizeof(struct statinfo)); 527 statinfo.dinfo = malloc(devs * sizeof(struct statinfo)); 528 namelist = malloc(devs * (DEVSTAT_NAME_LEN + 8)); 529 token = malloc((devs + 1) * sizeof(char *)); 530 if ((statinfo.dinfo == NULL) || (namelist == NULL) || (token == NULL)) { 531 fprintf(stderr, "Can't allocate memory for drive list\n"); 532 return; 533 } 534 bzero(statinfo.dinfo, sizeof(struct devinfo)); 535 536 tokens = 0; /* no tokens yet */ 537 if (getdevs(&statinfo) < 0) { /* find out what devices we have */ 538 perror("Can't get device list"); 539 return; 540 } 541 namelist[0] = '\0'; /* start with empty namelist */ 542 enamelist = namelist; /* point to the end of the list */ 543 544 for (i = 0; i < devs; i++) { 545 struct devstat *stat = &statinfo.dinfo->devices[i]; 546 547 if ((((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) /* disk device */ 548 || ((stat->device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) /* storage array */ 549 &&((stat->device_type & DEVSTAT_TYPE_IF_MASK) != DEVSTAT_TYPE_IF_OTHER) /* and not md */ 550 &&((stat->device_type & DEVSTAT_TYPE_PASS) == 0) /* and not passthrough */ 551 &&((stat->device_name[0] != '\0'))) { /* and it has a name */ 552 sprintf(enamelist, "%s%s%d", _PATH_DEV, stat->device_name, stat->unit_number); 553 token[tokens] = enamelist; /* point to it */ 554 tokens++; /* one more token */ 555 enamelist = &enamelist[strlen(enamelist) + 1]; /* and start beyond the end */ 556 } 557 } 558 free(statinfo.dinfo); /* don't need the list any more */ 559 vinum_read(tokens, token, &token[0]); /* start the system */ 560 free(namelist); 561 free(token); 562 list_defective_objects(); /* and list anything that's down */ 563 } else { /* start specified objects */ 564 int index; 565 enum objecttype type; 566 567 for (index = 0; index < argc; index++) { 568 object = find_object(argv[index], &type); /* look for it */ 569 if (type == invalid_object) 570 fprintf(stderr, "Can't find object: %s\n", argv[index]); 571 else { 572 int doit = 0; /* set to 1 if we pass our tests */ 573 switch (type) { 574 case drive_object: 575 if (drive.state == drive_up) /* already up */ 576 fprintf(stderr, "%s is already up\n", drive.label.name); 577 else 578 doit = 1; 579 break; 580 581 case sd_object: 582 if (sd.state == sd_up) /* already up */ 583 fprintf(stderr, "%s is already up\n", sd.name); 584 else 585 doit = 1; 586 break; 587 588 case plex_object: 589 if (plex.state == plex_up) /* already up */ 590 fprintf(stderr, "%s is already up\n", plex.name); 591 else { 592 int sdno; 593 594 /* 595 * First, see if we can bring it up 596 * just by asking. This might happen 597 * if somebody has used setupstate on 598 * the subdisks. If we don't do this, 599 * we'll return success, but the plex 600 * won't have changed state. Note 601 * that we don't check for errors 602 * here. 603 */ 604 message->index = plex.plexno; /* pass object number */ 605 message->type = plex_object; /* it's a plex */ 606 message->state = object_up; 607 message->force = 0; /* don't force it */ 608 ioctl(superdev, VINUM_SETSTATE, message); 609 for (sdno = 0; sdno < plex.subdisks; sdno++) { 610 get_plex_sd_info(&sd, object, sdno); 611 if ((sd.state >= sd_empty) 612 && (sd.state <= sd_reviving)) { /* candidate for start */ 613 message->index = sd.sdno; /* pass object number */ 614 message->type = sd_object; /* it's a subdisk */ 615 message->state = object_up; 616 message->force = force; /* don't force it, use a larger hammer */ 617 618 /* 619 * We don't do any checking here. 620 * The kernel module has a better 621 * understanding of these things, 622 * let it do it. 623 */ 624 if (SSize != 0) { /* specified a size for init */ 625 if (SSize < 512) 626 SSize <<= DEV_BSHIFT; 627 message->blocksize = SSize; 628 } else 629 message->blocksize = DEFAULT_REVIVE_BLOCKSIZE; 630 ioctl(superdev, VINUM_SETSTATE, message); 631 if (reply.error != 0) { 632 if (reply.error == EAGAIN) /* we're reviving */ 633 continue_revive(sd.sdno); 634 else 635 fprintf(stderr, 636 "Can't start %s: %s (%d)\n", 637 sd.name, 638 reply.msg[0] ? reply.msg : strerror(reply.error), 639 reply.error); 640 } 641 if (Verbose) 642 vinum_lsi(sd.sdno, 0); 643 } 644 } 645 } 646 break; 647 648 case volume_object: 649 if (vol.state == volume_up) /* already up */ 650 fprintf(stderr, "%s is already up\n", vol.name); 651 else 652 doit = 1; 653 break; 654 655 default: 656 break; 657 } 658 659 if (doit) { 660 message->index = object; /* pass object number */ 661 message->type = type; /* and type of object */ 662 message->state = object_up; 663 message->force = force; /* don't force it, use a larger hammer */ 664 665 /* 666 * We don't do any checking here. 667 * The kernel module has a better 668 * understanding of these things, 669 * let it do it. 670 */ 671 if (SSize != 0) { /* specified a size for init or revive */ 672 if (SSize < 512) 673 SSize <<= DEV_BSHIFT; 674 message->blocksize = SSize; 675 } else 676 message->blocksize = 0; 677 ioctl(superdev, VINUM_SETSTATE, message); 678 if (reply.error != 0) { 679 if ((reply.error == EAGAIN) /* we're reviving */ 680 &&(type == sd_object)) 681 continue_revive(object); 682 else 683 fprintf(stderr, 684 "Can't start %s: %s (%d)\n", 685 argv[index], 686 reply.msg[0] ? reply.msg : strerror(reply.error), 687 reply.error); 688 } 689 if (Verbose) 690 vinum_li(object, type); 691 } 692 } 693 } 694 } 695 checkupdates(); /* make sure we're updating */ 696 } 697 698 void 699 vinum_stop(int argc, char *argv[], char *arg0[]) 700 { 701 int object; 702 struct _ioctl_reply reply; 703 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; 704 705 if (checkupdates() && (!force)) /* not updating? */ 706 return; 707 message->force = force; /* should we force the transition? */ 708 if (argc == 0) { /* stop vinum */ 709 int fileid = 0; /* ID of Vinum kld */ 710 711 close(superdev); /* we can't stop if we have vinum open */ 712 sleep(1); /* wait for the daemon to let go */ 713 fileid = kldfind(VINUMMOD); 714 if ((fileid < 0) /* no go */ 715 ||(kldunload(fileid) < 0)) 716 perror("Can't unload " VINUMMOD); 717 else { 718 fprintf(stderr, VINUMMOD " unloaded\n"); 719 exit(0); 720 } 721 722 /* If we got here, the stop failed. Reopen the superdevice. */ 723 superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* reopen vinum superdevice */ 724 if (superdev < 0) { 725 perror("Can't reopen Vinum superdevice"); 726 exit(1); 727 } 728 } else { /* stop specified objects */ 729 int i; 730 enum objecttype type; 731 732 for (i = 0; i < argc; i++) { 733 object = find_object(argv[i], &type); /* look for it */ 734 if (type == invalid_object) 735 fprintf(stderr, "Can't find object: %s\n", argv[i]); 736 else { 737 message->index = object; /* pass object number */ 738 message->type = type; /* and type of object */ 739 message->state = object_down; 740 ioctl(superdev, VINUM_SETSTATE, message); 741 if (reply.error != 0) 742 fprintf(stderr, 743 "Can't stop %s: %s (%d)\n", 744 argv[i], 745 reply.msg[0] ? reply.msg : strerror(reply.error), 746 reply.error); 747 if (Verbose) 748 vinum_li(object, type); 749 } 750 } 751 } 752 } 753 754 void 755 vinum_label(int argc, char *argv[], char *arg0[]) 756 { 757 int object; 758 struct _ioctl_reply reply; 759 int *message = (int *) &reply; 760 761 if (argc == 0) /* start everything */ 762 fprintf(stderr, "label: please specify one or more volume names\n"); 763 else { /* start specified objects */ 764 int i; 765 enum objecttype type; 766 767 for (i = 0; i < argc; i++) { 768 object = find_object(argv[i], &type); /* look for it */ 769 if (type == invalid_object) 770 fprintf(stderr, "Can't find object: %s\n", argv[i]); 771 else if (type != volume_object) /* it exists, but it isn't a volume */ 772 fprintf(stderr, "%s is not a volume\n", argv[i]); 773 else { 774 message[0] = object; /* pass object number */ 775 ioctl(superdev, VINUM_LABEL, message); 776 if (reply.error != 0) 777 fprintf(stderr, 778 "Can't label %s: %s (%d)\n", 779 argv[i], 780 reply.msg[0] ? reply.msg : strerror(reply.error), 781 reply.error); 782 if (Verbose) 783 vinum_li(object, type); 784 } 785 } 786 } 787 checkupdates(); /* not updating? */ 788 } 789 790 void 791 reset_volume_stats(int volno, int recurse) 792 { 793 struct vinum_ioctl_msg msg; 794 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; 795 796 msg.index = volno; 797 msg.type = volume_object; 798 /* XXX get these numbers right if we ever 799 * actually return errors */ 800 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) { 801 fprintf(stderr, "Can't reset stats for volume %d: %s\n", volno, reply->msg); 802 longjmp(command_fail, -1); 803 } else if (recurse) { 804 struct volume vol; 805 int plexno; 806 807 get_volume_info(&vol, volno); 808 for (plexno = 0; plexno < vol.plexes; plexno++) 809 reset_plex_stats(vol.plex[plexno], recurse); 810 } 811 } 812 813 void 814 reset_plex_stats(int plexno, int recurse) 815 { 816 struct vinum_ioctl_msg msg; 817 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; 818 819 msg.index = plexno; 820 msg.type = plex_object; 821 /* XXX get these numbers right if we ever 822 * actually return errors */ 823 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) { 824 fprintf(stderr, "Can't reset stats for plex %d: %s\n", plexno, reply->msg); 825 longjmp(command_fail, -1); 826 } else if (recurse) { 827 struct plex plex; 828 struct sd sd; 829 int sdno; 830 831 get_plex_info(&plex, plexno); 832 for (sdno = 0; sdno < plex.subdisks; sdno++) { 833 get_plex_sd_info(&sd, plex.plexno, sdno); 834 reset_sd_stats(sd.sdno, recurse); 835 } 836 } 837 } 838 839 void 840 reset_sd_stats(int sdno, int recurse) 841 { 842 struct vinum_ioctl_msg msg; 843 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; 844 845 msg.index = sdno; 846 msg.type = sd_object; 847 /* XXX get these numbers right if we ever 848 * actually return errors */ 849 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) { 850 fprintf(stderr, "Can't reset stats for subdisk %d: %s\n", sdno, reply->msg); 851 longjmp(command_fail, -1); 852 } else if (recurse) { 853 get_sd_info(&sd, sdno); /* get the info */ 854 reset_drive_stats(sd.driveno); /* and clear the drive */ 855 } 856 } 857 858 void 859 reset_drive_stats(int driveno) 860 { 861 struct vinum_ioctl_msg msg; 862 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; 863 864 msg.index = driveno; 865 msg.type = drive_object; 866 /* XXX get these numbers right if we ever 867 * actually return errors */ 868 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) { 869 fprintf(stderr, "Can't reset stats for drive %d: %s\n", driveno, reply->msg); 870 longjmp(command_fail, -1); 871 } 872 } 873 874 void 875 vinum_resetstats(int argc, char *argv[], char *argv0[]) 876 { 877 int i; 878 int objno; 879 enum objecttype type; 880 881 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 882 perror("Can't get vinum config"); 883 return; 884 } 885 if (argc == 0) { 886 for (objno = 0; objno < vinum_conf.volumes_allocated; objno++) 887 reset_volume_stats(objno, 1); /* clear everything recursively */ 888 } else { 889 for (i = 0; i < argc; i++) { 890 objno = find_object(argv[i], &type); 891 if (objno >= 0) { /* not invalid */ 892 switch (type) { 893 case drive_object: 894 reset_drive_stats(objno); 895 break; 896 897 case sd_object: 898 reset_sd_stats(objno, recurse); 899 break; 900 901 case plex_object: 902 reset_plex_stats(objno, recurse); 903 break; 904 905 case volume_object: 906 reset_volume_stats(objno, recurse); 907 break; 908 909 case invalid_object: /* can't get this */ 910 break; 911 } 912 } 913 } 914 } 915 } 916 917 /* Attach a subdisk to a plex, or a plex to a volume. 918 * attach subdisk plex [offset] [rename] 919 * attach plex volume [rename] 920 */ 921 void 922 vinum_attach(int argc, char *argv[], char *argv0[]) 923 { 924 int i; 925 enum objecttype supertype; 926 struct vinum_ioctl_msg msg; 927 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; 928 const char *objname = argv[0]; 929 const char *supername = argv[1]; 930 int sdno = -1; 931 int plexno = -1; 932 char oldname[MAXNAME + 8]; 933 char newname[MAXNAME + 8]; 934 int rename = 0; /* set if we want to rename the object */ 935 936 if ((argc < 2) 937 || (argc > 4)) { 938 fprintf(stderr, 939 "Usage: \tattach <subdisk> <plex> [rename] [<plexoffset>]\n" 940 "\tattach <plex> <volume> [rename]\n"); 941 return; 942 } 943 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 944 perror("Can't get vinum config"); 945 return; 946 } 947 msg.index = find_object(objname, &msg.type); /* find the object to attach */ 948 msg.otherobject = find_object(supername, &supertype); /* and the object to attach to */ 949 msg.force = force; /* did we specify the use of force? */ 950 msg.recurse = recurse; 951 msg.offset = -1; /* and no offset */ 952 953 for (i = 2; i < argc; i++) { 954 if (!strcmp(argv[i], "rename")) { 955 rename = 1; 956 msg.rename = 1; /* do renaming */ 957 } else if (!isdigit(argv[i][0])) { /* not an offset */ 958 fprintf(stderr, "Unknown attribute: %s\n", supername); 959 return; 960 } else 961 msg.offset = sizespec(argv[i]); 962 } 963 964 switch (msg.type) { 965 case sd_object: 966 find_object(argv[1], &supertype); 967 if (supertype != plex_object) { /* huh? */ 968 fprintf(stderr, "%s can only be attached to a plex\n", objname); 969 return; 970 } 971 if ((plex.organization != plex_concat) /* not a cat plex, */ 972 &&(!force)) { 973 fprintf(stderr, "Can't attach subdisks to a %s plex\n", plex_org(plex.organization)); 974 return; 975 } 976 sdno = msg.index; /* note the subdisk number for later */ 977 break; 978 979 case plex_object: 980 find_object(argv[1], &supertype); 981 if (supertype != volume_object) { /* huh? */ 982 fprintf(stderr, "%s can only be attached to a volume\n", objname); 983 return; 984 } 985 break; 986 987 case volume_object: 988 case drive_object: 989 fprintf(stderr, "Can only attach subdisks and plexes\n"); 990 return; 991 992 default: 993 fprintf(stderr, "%s is not a Vinum object\n", objname); 994 return; 995 } 996 997 ioctl(superdev, VINUM_ATTACH, &msg); 998 if (reply->error != 0) { 999 if (reply->error == EAGAIN) /* reviving */ 1000 continue_revive(sdno); /* continue the revive */ 1001 else 1002 fprintf(stderr, 1003 "Can't attach %s to %s: %s (%d)\n", 1004 objname, 1005 supername, 1006 reply->msg[0] ? reply->msg : strerror(reply->error), 1007 reply->error); 1008 } 1009 if (rename) { 1010 struct sd; 1011 struct plex; 1012 struct volume; 1013 1014 /* we've overwritten msg with the 1015 * ioctl reply, start again */ 1016 msg.index = find_object(objname, &msg.type); /* find the object to rename */ 1017 switch (msg.type) { 1018 case sd_object: 1019 get_sd_info(&sd, msg.index); 1020 get_plex_info(&plex, sd.plexno); 1021 for (sdno = 0; sdno < plex.subdisks; sdno++) { 1022 if (plex.sdnos[sdno] == msg.index) /* found our subdisk */ 1023 break; 1024 } 1025 sprintf(newname, "%s.s%d", plex.name, sdno); 1026 sprintf(oldname, "%s", sd.name); 1027 vinum_rename_2(oldname, newname); 1028 break; 1029 1030 case plex_object: 1031 get_plex_info(&plex, msg.index); 1032 get_volume_info(&vol, plex.volno); 1033 for (plexno = 0; plexno < vol.plexes; plexno++) { 1034 if (vol.plex[plexno] == msg.index) /* found our subdisk */ 1035 break; 1036 } 1037 sprintf(newname, "%s.p%d", vol.name, plexno); 1038 sprintf(oldname, "%s", plex.name); 1039 vinum_rename_2(oldname, newname); /* this may recurse */ 1040 break; 1041 1042 default: /* can't get here */ 1043 break; 1044 } 1045 } 1046 checkupdates(); /* make sure we're updating */ 1047 } 1048 1049 /* Detach a subdisk from a plex, or a plex from a volume. 1050 * detach subdisk plex [rename] 1051 * detach plex volume [rename] 1052 */ 1053 void 1054 vinum_detach(int argc, char *argv[], char *argv0[]) 1055 { 1056 struct vinum_ioctl_msg msg; 1057 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; 1058 1059 if ((argc < 1) 1060 || (argc > 2)) { 1061 fprintf(stderr, 1062 "Usage: \tdetach <subdisk> [rename]\n" 1063 "\tdetach <plex> [rename]\n"); 1064 return; 1065 } 1066 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 1067 perror("Can't get vinum config"); 1068 return; 1069 } 1070 msg.index = find_object(argv[0], &msg.type); /* find the object to detach */ 1071 msg.force = force; /* did we specify the use of force? */ 1072 msg.rename = 0; /* don't specify new name */ 1073 msg.recurse = recurse; /* but recurse if we have to */ 1074 1075 /* XXX are we going to keep this? 1076 * Don't document it yet, since the 1077 * kernel side of things doesn't 1078 * implement it */ 1079 if (argc == 2) { 1080 if (!strcmp(argv[1], "rename")) 1081 msg.rename = 1; /* do renaming */ 1082 else { 1083 fprintf(stderr, "Unknown attribute: %s\n", argv[1]); 1084 return; 1085 } 1086 } 1087 if ((msg.type != sd_object) 1088 && (msg.type != plex_object)) { 1089 fprintf(stderr, "Can only detach subdisks and plexes\n"); 1090 return; 1091 } 1092 ioctl(superdev, VINUM_DETACH, &msg); 1093 if (reply->error != 0) 1094 fprintf(stderr, 1095 "Can't detach %s: %s (%d)\n", 1096 argv[0], 1097 reply->msg[0] ? reply->msg : strerror(reply->error), 1098 reply->error); 1099 checkupdates(); /* make sure we're updating */ 1100 } 1101 1102 static void 1103 dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen) 1104 { 1105 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg; 1106 1107 if (strlen(name) > maxlen) { 1108 fprintf(stderr, "%s is too long\n", name); 1109 return; 1110 } 1111 strcpy(msg->newname, name); 1112 ioctl(superdev, VINUM_RENAME, msg); 1113 if (reply->error != 0) 1114 fprintf(stderr, 1115 "Can't rename %s to %s: %s (%d)\n", 1116 oldname, 1117 name, 1118 reply->msg[0] ? reply->msg : strerror(reply->error), 1119 reply->error); 1120 } 1121 1122 /* Rename an object: 1123 * rename <object> "newname" 1124 */ 1125 void 1126 vinum_rename_2(char *oldname, char *newname) 1127 { 1128 struct vinum_rename_msg msg; 1129 int volno; 1130 int plexno; 1131 1132 msg.index = find_object(oldname, &msg.type); /* find the object to rename */ 1133 msg.recurse = recurse; 1134 1135 /* Ugh. Determine how long the name may be */ 1136 switch (msg.type) { 1137 case drive_object: 1138 dorename(&msg, oldname, newname, MAXDRIVENAME); 1139 break; 1140 1141 case sd_object: 1142 dorename(&msg, oldname, newname, MAXSDNAME); 1143 break; 1144 1145 case plex_object: 1146 plexno = msg.index; 1147 dorename(&msg, oldname, newname, MAXPLEXNAME); 1148 if (recurse) { 1149 int sdno; 1150 1151 get_plex_info(&plex, plexno); /* find out who we are */ 1152 msg.type = sd_object; 1153 for (sdno = 0; sdno < plex.subdisks; sdno++) { 1154 char sdname[MAXPLEXNAME + 8]; 1155 1156 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */ 1157 sprintf(sdname, "%s.s%d", newname, sdno); 1158 msg.index = sd.sdno; /* number of the subdisk */ 1159 dorename(&msg, sd.name, sdname, MAXSDNAME); 1160 } 1161 } 1162 break; 1163 1164 case volume_object: 1165 volno = msg.index; 1166 dorename(&msg, oldname, newname, MAXVOLNAME); 1167 if (recurse) { 1168 int sdno; 1169 int plexno; 1170 1171 get_volume_info(&vol, volno); /* find out who we are */ 1172 for (plexno = 0; plexno < vol.plexes; plexno++) { 1173 char plexname[MAXVOLNAME + 8]; 1174 1175 msg.type = plex_object; 1176 sprintf(plexname, "%s.p%d", newname, plexno); 1177 msg.index = vol.plex[plexno]; /* number of the plex */ 1178 dorename(&msg, plex.name, plexname, MAXPLEXNAME); 1179 get_plex_info(&plex, vol.plex[plexno]); /* find out who we are */ 1180 msg.type = sd_object; 1181 for (sdno = 0; sdno < plex.subdisks; sdno++) { 1182 char sdname[MAXPLEXNAME + 8]; 1183 1184 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */ 1185 sprintf(sdname, "%s.s%d", plexname, sdno); 1186 msg.index = sd.sdno; /* number of the subdisk */ 1187 dorename(&msg, sd.name, sdname, MAXSDNAME); 1188 } 1189 } 1190 } 1191 break; 1192 1193 default: 1194 fprintf(stderr, "%s is not a Vinum object\n", oldname); 1195 return; 1196 } 1197 } 1198 1199 void 1200 vinum_rename(int argc, char *argv[], char *argv0[]) 1201 { 1202 if (argc != 2) { 1203 fprintf(stderr, "Usage: \trename <object> <new name>\n"); 1204 return; 1205 } 1206 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 1207 perror("Can't get vinum config"); 1208 return; 1209 } 1210 vinum_rename_2(argv[0], argv[1]); 1211 checkupdates(); /* make sure we're updating */ 1212 } 1213 1214 /* 1215 * Move objects: 1216 * 1217 * mv <dest> <src> ... 1218 */ 1219 void 1220 vinum_mv(int argc, char *argv[], char *argv0[]) 1221 { 1222 int i; /* loop index */ 1223 int srcobj; 1224 int destobj; 1225 enum objecttype srct; 1226 enum objecttype destt; 1227 int sdno; 1228 struct _ioctl_reply reply; 1229 struct vinum_ioctl_msg *msg = (struct vinum_ioctl_msg *) &reply; 1230 1231 if (argc < 2) { 1232 fprintf(stderr, "Usage: \tmove <dest> <src> ...\n"); 1233 return; 1234 } 1235 /* Get current config */ 1236 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 1237 perror("Cannot get vinum config\n"); 1238 return; 1239 } 1240 /* Get our destination */ 1241 destobj = find_object(argv[0], &destt); 1242 if (destobj == -1) { 1243 fprintf(stderr, "Can't find %s\n", argv[0]); 1244 return; 1245 } 1246 /* Verify that the target is a drive */ 1247 if (destt != drive_object) { 1248 fprintf(stderr, "%s is not a drive\n", argv[0]); 1249 return; 1250 } 1251 for (i = 1; i < argc; i++) { /* for all the sources */ 1252 srcobj = find_object(argv[i], &srct); 1253 if (srcobj == -1) { 1254 fprintf(stderr, "Can't find %s\n", argv[i]); 1255 continue; 1256 } 1257 msg->index = destobj; 1258 switch (srct) { /* Handle the source object */ 1259 case drive_object: /* Move all subdisks on the drive to dst. */ 1260 get_drive_info(&drive, srcobj); /* get info on drive */ 1261 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; ++sdno) { 1262 get_sd_info(&sd, sdno); 1263 if (sd.driveno == srcobj) { 1264 msg->index = destobj; 1265 msg->otherobject = sd.sdno; 1266 if (ioctl(superdev, VINUM_MOVE, msg) < 0) 1267 fprintf(stderr, 1268 "Can't move %s (part of %s) to %s: %s (%d)\n", 1269 sd.name, 1270 drive.label.name, 1271 argv[0], 1272 strerror(reply.error), 1273 reply.error); 1274 } 1275 } 1276 break; 1277 1278 case sd_object: 1279 msg->otherobject = srcobj; 1280 if (ioctl(superdev, VINUM_MOVE, msg) < 0) 1281 fprintf(stderr, 1282 "Can't move %s to %s: %s (%d)\n", 1283 sd.name, 1284 argv[0], 1285 strerror(reply.error), 1286 reply.error); 1287 break; 1288 1289 case plex_object: 1290 get_plex_info(&plex, srcobj); 1291 for (sdno = 0; sdno < plex.subdisks; ++sdno) { 1292 get_plex_sd_info(&sd, plex.plexno, sdno); 1293 msg->index = destobj; 1294 msg->otherobject = sd.sdno; 1295 if (ioctl(superdev, VINUM_MOVE, msg) < 0) 1296 fprintf(stderr, 1297 "Can't move %s (part of %s) to %s: %s (%d)\n", 1298 sd.name, 1299 plex.name, 1300 argv[0], 1301 strerror(reply.error), 1302 reply.error); 1303 } 1304 break; 1305 1306 case volume_object: 1307 case invalid_object: 1308 default: 1309 fprintf(stderr, "Can't move %s (inappropriate object).\n", argv[i]); 1310 break; 1311 } 1312 if (reply.error) 1313 fprintf(stderr, 1314 "Can't move %s to %s: %s (%d)\n", 1315 argv[i], 1316 argv[0], 1317 strerror(reply.error), 1318 reply.error); 1319 } 1320 checkupdates(); /* make sure we're updating */ 1321 } 1322 1323 /* 1324 * Replace objects. Not implemented, may never be. 1325 */ 1326 void 1327 vinum_replace(int argc, char *argv[], char *argv0[]) 1328 { 1329 fprintf(stderr, "'replace' not implemented yet. Use 'move' instead\n"); 1330 } 1331 1332 /* Primitive help function */ 1333 void 1334 vinum_help(int argc, char *argv[], char *argv0[]) 1335 { 1336 char commands[] = 1337 { 1338 "COMMANDS\n" 1339 "create [-f description-file]\n" 1340 " Create a volume as described in description-file\n" 1341 "attach plex volume [rename]\n" 1342 "attach subdisk plex [offset] [rename]\n" 1343 " Attach a plex to a volume, or a subdisk to a plex.\n" 1344 "debug\n" 1345 " Cause the volume manager to enter the kernel debugger.\n" 1346 "debug flags\n" 1347 " Set debugging flags.\n" 1348 "detach [plex | subdisk]\n" 1349 " Detach a plex or subdisk from the volume or plex to which it is\n" 1350 " attached.\n" 1351 "info [-v]\n" 1352 " List information about volume manager state.\n" 1353 "init [-v] [-w] plex\n" 1354 " Initialize a plex by writing zeroes to all its subdisks.\n" 1355 "label volume\n" 1356 " Create a volume label\n" 1357 "list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n" 1358 " List information about specified objects\n" 1359 "l [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n" 1360 " List information about specified objects (alternative to\n" 1361 " list command)\n" 1362 "ld [-r] [-s] [-v] [-V] [volume]\n" 1363 " List information about drives\n" 1364 "ls [-r] [-s] [-v] [-V] [subdisk]\n" 1365 " List information about subdisks\n" 1366 "lp [-r] [-s] [-v] [-V] [plex]\n" 1367 " List information about plexes\n" 1368 "lv [-r] [-s] [-v] [-V] [volume]\n" 1369 " List information about volumes\n" 1370 "printconfig [file]\n" 1371 " Write a copy of the current configuration to file.\n" 1372 "makedev\n" 1373 " Remake the device nodes in " _PATH_DEV "vinum.\n" 1374 "move drive [subdisk | plex | drive]\n" 1375 " Move the subdisks of the specified object(s) to drive.\n" 1376 "quit\n" 1377 " Exit the vinum program when running in interactive mode. Nor-\n" 1378 " mally this would be done by entering the EOF character.\n" 1379 "read disk [disk...]\n" 1380 " Read the vinum configuration from the specified disks.\n" 1381 "rename [-r] [drive | subdisk | plex | volume] newname\n" 1382 " Change the name of the specified object.\n" 1383 "resetconfig\n" 1384 " Reset the complete vinum configuration.\n" 1385 "resetstats [-r] [volume | plex | subdisk]\n" 1386 " Reset statistisc counters for the specified objects, or for all\n" 1387 " objects if none are specified.\n" 1388 "rm [-f] [-r] volume | plex | subdisk\n" 1389 " Remove an object\n" 1390 "saveconfig\n" 1391 " Save vinum configuration to disk.\n" 1392 "setdaemon [value]\n" 1393 " Set daemon configuration.\n" 1394 "start\n" 1395 " Read configuration from all vinum drives.\n" 1396 "start [volume | plex | subdisk]\n" 1397 " Allow the system to access the objects\n" 1398 "stop [-f] [volume | plex | subdisk]\n" 1399 " Terminate access to the objects, or stop vinum if no parameters\n" 1400 " are specified.\n" 1401 }; 1402 puts(commands); 1403 } 1404 1405 /* Set daemon options. 1406 * XXX quick and dirty: use a bitmap, which requires 1407 * knowing which bit does what. FIXME */ 1408 void 1409 vinum_setdaemon(int argc, char *argv[], char *argv0[]) 1410 { 1411 int options; 1412 1413 switch (argc) { 1414 case 0: 1415 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0) 1416 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno); 1417 else 1418 printf("Options mask: %d\n", options); 1419 break; 1420 1421 case 1: 1422 options = atoi(argv[0]); 1423 if (ioctl(superdev, VINUM_SETDAEMON, &options) < 0) 1424 fprintf(stderr, "Can't set daemon options: %s (%d)\n", strerror(errno), errno); 1425 break; 1426 1427 default: 1428 fprintf(stderr, "Usage: \tsetdaemon [<bitmask>]\n"); 1429 } 1430 checkupdates(); /* make sure we're updating */ 1431 } 1432 1433 int 1434 checkupdates(void) 1435 { 1436 int options; 1437 1438 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0) 1439 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno); 1440 if (options & daemon_noupdate) { 1441 fprintf(stderr, "*** Warning: configuration updates are disabled. ***\n"); 1442 return 1; 1443 } else 1444 return 0; 1445 } 1446 1447 /* Save config info */ 1448 void 1449 vinum_saveconfig(int argc, char *argv[], char *argv0[]) 1450 { 1451 int ioctltype; 1452 1453 if (argc != 0) { 1454 printf("Usage: saveconfig\n"); 1455 return; 1456 } 1457 ioctltype = 1; /* user saveconfig */ 1458 if (ioctl(superdev, VINUM_SAVECONFIG, &ioctltype) < 0) 1459 fprintf(stderr, "Can't save configuration: %s (%d)\n", strerror(errno), errno); 1460 checkupdates(); /* make sure we're updating */ 1461 } 1462 1463 /* 1464 * Create a volume name for the quick and dirty 1465 * commands. It will be of the form "vinum#", 1466 * where # is a small positive number. 1467 */ 1468 void 1469 genvolname(void) 1470 { 1471 int v; /* volume number */ 1472 static char volumename[MAXVOLNAME]; /* name to create */ 1473 enum objecttype type; 1474 1475 objectname = volumename; /* point to it */ 1476 for (v = 0;; v++) { 1477 sprintf(objectname, "vinum%d", v); /* create the name */ 1478 if (find_object(objectname, &type) == -1) /* does it exist? */ 1479 return; /* no, it's ours */ 1480 } 1481 } 1482 1483 /* 1484 * Create a drive for the quick and dirty 1485 * commands. The name will be of the form 1486 * vinumdrive#, where # is a small positive 1487 * number. Return the name of the drive. 1488 */ 1489 struct drive * 1490 create_drive(char *devicename) 1491 { 1492 int d; /* volume number */ 1493 static char drivename[MAXDRIVENAME]; /* name to create */ 1494 enum objecttype type; 1495 struct _ioctl_reply *reply; 1496 1497 /* 1498 * We're never likely to get anything 1499 * like 10000 drives. The only reason for 1500 * this limit is to stop the thing 1501 * looping if we have a bug somewhere. 1502 */ 1503 for (d = 0; d < 100000; d++) { /* look for a free drive number */ 1504 sprintf(drivename, "vinumdrive%d", d); /* create the name */ 1505 if (find_object(drivename, &type) == -1) { /* does it exist? */ 1506 char command[MAXDRIVENAME * 2]; 1507 1508 sprintf(command, "drive %s device %s", drivename, devicename); /* create a create command */ 1509 if (vflag) 1510 printf("drive %s device %s\n", drivename, devicename); /* create a create command */ 1511 ioctl(superdev, VINUM_CREATE, command); 1512 reply = (struct _ioctl_reply *) &command; 1513 if (reply->error != 0) { /* error in config */ 1514 if (reply->msg[0]) 1515 fprintf(stderr, 1516 "Can't create drive %s, device %s: %s\n", 1517 drivename, 1518 devicename, 1519 reply->msg); 1520 else 1521 fprintf(stderr, 1522 "Can't create drive %s, device %s: %s (%d)\n", 1523 drivename, 1524 devicename, 1525 strerror(reply->error), 1526 reply->error); 1527 longjmp(command_fail, -1); /* give up */ 1528 } 1529 find_object(drivename, &type); 1530 return &drive; /* return the name of the drive */ 1531 } 1532 } 1533 fprintf(stderr, "Can't generate a drive name\n"); 1534 /* NOTREACHED */ 1535 return NULL; 1536 } 1537 1538 /* 1539 * Create a volume with a single concatenated plex from 1540 * as much space as we can get on the specified drives. 1541 * If the drives aren't Vinum drives, make them so. 1542 */ 1543 void 1544 vinum_concat(int argc, char *argv[], char *argv0[]) 1545 { 1546 int o; /* object number */ 1547 char buffer[BUFSIZE]; 1548 struct drive *drive; /* drive we're currently looking at */ 1549 struct _ioctl_reply *reply; 1550 int ioctltype; 1551 int error; 1552 enum objecttype type; 1553 1554 reply = (struct _ioctl_reply *) &buffer; 1555 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ 1556 printf("Can't configure: %s (%d)\n", strerror(errno), errno); 1557 return; 1558 } 1559 if (!objectname) /* we need a name for our object */ 1560 genvolname(); 1561 sprintf(buffer, "volume %s", objectname); 1562 if (vflag) 1563 printf("volume %s\n", objectname); 1564 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */ 1565 if (reply->error != 0) { /* error in config */ 1566 if (reply->msg[0]) 1567 fprintf(stderr, 1568 "Can't create volume %s: %s\n", 1569 objectname, 1570 reply->msg); 1571 else 1572 fprintf(stderr, 1573 "Can't create volume %s: %s (%d)\n", 1574 objectname, 1575 strerror(reply->error), 1576 reply->error); 1577 longjmp(command_fail, -1); /* give up */ 1578 } 1579 sprintf(buffer, "plex name %s.p0 org concat", objectname); 1580 if (vflag) 1581 printf(" plex name %s.p0 org concat\n", objectname); 1582 ioctl(superdev, VINUM_CREATE, buffer); 1583 if (reply->error != 0) { /* error in config */ 1584 if (reply->msg[0]) 1585 fprintf(stderr, 1586 "Can't create plex %s.p0: %s\n", 1587 objectname, 1588 reply->msg); 1589 else 1590 fprintf(stderr, 1591 "Can't create plex %s.p0: %s (%d)\n", 1592 objectname, 1593 strerror(reply->error), 1594 reply->error); 1595 longjmp(command_fail, -1); /* give up */ 1596 } 1597 for (o = 0; o < argc; o++) { 1598 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */ 1599 drive = create_drive(argv[o]); /* create it */ 1600 sprintf(buffer, "sd name %s.p0.s%d drive %s size 0", objectname, o, drive->label.name); 1601 if (vflag) 1602 printf(" sd name %s.p0.s%d drive %s size 0\n", objectname, o, drive->label.name); 1603 ioctl(superdev, VINUM_CREATE, buffer); 1604 if (reply->error != 0) { /* error in config */ 1605 if (reply->msg[0]) 1606 fprintf(stderr, 1607 "Can't create subdisk %s.p0.s%d: %s\n", 1608 objectname, 1609 o, 1610 reply->msg); 1611 else 1612 fprintf(stderr, 1613 "Can't create subdisk %s.p0.s%d: %s (%d)\n", 1614 objectname, 1615 o, 1616 strerror(reply->error), 1617 reply->error); 1618 longjmp(command_fail, -1); /* give up */ 1619 } 1620 } 1621 1622 /* done, save the config */ 1623 ioctltype = 0; /* saveconfig after update */ 1624 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ 1625 if (error != 0) 1626 perror("Can't save Vinum config"); 1627 find_object(objectname, &type); /* find the index of the volume */ 1628 make_vol_dev(vol.volno, 1); /* and create the devices */ 1629 if (vflag) { 1630 vflag--; /* XXX don't give too much detail */ 1631 find_object(objectname, &type); /* point to the volume */ 1632 vinum_lvi(vol.volno, 1); /* and print info about it */ 1633 } 1634 } 1635 1636 1637 /* 1638 * Create a volume with a single striped plex from 1639 * as much space as we can get on the specified drives. 1640 * If the drives aren't Vinum drives, make them so. 1641 */ 1642 void 1643 vinum_stripe(int argc, char *argv[], char *argv0[]) 1644 { 1645 int o; /* object number */ 1646 char buffer[BUFSIZE]; 1647 struct drive *drive; /* drive we're currently looking at */ 1648 struct _ioctl_reply *reply; 1649 int ioctltype; 1650 int error; 1651 enum objecttype type; 1652 off_t maxsize; 1653 int fe; /* freelist entry index */ 1654 union freeunion { 1655 struct drive_freelist freelist; 1656 struct ferq { /* request to pass to ioctl */ 1657 int driveno; 1658 int fe; 1659 } ferq; 1660 } freeunion; 1661 u_int64_t bigchunk; /* biggest chunk in freelist */ 1662 1663 maxsize = QUAD_MAX; 1664 reply = (struct _ioctl_reply *) &buffer; 1665 1666 /* 1667 * First, check our drives. 1668 */ 1669 if (argc < 2) { 1670 fprintf(stderr, "You need at least two drives to create a striped plex\n"); 1671 return; 1672 } 1673 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ 1674 printf("Can't configure: %s (%d)\n", strerror(errno), errno); 1675 return; 1676 } 1677 if (!objectname) /* we need a name for our object */ 1678 genvolname(); 1679 for (o = 0; o < argc; o++) { 1680 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */ 1681 drive = create_drive(argv[o]); /* create it */ 1682 /* Now find the largest chunk available on the drive */ 1683 bigchunk = 0; /* ain't found nothin' yet */ 1684 for (fe = 0; fe < drive->freelist_entries; fe++) { 1685 freeunion.ferq.driveno = drive->driveno; 1686 freeunion.ferq.fe = fe; 1687 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) { 1688 fprintf(stderr, 1689 "Can't get free list element %d: %s\n", 1690 fe, 1691 strerror(errno)); 1692 longjmp(command_fail, -1); 1693 } 1694 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */ 1695 } 1696 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */ 1697 } 1698 1699 /* Now create the volume */ 1700 sprintf(buffer, "volume %s", objectname); 1701 if (vflag) 1702 printf("volume %s\n", objectname); 1703 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */ 1704 if (reply->error != 0) { /* error in config */ 1705 if (reply->msg[0]) 1706 fprintf(stderr, 1707 "Can't create volume %s: %s\n", 1708 objectname, 1709 reply->msg); 1710 else 1711 fprintf(stderr, 1712 "Can't create volume %s: %s (%d)\n", 1713 objectname, 1714 strerror(reply->error), 1715 reply->error); 1716 longjmp(command_fail, -1); /* give up */ 1717 } 1718 sprintf(buffer, "plex name %s.p0 org striped 256k", objectname); 1719 if (vflag) 1720 printf(" plex name %s.p0 org striped 256k\n", objectname); 1721 ioctl(superdev, VINUM_CREATE, buffer); 1722 if (reply->error != 0) { /* error in config */ 1723 if (reply->msg[0]) 1724 fprintf(stderr, 1725 "Can't create plex %s.p0: %s\n", 1726 objectname, 1727 reply->msg); 1728 else 1729 fprintf(stderr, 1730 "Can't create plex %s.p0: %s (%d)\n", 1731 objectname, 1732 strerror(reply->error), 1733 reply->error); 1734 longjmp(command_fail, -1); /* give up */ 1735 } 1736 for (o = 0; o < argc; o++) { 1737 drive = find_drive_by_devname(argv[o]); /* we know it exists... */ 1738 sprintf(buffer, 1739 "sd name %s.p0.s%d drive %s size %lldb", 1740 objectname, 1741 o, 1742 drive->label.name, 1743 (long long) maxsize); 1744 if (vflag) 1745 printf(" sd name %s.p0.s%d drive %s size %lldb\n", 1746 objectname, 1747 o, 1748 drive->label.name, 1749 (long long) maxsize); 1750 ioctl(superdev, VINUM_CREATE, buffer); 1751 if (reply->error != 0) { /* error in config */ 1752 if (reply->msg[0]) 1753 fprintf(stderr, 1754 "Can't create subdisk %s.p0.s%d: %s\n", 1755 objectname, 1756 o, 1757 reply->msg); 1758 else 1759 fprintf(stderr, 1760 "Can't create subdisk %s.p0.s%d: %s (%d)\n", 1761 objectname, 1762 o, 1763 strerror(reply->error), 1764 reply->error); 1765 longjmp(command_fail, -1); /* give up */ 1766 } 1767 } 1768 1769 /* done, save the config */ 1770 ioctltype = 0; /* saveconfig after update */ 1771 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ 1772 if (error != 0) 1773 perror("Can't save Vinum config"); 1774 find_object(objectname, &type); /* find the index of the volume */ 1775 make_vol_dev(vol.volno, 1); /* and create the devices */ 1776 if (vflag) { 1777 vflag--; /* XXX don't give too much detail */ 1778 find_object(objectname, &type); /* point to the volume */ 1779 vinum_lvi(vol.volno, 1); /* and print info about it */ 1780 } 1781 } 1782 1783 /* 1784 * Create a volume with a single RAID-4 plex from 1785 * as much space as we can get on the specified drives. 1786 * If the drives aren't Vinum drives, make them so. 1787 */ 1788 void 1789 vinum_raid4(int argc, char *argv[], char *argv0[]) 1790 { 1791 int o; /* object number */ 1792 char buffer[BUFSIZE]; 1793 struct drive *drive; /* drive we're currently looking at */ 1794 struct _ioctl_reply *reply; 1795 int ioctltype; 1796 int error; 1797 enum objecttype type; 1798 off_t maxsize; 1799 int fe; /* freelist entry index */ 1800 union freeunion { 1801 struct drive_freelist freelist; 1802 struct ferq { /* request to pass to ioctl */ 1803 int driveno; 1804 int fe; 1805 } ferq; 1806 } freeunion; 1807 u_int64_t bigchunk; /* biggest chunk in freelist */ 1808 1809 maxsize = QUAD_MAX; 1810 reply = (struct _ioctl_reply *) &buffer; 1811 1812 /* 1813 * First, check our drives. 1814 */ 1815 if (argc < 3) { 1816 fprintf(stderr, "You need at least three drives to create a RAID-4 plex\n"); 1817 return; 1818 } 1819 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ 1820 printf("Can't configure: %s (%d)\n", strerror(errno), errno); 1821 return; 1822 } 1823 if (!objectname) /* we need a name for our object */ 1824 genvolname(); 1825 for (o = 0; o < argc; o++) { 1826 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */ 1827 drive = create_drive(argv[o]); /* create it */ 1828 /* Now find the largest chunk available on the drive */ 1829 bigchunk = 0; /* ain't found nothin' yet */ 1830 for (fe = 0; fe < drive->freelist_entries; fe++) { 1831 freeunion.ferq.driveno = drive->driveno; 1832 freeunion.ferq.fe = fe; 1833 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) { 1834 fprintf(stderr, 1835 "Can't get free list element %d: %s\n", 1836 fe, 1837 strerror(errno)); 1838 longjmp(command_fail, -1); 1839 } 1840 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */ 1841 } 1842 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */ 1843 } 1844 1845 /* Now create the volume */ 1846 sprintf(buffer, "volume %s", objectname); 1847 if (vflag) 1848 printf("volume %s\n", objectname); 1849 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */ 1850 if (reply->error != 0) { /* error in config */ 1851 if (reply->msg[0]) 1852 fprintf(stderr, 1853 "Can't create volume %s: %s\n", 1854 objectname, 1855 reply->msg); 1856 else 1857 fprintf(stderr, 1858 "Can't create volume %s: %s (%d)\n", 1859 objectname, 1860 strerror(reply->error), 1861 reply->error); 1862 longjmp(command_fail, -1); /* give up */ 1863 } 1864 sprintf(buffer, "plex name %s.p0 org raid4 256k", objectname); 1865 if (vflag) 1866 printf(" plex name %s.p0 org raid4 256k\n", objectname); 1867 ioctl(superdev, VINUM_CREATE, buffer); 1868 if (reply->error != 0) { /* error in config */ 1869 if (reply->msg[0]) 1870 fprintf(stderr, 1871 "Can't create plex %s.p0: %s\n", 1872 objectname, 1873 reply->msg); 1874 else 1875 fprintf(stderr, 1876 "Can't create plex %s.p0: %s (%d)\n", 1877 objectname, 1878 strerror(reply->error), 1879 reply->error); 1880 longjmp(command_fail, -1); /* give up */ 1881 } 1882 for (o = 0; o < argc; o++) { 1883 drive = find_drive_by_devname(argv[o]); /* we know it exists... */ 1884 sprintf(buffer, 1885 "sd name %s.p0.s%d drive %s size %lldb", 1886 objectname, 1887 o, 1888 drive->label.name, 1889 (long long) maxsize); 1890 if (vflag) 1891 printf(" sd name %s.p0.s%d drive %s size %lldb\n", 1892 objectname, 1893 o, 1894 drive->label.name, 1895 (long long) maxsize); 1896 ioctl(superdev, VINUM_CREATE, buffer); 1897 if (reply->error != 0) { /* error in config */ 1898 if (reply->msg[0]) 1899 fprintf(stderr, 1900 "Can't create subdisk %s.p0.s%d: %s\n", 1901 objectname, 1902 o, 1903 reply->msg); 1904 else 1905 fprintf(stderr, 1906 "Can't create subdisk %s.p0.s%d: %s (%d)\n", 1907 objectname, 1908 o, 1909 strerror(reply->error), 1910 reply->error); 1911 longjmp(command_fail, -1); /* give up */ 1912 } 1913 } 1914 1915 /* done, save the config */ 1916 ioctltype = 0; /* saveconfig after update */ 1917 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ 1918 if (error != 0) 1919 perror("Can't save Vinum config"); 1920 find_object(objectname, &type); /* find the index of the volume */ 1921 make_vol_dev(vol.volno, 1); /* and create the devices */ 1922 if (vflag) { 1923 vflag--; /* XXX don't give too much detail */ 1924 find_object(objectname, &type); /* point to the volume */ 1925 vinum_lvi(vol.volno, 1); /* and print info about it */ 1926 } 1927 } 1928 1929 /* 1930 * Create a volume with a single RAID-4 plex from 1931 * as much space as we can get on the specified drives. 1932 * If the drives aren't Vinum drives, make them so. 1933 */ 1934 void 1935 vinum_raid5(int argc, char *argv[], char *argv0[]) 1936 { 1937 int o; /* object number */ 1938 char buffer[BUFSIZE]; 1939 struct drive *drive; /* drive we're currently looking at */ 1940 struct _ioctl_reply *reply; 1941 int ioctltype; 1942 int error; 1943 enum objecttype type; 1944 off_t maxsize; 1945 int fe; /* freelist entry index */ 1946 union freeunion { 1947 struct drive_freelist freelist; 1948 struct ferq { /* request to pass to ioctl */ 1949 int driveno; 1950 int fe; 1951 } ferq; 1952 } freeunion; 1953 u_int64_t bigchunk; /* biggest chunk in freelist */ 1954 1955 maxsize = QUAD_MAX; 1956 reply = (struct _ioctl_reply *) &buffer; 1957 1958 /* 1959 * First, check our drives. 1960 */ 1961 if (argc < 3) { 1962 fprintf(stderr, "You need at least three drives to create a RAID-5 plex\n"); 1963 return; 1964 } 1965 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ 1966 printf("Can't configure: %s (%d)\n", strerror(errno), errno); 1967 return; 1968 } 1969 if (!objectname) /* we need a name for our object */ 1970 genvolname(); 1971 for (o = 0; o < argc; o++) { 1972 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */ 1973 drive = create_drive(argv[o]); /* create it */ 1974 /* Now find the largest chunk available on the drive */ 1975 bigchunk = 0; /* ain't found nothin' yet */ 1976 for (fe = 0; fe < drive->freelist_entries; fe++) { 1977 freeunion.ferq.driveno = drive->driveno; 1978 freeunion.ferq.fe = fe; 1979 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) { 1980 fprintf(stderr, 1981 "Can't get free list element %d: %s\n", 1982 fe, 1983 strerror(errno)); 1984 longjmp(command_fail, -1); 1985 } 1986 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */ 1987 } 1988 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */ 1989 } 1990 1991 /* Now create the volume */ 1992 sprintf(buffer, "volume %s", objectname); 1993 if (vflag) 1994 printf("volume %s\n", objectname); 1995 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */ 1996 if (reply->error != 0) { /* error in config */ 1997 if (reply->msg[0]) 1998 fprintf(stderr, 1999 "Can't create volume %s: %s\n", 2000 objectname, 2001 reply->msg); 2002 else 2003 fprintf(stderr, 2004 "Can't create volume %s: %s (%d)\n", 2005 objectname, 2006 strerror(reply->error), 2007 reply->error); 2008 longjmp(command_fail, -1); /* give up */ 2009 } 2010 sprintf(buffer, "plex name %s.p0 org raid5 256k", objectname); 2011 if (vflag) 2012 printf(" plex name %s.p0 org raid5 256k\n", objectname); 2013 ioctl(superdev, VINUM_CREATE, buffer); 2014 if (reply->error != 0) { /* error in config */ 2015 if (reply->msg[0]) 2016 fprintf(stderr, 2017 "Can't create plex %s.p0: %s\n", 2018 objectname, 2019 reply->msg); 2020 else 2021 fprintf(stderr, 2022 "Can't create plex %s.p0: %s (%d)\n", 2023 objectname, 2024 strerror(reply->error), 2025 reply->error); 2026 longjmp(command_fail, -1); /* give up */ 2027 } 2028 for (o = 0; o < argc; o++) { 2029 drive = find_drive_by_devname(argv[o]); /* we know it exists... */ 2030 sprintf(buffer, 2031 "sd name %s.p0.s%d drive %s size %lldb", 2032 objectname, 2033 o, 2034 drive->label.name, 2035 (long long) maxsize); 2036 if (vflag) 2037 printf(" sd name %s.p0.s%d drive %s size %lldb\n", 2038 objectname, 2039 o, 2040 drive->label.name, 2041 (long long) maxsize); 2042 ioctl(superdev, VINUM_CREATE, buffer); 2043 if (reply->error != 0) { /* error in config */ 2044 if (reply->msg[0]) 2045 fprintf(stderr, 2046 "Can't create subdisk %s.p0.s%d: %s\n", 2047 objectname, 2048 o, 2049 reply->msg); 2050 else 2051 fprintf(stderr, 2052 "Can't create subdisk %s.p0.s%d: %s (%d)\n", 2053 objectname, 2054 o, 2055 strerror(reply->error), 2056 reply->error); 2057 longjmp(command_fail, -1); /* give up */ 2058 } 2059 } 2060 2061 /* done, save the config */ 2062 ioctltype = 0; /* saveconfig after update */ 2063 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ 2064 if (error != 0) 2065 perror("Can't save Vinum config"); 2066 find_object(objectname, &type); /* find the index of the volume */ 2067 make_vol_dev(vol.volno, 1); /* and create the devices */ 2068 if (vflag) { 2069 vflag--; /* XXX don't give too much detail */ 2070 find_object(objectname, &type); /* point to the volume */ 2071 vinum_lvi(vol.volno, 1); /* and print info about it */ 2072 } 2073 } 2074 2075 /* 2076 * Create a volume with a two plexes from as much space 2077 * as we can get on the specified drives. If the 2078 * drives aren't Vinum drives, make them so. 2079 * 2080 * The number of drives must be even, and at least 4 2081 * for a striped plex. Specify striped plexes with the 2082 * -s flag; otherwise they will be concatenated. It's 2083 * possible that the two plexes may differ in length. 2084 */ 2085 void 2086 vinum_mirror(int argc, char *argv[], char *argv0[]) 2087 { 2088 int o; /* object number */ 2089 int p; /* plex number */ 2090 char buffer[BUFSIZE]; 2091 struct drive *drive; /* drive we're currently looking at */ 2092 struct _ioctl_reply *reply; 2093 int ioctltype; 2094 int error; 2095 enum objecttype type; 2096 off_t maxsize[2]; /* maximum subdisk size for striped plexes */ 2097 int fe; /* freelist entry index */ 2098 union freeunion { 2099 struct drive_freelist freelist; 2100 struct ferq { /* request to pass to ioctl */ 2101 int driveno; 2102 int fe; 2103 } ferq; 2104 } freeunion; 2105 u_int64_t bigchunk; /* biggest chunk in freelist */ 2106 2107 if (sflag) /* striped, */ 2108 maxsize[0] = maxsize[1] = QUAD_MAX; /* we need to calculate sd size */ 2109 else 2110 maxsize[0] = maxsize[1] = 0; /* let the kernel routines do it */ 2111 2112 reply = (struct _ioctl_reply *) &buffer; 2113 2114 /* 2115 * First, check our drives. 2116 */ 2117 if (argc & 1) { 2118 fprintf(stderr, "You need an even number of drives to create a mirrored volume\n"); 2119 return; 2120 } 2121 if (sflag && (argc < 4)) { 2122 fprintf(stderr, "You need at least 4 drives to create a mirrored, striped volume\n"); 2123 return; 2124 } 2125 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ 2126 printf("Can't configure: %s (%d)\n", strerror(errno), errno); 2127 return; 2128 } 2129 if (!objectname) /* we need a name for our object */ 2130 genvolname(); 2131 for (o = 0; o < argc; o++) { 2132 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */ 2133 drive = create_drive(argv[o]); /* create it */ 2134 if (sflag) { /* striping, */ 2135 /* Find the largest chunk available on the drive */ 2136 bigchunk = 0; /* ain't found nothin' yet */ 2137 for (fe = 0; fe < drive->freelist_entries; fe++) { 2138 freeunion.ferq.driveno = drive->driveno; 2139 freeunion.ferq.fe = fe; 2140 if (ioctl(superdev, VINUM_GETFREELIST, &freeunion.freelist) < 0) { 2141 fprintf(stderr, 2142 "Can't get free list element %d: %s\n", 2143 fe, 2144 strerror(errno)); 2145 longjmp(command_fail, -1); 2146 } 2147 bigchunk = bigchunk > freeunion.freelist.sectors ? bigchunk : freeunion.freelist.sectors; /* max it */ 2148 } 2149 maxsize[o & 1] = min(maxsize[o & 1], bigchunk); /* get the maximum size of a subdisk */ 2150 } 2151 } 2152 2153 /* Now create the volume */ 2154 sprintf(buffer, "volume %s setupstate", objectname); 2155 if (vflag) 2156 printf("volume %s setupstate\n", objectname); 2157 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */ 2158 if (reply->error != 0) { /* error in config */ 2159 if (reply->msg[0]) 2160 fprintf(stderr, 2161 "Can't create volume %s: %s\n", 2162 objectname, 2163 reply->msg); 2164 else 2165 fprintf(stderr, 2166 "Can't create volume %s: %s (%d)\n", 2167 objectname, 2168 strerror(reply->error), 2169 reply->error); 2170 longjmp(command_fail, -1); /* give up */ 2171 } 2172 for (p = 0; p < 2; p++) { /* create each plex */ 2173 if (sflag) { 2174 sprintf(buffer, "plex name %s.p%d org striped 256k", objectname, p); 2175 if (vflag) 2176 printf(" plex name %s.p%d org striped 256k\n", objectname, p); 2177 } else { /* concat */ 2178 sprintf(buffer, "plex name %s.p%d org concat", objectname, p); 2179 if (vflag) 2180 printf(" plex name %s.p%d org concat\n", objectname, p); 2181 } 2182 ioctl(superdev, VINUM_CREATE, buffer); 2183 if (reply->error != 0) { /* error in config */ 2184 if (reply->msg[0]) 2185 fprintf(stderr, 2186 "Can't create plex %s.p%d: %s\n", 2187 objectname, 2188 p, 2189 reply->msg); 2190 else 2191 fprintf(stderr, 2192 "Can't create plex %s.p%d: %s (%d)\n", 2193 objectname, 2194 p, 2195 strerror(reply->error), 2196 reply->error); 2197 longjmp(command_fail, -1); /* give up */ 2198 } 2199 /* Now look at the subdisks */ 2200 for (o = p; o < argc; o += 2) { /* every second one */ 2201 drive = find_drive_by_devname(argv[o]); /* we know it exists... */ 2202 sprintf(buffer, 2203 "sd name %s.p%d.s%d drive %s size %lldb", 2204 objectname, 2205 p, 2206 o >> 1, 2207 drive->label.name, 2208 (long long) maxsize[p]); 2209 if (vflag) 2210 printf(" sd name %s.p%d.s%d drive %s size %lldb\n", 2211 objectname, 2212 p, 2213 o >> 1, 2214 drive->label.name, 2215 (long long) maxsize[p]); 2216 ioctl(superdev, VINUM_CREATE, buffer); 2217 if (reply->error != 0) { /* error in config */ 2218 if (reply->msg[0]) 2219 fprintf(stderr, 2220 "Can't create subdisk %s.p%d.s%d: %s\n", 2221 objectname, 2222 p, 2223 o >> 1, 2224 reply->msg); 2225 else 2226 fprintf(stderr, 2227 "Can't create subdisk %s.p%d.s%d: %s (%d)\n", 2228 objectname, 2229 p, 2230 o >> 1, 2231 strerror(reply->error), 2232 reply->error); 2233 longjmp(command_fail, -1); /* give up */ 2234 } 2235 } 2236 } 2237 2238 /* done, save the config */ 2239 ioctltype = 0; /* saveconfig after update */ 2240 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ 2241 if (error != 0) 2242 perror("Can't save Vinum config"); 2243 find_object(objectname, &type); /* find the index of the volume */ 2244 make_vol_dev(vol.volno, 1); /* and create the devices */ 2245 if (vflag) { 2246 vflag--; /* XXX don't give too much detail */ 2247 sflag = 0; /* no stats, please */ 2248 find_object(objectname, &type); /* point to the volume */ 2249 vinum_lvi(vol.volno, 1); /* and print info about it */ 2250 } 2251 } 2252 2253 void 2254 vinum_readpol(int argc, char *argv[], char *argv0[]) 2255 { 2256 int object; 2257 struct _ioctl_reply reply; 2258 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; 2259 enum objecttype type; 2260 struct plex plex; 2261 struct volume vol; 2262 int plexno; 2263 2264 if (argc == 0) { /* start everything */ 2265 fprintf(stderr, "Usage: readpol <volume> <plex>|round\n"); 2266 return; 2267 } 2268 object = find_object(argv[1], &type); /* look for it */ 2269 if (type != volume_object) { 2270 fprintf(stderr, "%s is not a volume\n", argv[1]); 2271 return; 2272 } 2273 get_volume_info(&vol, object); 2274 if (strcmp(argv[2], "round")) { /* not 'round' */ 2275 object = find_object(argv[2], &type); /* look for it */ 2276 if (type != plex_object) { 2277 fprintf(stderr, "%s is not a plex\n", argv[2]); 2278 return; 2279 } 2280 get_plex_info(&plex, object); 2281 plexno = plex.plexno; 2282 } else /* round */ 2283 plexno = -1; 2284 2285 /* Set the value */ 2286 message->index = vol.volno; 2287 message->otherobject = plexno; 2288 if (ioctl(superdev, VINUM_READPOL, message) < 0) 2289 fprintf(stderr, "Can't set read policy: %s (%d)\n", strerror(errno), errno); 2290 if (vflag) 2291 vinum_lpi(plexno, recurse); 2292 } 2293 2294 /* 2295 * Brute force set state function. Don't look at 2296 * any dependencies, just do it. 2297 */ 2298 void 2299 vinum_setstate(int argc, char *argv[], char *argv0[]) 2300 { 2301 int object; 2302 struct _ioctl_reply reply; 2303 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; 2304 int index; 2305 enum objecttype type; 2306 int state; 2307 2308 for (index = 1; index < argc; index++) { 2309 object = find_object(argv[index], &type); /* look for it */ 2310 if (type == invalid_object) 2311 fprintf(stderr, "Can't find object: %s\n", argv[index]); 2312 else { 2313 int doit = 0; /* set to 1 if we pass our tests */ 2314 switch (type) { 2315 case drive_object: 2316 state = DriveState(argv[0]); /* get the state */ 2317 if (drive.state == state) /* already in that state */ 2318 fprintf(stderr, "%s is already %s\n", drive.label.name, argv[0]); 2319 else 2320 doit = 1; 2321 break; 2322 2323 case sd_object: 2324 state = SdState(argv[0]); /* get the state */ 2325 if (sd.state == state) /* already in that state */ 2326 fprintf(stderr, "%s is already %s\n", sd.name, argv[0]); 2327 else 2328 doit = 1; 2329 break; 2330 2331 case plex_object: 2332 state = PlexState(argv[0]); /* get the state */ 2333 if (plex.state == state) /* already in that state */ 2334 fprintf(stderr, "%s is already %s\n", plex.name, argv[0]); 2335 else 2336 doit = 1; 2337 break; 2338 2339 case volume_object: 2340 state = VolState(argv[0]); /* get the state */ 2341 if (vol.state == state) /* already in that state */ 2342 fprintf(stderr, "%s is already %s\n", vol.name, argv[0]); 2343 else 2344 doit = 1; 2345 break; 2346 2347 default: 2348 state = 0; /* to keep the compiler happy */ 2349 } 2350 2351 if (state == -1) 2352 fprintf(stderr, "Invalid state for object: %s\n", argv[0]); 2353 else if (doit) { 2354 message->index = object; /* pass object number */ 2355 message->type = type; /* and type of object */ 2356 message->state = state; 2357 message->force = force; /* don't force it, use a larger hammer */ 2358 ioctl(superdev, VINUM_SETSTATE_FORCE, message); 2359 if (reply.error != 0) 2360 fprintf(stderr, 2361 "Can't start %s: %s (%d)\n", 2362 argv[index], 2363 reply.msg[0] ? reply.msg : strerror(reply.error), 2364 reply.error); 2365 if (Verbose) 2366 vinum_li(object, type); 2367 } 2368 } 2369 } 2370 } 2371 2372 void 2373 vinum_checkparity(int argc, char *argv[], char *argv0[]) 2374 { 2375 Verbose = vflag; /* accept -v for verbose */ 2376 if (argc == 0) /* no parameters? */ 2377 fprintf(stderr, "Usage: checkparity object [object...]\n"); 2378 else 2379 parityops(argc, argv, checkparity); 2380 } 2381 2382 void 2383 vinum_rebuildparity(int argc, char *argv[], char *argv0[]) 2384 { 2385 if (argc == 0) /* no parameters? */ 2386 fprintf(stderr, "Usage: rebuildparity object [object...]\n"); 2387 else 2388 parityops(argc, argv, vflag ? rebuildandcheckparity : rebuildparity); 2389 } 2390 2391 /* 2392 * Common code for rebuildparity and checkparity. 2393 * We bend the meanings of some flags here: 2394 * 2395 * -v: Report incorrect parity on rebuild. 2396 * -V: Show running count of position being checked. 2397 * -f: Start from beginning of the plex. 2398 */ 2399 void 2400 parityops(int argc, char *argv[], enum parityop op) 2401 { 2402 int object; 2403 struct plex plex; 2404 struct _ioctl_reply reply; 2405 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; 2406 int index; 2407 enum objecttype type; 2408 char *msg; 2409 off_t block; 2410 2411 if (op == checkparity) 2412 msg = "Checking"; 2413 else 2414 msg = "Rebuilding"; 2415 for (index = 0; index < argc; index++) { 2416 object = find_object(argv[index], &type); /* look for it */ 2417 if (type != plex_object) 2418 fprintf(stderr, "%s is not a plex\n", argv[index]); 2419 else { 2420 get_plex_info(&plex, object); 2421 if (!isparity((&plex))) 2422 fprintf(stderr, "%s is not a RAID-4 or RAID-5 plex\n", argv[index]); 2423 else { 2424 do { 2425 message->index = object; /* pass object number */ 2426 message->type = type; /* and type of object */ 2427 message->op = op; /* what to do */ 2428 if (force) 2429 message->offset = 0; /* start at the beginning */ 2430 else 2431 message->offset = plex.checkblock; /* continue where we left off */ 2432 force = 0; /* don't reset after the first time */ 2433 ioctl(superdev, VINUM_PARITYOP, message); 2434 get_plex_info(&plex, object); 2435 if (Verbose) { 2436 block = (plex.checkblock << DEV_BSHIFT) * (plex.subdisks - 1); 2437 if (block != 0) 2438 printf("\r%s at %s (%d%%) ", 2439 msg, 2440 roughlength(block, 1), 2441 ((int) (block * 100 / plex.length) >> DEV_BSHIFT)); 2442 if ((reply.error == EAGAIN) 2443 && (reply.msg[0])) /* got a comment back */ 2444 fputs(reply.msg, stderr); /* show it */ 2445 fflush(stdout); 2446 } 2447 } 2448 while (reply.error == EAGAIN); 2449 if (reply.error != 0) { 2450 if (reply.msg[0]) 2451 fputs(reply.msg, stderr); 2452 else 2453 fprintf(stderr, 2454 "%s failed: %s\n", 2455 msg, 2456 strerror(reply.error)); 2457 } else if (Verbose) { 2458 if (op == checkparity) 2459 fprintf(stderr, "%s has correct parity\n", argv[index]); 2460 else 2461 fprintf(stderr, "Rebuilt parity on %s\n", argv[index]); 2462 } 2463 } 2464 } 2465 } 2466 } 2467 2468 /* Local Variables: */ 2469 /* fill-column: 50 */ 2470 /* End: */ 2471