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