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