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