raidctl.c revision 1.27
1/* $NetBSD: raidctl.c,v 1.27 2001/07/10 01:30:52 lukem Exp $ */ 2 3/*- 4 * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Greg Oster 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39/* 40 * This program is a re-write of the original rf_ctrl program 41 * distributed by CMU with RAIDframe 1.1. 42 * 43 * This program is the user-land interface to the RAIDframe kernel 44 * driver in NetBSD. 45 */ 46 47#include <sys/param.h> 48#include <sys/ioctl.h> 49#include <sys/stat.h> 50#include <sys/disklabel.h> 51 52#include <ctype.h> 53#include <err.h> 54#include <errno.h> 55#include <fcntl.h> 56#include <stdio.h> 57#include <stdlib.h> 58#include <string.h> 59#include <unistd.h> 60#include <util.h> 61 62#include "rf_raidframe.h" 63 64int main __P((int, char *[])); 65void do_ioctl __P((int, u_long, void *, const char *)); 66static void rf_configure __P((int, char*, int)); 67static const char *device_status __P((RF_DiskStatus_t)); 68static void rf_get_device_status __P((int)); 69static void rf_output_configuration __P((int, const char *)); 70static void get_component_number __P((int, char *, int *, int *)); 71static void rf_fail_disk __P((int, char *, int)); 72static void usage __P((void)); 73static void get_component_label __P((int, char *)); 74static void set_component_label __P((int, char *)); 75static void init_component_labels __P((int, int)); 76static void set_autoconfig __P((int, int, char *)); 77static void add_hot_spare __P((int, char *)); 78static void remove_hot_spare __P((int, char *)); 79static void rebuild_in_place __P((int, char *)); 80static void check_status __P((int,int)); 81static void check_parity __P((int,int, char *)); 82static void do_meter __P((int, u_long)); 83static void get_bar __P((char *, double, int)); 84static void get_time_string __P((char *, int)); 85 86int verbose; 87 88int 89main(argc,argv) 90 int argc; 91 char *argv[]; 92{ 93 int ch; 94 int num_options; 95 unsigned long action; 96 char config_filename[PATH_MAX]; 97 char dev_name[PATH_MAX]; 98 char name[PATH_MAX]; 99 char component[PATH_MAX]; 100 char autoconf[10]; 101 int do_output; 102 int do_recon; 103 int do_rewrite; 104 int is_clean; 105 int raidID; 106 int serial_number; 107 struct stat st; 108 int fd; 109 int force; 110 111 num_options = 0; 112 action = 0; 113 do_output = 0; 114 do_recon = 0; 115 do_rewrite = 0; 116 is_clean = 0; 117 force = 0; 118 119 while ((ch = getopt(argc, argv, "a:A:Bc:C:f:F:g:GiI:l:r:R:sSpPuv")) 120 != -1) 121 switch(ch) { 122 case 'a': 123 action = RAIDFRAME_ADD_HOT_SPARE; 124 strncpy(component, optarg, PATH_MAX); 125 num_options++; 126 break; 127 case 'A': 128 action = RAIDFRAME_SET_AUTOCONFIG; 129 strncpy(autoconf, optarg, 10); 130 num_options++; 131 break; 132 case 'B': 133 action = RAIDFRAME_COPYBACK; 134 num_options++; 135 break; 136 case 'c': 137 action = RAIDFRAME_CONFIGURE; 138 strncpy(config_filename,optarg,PATH_MAX); 139 force = 0; 140 num_options++; 141 break; 142 case 'C': 143 strncpy(config_filename,optarg,PATH_MAX); 144 action = RAIDFRAME_CONFIGURE; 145 force = 1; 146 num_options++; 147 break; 148 case 'f': 149 action = RAIDFRAME_FAIL_DISK; 150 strncpy(component, optarg, PATH_MAX); 151 do_recon = 0; 152 num_options++; 153 break; 154 case 'F': 155 action = RAIDFRAME_FAIL_DISK; 156 strncpy(component, optarg, PATH_MAX); 157 do_recon = 1; 158 num_options++; 159 break; 160 case 'g': 161 action = RAIDFRAME_GET_COMPONENT_LABEL; 162 strncpy(component, optarg, PATH_MAX); 163 num_options++; 164 break; 165 case 'G': 166 action = RAIDFRAME_GET_INFO; 167 do_output = 1; 168 num_options++; 169 break; 170 case 'i': 171 action = RAIDFRAME_REWRITEPARITY; 172 num_options++; 173 break; 174 case 'I': 175 action = RAIDFRAME_INIT_LABELS; 176 serial_number = atoi(optarg); 177 num_options++; 178 break; 179 case 'l': 180 action = RAIDFRAME_SET_COMPONENT_LABEL; 181 strncpy(component, optarg, PATH_MAX); 182 num_options++; 183 break; 184 case 'r': 185 action = RAIDFRAME_REMOVE_HOT_SPARE; 186 strncpy(component, optarg, PATH_MAX); 187 num_options++; 188 break; 189 case 'R': 190 strncpy(component,optarg,PATH_MAX); 191 action = RAIDFRAME_REBUILD_IN_PLACE; 192 num_options++; 193 break; 194 case 's': 195 action = RAIDFRAME_GET_INFO; 196 num_options++; 197 break; 198 case 'S': 199 action = RAIDFRAME_CHECK_RECON_STATUS_EXT; 200 num_options++; 201 break; 202 case 'p': 203 action = RAIDFRAME_CHECK_PARITY; 204 num_options++; 205 break; 206 case 'P': 207 action = RAIDFRAME_CHECK_PARITY; 208 do_rewrite = 1; 209 num_options++; 210 break; 211 case 'u': 212 action = RAIDFRAME_SHUTDOWN; 213 num_options++; 214 break; 215 case 'v': 216 verbose = 1; 217 /* Don't bump num_options, as '-v' is not 218 an option like the others */ 219 /* num_options++; */ 220 break; 221 default: 222 usage(); 223 } 224 argc -= optind; 225 argv += optind; 226 227 if ((num_options > 1) || (argc == NULL)) 228 usage(); 229 230 strncpy(name,argv[0],PATH_MAX); 231 fd = opendisk(name, O_RDWR, dev_name, sizeof(dev_name), 1); 232 if (fd == -1) { 233 fprintf(stderr, "%s: unable to open device file: %s\n", 234 getprogname(), name); 235 exit(1); 236 } 237 if (fstat(fd, &st) != 0) { 238 fprintf(stderr,"%s: stat failure on: %s\n", 239 getprogname(), dev_name); 240 exit(1); 241 } 242 if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) { 243 fprintf(stderr,"%s: invalid device: %s\n", 244 getprogname(), dev_name); 245 exit(1); 246 } 247 248 raidID = RF_DEV2RAIDID(st.st_rdev); 249 250 switch(action) { 251 case RAIDFRAME_ADD_HOT_SPARE: 252 add_hot_spare(fd, component); 253 break; 254 case RAIDFRAME_REMOVE_HOT_SPARE: 255 remove_hot_spare(fd, component); 256 break; 257 case RAIDFRAME_CONFIGURE: 258 rf_configure(fd, config_filename, force); 259 break; 260 case RAIDFRAME_SET_AUTOCONFIG: 261 set_autoconfig(fd, raidID, autoconf); 262 break; 263 case RAIDFRAME_COPYBACK: 264 printf("Copyback.\n"); 265 do_ioctl(fd, RAIDFRAME_COPYBACK, NULL, "RAIDFRAME_COPYBACK"); 266 if (verbose) { 267 sleep(3); /* XXX give the copyback a chance to start */ 268 printf("Copyback status:\n"); 269 do_meter(fd,RAIDFRAME_CHECK_COPYBACK_STATUS_EXT); 270 } 271 break; 272 case RAIDFRAME_FAIL_DISK: 273 rf_fail_disk(fd, component, do_recon); 274 break; 275 case RAIDFRAME_SET_COMPONENT_LABEL: 276 set_component_label(fd, component); 277 break; 278 case RAIDFRAME_GET_COMPONENT_LABEL: 279 get_component_label(fd, component); 280 break; 281 case RAIDFRAME_INIT_LABELS: 282 init_component_labels(fd, serial_number); 283 break; 284 case RAIDFRAME_REWRITEPARITY: 285 printf("Initiating re-write of parity\n"); 286 do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL, 287 "RAIDFRAME_REWRITEPARITY"); 288 if (verbose) { 289 sleep(3); /* XXX give it time to get started */ 290 printf("Parity Re-write status:\n"); 291 do_meter(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT); 292 } 293 break; 294 case RAIDFRAME_CHECK_RECON_STATUS_EXT: 295 check_status(fd,1); 296 break; 297 case RAIDFRAME_GET_INFO: 298 if (do_output) 299 rf_output_configuration(fd, dev_name); 300 else 301 rf_get_device_status(fd); 302 break; 303 case RAIDFRAME_REBUILD_IN_PLACE: 304 rebuild_in_place(fd, component); 305 break; 306 case RAIDFRAME_CHECK_PARITY: 307 check_parity(fd, do_rewrite, dev_name); 308 break; 309 case RAIDFRAME_SHUTDOWN: 310 do_ioctl(fd, RAIDFRAME_SHUTDOWN, NULL, "RAIDFRAME_SHUTDOWN"); 311 break; 312 default: 313 break; 314 } 315 316 close(fd); 317 exit(0); 318} 319 320void 321do_ioctl(fd, command, arg, ioctl_name) 322 int fd; 323 unsigned long command; 324 void *arg; 325 const char *ioctl_name; 326{ 327 if (ioctl(fd, command, arg) < 0) { 328 warn("ioctl (%s) failed", ioctl_name); 329 exit(1); 330 } 331} 332 333 334static void 335rf_configure(fd,config_file,force) 336 int fd; 337 char *config_file; 338 int force; 339{ 340 void *generic; 341 RF_Config_t cfg; 342 343 if (rf_MakeConfig( config_file, &cfg ) != 0) { 344 fprintf(stderr,"%s: unable to create RAIDframe %s\n", 345 getprogname(), "configuration structure\n"); 346 exit(1); 347 } 348 349 cfg.force = force; 350 351 /* 352 * Note the extra level of redirection needed here, since 353 * what we really want to pass in is a pointer to the pointer to 354 * the configuration structure. 355 */ 356 357 generic = (void *) &cfg; 358 do_ioctl(fd, RAIDFRAME_CONFIGURE, &generic, "RAIDFRAME_CONFIGURE"); 359} 360 361static const char * 362device_status(status) 363 RF_DiskStatus_t status; 364{ 365 366 switch (status) { 367 case rf_ds_optimal: 368 return ("optimal"); 369 break; 370 case rf_ds_failed: 371 return ("failed"); 372 break; 373 case rf_ds_reconstructing: 374 return ("reconstructing"); 375 break; 376 case rf_ds_dist_spared: 377 return ("dist_spared"); 378 break; 379 case rf_ds_spared: 380 return ("spared"); 381 break; 382 case rf_ds_spare: 383 return ("spare"); 384 break; 385 case rf_ds_used_spare: 386 return ("used_spare"); 387 break; 388 default: 389 return ("UNKNOWN"); 390 } 391 /* NOTREACHED */ 392} 393 394static void 395rf_get_device_status(fd) 396 int fd; 397{ 398 RF_DeviceConfig_t device_config; 399 void *cfg_ptr; 400 int is_clean; 401 int i; 402 403 cfg_ptr = &device_config; 404 405 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO"); 406 407 printf("Components:\n"); 408 for(i=0; i < device_config.ndevs; i++) { 409 printf("%20s: %s\n", device_config.devs[i].devname, 410 device_status(device_config.devs[i].status)); 411 } 412 if (device_config.nspares > 0) { 413 printf("Spares:\n"); 414 for(i=0; i < device_config.nspares; i++) { 415 printf("%20s: %s\n", 416 device_config.spares[i].devname, 417 device_status(device_config.spares[i].status)); 418 } 419 } else { 420 printf("No spares.\n"); 421 } 422 for(i=0; i < device_config.ndevs; i++) { 423 if (device_config.devs[i].status == rf_ds_optimal) { 424 get_component_label(fd, device_config.devs[i].devname); 425 } else { 426 printf("%s status is: %s. Skipping label.\n", 427 device_config.devs[i].devname, 428 device_status(device_config.devs[i].status)); 429 } 430 } 431 432 if (device_config.nspares > 0) { 433 for(i=0; i < device_config.nspares; i++) { 434 if ((device_config.spares[i].status == 435 rf_ds_optimal) || 436 (device_config.spares[i].status == 437 rf_ds_used_spare)) { 438 get_component_label(fd, 439 device_config.spares[i].devname); 440 } else { 441 printf("%s status is: %s. Skipping label.\n", 442 device_config.spares[i].devname, 443 device_status(device_config.spares[i].status)); 444 } 445 } 446 } 447 448 do_ioctl(fd, RAIDFRAME_CHECK_PARITY, &is_clean, 449 "RAIDFRAME_CHECK_PARITY"); 450 if (is_clean) { 451 printf("Parity status: clean\n"); 452 } else { 453 printf("Parity status: DIRTY\n"); 454 } 455 check_status(fd,0); 456} 457 458static void 459rf_output_configuration(fd, name) 460 int fd; 461 const char *name; 462{ 463 RF_DeviceConfig_t device_config; 464 void *cfg_ptr; 465 int i; 466 RF_ComponentLabel_t component_label; 467 void *label_ptr; 468 int component_num; 469 int num_cols; 470 471 cfg_ptr = &device_config; 472 473 printf("# raidctl config file for %s\n", name); 474 printf("\n"); 475 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO"); 476 477 printf("START array\n"); 478 printf("# numRow numCol numSpare\n"); 479 printf("%d %d %d\n", device_config.rows, device_config.cols, 480 device_config.nspares); 481 printf("\n"); 482 483 printf("START disks\n"); 484 for(i=0; i < device_config.ndevs; i++) 485 printf("%s\n", device_config.devs[i].devname); 486 printf("\n"); 487 488 if (device_config.nspares > 0) { 489 printf("START spare\n"); 490 for(i=0; i < device_config.nspares; i++) 491 printf("%s\n", device_config.spares[i].devname); 492 printf("\n"); 493 } 494 495 for(i=0; i < device_config.ndevs; i++) { 496 if (device_config.devs[i].status == rf_ds_optimal) 497 break; 498 } 499 if (i == device_config.ndevs) { 500 printf("# WARNING: no optimal components; using %s\n", 501 device_config.devs[0].devname); 502 i = 0; 503 } 504 get_component_number(fd, device_config.devs[i].devname, 505 &component_num, &num_cols); 506 memset(&component_label, 0, sizeof(RF_ComponentLabel_t)); 507 component_label.row = component_num / num_cols; 508 component_label.column = component_num % num_cols; 509 label_ptr = &component_label; 510 do_ioctl(fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr, 511 "RAIDFRAME_GET_COMPONENT_LABEL"); 512 513 printf("START layout\n"); 514 printf( 515 "# sectPerSU SUsPerParityUnit SUsPerReconUnit RAID_level_%c\n", 516 (char) component_label.parityConfig); 517 printf("%d %d %d %c\n", 518 component_label.sectPerSU, component_label.SUsPerPU, 519 component_label.SUsPerRU, (char) component_label.parityConfig); 520 printf("\n"); 521 522 printf("START queue\n"); 523 printf("fifo %d\n", device_config.maxqdepth); 524} 525 526static void 527get_component_number(fd, component_name, component_number, num_columns) 528 int fd; 529 char *component_name; 530 int *component_number; 531 int *num_columns; 532{ 533 RF_DeviceConfig_t device_config; 534 void *cfg_ptr; 535 int i; 536 int found; 537 538 *component_number = -1; 539 540 /* Assuming a full path spec... */ 541 cfg_ptr = &device_config; 542 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, 543 "RAIDFRAME_GET_INFO"); 544 545 *num_columns = device_config.cols; 546 547 found = 0; 548 for(i=0; i < device_config.ndevs; i++) { 549 if (strncmp(component_name, device_config.devs[i].devname, 550 PATH_MAX)==0) { 551 found = 1; 552 *component_number = i; 553 } 554 } 555 if (!found) { /* maybe it's a spare? */ 556 for(i=0; i < device_config.nspares; i++) { 557 if (strncmp(component_name, 558 device_config.spares[i].devname, 559 PATH_MAX)==0) { 560 found = 1; 561 *component_number = i + device_config.ndevs; 562 /* the way spares are done should 563 really change... */ 564 *num_columns = device_config.cols + 565 device_config.nspares; 566 } 567 } 568 } 569 570 if (!found) { 571 fprintf(stderr,"%s: %s is not a component %s", getprogname(), 572 component_name, "of this device\n"); 573 exit(1); 574 } 575} 576 577static void 578rf_fail_disk(fd, component_to_fail, do_recon) 579 int fd; 580 char *component_to_fail; 581 int do_recon; 582{ 583 struct rf_recon_req recon_request; 584 int component_num; 585 int num_cols; 586 587 get_component_number(fd, component_to_fail, &component_num, &num_cols); 588 589 recon_request.row = component_num / num_cols; 590 recon_request.col = component_num % num_cols; 591 if (do_recon) { 592 recon_request.flags = RF_FDFLAGS_RECON; 593 } else { 594 recon_request.flags = RF_FDFLAGS_NONE; 595 } 596 do_ioctl(fd, RAIDFRAME_FAIL_DISK, &recon_request, 597 "RAIDFRAME_FAIL_DISK"); 598 if (do_recon && verbose) { 599 printf("Reconstruction status:\n"); 600 sleep(3); /* XXX give reconstruction a chance to start */ 601 do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS_EXT); 602 } 603} 604 605static void 606get_component_label(fd, component) 607 int fd; 608 char *component; 609{ 610 RF_ComponentLabel_t component_label; 611 void *label_ptr; 612 int component_num; 613 int num_cols; 614 615 get_component_number(fd, component, &component_num, &num_cols); 616 617 memset( &component_label, 0, sizeof(RF_ComponentLabel_t)); 618 component_label.row = component_num / num_cols; 619 component_label.column = component_num % num_cols; 620 621 label_ptr = &component_label; 622 do_ioctl( fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr, 623 "RAIDFRAME_GET_COMPONENT_LABEL"); 624 625 printf("Component label for %s:\n",component); 626 627 printf(" Row: %d, Column: %d, Num Rows: %d, Num Columns: %d\n", 628 component_label.row, component_label.column, 629 component_label.num_rows, component_label.num_columns); 630 printf(" Version: %d, Serial Number: %d, Mod Counter: %d\n", 631 component_label.version, component_label.serial_number, 632 component_label.mod_counter); 633 printf(" Clean: %s, Status: %d\n", 634 component_label.clean ? "Yes" : "No", 635 component_label.status ); 636 printf(" sectPerSU: %d, SUsPerPU: %d, SUsPerRU: %d\n", 637 component_label.sectPerSU, component_label.SUsPerPU, 638 component_label.SUsPerRU); 639 printf(" Queue size: %d, blocksize: %d, numBlocks: %d\n", 640 component_label.maxOutstanding, component_label.blockSize, 641 component_label.numBlocks); 642 printf(" RAID Level: %c\n", (char) component_label.parityConfig); 643 printf(" Autoconfig: %s\n", 644 component_label.autoconfigure ? "Yes" : "No" ); 645 printf(" Root partition: %s\n", 646 component_label.root_partition ? "Yes" : "No" ); 647 printf(" Last configured as: raid%d\n", component_label.last_unit ); 648} 649 650static void 651set_component_label(fd, component) 652 int fd; 653 char *component; 654{ 655 RF_ComponentLabel_t component_label; 656 int component_num; 657 int num_cols; 658 659 get_component_number(fd, component, &component_num, &num_cols); 660 661 /* XXX This is currently here for testing, and future expandability */ 662 663 component_label.version = 1; 664 component_label.serial_number = 123456; 665 component_label.mod_counter = 0; 666 component_label.row = component_num / num_cols; 667 component_label.column = component_num % num_cols; 668 component_label.num_rows = 0; 669 component_label.num_columns = 5; 670 component_label.clean = 0; 671 component_label.status = 1; 672 673 do_ioctl( fd, RAIDFRAME_SET_COMPONENT_LABEL, &component_label, 674 "RAIDFRAME_SET_COMPONENT_LABEL"); 675} 676 677 678static void 679init_component_labels(fd, serial_number) 680 int fd; 681 int serial_number; 682{ 683 RF_ComponentLabel_t component_label; 684 685 component_label.version = 0; 686 component_label.serial_number = serial_number; 687 component_label.mod_counter = 0; 688 component_label.row = 0; 689 component_label.column = 0; 690 component_label.num_rows = 0; 691 component_label.num_columns = 0; 692 component_label.clean = 0; 693 component_label.status = 0; 694 695 do_ioctl( fd, RAIDFRAME_INIT_LABELS, &component_label, 696 "RAIDFRAME_SET_COMPONENT_LABEL"); 697} 698 699static void 700set_autoconfig(fd, raidID, autoconf) 701 int fd; 702 int raidID; 703 char *autoconf; 704{ 705 int auto_config; 706 int root_config; 707 708 auto_config = 0; 709 root_config = 0; 710 711 if (strncasecmp(autoconf,"root", 4) == 0) { 712 root_config = 1; 713 } 714 715 if ((strncasecmp(autoconf,"yes", 3) == 0) || 716 root_config == 1) { 717 auto_config = 1; 718 } 719 720 do_ioctl(fd, RAIDFRAME_SET_AUTOCONFIG, &auto_config, 721 "RAIDFRAME_SET_AUTOCONFIG"); 722 723 do_ioctl(fd, RAIDFRAME_SET_ROOT, &root_config, 724 "RAIDFRAME_SET_ROOT"); 725 726 printf("raid%d: Autoconfigure: %s\n", raidID, 727 auto_config ? "Yes" : "No"); 728 729 if (root_config == 1) { 730 printf("raid%d: Root: %s\n", raidID, 731 auto_config ? "Yes" : "No"); 732 } 733} 734 735static void 736add_hot_spare(fd, component) 737 int fd; 738 char *component; 739{ 740 RF_SingleComponent_t hot_spare; 741 742 hot_spare.row = 0; 743 hot_spare.column = 0; 744 strncpy(hot_spare.component_name, component, 745 sizeof(hot_spare.component_name)); 746 747 do_ioctl( fd, RAIDFRAME_ADD_HOT_SPARE, &hot_spare, 748 "RAIDFRAME_ADD_HOT_SPARE"); 749} 750 751static void 752remove_hot_spare(fd, component) 753 int fd; 754 char *component; 755{ 756 RF_SingleComponent_t hot_spare; 757 int component_num; 758 int num_cols; 759 760 get_component_number(fd, component, &component_num, &num_cols); 761 762 hot_spare.row = component_num / num_cols; 763 hot_spare.column = component_num % num_cols; 764 765 strncpy(hot_spare.component_name, component, 766 sizeof(hot_spare.component_name)); 767 768 do_ioctl( fd, RAIDFRAME_REMOVE_HOT_SPARE, &hot_spare, 769 "RAIDFRAME_REMOVE_HOT_SPARE"); 770} 771 772static void 773rebuild_in_place( fd, component ) 774 int fd; 775 char *component; 776{ 777 RF_SingleComponent_t comp; 778 int component_num; 779 int num_cols; 780 781 get_component_number(fd, component, &component_num, &num_cols); 782 783 comp.row = 0; 784 comp.column = component_num; 785 strncpy(comp.component_name, component, sizeof(comp.component_name)); 786 787 do_ioctl( fd, RAIDFRAME_REBUILD_IN_PLACE, &comp, 788 "RAIDFRAME_REBUILD_IN_PLACE"); 789 790 if (verbose) { 791 printf("Reconstruction status:\n"); 792 sleep(3); /* XXX give reconstruction a chance to start */ 793 do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS_EXT); 794 } 795 796} 797 798static void 799check_parity( fd, do_rewrite, dev_name ) 800 int fd; 801 int do_rewrite; 802 char *dev_name; 803{ 804 int is_clean; 805 int percent_done; 806 807 is_clean = 0; 808 percent_done = 0; 809 do_ioctl(fd, RAIDFRAME_CHECK_PARITY, &is_clean, 810 "RAIDFRAME_CHECK_PARITY"); 811 if (is_clean) { 812 printf("%s: Parity status: clean\n",dev_name); 813 } else { 814 printf("%s: Parity status: DIRTY\n",dev_name); 815 if (do_rewrite) { 816 printf("%s: Initiating re-write of parity\n", 817 dev_name); 818 do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL, 819 "RAIDFRAME_REWRITEPARITY"); 820 sleep(3); /* XXX give it time to 821 get started. */ 822 if (verbose) { 823 printf("Parity Re-write status:\n"); 824 do_meter(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT); 825 } else { 826 do_ioctl(fd, 827 RAIDFRAME_CHECK_PARITYREWRITE_STATUS, 828 &percent_done, 829 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS" 830 ); 831 while( percent_done < 100 ) { 832 sleep(3); /* wait a bit... */ 833 do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS, 834 &percent_done, "RAIDFRAME_CHECK_PARITYREWRITE_STATUS"); 835 } 836 837 } 838 printf("%s: Parity Re-write complete\n", 839 dev_name); 840 } else { 841 /* parity is wrong, and is not being fixed. 842 Exit w/ an error. */ 843 exit(1); 844 } 845 } 846} 847 848 849static void 850check_status( fd, meter ) 851 int fd; 852 int meter; 853{ 854 int recon_percent_done = 0; 855 int parity_percent_done = 0; 856 int copyback_percent_done = 0; 857 858 do_ioctl(fd, RAIDFRAME_CHECK_RECON_STATUS, &recon_percent_done, 859 "RAIDFRAME_CHECK_RECON_STATUS"); 860 printf("Reconstruction is %d%% complete.\n", recon_percent_done); 861 do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS, 862 &parity_percent_done, 863 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS"); 864 printf("Parity Re-write is %d%% complete.\n", parity_percent_done); 865 do_ioctl(fd, RAIDFRAME_CHECK_COPYBACK_STATUS, ©back_percent_done, 866 "RAIDFRAME_CHECK_COPYBACK_STATUS"); 867 printf("Copyback is %d%% complete.\n", copyback_percent_done); 868 869 if (meter) { 870 /* These 3 should be mutually exclusive at this point */ 871 if (recon_percent_done < 100) { 872 printf("Reconstruction status:\n"); 873 do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS_EXT); 874 } else if (parity_percent_done < 100) { 875 printf("Parity Re-write status:\n"); 876 do_meter(fd,RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT); 877 } else if (copyback_percent_done < 100) { 878 printf("Copyback status:\n"); 879 do_meter(fd,RAIDFRAME_CHECK_COPYBACK_STATUS_EXT); 880 } 881 } 882} 883 884const char *tbits = "|/-\\"; 885 886static void 887do_meter(fd, option) 888 int fd; 889 u_long option; 890{ 891 int percent_done; 892 int last_value; 893 int start_value; 894 RF_ProgressInfo_t progressInfo; 895 void *pInfoPtr; 896 struct timeval start_time; 897 struct timeval last_time; 898 struct timeval current_time; 899 double elapsed; 900 int elapsed_sec; 901 int elapsed_usec; 902 int simple_eta,last_eta; 903 double rate; 904 int amount; 905 int tbit_value; 906 int wait_for_more_data; 907 char buffer[1024]; 908 char bar_buffer[1024]; 909 char eta_buffer[1024]; 910 911 if (gettimeofday(&start_time,NULL)) { 912 fprintf(stderr,"%s: gettimeofday failed!?!?\n", getprogname()); 913 exit(errno); 914 } 915 memset(&progressInfo, 0, sizeof(RF_ProgressInfo_t)); 916 pInfoPtr=&progressInfo; 917 918 percent_done = 0; 919 do_ioctl(fd, option, &pInfoPtr, ""); 920 last_value = progressInfo.completed; 921 start_value = last_value; 922 last_time = start_time; 923 current_time = start_time; 924 925 wait_for_more_data = 0; 926 tbit_value = 0; 927 while(progressInfo.completed < progressInfo.total) { 928 929 percent_done = (progressInfo.completed * 100) / 930 progressInfo.total; 931 932 get_bar(bar_buffer, percent_done, 40); 933 934 elapsed_sec = current_time.tv_sec - start_time.tv_sec; 935 elapsed_usec = current_time.tv_usec - start_time.tv_usec; 936 if (elapsed_usec < 0) { 937 elapsed_usec-=1000000; 938 elapsed_sec++; 939 } 940 941 elapsed = (double) elapsed_sec + 942 (double) elapsed_usec / 1000000.0; 943 944 amount = progressInfo.completed - start_value; 945 946 if (amount <= 0) { /* we don't do negatives (yet?) */ 947 amount = 0; 948 wait_for_more_data = 1; 949 } else { 950 wait_for_more_data = 0; 951 } 952 953 if (elapsed == 0) 954 rate = 0.0; 955 else 956 rate = amount / elapsed; 957 958 if (rate > 0.0) { 959 simple_eta = (int) (((double)progressInfo.total - 960 (double) progressInfo.completed) 961 / rate); 962 } else { 963 simple_eta = -1; 964 } 965 966 if (simple_eta <=0) { 967 simple_eta = last_eta; 968 } else { 969 last_eta = simple_eta; 970 } 971 972 get_time_string(eta_buffer, simple_eta); 973 974 snprintf(buffer,1024,"\r%3d%% |%s| ETA: %s %c", 975 percent_done,bar_buffer,eta_buffer,tbits[tbit_value]); 976 977 write(fileno(stdout),buffer,strlen(buffer)); 978 fflush(stdout); 979 980 /* resolution wasn't high enough... wait until we get another 981 timestamp and perhaps more "work" done. */ 982 983 if (!wait_for_more_data) { 984 last_time = current_time; 985 last_value = progressInfo.completed; 986 } 987 988 if (++tbit_value>3) 989 tbit_value = 0; 990 991 sleep(2); 992 993 if (gettimeofday(¤t_time,NULL)) { 994 fprintf(stderr,"%s: gettimeofday failed!?!?\n", 995 getprogname()); 996 exit(errno); 997 } 998 999 do_ioctl( fd, option, &pInfoPtr, ""); 1000 1001 1002 } 1003 printf("\n"); 1004} 1005/* 40 '*''s per line, then 40 ' ''s line. */ 1006/* If you've got a screen wider than 160 characters, "tough" */ 1007 1008#define STAR_MIDPOINT 4*40 1009const char stars[] = "****************************************" 1010 "****************************************" 1011 "****************************************" 1012 "****************************************" 1013 " " 1014 " " 1015 " " 1016 " " 1017 " "; 1018 1019static void 1020get_bar(string,percent,max_strlen) 1021 char *string; 1022 double percent; 1023 int max_strlen; 1024{ 1025 int offset; 1026 1027 if (max_strlen > STAR_MIDPOINT) { 1028 max_strlen = STAR_MIDPOINT; 1029 } 1030 offset = STAR_MIDPOINT - 1031 (int)((percent * max_strlen)/ 100); 1032 if (offset < 0) 1033 offset = 0; 1034 snprintf(string,max_strlen,"%s",&stars[offset]); 1035} 1036 1037static void 1038get_time_string(string,simple_time) 1039 char *string; 1040 int simple_time; 1041{ 1042 int minutes, seconds, hours; 1043 char hours_buffer[5]; 1044 char minutes_buffer[5]; 1045 char seconds_buffer[5]; 1046 1047 if (simple_time >= 0) { 1048 1049 minutes = (int) simple_time / 60; 1050 seconds = ((int)simple_time - 60*minutes); 1051 hours = minutes / 60; 1052 minutes = minutes - 60*hours; 1053 1054 if (hours > 0) { 1055 snprintf(hours_buffer,5,"%02d:",hours); 1056 } else { 1057 snprintf(hours_buffer,5," "); 1058 } 1059 1060 snprintf(minutes_buffer,5,"%02d:",minutes); 1061 snprintf(seconds_buffer,5,"%02d",seconds); 1062 snprintf(string,1024,"%s%s%s", 1063 hours_buffer, minutes_buffer, seconds_buffer); 1064 } else { 1065 snprintf(string,1024," --:--"); 1066 } 1067 1068} 1069 1070static void 1071usage() 1072{ 1073 const char *progname = getprogname(); 1074 1075 fprintf(stderr, "usage: %s [-v] -a component dev\n", progname); 1076 fprintf(stderr, " %s [-v] -A yes | no | root dev\n", progname); 1077 fprintf(stderr, " %s [-v] -B dev\n", progname); 1078 fprintf(stderr, " %s [-v] -c config_file dev\n", progname); 1079 fprintf(stderr, " %s [-v] -C config_file dev\n", progname); 1080 fprintf(stderr, " %s [-v] -f component dev\n", progname); 1081 fprintf(stderr, " %s [-v] -F component dev\n", progname); 1082 fprintf(stderr, " %s [-v] -g component dev\n", progname); 1083 fprintf(stderr, " %s [-v] -G dev\n", progname); 1084 fprintf(stderr, " %s [-v] -i dev\n", progname); 1085 fprintf(stderr, " %s [-v] -I serial_number dev\n", progname); 1086 fprintf(stderr, " %s [-v] -r component dev\n", progname); 1087 fprintf(stderr, " %s [-v] -R component dev\n", progname); 1088 fprintf(stderr, " %s [-v] -s dev\n", progname); 1089 fprintf(stderr, " %s [-v] -S dev\n", progname); 1090 fprintf(stderr, " %s [-v] -u dev\n", progname); 1091#if 0 1092 fprintf(stderr, "usage: %s %s\n", progname, 1093 "-a | -f | -F | -g | -r | -R component dev"); 1094 fprintf(stderr, " %s -B | -i | -s | -S -u dev\n", progname); 1095 fprintf(stderr, " %s -c | -C config_file dev\n", progname); 1096 fprintf(stderr, " %s -I serial_number dev\n", progname); 1097#endif 1098 exit(1); 1099 /* NOTREACHED */ 1100} 1101