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.4 2003/11/21 22:46:13 dillon 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 } 662 663 if (doit) { 664 message->index = object; /* pass object number */ 665 message->type = type; /* and type of object */ 666 message->state = object_up; 667 message->force = force; /* don't force it, use a larger hammer */ 668 669 /* 670 * We don't do any checking here. 671 * The kernel module has a better 672 * understanding of these things, 673 * let it do it. 674 */ 675 if (SSize != 0) { /* specified a size for init or revive */ 676 if (SSize < 512) 677 SSize <<= DEV_BSHIFT; 678 message->blocksize = SSize; 679 } else 680 message->blocksize = 0; 681 ioctl(superdev, VINUM_SETSTATE, message); 682 if (reply.error != 0) { 683 if ((reply.error == EAGAIN) /* we're reviving */ 684 &&(type == sd_object)) 685 continue_revive(object); 686 else 687 fprintf(stderr, 688 "Can't start %s: %s (%d)\n", 689 argv[index], 690 reply.msg[0] ? reply.msg : strerror(reply.error), 691 reply.error); 692 } 693 if (Verbose) 694 vinum_li(object, type); 695 } 696 } 697 } 698 } 699 checkupdates(); /* make sure we're updating */ 700 } 701 702 void 703 vinum_stop(int argc, char *argv[], char *arg0[]) 704 { 705 int object; 706 struct _ioctl_reply reply; 707 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; 708 709 if (checkupdates() && (!force)) /* not updating? */ 710 return; 711 message->force = force; /* should we force the transition? */ 712 if (argc == 0) { /* stop vinum */ 713 int fileid = 0; /* ID of Vinum kld */ 714 715 close(superdev); /* we can't stop if we have vinum open */ 716 sleep(1); /* wait for the daemon to let go */ 717 fileid = kldfind(VINUMMOD); 718 if ((fileid < 0) /* no go */ 719 ||(kldunload(fileid) < 0)) 720 perror("Can't unload " VINUMMOD); 721 else { 722 fprintf(stderr, VINUMMOD " unloaded\n"); 723 exit(0); 724 } 725 726 /* If we got here, the stop failed. Reopen the superdevice. */ 727 superdev = open(VINUM_SUPERDEV_NAME, O_RDWR); /* reopen vinum superdevice */ 728 if (superdev < 0) { 729 perror("Can't reopen Vinum superdevice"); 730 exit(1); 731 } 732 } else { /* stop specified objects */ 733 int i; 734 enum objecttype type; 735 736 for (i = 0; i < argc; i++) { 737 object = find_object(argv[i], &type); /* look for it */ 738 if (type == invalid_object) 739 fprintf(stderr, "Can't find object: %s\n", argv[i]); 740 else { 741 message->index = object; /* pass object number */ 742 message->type = type; /* and type of object */ 743 message->state = object_down; 744 ioctl(superdev, VINUM_SETSTATE, message); 745 if (reply.error != 0) 746 fprintf(stderr, 747 "Can't stop %s: %s (%d)\n", 748 argv[i], 749 reply.msg[0] ? reply.msg : strerror(reply.error), 750 reply.error); 751 if (Verbose) 752 vinum_li(object, type); 753 } 754 } 755 } 756 } 757 758 void 759 vinum_label(int argc, char *argv[], char *arg0[]) 760 { 761 int object; 762 struct _ioctl_reply reply; 763 int *message = (int *) &reply; 764 765 if (argc == 0) /* start everything */ 766 fprintf(stderr, "label: please specify one or more volume names\n"); 767 else { /* start specified objects */ 768 int i; 769 enum objecttype type; 770 771 for (i = 0; i < argc; i++) { 772 object = find_object(argv[i], &type); /* look for it */ 773 if (type == invalid_object) 774 fprintf(stderr, "Can't find object: %s\n", argv[i]); 775 else if (type != volume_object) /* it exists, but it isn't a volume */ 776 fprintf(stderr, "%s is not a volume\n", argv[i]); 777 else { 778 message[0] = object; /* pass object number */ 779 ioctl(superdev, VINUM_LABEL, message); 780 if (reply.error != 0) 781 fprintf(stderr, 782 "Can't label %s: %s (%d)\n", 783 argv[i], 784 reply.msg[0] ? reply.msg : strerror(reply.error), 785 reply.error); 786 if (Verbose) 787 vinum_li(object, type); 788 } 789 } 790 } 791 checkupdates(); /* not updating? */ 792 } 793 794 void 795 reset_volume_stats(int volno, int recurse) 796 { 797 struct vinum_ioctl_msg msg; 798 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; 799 800 msg.index = volno; 801 msg.type = volume_object; 802 /* XXX get these numbers right if we ever 803 * actually return errors */ 804 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) { 805 fprintf(stderr, "Can't reset stats for volume %d: %s\n", volno, reply->msg); 806 longjmp(command_fail, -1); 807 } else if (recurse) { 808 struct volume vol; 809 int plexno; 810 811 get_volume_info(&vol, volno); 812 for (plexno = 0; plexno < vol.plexes; plexno++) 813 reset_plex_stats(vol.plex[plexno], recurse); 814 } 815 } 816 817 void 818 reset_plex_stats(int plexno, int recurse) 819 { 820 struct vinum_ioctl_msg msg; 821 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; 822 823 msg.index = plexno; 824 msg.type = plex_object; 825 /* XXX get these numbers right if we ever 826 * actually return errors */ 827 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) { 828 fprintf(stderr, "Can't reset stats for plex %d: %s\n", plexno, reply->msg); 829 longjmp(command_fail, -1); 830 } else if (recurse) { 831 struct plex plex; 832 struct sd sd; 833 int sdno; 834 835 get_plex_info(&plex, plexno); 836 for (sdno = 0; sdno < plex.subdisks; sdno++) { 837 get_plex_sd_info(&sd, plex.plexno, sdno); 838 reset_sd_stats(sd.sdno, recurse); 839 } 840 } 841 } 842 843 void 844 reset_sd_stats(int sdno, int recurse) 845 { 846 struct vinum_ioctl_msg msg; 847 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; 848 849 msg.index = sdno; 850 msg.type = sd_object; 851 /* XXX get these numbers right if we ever 852 * actually return errors */ 853 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) { 854 fprintf(stderr, "Can't reset stats for subdisk %d: %s\n", sdno, reply->msg); 855 longjmp(command_fail, -1); 856 } else if (recurse) { 857 get_sd_info(&sd, sdno); /* get the info */ 858 reset_drive_stats(sd.driveno); /* and clear the drive */ 859 } 860 } 861 862 void 863 reset_drive_stats(int driveno) 864 { 865 struct vinum_ioctl_msg msg; 866 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; 867 868 msg.index = driveno; 869 msg.type = drive_object; 870 /* XXX get these numbers right if we ever 871 * actually return errors */ 872 if (ioctl(superdev, VINUM_RESETSTATS, &msg) < 0) { 873 fprintf(stderr, "Can't reset stats for drive %d: %s\n", driveno, reply->msg); 874 longjmp(command_fail, -1); 875 } 876 } 877 878 void 879 vinum_resetstats(int argc, char *argv[], char *argv0[]) 880 { 881 int i; 882 int objno; 883 enum objecttype type; 884 885 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 886 perror("Can't get vinum config"); 887 return; 888 } 889 if (argc == 0) { 890 for (objno = 0; objno < vinum_conf.volumes_allocated; objno++) 891 reset_volume_stats(objno, 1); /* clear everything recursively */ 892 } else { 893 for (i = 0; i < argc; i++) { 894 objno = find_object(argv[i], &type); 895 if (objno >= 0) { /* not invalid */ 896 switch (type) { 897 case drive_object: 898 reset_drive_stats(objno); 899 break; 900 901 case sd_object: 902 reset_sd_stats(objno, recurse); 903 break; 904 905 case plex_object: 906 reset_plex_stats(objno, recurse); 907 break; 908 909 case volume_object: 910 reset_volume_stats(objno, recurse); 911 break; 912 913 case invalid_object: /* can't get this */ 914 break; 915 } 916 } 917 } 918 } 919 } 920 921 /* Attach a subdisk to a plex, or a plex to a volume. 922 * attach subdisk plex [offset] [rename] 923 * attach plex volume [rename] 924 */ 925 void 926 vinum_attach(int argc, char *argv[], char *argv0[]) 927 { 928 int i; 929 enum objecttype supertype; 930 struct vinum_ioctl_msg msg; 931 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; 932 const char *objname = argv[0]; 933 const char *supername = argv[1]; 934 int sdno = -1; 935 int plexno = -1; 936 char oldname[MAXNAME + 8]; 937 char newname[MAXNAME + 8]; 938 int rename = 0; /* set if we want to rename the object */ 939 940 if ((argc < 2) 941 || (argc > 4)) { 942 fprintf(stderr, 943 "Usage: \tattach <subdisk> <plex> [rename] [<plexoffset>]\n" 944 "\tattach <plex> <volume> [rename]\n"); 945 return; 946 } 947 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 948 perror("Can't get vinum config"); 949 return; 950 } 951 msg.index = find_object(objname, &msg.type); /* find the object to attach */ 952 msg.otherobject = find_object(supername, &supertype); /* and the object to attach to */ 953 msg.force = force; /* did we specify the use of force? */ 954 msg.recurse = recurse; 955 msg.offset = -1; /* and no offset */ 956 957 for (i = 2; i < argc; i++) { 958 if (!strcmp(argv[i], "rename")) { 959 rename = 1; 960 msg.rename = 1; /* do renaming */ 961 } else if (!isdigit(argv[i][0])) { /* not an offset */ 962 fprintf(stderr, "Unknown attribute: %s\n", supername); 963 return; 964 } else 965 msg.offset = sizespec(argv[i]); 966 } 967 968 switch (msg.type) { 969 case sd_object: 970 find_object(argv[1], &supertype); 971 if (supertype != plex_object) { /* huh? */ 972 fprintf(stderr, "%s can only be attached to a plex\n", objname); 973 return; 974 } 975 if ((plex.organization != plex_concat) /* not a cat plex, */ 976 &&(!force)) { 977 fprintf(stderr, "Can't attach subdisks to a %s plex\n", plex_org(plex.organization)); 978 return; 979 } 980 sdno = msg.index; /* note the subdisk number for later */ 981 break; 982 983 case plex_object: 984 find_object(argv[1], &supertype); 985 if (supertype != volume_object) { /* huh? */ 986 fprintf(stderr, "%s can only be attached to a volume\n", objname); 987 return; 988 } 989 break; 990 991 case volume_object: 992 case drive_object: 993 fprintf(stderr, "Can only attach subdisks and plexes\n"); 994 return; 995 996 default: 997 fprintf(stderr, "%s is not a Vinum object\n", objname); 998 return; 999 } 1000 1001 ioctl(superdev, VINUM_ATTACH, &msg); 1002 if (reply->error != 0) { 1003 if (reply->error == EAGAIN) /* reviving */ 1004 continue_revive(sdno); /* continue the revive */ 1005 else 1006 fprintf(stderr, 1007 "Can't attach %s to %s: %s (%d)\n", 1008 objname, 1009 supername, 1010 reply->msg[0] ? reply->msg : strerror(reply->error), 1011 reply->error); 1012 } 1013 if (rename) { 1014 struct sd; 1015 struct plex; 1016 struct volume; 1017 1018 /* we've overwritten msg with the 1019 * ioctl reply, start again */ 1020 msg.index = find_object(objname, &msg.type); /* find the object to rename */ 1021 switch (msg.type) { 1022 case sd_object: 1023 get_sd_info(&sd, msg.index); 1024 get_plex_info(&plex, sd.plexno); 1025 for (sdno = 0; sdno < plex.subdisks; sdno++) { 1026 if (plex.sdnos[sdno] == msg.index) /* found our subdisk */ 1027 break; 1028 } 1029 sprintf(newname, "%s.s%d", plex.name, sdno); 1030 sprintf(oldname, "%s", sd.name); 1031 vinum_rename_2(oldname, newname); 1032 break; 1033 1034 case plex_object: 1035 get_plex_info(&plex, msg.index); 1036 get_volume_info(&vol, plex.volno); 1037 for (plexno = 0; plexno < vol.plexes; plexno++) { 1038 if (vol.plex[plexno] == msg.index) /* found our subdisk */ 1039 break; 1040 } 1041 sprintf(newname, "%s.p%d", vol.name, plexno); 1042 sprintf(oldname, "%s", plex.name); 1043 vinum_rename_2(oldname, newname); /* this may recurse */ 1044 break; 1045 1046 default: /* can't get here */ 1047 } 1048 } 1049 checkupdates(); /* make sure we're updating */ 1050 } 1051 1052 /* Detach a subdisk from a plex, or a plex from a volume. 1053 * detach subdisk plex [rename] 1054 * detach plex volume [rename] 1055 */ 1056 void 1057 vinum_detach(int argc, char *argv[], char *argv0[]) 1058 { 1059 struct vinum_ioctl_msg msg; 1060 struct _ioctl_reply *reply = (struct _ioctl_reply *) &msg; 1061 1062 if ((argc < 1) 1063 || (argc > 2)) { 1064 fprintf(stderr, 1065 "Usage: \tdetach <subdisk> [rename]\n" 1066 "\tdetach <plex> [rename]\n"); 1067 return; 1068 } 1069 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 1070 perror("Can't get vinum config"); 1071 return; 1072 } 1073 msg.index = find_object(argv[0], &msg.type); /* find the object to detach */ 1074 msg.force = force; /* did we specify the use of force? */ 1075 msg.rename = 0; /* don't specify new name */ 1076 msg.recurse = recurse; /* but recurse if we have to */ 1077 1078 /* XXX are we going to keep this? 1079 * Don't document it yet, since the 1080 * kernel side of things doesn't 1081 * implement it */ 1082 if (argc == 2) { 1083 if (!strcmp(argv[1], "rename")) 1084 msg.rename = 1; /* do renaming */ 1085 else { 1086 fprintf(stderr, "Unknown attribute: %s\n", argv[1]); 1087 return; 1088 } 1089 } 1090 if ((msg.type != sd_object) 1091 && (msg.type != plex_object)) { 1092 fprintf(stderr, "Can only detach subdisks and plexes\n"); 1093 return; 1094 } 1095 ioctl(superdev, VINUM_DETACH, &msg); 1096 if (reply->error != 0) 1097 fprintf(stderr, 1098 "Can't detach %s: %s (%d)\n", 1099 argv[0], 1100 reply->msg[0] ? reply->msg : strerror(reply->error), 1101 reply->error); 1102 checkupdates(); /* make sure we're updating */ 1103 } 1104 1105 static void 1106 dorename(struct vinum_rename_msg *msg, const char *oldname, const char *name, int maxlen) 1107 { 1108 struct _ioctl_reply *reply = (struct _ioctl_reply *) msg; 1109 1110 if (strlen(name) > maxlen) { 1111 fprintf(stderr, "%s is too long\n", name); 1112 return; 1113 } 1114 strcpy(msg->newname, name); 1115 ioctl(superdev, VINUM_RENAME, msg); 1116 if (reply->error != 0) 1117 fprintf(stderr, 1118 "Can't rename %s to %s: %s (%d)\n", 1119 oldname, 1120 name, 1121 reply->msg[0] ? reply->msg : strerror(reply->error), 1122 reply->error); 1123 } 1124 1125 /* Rename an object: 1126 * rename <object> "newname" 1127 */ 1128 void 1129 vinum_rename_2(char *oldname, char *newname) 1130 { 1131 struct vinum_rename_msg msg; 1132 int volno; 1133 int plexno; 1134 1135 msg.index = find_object(oldname, &msg.type); /* find the object to rename */ 1136 msg.recurse = recurse; 1137 1138 /* Ugh. Determine how long the name may be */ 1139 switch (msg.type) { 1140 case drive_object: 1141 dorename(&msg, oldname, newname, MAXDRIVENAME); 1142 break; 1143 1144 case sd_object: 1145 dorename(&msg, oldname, newname, MAXSDNAME); 1146 break; 1147 1148 case plex_object: 1149 plexno = msg.index; 1150 dorename(&msg, oldname, newname, MAXPLEXNAME); 1151 if (recurse) { 1152 int sdno; 1153 1154 get_plex_info(&plex, plexno); /* find out who we are */ 1155 msg.type = sd_object; 1156 for (sdno = 0; sdno < plex.subdisks; sdno++) { 1157 char sdname[MAXPLEXNAME + 8]; 1158 1159 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */ 1160 sprintf(sdname, "%s.s%d", newname, sdno); 1161 msg.index = sd.sdno; /* number of the subdisk */ 1162 dorename(&msg, sd.name, sdname, MAXSDNAME); 1163 } 1164 } 1165 break; 1166 1167 case volume_object: 1168 volno = msg.index; 1169 dorename(&msg, oldname, newname, MAXVOLNAME); 1170 if (recurse) { 1171 int sdno; 1172 int plexno; 1173 1174 get_volume_info(&vol, volno); /* find out who we are */ 1175 for (plexno = 0; plexno < vol.plexes; plexno++) { 1176 char plexname[MAXVOLNAME + 8]; 1177 1178 msg.type = plex_object; 1179 sprintf(plexname, "%s.p%d", newname, plexno); 1180 msg.index = vol.plex[plexno]; /* number of the plex */ 1181 dorename(&msg, plex.name, plexname, MAXPLEXNAME); 1182 get_plex_info(&plex, vol.plex[plexno]); /* find out who we are */ 1183 msg.type = sd_object; 1184 for (sdno = 0; sdno < plex.subdisks; sdno++) { 1185 char sdname[MAXPLEXNAME + 8]; 1186 1187 get_plex_sd_info(&sd, plex.plexno, sdno); /* get info about the subdisk */ 1188 sprintf(sdname, "%s.s%d", plexname, sdno); 1189 msg.index = sd.sdno; /* number of the subdisk */ 1190 dorename(&msg, sd.name, sdname, MAXSDNAME); 1191 } 1192 } 1193 } 1194 break; 1195 1196 default: 1197 fprintf(stderr, "%s is not a Vinum object\n", oldname); 1198 return; 1199 } 1200 } 1201 1202 void 1203 vinum_rename(int argc, char *argv[], char *argv0[]) 1204 { 1205 if (argc != 2) { 1206 fprintf(stderr, "Usage: \trename <object> <new name>\n"); 1207 return; 1208 } 1209 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 1210 perror("Can't get vinum config"); 1211 return; 1212 } 1213 vinum_rename_2(argv[0], argv[1]); 1214 checkupdates(); /* make sure we're updating */ 1215 } 1216 1217 /* 1218 * Move objects: 1219 * 1220 * mv <dest> <src> ... 1221 */ 1222 void 1223 vinum_mv(int argc, char *argv[], char *argv0[]) 1224 { 1225 int i; /* loop index */ 1226 int srcobj; 1227 int destobj; 1228 enum objecttype srct; 1229 enum objecttype destt; 1230 int sdno; 1231 struct _ioctl_reply reply; 1232 struct vinum_ioctl_msg *msg = (struct vinum_ioctl_msg *) &reply; 1233 1234 if (argc < 2) { 1235 fprintf(stderr, "Usage: \tmove <dest> <src> ...\n"); 1236 return; 1237 } 1238 /* Get current config */ 1239 if (ioctl(superdev, VINUM_GETCONFIG, &vinum_conf) < 0) { 1240 perror("Cannot get vinum config\n"); 1241 return; 1242 } 1243 /* Get our destination */ 1244 destobj = find_object(argv[0], &destt); 1245 if (destobj == -1) { 1246 fprintf(stderr, "Can't find %s\n", argv[0]); 1247 return; 1248 } 1249 /* Verify that the target is a drive */ 1250 if (destt != drive_object) { 1251 fprintf(stderr, "%s is not a drive\n", argv[0]); 1252 return; 1253 } 1254 for (i = 1; i < argc; i++) { /* for all the sources */ 1255 srcobj = find_object(argv[i], &srct); 1256 if (srcobj == -1) { 1257 fprintf(stderr, "Can't find %s\n", argv[i]); 1258 continue; 1259 } 1260 msg->index = destobj; 1261 switch (srct) { /* Handle the source object */ 1262 case drive_object: /* Move all subdisks on the drive to dst. */ 1263 get_drive_info(&drive, srcobj); /* get info on drive */ 1264 for (sdno = 0; sdno < vinum_conf.subdisks_allocated; ++sdno) { 1265 get_sd_info(&sd, sdno); 1266 if (sd.driveno == srcobj) { 1267 msg->index = destobj; 1268 msg->otherobject = sd.sdno; 1269 if (ioctl(superdev, VINUM_MOVE, msg) < 0) 1270 fprintf(stderr, 1271 "Can't move %s (part of %s) to %s: %s (%d)\n", 1272 sd.name, 1273 drive.label.name, 1274 argv[0], 1275 strerror(reply.error), 1276 reply.error); 1277 } 1278 } 1279 break; 1280 1281 case sd_object: 1282 msg->otherobject = srcobj; 1283 if (ioctl(superdev, VINUM_MOVE, msg) < 0) 1284 fprintf(stderr, 1285 "Can't move %s to %s: %s (%d)\n", 1286 sd.name, 1287 argv[0], 1288 strerror(reply.error), 1289 reply.error); 1290 break; 1291 1292 case plex_object: 1293 get_plex_info(&plex, srcobj); 1294 for (sdno = 0; sdno < plex.subdisks; ++sdno) { 1295 get_plex_sd_info(&sd, plex.plexno, sdno); 1296 msg->index = destobj; 1297 msg->otherobject = sd.sdno; 1298 if (ioctl(superdev, VINUM_MOVE, msg) < 0) 1299 fprintf(stderr, 1300 "Can't move %s (part of %s) to %s: %s (%d)\n", 1301 sd.name, 1302 plex.name, 1303 argv[0], 1304 strerror(reply.error), 1305 reply.error); 1306 } 1307 break; 1308 1309 case volume_object: 1310 case invalid_object: 1311 default: 1312 fprintf(stderr, "Can't move %s (inappropriate object).\n", argv[i]); 1313 break; 1314 } 1315 if (reply.error) 1316 fprintf(stderr, 1317 "Can't move %s to %s: %s (%d)\n", 1318 argv[i], 1319 argv[0], 1320 strerror(reply.error), 1321 reply.error); 1322 } 1323 checkupdates(); /* make sure we're updating */ 1324 } 1325 1326 /* 1327 * Replace objects. Not implemented, may never be. 1328 */ 1329 void 1330 vinum_replace(int argc, char *argv[], char *argv0[]) 1331 { 1332 fprintf(stderr, "'replace' not implemented yet. Use 'move' instead\n"); 1333 } 1334 1335 /* Primitive help function */ 1336 void 1337 vinum_help(int argc, char *argv[], char *argv0[]) 1338 { 1339 char commands[] = 1340 { 1341 "COMMANDS\n" 1342 "create [-f description-file]\n" 1343 " Create a volume as described in description-file\n" 1344 "attach plex volume [rename]\n" 1345 "attach subdisk plex [offset] [rename]\n" 1346 " Attach a plex to a volume, or a subdisk to a plex.\n" 1347 "debug\n" 1348 " Cause the volume manager to enter the kernel debugger.\n" 1349 "debug flags\n" 1350 " Set debugging flags.\n" 1351 "detach [plex | subdisk]\n" 1352 " Detach a plex or subdisk from the volume or plex to which it is\n" 1353 " attached.\n" 1354 "info [-v]\n" 1355 " List information about volume manager state.\n" 1356 "init [-v] [-w] plex\n" 1357 " Initialize a plex by writing zeroes to all its subdisks.\n" 1358 "label volume\n" 1359 " Create a volume label\n" 1360 "list [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n" 1361 " List information about specified objects\n" 1362 "l [-r] [-s] [-v] [-V] [volume | plex | subdisk]\n" 1363 " List information about specified objects (alternative to\n" 1364 " list command)\n" 1365 "ld [-r] [-s] [-v] [-V] [volume]\n" 1366 " List information about drives\n" 1367 "ls [-r] [-s] [-v] [-V] [subdisk]\n" 1368 " List information about subdisks\n" 1369 "lp [-r] [-s] [-v] [-V] [plex]\n" 1370 " List information about plexes\n" 1371 "lv [-r] [-s] [-v] [-V] [volume]\n" 1372 " List information about volumes\n" 1373 "printconfig [file]\n" 1374 " Write a copy of the current configuration to file.\n" 1375 "makedev\n" 1376 " Remake the device nodes in " _PATH_DEV "vinum.\n" 1377 "move drive [subdisk | plex | drive]\n" 1378 " Move the subdisks of the specified object(s) to drive.\n" 1379 "quit\n" 1380 " Exit the vinum program when running in interactive mode. Nor-\n" 1381 " mally this would be done by entering the EOF character.\n" 1382 "read disk [disk...]\n" 1383 " Read the vinum configuration from the specified disks.\n" 1384 "rename [-r] [drive | subdisk | plex | volume] newname\n" 1385 " Change the name of the specified object.\n" 1386 "resetconfig\n" 1387 " Reset the complete vinum configuration.\n" 1388 "resetstats [-r] [volume | plex | subdisk]\n" 1389 " Reset statistisc counters for the specified objects, or for all\n" 1390 " objects if none are specified.\n" 1391 "rm [-f] [-r] volume | plex | subdisk\n" 1392 " Remove an object\n" 1393 "saveconfig\n" 1394 " Save vinum configuration to disk.\n" 1395 "setdaemon [value]\n" 1396 " Set daemon configuration.\n" 1397 "start\n" 1398 " Read configuration from all vinum drives.\n" 1399 "start [volume | plex | subdisk]\n" 1400 " Allow the system to access the objects\n" 1401 "stop [-f] [volume | plex | subdisk]\n" 1402 " Terminate access to the objects, or stop vinum if no parameters\n" 1403 " are specified.\n" 1404 }; 1405 puts(commands); 1406 } 1407 1408 /* Set daemon options. 1409 * XXX quick and dirty: use a bitmap, which requires 1410 * knowing which bit does what. FIXME */ 1411 void 1412 vinum_setdaemon(int argc, char *argv[], char *argv0[]) 1413 { 1414 int options; 1415 1416 switch (argc) { 1417 case 0: 1418 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0) 1419 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno); 1420 else 1421 printf("Options mask: %d\n", options); 1422 break; 1423 1424 case 1: 1425 options = atoi(argv[0]); 1426 if (ioctl(superdev, VINUM_SETDAEMON, &options) < 0) 1427 fprintf(stderr, "Can't set daemon options: %s (%d)\n", strerror(errno), errno); 1428 break; 1429 1430 default: 1431 fprintf(stderr, "Usage: \tsetdaemon [<bitmask>]\n"); 1432 } 1433 checkupdates(); /* make sure we're updating */ 1434 } 1435 1436 int 1437 checkupdates() 1438 { 1439 int options; 1440 1441 if (ioctl(superdev, VINUM_GETDAEMON, &options) < 0) 1442 fprintf(stderr, "Can't get daemon options: %s (%d)\n", strerror(errno), errno); 1443 if (options & daemon_noupdate) { 1444 fprintf(stderr, "*** Warning: configuration updates are disabled. ***\n"); 1445 return 1; 1446 } else 1447 return 0; 1448 } 1449 1450 /* Save config info */ 1451 void 1452 vinum_saveconfig(int argc, char *argv[], char *argv0[]) 1453 { 1454 int ioctltype; 1455 1456 if (argc != 0) { 1457 printf("Usage: saveconfig\n"); 1458 return; 1459 } 1460 ioctltype = 1; /* user saveconfig */ 1461 if (ioctl(superdev, VINUM_SAVECONFIG, &ioctltype) < 0) 1462 fprintf(stderr, "Can't save configuration: %s (%d)\n", strerror(errno), errno); 1463 checkupdates(); /* make sure we're updating */ 1464 } 1465 1466 /* 1467 * Create a volume name for the quick and dirty 1468 * commands. It will be of the form "vinum#", 1469 * where # is a small positive number. 1470 */ 1471 void 1472 genvolname() 1473 { 1474 int v; /* volume number */ 1475 static char volumename[MAXVOLNAME]; /* name to create */ 1476 enum objecttype type; 1477 1478 objectname = volumename; /* point to it */ 1479 for (v = 0;; v++) { 1480 sprintf(objectname, "vinum%d", v); /* create the name */ 1481 if (find_object(objectname, &type) == -1) /* does it exist? */ 1482 return; /* no, it's ours */ 1483 } 1484 } 1485 1486 /* 1487 * Create a drive for the quick and dirty 1488 * commands. The name will be of the form 1489 * vinumdrive#, where # is a small positive 1490 * number. Return the name of the drive. 1491 */ 1492 struct drive * 1493 create_drive(char *devicename) 1494 { 1495 int d; /* volume number */ 1496 static char drivename[MAXDRIVENAME]; /* name to create */ 1497 enum objecttype type; 1498 struct _ioctl_reply *reply; 1499 1500 /* 1501 * We're never likely to get anything 1502 * like 10000 drives. The only reason for 1503 * this limit is to stop the thing 1504 * looping if we have a bug somewhere. 1505 */ 1506 for (d = 0; d < 100000; d++) { /* look for a free drive number */ 1507 sprintf(drivename, "vinumdrive%d", d); /* create the name */ 1508 if (find_object(drivename, &type) == -1) { /* does it exist? */ 1509 char command[MAXDRIVENAME * 2]; 1510 1511 sprintf(command, "drive %s device %s", drivename, devicename); /* create a create command */ 1512 if (vflag) 1513 printf("drive %s device %s\n", drivename, devicename); /* create a create command */ 1514 ioctl(superdev, VINUM_CREATE, command); 1515 reply = (struct _ioctl_reply *) &command; 1516 if (reply->error != 0) { /* error in config */ 1517 if (reply->msg[0]) 1518 fprintf(stderr, 1519 "Can't create drive %s, device %s: %s\n", 1520 drivename, 1521 devicename, 1522 reply->msg); 1523 else 1524 fprintf(stderr, 1525 "Can't create drive %s, device %s: %s (%d)\n", 1526 drivename, 1527 devicename, 1528 strerror(reply->error), 1529 reply->error); 1530 longjmp(command_fail, -1); /* give up */ 1531 } 1532 find_object(drivename, &type); 1533 return &drive; /* return the name of the drive */ 1534 } 1535 } 1536 fprintf(stderr, "Can't generate a drive name\n"); 1537 /* NOTREACHED */ 1538 return NULL; 1539 } 1540 1541 /* 1542 * Create a volume with a single concatenated plex from 1543 * as much space as we can get on the specified drives. 1544 * If the drives aren't Vinum drives, make them so. 1545 */ 1546 void 1547 vinum_concat(int argc, char *argv[], char *argv0[]) 1548 { 1549 int o; /* object number */ 1550 char buffer[BUFSIZE]; 1551 struct drive *drive; /* drive we're currently looking at */ 1552 struct _ioctl_reply *reply; 1553 int ioctltype; 1554 int error; 1555 enum objecttype type; 1556 1557 reply = (struct _ioctl_reply *) &buffer; 1558 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ 1559 printf("Can't configure: %s (%d)\n", strerror(errno), errno); 1560 return; 1561 } 1562 if (!objectname) /* we need a name for our object */ 1563 genvolname(); 1564 sprintf(buffer, "volume %s", objectname); 1565 if (vflag) 1566 printf("volume %s\n", objectname); 1567 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */ 1568 if (reply->error != 0) { /* error in config */ 1569 if (reply->msg[0]) 1570 fprintf(stderr, 1571 "Can't create volume %s: %s\n", 1572 objectname, 1573 reply->msg); 1574 else 1575 fprintf(stderr, 1576 "Can't create volume %s: %s (%d)\n", 1577 objectname, 1578 strerror(reply->error), 1579 reply->error); 1580 longjmp(command_fail, -1); /* give up */ 1581 } 1582 sprintf(buffer, "plex name %s.p0 org concat", objectname); 1583 if (vflag) 1584 printf(" plex name %s.p0 org concat\n", objectname); 1585 ioctl(superdev, VINUM_CREATE, buffer); 1586 if (reply->error != 0) { /* error in config */ 1587 if (reply->msg[0]) 1588 fprintf(stderr, 1589 "Can't create plex %s.p0: %s\n", 1590 objectname, 1591 reply->msg); 1592 else 1593 fprintf(stderr, 1594 "Can't create plex %s.p0: %s (%d)\n", 1595 objectname, 1596 strerror(reply->error), 1597 reply->error); 1598 longjmp(command_fail, -1); /* give up */ 1599 } 1600 for (o = 0; o < argc; o++) { 1601 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */ 1602 drive = create_drive(argv[o]); /* create it */ 1603 sprintf(buffer, "sd name %s.p0.s%d drive %s size 0", objectname, o, drive->label.name); 1604 if (vflag) 1605 printf(" sd name %s.p0.s%d drive %s size 0\n", objectname, o, drive->label.name); 1606 ioctl(superdev, VINUM_CREATE, buffer); 1607 if (reply->error != 0) { /* error in config */ 1608 if (reply->msg[0]) 1609 fprintf(stderr, 1610 "Can't create subdisk %s.p0.s%d: %s\n", 1611 objectname, 1612 o, 1613 reply->msg); 1614 else 1615 fprintf(stderr, 1616 "Can't create subdisk %s.p0.s%d: %s (%d)\n", 1617 objectname, 1618 o, 1619 strerror(reply->error), 1620 reply->error); 1621 longjmp(command_fail, -1); /* give up */ 1622 } 1623 } 1624 1625 /* done, save the config */ 1626 ioctltype = 0; /* saveconfig after update */ 1627 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ 1628 if (error != 0) 1629 perror("Can't save Vinum config"); 1630 find_object(objectname, &type); /* find the index of the volume */ 1631 make_vol_dev(vol.volno, 1); /* and create the devices */ 1632 if (vflag) { 1633 vflag--; /* XXX don't give too much detail */ 1634 find_object(objectname, &type); /* point to the volume */ 1635 vinum_lvi(vol.volno, 1); /* and print info about it */ 1636 } 1637 } 1638 1639 1640 /* 1641 * Create a volume with a single striped plex from 1642 * as much space as we can get on the specified drives. 1643 * If the drives aren't Vinum drives, make them so. 1644 */ 1645 void 1646 vinum_stripe(int argc, char *argv[], char *argv0[]) 1647 { 1648 int o; /* object number */ 1649 char buffer[BUFSIZE]; 1650 struct drive *drive; /* drive we're currently looking at */ 1651 struct _ioctl_reply *reply; 1652 int ioctltype; 1653 int error; 1654 enum objecttype type; 1655 off_t maxsize; 1656 int fe; /* freelist entry index */ 1657 struct drive_freelist freelist; 1658 struct ferq { /* request to pass to ioctl */ 1659 int driveno; 1660 int fe; 1661 } *ferq = (struct ferq *) &freelist; 1662 u_int64_t bigchunk; /* biggest chunk in freelist */ 1663 1664 maxsize = QUAD_MAX; 1665 reply = (struct _ioctl_reply *) &buffer; 1666 1667 /* 1668 * First, check our drives. 1669 */ 1670 if (argc < 2) { 1671 fprintf(stderr, "You need at least two drives to create a striped plex\n"); 1672 return; 1673 } 1674 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ 1675 printf("Can't configure: %s (%d)\n", strerror(errno), errno); 1676 return; 1677 } 1678 if (!objectname) /* we need a name for our object */ 1679 genvolname(); 1680 for (o = 0; o < argc; o++) { 1681 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */ 1682 drive = create_drive(argv[o]); /* create it */ 1683 /* Now find the largest chunk available on the drive */ 1684 bigchunk = 0; /* ain't found nothin' yet */ 1685 for (fe = 0; fe < drive->freelist_entries; fe++) { 1686 ferq->driveno = drive->driveno; 1687 ferq->fe = fe; 1688 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) { 1689 fprintf(stderr, 1690 "Can't get free list element %d: %s\n", 1691 fe, 1692 strerror(errno)); 1693 longjmp(command_fail, -1); 1694 } 1695 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */ 1696 } 1697 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */ 1698 } 1699 1700 /* Now create the volume */ 1701 sprintf(buffer, "volume %s", objectname); 1702 if (vflag) 1703 printf("volume %s\n", objectname); 1704 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */ 1705 if (reply->error != 0) { /* error in config */ 1706 if (reply->msg[0]) 1707 fprintf(stderr, 1708 "Can't create volume %s: %s\n", 1709 objectname, 1710 reply->msg); 1711 else 1712 fprintf(stderr, 1713 "Can't create volume %s: %s (%d)\n", 1714 objectname, 1715 strerror(reply->error), 1716 reply->error); 1717 longjmp(command_fail, -1); /* give up */ 1718 } 1719 sprintf(buffer, "plex name %s.p0 org striped 256k", objectname); 1720 if (vflag) 1721 printf(" plex name %s.p0 org striped 256k\n", objectname); 1722 ioctl(superdev, VINUM_CREATE, buffer); 1723 if (reply->error != 0) { /* error in config */ 1724 if (reply->msg[0]) 1725 fprintf(stderr, 1726 "Can't create plex %s.p0: %s\n", 1727 objectname, 1728 reply->msg); 1729 else 1730 fprintf(stderr, 1731 "Can't create plex %s.p0: %s (%d)\n", 1732 objectname, 1733 strerror(reply->error), 1734 reply->error); 1735 longjmp(command_fail, -1); /* give up */ 1736 } 1737 for (o = 0; o < argc; o++) { 1738 drive = find_drive_by_devname(argv[o]); /* we know it exists... */ 1739 sprintf(buffer, 1740 "sd name %s.p0.s%d drive %s size %lldb", 1741 objectname, 1742 o, 1743 drive->label.name, 1744 (long long) maxsize); 1745 if (vflag) 1746 printf(" sd name %s.p0.s%d drive %s size %lldb\n", 1747 objectname, 1748 o, 1749 drive->label.name, 1750 (long long) maxsize); 1751 ioctl(superdev, VINUM_CREATE, buffer); 1752 if (reply->error != 0) { /* error in config */ 1753 if (reply->msg[0]) 1754 fprintf(stderr, 1755 "Can't create subdisk %s.p0.s%d: %s\n", 1756 objectname, 1757 o, 1758 reply->msg); 1759 else 1760 fprintf(stderr, 1761 "Can't create subdisk %s.p0.s%d: %s (%d)\n", 1762 objectname, 1763 o, 1764 strerror(reply->error), 1765 reply->error); 1766 longjmp(command_fail, -1); /* give up */ 1767 } 1768 } 1769 1770 /* done, save the config */ 1771 ioctltype = 0; /* saveconfig after update */ 1772 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ 1773 if (error != 0) 1774 perror("Can't save Vinum config"); 1775 find_object(objectname, &type); /* find the index of the volume */ 1776 make_vol_dev(vol.volno, 1); /* and create the devices */ 1777 if (vflag) { 1778 vflag--; /* XXX don't give too much detail */ 1779 find_object(objectname, &type); /* point to the volume */ 1780 vinum_lvi(vol.volno, 1); /* and print info about it */ 1781 } 1782 } 1783 1784 /* 1785 * Create a volume with a single RAID-4 plex from 1786 * as much space as we can get on the specified drives. 1787 * If the drives aren't Vinum drives, make them so. 1788 */ 1789 void 1790 vinum_raid4(int argc, char *argv[], char *argv0[]) 1791 { 1792 int o; /* object number */ 1793 char buffer[BUFSIZE]; 1794 struct drive *drive; /* drive we're currently looking at */ 1795 struct _ioctl_reply *reply; 1796 int ioctltype; 1797 int error; 1798 enum objecttype type; 1799 off_t maxsize; 1800 int fe; /* freelist entry index */ 1801 struct drive_freelist freelist; 1802 struct ferq { /* request to pass to ioctl */ 1803 int driveno; 1804 int fe; 1805 } *ferq = (struct ferq *) &freelist; 1806 u_int64_t bigchunk; /* biggest chunk in freelist */ 1807 1808 maxsize = QUAD_MAX; 1809 reply = (struct _ioctl_reply *) &buffer; 1810 1811 /* 1812 * First, check our drives. 1813 */ 1814 if (argc < 3) { 1815 fprintf(stderr, "You need at least three drives to create a RAID-4 plex\n"); 1816 return; 1817 } 1818 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ 1819 printf("Can't configure: %s (%d)\n", strerror(errno), errno); 1820 return; 1821 } 1822 if (!objectname) /* we need a name for our object */ 1823 genvolname(); 1824 for (o = 0; o < argc; o++) { 1825 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */ 1826 drive = create_drive(argv[o]); /* create it */ 1827 /* Now find the largest chunk available on the drive */ 1828 bigchunk = 0; /* ain't found nothin' yet */ 1829 for (fe = 0; fe < drive->freelist_entries; fe++) { 1830 ferq->driveno = drive->driveno; 1831 ferq->fe = fe; 1832 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) { 1833 fprintf(stderr, 1834 "Can't get free list element %d: %s\n", 1835 fe, 1836 strerror(errno)); 1837 longjmp(command_fail, -1); 1838 } 1839 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */ 1840 } 1841 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */ 1842 } 1843 1844 /* Now create the volume */ 1845 sprintf(buffer, "volume %s", objectname); 1846 if (vflag) 1847 printf("volume %s\n", objectname); 1848 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */ 1849 if (reply->error != 0) { /* error in config */ 1850 if (reply->msg[0]) 1851 fprintf(stderr, 1852 "Can't create volume %s: %s\n", 1853 objectname, 1854 reply->msg); 1855 else 1856 fprintf(stderr, 1857 "Can't create volume %s: %s (%d)\n", 1858 objectname, 1859 strerror(reply->error), 1860 reply->error); 1861 longjmp(command_fail, -1); /* give up */ 1862 } 1863 sprintf(buffer, "plex name %s.p0 org raid4 256k", objectname); 1864 if (vflag) 1865 printf(" plex name %s.p0 org raid4 256k\n", objectname); 1866 ioctl(superdev, VINUM_CREATE, buffer); 1867 if (reply->error != 0) { /* error in config */ 1868 if (reply->msg[0]) 1869 fprintf(stderr, 1870 "Can't create plex %s.p0: %s\n", 1871 objectname, 1872 reply->msg); 1873 else 1874 fprintf(stderr, 1875 "Can't create plex %s.p0: %s (%d)\n", 1876 objectname, 1877 strerror(reply->error), 1878 reply->error); 1879 longjmp(command_fail, -1); /* give up */ 1880 } 1881 for (o = 0; o < argc; o++) { 1882 drive = find_drive_by_devname(argv[o]); /* we know it exists... */ 1883 sprintf(buffer, 1884 "sd name %s.p0.s%d drive %s size %lldb", 1885 objectname, 1886 o, 1887 drive->label.name, 1888 (long long) maxsize); 1889 if (vflag) 1890 printf(" sd name %s.p0.s%d drive %s size %lldb\n", 1891 objectname, 1892 o, 1893 drive->label.name, 1894 (long long) maxsize); 1895 ioctl(superdev, VINUM_CREATE, buffer); 1896 if (reply->error != 0) { /* error in config */ 1897 if (reply->msg[0]) 1898 fprintf(stderr, 1899 "Can't create subdisk %s.p0.s%d: %s\n", 1900 objectname, 1901 o, 1902 reply->msg); 1903 else 1904 fprintf(stderr, 1905 "Can't create subdisk %s.p0.s%d: %s (%d)\n", 1906 objectname, 1907 o, 1908 strerror(reply->error), 1909 reply->error); 1910 longjmp(command_fail, -1); /* give up */ 1911 } 1912 } 1913 1914 /* done, save the config */ 1915 ioctltype = 0; /* saveconfig after update */ 1916 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ 1917 if (error != 0) 1918 perror("Can't save Vinum config"); 1919 find_object(objectname, &type); /* find the index of the volume */ 1920 make_vol_dev(vol.volno, 1); /* and create the devices */ 1921 if (vflag) { 1922 vflag--; /* XXX don't give too much detail */ 1923 find_object(objectname, &type); /* point to the volume */ 1924 vinum_lvi(vol.volno, 1); /* and print info about it */ 1925 } 1926 } 1927 1928 /* 1929 * Create a volume with a single RAID-4 plex from 1930 * as much space as we can get on the specified drives. 1931 * If the drives aren't Vinum drives, make them so. 1932 */ 1933 void 1934 vinum_raid5(int argc, char *argv[], char *argv0[]) 1935 { 1936 int o; /* object number */ 1937 char buffer[BUFSIZE]; 1938 struct drive *drive; /* drive we're currently looking at */ 1939 struct _ioctl_reply *reply; 1940 int ioctltype; 1941 int error; 1942 enum objecttype type; 1943 off_t maxsize; 1944 int fe; /* freelist entry index */ 1945 struct drive_freelist freelist; 1946 struct ferq { /* request to pass to ioctl */ 1947 int driveno; 1948 int fe; 1949 } *ferq = (struct ferq *) &freelist; 1950 u_int64_t bigchunk; /* biggest chunk in freelist */ 1951 1952 maxsize = QUAD_MAX; 1953 reply = (struct _ioctl_reply *) &buffer; 1954 1955 /* 1956 * First, check our drives. 1957 */ 1958 if (argc < 3) { 1959 fprintf(stderr, "You need at least three drives to create a RAID-5 plex\n"); 1960 return; 1961 } 1962 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ 1963 printf("Can't configure: %s (%d)\n", strerror(errno), errno); 1964 return; 1965 } 1966 if (!objectname) /* we need a name for our object */ 1967 genvolname(); 1968 for (o = 0; o < argc; o++) { 1969 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */ 1970 drive = create_drive(argv[o]); /* create it */ 1971 /* Now find the largest chunk available on the drive */ 1972 bigchunk = 0; /* ain't found nothin' yet */ 1973 for (fe = 0; fe < drive->freelist_entries; fe++) { 1974 ferq->driveno = drive->driveno; 1975 ferq->fe = fe; 1976 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) { 1977 fprintf(stderr, 1978 "Can't get free list element %d: %s\n", 1979 fe, 1980 strerror(errno)); 1981 longjmp(command_fail, -1); 1982 } 1983 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */ 1984 } 1985 maxsize = min(maxsize, bigchunk); /* this is as much as we can do */ 1986 } 1987 1988 /* Now create the volume */ 1989 sprintf(buffer, "volume %s", objectname); 1990 if (vflag) 1991 printf("volume %s\n", objectname); 1992 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */ 1993 if (reply->error != 0) { /* error in config */ 1994 if (reply->msg[0]) 1995 fprintf(stderr, 1996 "Can't create volume %s: %s\n", 1997 objectname, 1998 reply->msg); 1999 else 2000 fprintf(stderr, 2001 "Can't create volume %s: %s (%d)\n", 2002 objectname, 2003 strerror(reply->error), 2004 reply->error); 2005 longjmp(command_fail, -1); /* give up */ 2006 } 2007 sprintf(buffer, "plex name %s.p0 org raid5 256k", objectname); 2008 if (vflag) 2009 printf(" plex name %s.p0 org raid5 256k\n", objectname); 2010 ioctl(superdev, VINUM_CREATE, buffer); 2011 if (reply->error != 0) { /* error in config */ 2012 if (reply->msg[0]) 2013 fprintf(stderr, 2014 "Can't create plex %s.p0: %s\n", 2015 objectname, 2016 reply->msg); 2017 else 2018 fprintf(stderr, 2019 "Can't create plex %s.p0: %s (%d)\n", 2020 objectname, 2021 strerror(reply->error), 2022 reply->error); 2023 longjmp(command_fail, -1); /* give up */ 2024 } 2025 for (o = 0; o < argc; o++) { 2026 drive = find_drive_by_devname(argv[o]); /* we know it exists... */ 2027 sprintf(buffer, 2028 "sd name %s.p0.s%d drive %s size %lldb", 2029 objectname, 2030 o, 2031 drive->label.name, 2032 (long long) maxsize); 2033 if (vflag) 2034 printf(" sd name %s.p0.s%d drive %s size %lldb\n", 2035 objectname, 2036 o, 2037 drive->label.name, 2038 (long long) maxsize); 2039 ioctl(superdev, VINUM_CREATE, buffer); 2040 if (reply->error != 0) { /* error in config */ 2041 if (reply->msg[0]) 2042 fprintf(stderr, 2043 "Can't create subdisk %s.p0.s%d: %s\n", 2044 objectname, 2045 o, 2046 reply->msg); 2047 else 2048 fprintf(stderr, 2049 "Can't create subdisk %s.p0.s%d: %s (%d)\n", 2050 objectname, 2051 o, 2052 strerror(reply->error), 2053 reply->error); 2054 longjmp(command_fail, -1); /* give up */ 2055 } 2056 } 2057 2058 /* done, save the config */ 2059 ioctltype = 0; /* saveconfig after update */ 2060 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ 2061 if (error != 0) 2062 perror("Can't save Vinum config"); 2063 find_object(objectname, &type); /* find the index of the volume */ 2064 make_vol_dev(vol.volno, 1); /* and create the devices */ 2065 if (vflag) { 2066 vflag--; /* XXX don't give too much detail */ 2067 find_object(objectname, &type); /* point to the volume */ 2068 vinum_lvi(vol.volno, 1); /* and print info about it */ 2069 } 2070 } 2071 2072 /* 2073 * Create a volume with a two plexes from as much space 2074 * as we can get on the specified drives. If the 2075 * drives aren't Vinum drives, make them so. 2076 * 2077 * The number of drives must be even, and at least 4 2078 * for a striped plex. Specify striped plexes with the 2079 * -s flag; otherwise they will be concatenated. It's 2080 * possible that the two plexes may differ in length. 2081 */ 2082 void 2083 vinum_mirror(int argc, char *argv[], char *argv0[]) 2084 { 2085 int o; /* object number */ 2086 int p; /* plex number */ 2087 char buffer[BUFSIZE]; 2088 struct drive *drive; /* drive we're currently looking at */ 2089 struct _ioctl_reply *reply; 2090 int ioctltype; 2091 int error; 2092 enum objecttype type; 2093 off_t maxsize[2]; /* maximum subdisk size for striped plexes */ 2094 int fe; /* freelist entry index */ 2095 struct drive_freelist freelist; 2096 struct ferq { /* request to pass to ioctl */ 2097 int driveno; 2098 int fe; 2099 } *ferq = (struct ferq *) &freelist; 2100 u_int64_t bigchunk; /* biggest chunk in freelist */ 2101 2102 if (sflag) /* striped, */ 2103 maxsize[0] = maxsize[1] = QUAD_MAX; /* we need to calculate sd size */ 2104 else 2105 maxsize[0] = maxsize[1] = 0; /* let the kernel routines do it */ 2106 2107 reply = (struct _ioctl_reply *) &buffer; 2108 2109 /* 2110 * First, check our drives. 2111 */ 2112 if (argc & 1) { 2113 fprintf(stderr, "You need an even number of drives to create a mirrored volume\n"); 2114 return; 2115 } 2116 if (sflag && (argc < 4)) { 2117 fprintf(stderr, "You need at least 4 drives to create a mirrored, striped volume\n"); 2118 return; 2119 } 2120 if (ioctl(superdev, VINUM_STARTCONFIG, &force)) { /* can't get config? */ 2121 printf("Can't configure: %s (%d)\n", strerror(errno), errno); 2122 return; 2123 } 2124 if (!objectname) /* we need a name for our object */ 2125 genvolname(); 2126 for (o = 0; o < argc; o++) { 2127 if ((drive = find_drive_by_devname(argv[o])) == NULL) /* doesn't exist */ 2128 drive = create_drive(argv[o]); /* create it */ 2129 if (sflag) { /* striping, */ 2130 /* Find the largest chunk available on the drive */ 2131 bigchunk = 0; /* ain't found nothin' yet */ 2132 for (fe = 0; fe < drive->freelist_entries; fe++) { 2133 ferq->driveno = drive->driveno; 2134 ferq->fe = fe; 2135 if (ioctl(superdev, VINUM_GETFREELIST, &freelist) < 0) { 2136 fprintf(stderr, 2137 "Can't get free list element %d: %s\n", 2138 fe, 2139 strerror(errno)); 2140 longjmp(command_fail, -1); 2141 } 2142 bigchunk = bigchunk > freelist.sectors ? bigchunk : freelist.sectors; /* max it */ 2143 } 2144 maxsize[o & 1] = min(maxsize[o & 1], bigchunk); /* get the maximum size of a subdisk */ 2145 } 2146 } 2147 2148 /* Now create the volume */ 2149 sprintf(buffer, "volume %s setupstate", objectname); 2150 if (vflag) 2151 printf("volume %s setupstate\n", objectname); 2152 ioctl(superdev, VINUM_CREATE, buffer); /* create the volume */ 2153 if (reply->error != 0) { /* error in config */ 2154 if (reply->msg[0]) 2155 fprintf(stderr, 2156 "Can't create volume %s: %s\n", 2157 objectname, 2158 reply->msg); 2159 else 2160 fprintf(stderr, 2161 "Can't create volume %s: %s (%d)\n", 2162 objectname, 2163 strerror(reply->error), 2164 reply->error); 2165 longjmp(command_fail, -1); /* give up */ 2166 } 2167 for (p = 0; p < 2; p++) { /* create each plex */ 2168 if (sflag) { 2169 sprintf(buffer, "plex name %s.p%d org striped 256k", objectname, p); 2170 if (vflag) 2171 printf(" plex name %s.p%d org striped 256k\n", objectname, p); 2172 } else { /* concat */ 2173 sprintf(buffer, "plex name %s.p%d org concat", objectname, p); 2174 if (vflag) 2175 printf(" plex name %s.p%d org concat\n", objectname, p); 2176 } 2177 ioctl(superdev, VINUM_CREATE, buffer); 2178 if (reply->error != 0) { /* error in config */ 2179 if (reply->msg[0]) 2180 fprintf(stderr, 2181 "Can't create plex %s.p%d: %s\n", 2182 objectname, 2183 p, 2184 reply->msg); 2185 else 2186 fprintf(stderr, 2187 "Can't create plex %s.p%d: %s (%d)\n", 2188 objectname, 2189 p, 2190 strerror(reply->error), 2191 reply->error); 2192 longjmp(command_fail, -1); /* give up */ 2193 } 2194 /* Now look at the subdisks */ 2195 for (o = p; o < argc; o += 2) { /* every second one */ 2196 drive = find_drive_by_devname(argv[o]); /* we know it exists... */ 2197 sprintf(buffer, 2198 "sd name %s.p%d.s%d drive %s size %lldb", 2199 objectname, 2200 p, 2201 o >> 1, 2202 drive->label.name, 2203 (long long) maxsize[p]); 2204 if (vflag) 2205 printf(" sd name %s.p%d.s%d drive %s size %lldb\n", 2206 objectname, 2207 p, 2208 o >> 1, 2209 drive->label.name, 2210 (long long) maxsize[p]); 2211 ioctl(superdev, VINUM_CREATE, buffer); 2212 if (reply->error != 0) { /* error in config */ 2213 if (reply->msg[0]) 2214 fprintf(stderr, 2215 "Can't create subdisk %s.p%d.s%d: %s\n", 2216 objectname, 2217 p, 2218 o >> 1, 2219 reply->msg); 2220 else 2221 fprintf(stderr, 2222 "Can't create subdisk %s.p%d.s%d: %s (%d)\n", 2223 objectname, 2224 p, 2225 o >> 1, 2226 strerror(reply->error), 2227 reply->error); 2228 longjmp(command_fail, -1); /* give up */ 2229 } 2230 } 2231 } 2232 2233 /* done, save the config */ 2234 ioctltype = 0; /* saveconfig after update */ 2235 error = ioctl(superdev, VINUM_SAVECONFIG, &ioctltype); /* save the config to disk */ 2236 if (error != 0) 2237 perror("Can't save Vinum config"); 2238 find_object(objectname, &type); /* find the index of the volume */ 2239 make_vol_dev(vol.volno, 1); /* and create the devices */ 2240 if (vflag) { 2241 vflag--; /* XXX don't give too much detail */ 2242 sflag = 0; /* no stats, please */ 2243 find_object(objectname, &type); /* point to the volume */ 2244 vinum_lvi(vol.volno, 1); /* and print info about it */ 2245 } 2246 } 2247 2248 void 2249 vinum_readpol(int argc, char *argv[], char *argv0[]) 2250 { 2251 int object; 2252 struct _ioctl_reply reply; 2253 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; 2254 enum objecttype type; 2255 struct plex plex; 2256 struct volume vol; 2257 int plexno; 2258 2259 if (argc == 0) { /* start everything */ 2260 fprintf(stderr, "Usage: readpol <volume> <plex>|round\n"); 2261 return; 2262 } 2263 object = find_object(argv[1], &type); /* look for it */ 2264 if (type != volume_object) { 2265 fprintf(stderr, "%s is not a volume\n", argv[1]); 2266 return; 2267 } 2268 get_volume_info(&vol, object); 2269 if (strcmp(argv[2], "round")) { /* not 'round' */ 2270 object = find_object(argv[2], &type); /* look for it */ 2271 if (type != plex_object) { 2272 fprintf(stderr, "%s is not a plex\n", argv[2]); 2273 return; 2274 } 2275 get_plex_info(&plex, object); 2276 plexno = plex.plexno; 2277 } else /* round */ 2278 plexno = -1; 2279 2280 /* Set the value */ 2281 message->index = vol.volno; 2282 message->otherobject = plexno; 2283 if (ioctl(superdev, VINUM_READPOL, message) < 0) 2284 fprintf(stderr, "Can't set read policy: %s (%d)\n", strerror(errno), errno); 2285 if (vflag) 2286 vinum_lpi(plexno, recurse); 2287 } 2288 2289 /* 2290 * Brute force set state function. Don't look at 2291 * any dependencies, just do it. 2292 */ 2293 void 2294 vinum_setstate(int argc, char *argv[], char *argv0[]) 2295 { 2296 int object; 2297 struct _ioctl_reply reply; 2298 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; 2299 int index; 2300 enum objecttype type; 2301 int state; 2302 2303 for (index = 1; index < argc; index++) { 2304 object = find_object(argv[index], &type); /* look for it */ 2305 if (type == invalid_object) 2306 fprintf(stderr, "Can't find object: %s\n", argv[index]); 2307 else { 2308 int doit = 0; /* set to 1 if we pass our tests */ 2309 switch (type) { 2310 case drive_object: 2311 state = DriveState(argv[0]); /* get the state */ 2312 if (drive.state == state) /* already in that state */ 2313 fprintf(stderr, "%s is already %s\n", drive.label.name, argv[0]); 2314 else 2315 doit = 1; 2316 break; 2317 2318 case sd_object: 2319 state = SdState(argv[0]); /* get the state */ 2320 if (sd.state == state) /* already in that state */ 2321 fprintf(stderr, "%s is already %s\n", sd.name, argv[0]); 2322 else 2323 doit = 1; 2324 break; 2325 2326 case plex_object: 2327 state = PlexState(argv[0]); /* get the state */ 2328 if (plex.state == state) /* already in that state */ 2329 fprintf(stderr, "%s is already %s\n", plex.name, argv[0]); 2330 else 2331 doit = 1; 2332 break; 2333 2334 case volume_object: 2335 state = VolState(argv[0]); /* get the state */ 2336 if (vol.state == state) /* already in that state */ 2337 fprintf(stderr, "%s is already %s\n", vol.name, argv[0]); 2338 else 2339 doit = 1; 2340 break; 2341 2342 default: 2343 state = 0; /* to keep the compiler happy */ 2344 } 2345 2346 if (state == -1) 2347 fprintf(stderr, "Invalid state for object: %s\n", argv[0]); 2348 else if (doit) { 2349 message->index = object; /* pass object number */ 2350 message->type = type; /* and type of object */ 2351 message->state = state; 2352 message->force = force; /* don't force it, use a larger hammer */ 2353 ioctl(superdev, VINUM_SETSTATE_FORCE, message); 2354 if (reply.error != 0) 2355 fprintf(stderr, 2356 "Can't start %s: %s (%d)\n", 2357 argv[index], 2358 reply.msg[0] ? reply.msg : strerror(reply.error), 2359 reply.error); 2360 if (Verbose) 2361 vinum_li(object, type); 2362 } 2363 } 2364 } 2365 } 2366 2367 void 2368 vinum_checkparity(int argc, char *argv[], char *argv0[]) 2369 { 2370 Verbose = vflag; /* accept -v for verbose */ 2371 if (argc == 0) /* no parameters? */ 2372 fprintf(stderr, "Usage: checkparity object [object...]\n"); 2373 else 2374 parityops(argc, argv, checkparity); 2375 } 2376 2377 void 2378 vinum_rebuildparity(int argc, char *argv[], char *argv0[]) 2379 { 2380 if (argc == 0) /* no parameters? */ 2381 fprintf(stderr, "Usage: rebuildparity object [object...]\n"); 2382 else 2383 parityops(argc, argv, vflag ? rebuildandcheckparity : rebuildparity); 2384 } 2385 2386 /* 2387 * Common code for rebuildparity and checkparity. 2388 * We bend the meanings of some flags here: 2389 * 2390 * -v: Report incorrect parity on rebuild. 2391 * -V: Show running count of position being checked. 2392 * -f: Start from beginning of the plex. 2393 */ 2394 void 2395 parityops(int argc, char *argv[], enum parityop op) 2396 { 2397 int object; 2398 struct plex plex; 2399 struct _ioctl_reply reply; 2400 struct vinum_ioctl_msg *message = (struct vinum_ioctl_msg *) &reply; 2401 int index; 2402 enum objecttype type; 2403 char *msg; 2404 off_t block; 2405 2406 if (op == checkparity) 2407 msg = "Checking"; 2408 else 2409 msg = "Rebuilding"; 2410 for (index = 0; index < argc; index++) { 2411 object = find_object(argv[index], &type); /* look for it */ 2412 if (type != plex_object) 2413 fprintf(stderr, "%s is not a plex\n", argv[index]); 2414 else { 2415 get_plex_info(&plex, object); 2416 if (!isparity((&plex))) 2417 fprintf(stderr, "%s is not a RAID-4 or RAID-5 plex\n", argv[index]); 2418 else { 2419 do { 2420 message->index = object; /* pass object number */ 2421 message->type = type; /* and type of object */ 2422 message->op = op; /* what to do */ 2423 if (force) 2424 message->offset = 0; /* start at the beginning */ 2425 else 2426 message->offset = plex.checkblock; /* continue where we left off */ 2427 force = 0; /* don't reset after the first time */ 2428 ioctl(superdev, VINUM_PARITYOP, message); 2429 get_plex_info(&plex, object); 2430 if (Verbose) { 2431 block = (plex.checkblock << DEV_BSHIFT) * (plex.subdisks - 1); 2432 if (block != 0) 2433 printf("\r%s at %s (%d%%) ", 2434 msg, 2435 roughlength(block, 1), 2436 ((int) (block * 100 / plex.length) >> DEV_BSHIFT)); 2437 if ((reply.error == EAGAIN) 2438 && (reply.msg[0])) /* got a comment back */ 2439 fputs(reply.msg, stderr); /* show it */ 2440 fflush(stdout); 2441 } 2442 } 2443 while (reply.error == EAGAIN); 2444 if (reply.error != 0) { 2445 if (reply.msg[0]) 2446 fputs(reply.msg, stderr); 2447 else 2448 fprintf(stderr, 2449 "%s failed: %s\n", 2450 msg, 2451 strerror(reply.error)); 2452 } else if (Verbose) { 2453 if (op == checkparity) 2454 fprintf(stderr, "%s has correct parity\n", argv[index]); 2455 else 2456 fprintf(stderr, "Rebuilt parity on %s\n", argv[index]); 2457 } 2458 } 2459 } 2460 } 2461 } 2462 2463 /* Local Variables: */ 2464 /* fill-column: 50 */ 2465 /* End: */ 2466