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