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