1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * ZFS Fault Injector 28 * 29 * This userland component takes a set of options and uses libzpool to translate 30 * from a user-visible object type and name to an internal representation. 31 * There are two basic types of faults: device faults and data faults. 32 * 33 * 34 * DEVICE FAULTS 35 * 36 * Errors can be injected into a particular vdev using the '-d' option. This 37 * option takes a path or vdev GUID to uniquely identify the device within a 38 * pool. There are two types of errors that can be injected, EIO and ENXIO, 39 * that can be controlled through the '-e' option. The default is ENXIO. For 40 * EIO failures, any attempt to read data from the device will return EIO, but 41 * subsequent attempt to reopen the device will succeed. For ENXIO failures, 42 * any attempt to read from the device will return EIO, but any attempt to 43 * reopen the device will also return ENXIO. 44 * For label faults, the -L option must be specified. This allows faults 45 * to be injected into either the nvlist or uberblock region of all the labels 46 * for the specified device. 47 * 48 * This form of the command looks like: 49 * 50 * zinject -d device [-e errno] [-L <uber | nvlist>] pool 51 * 52 * 53 * DATA FAULTS 54 * 55 * We begin with a tuple of the form: 56 * 57 * <type,level,range,object> 58 * 59 * type A string describing the type of data to target. Each type 60 * implicitly describes how to interpret 'object'. Currently, 61 * the following values are supported: 62 * 63 * data User data for a file 64 * dnode Dnode for a file or directory 65 * 66 * The following MOS objects are special. Instead of injecting 67 * errors on a particular object or blkid, we inject errors across 68 * all objects of the given type. 69 * 70 * mos Any data in the MOS 71 * mosdir object directory 72 * config pool configuration 73 * bplist blkptr list 74 * spacemap spacemap 75 * metaslab metaslab 76 * errlog persistent error log 77 * 78 * level Object level. Defaults to '0', not applicable to all types. If 79 * a range is given, this corresponds to the indirect block 80 * corresponding to the specific range. 81 * 82 * range A numerical range [start,end) within the object. Defaults to 83 * the full size of the file. 84 * 85 * object A string describing the logical location of the object. For 86 * files and directories (currently the only supported types), 87 * this is the path of the object on disk. 88 * 89 * This is translated, via libzpool, into the following internal representation: 90 * 91 * <type,objset,object,level,range> 92 * 93 * These types should be self-explanatory. This tuple is then passed to the 94 * kernel via a special ioctl() to initiate fault injection for the given 95 * object. Note that 'type' is not strictly necessary for fault injection, but 96 * is used when translating existing faults into a human-readable string. 97 * 98 * 99 * The command itself takes one of the forms: 100 * 101 * zinject 102 * zinject <-a | -u pool> 103 * zinject -c <id|all> 104 * zinject [-q] <-t type> [-f freq] [-u] [-a] [-m] [-e errno] [-l level] 105 * [-r range] <object> 106 * zinject [-f freq] [-a] [-m] [-u] -b objset:object:level:start:end pool 107 * 108 * With no arguments, the command prints all currently registered injection 109 * handlers, with their numeric identifiers. 110 * 111 * The '-c' option will clear the given handler, or all handlers if 'all' is 112 * specified. 113 * 114 * The '-e' option takes a string describing the errno to simulate. This must 115 * be either 'io' or 'checksum'. In most cases this will result in the same 116 * behavior, but RAID-Z will produce a different set of ereports for this 117 * situation. 118 * 119 * The '-a', '-u', and '-m' flags toggle internal flush behavior. If '-a' is 120 * specified, then the ARC cache is flushed appropriately. If '-u' is 121 * specified, then the underlying SPA is unloaded. Either of these flags can be 122 * specified independently of any other handlers. The '-m' flag automatically 123 * does an unmount and remount of the underlying dataset to aid in flushing the 124 * cache. 125 * 126 * The '-f' flag controls the frequency of errors injected, expressed as a 127 * integer percentage between 1 and 100. The default is 100. 128 * 129 * The this form is responsible for actually injecting the handler into the 130 * framework. It takes the arguments described above, translates them to the 131 * internal tuple using libzpool, and then issues an ioctl() to register the 132 * handler. 133 * 134 * The final form can target a specific bookmark, regardless of whether a 135 * human-readable interface has been designed. It allows developers to specify 136 * a particular block by number. 137 */ 138 139 #include <errno.h> 140 #include <fcntl.h> 141 #include <stdio.h> 142 #include <stdlib.h> 143 #include <strings.h> 144 #include <unistd.h> 145 146 #include <sys/fs/zfs.h> 147 #include <sys/mount.h> 148 149 #include <libzfs.h> 150 151 #undef verify /* both libzfs.h and zfs_context.h want to define this */ 152 153 #include "zinject.h" 154 155 libzfs_handle_t *g_zfs; 156 int zfs_fd; 157 158 #define ECKSUM EBADE 159 160 static const char *errtable[TYPE_INVAL] = { 161 "data", 162 "dnode", 163 "mos", 164 "mosdir", 165 "metaslab", 166 "config", 167 "bplist", 168 "spacemap", 169 "errlog", 170 "uber", 171 "nvlist" 172 }; 173 174 static err_type_t 175 name_to_type(const char *arg) 176 { 177 int i; 178 for (i = 0; i < TYPE_INVAL; i++) 179 if (strcmp(errtable[i], arg) == 0) 180 return (i); 181 182 return (TYPE_INVAL); 183 } 184 185 static const char * 186 type_to_name(uint64_t type) 187 { 188 switch (type) { 189 case DMU_OT_OBJECT_DIRECTORY: 190 return ("mosdir"); 191 case DMU_OT_OBJECT_ARRAY: 192 return ("metaslab"); 193 case DMU_OT_PACKED_NVLIST: 194 return ("config"); 195 case DMU_OT_BPLIST: 196 return ("bplist"); 197 case DMU_OT_SPACE_MAP: 198 return ("spacemap"); 199 case DMU_OT_ERROR_LOG: 200 return ("errlog"); 201 default: 202 return ("-"); 203 } 204 } 205 206 207 /* 208 * Print usage message. 209 */ 210 void 211 usage(void) 212 { 213 (void) printf( 214 "usage:\n" 215 "\n" 216 "\tzinject\n" 217 "\n" 218 "\t\tList all active injection records.\n" 219 "\n" 220 "\tzinject -c <id|all>\n" 221 "\n" 222 "\t\tClear the particular record (if given a numeric ID), or\n" 223 "\t\tall records if 'all' is specificed.\n" 224 "\n" 225 "\tzinject -p <function name> pool\n" 226 "\t\tInject a panic fault at the specified function. Only \n" 227 "\t\tfunctions which call spa_vdev_config_exit(), or \n" 228 "\t\tspa_vdev_exit() will trigger a panic.\n" 229 "\n" 230 "\tzinject -d device [-e errno] [-L <nvlist|uber>] [-F] pool\n" 231 "\t\tInject a fault into a particular device or the device's\n" 232 "\t\tlabel. Label injection can either be 'nvlist' or 'uber'.\n" 233 "\t\t'errno' can either be 'nxio' (the default) or 'io'.\n" 234 "\n" 235 "\tzinject -b objset:object:level:blkid pool\n" 236 "\n" 237 "\t\tInject an error into pool 'pool' with the numeric bookmark\n" 238 "\t\tspecified by the remaining tuple. Each number is in\n" 239 "\t\thexidecimal, and only one block can be specified.\n" 240 "\n" 241 "\tzinject [-q] <-t type> [-e errno] [-l level] [-r range]\n" 242 "\t [-a] [-m] [-u] [-f freq] <object>\n" 243 "\n" 244 "\t\tInject an error into the object specified by the '-t' option\n" 245 "\t\tand the object descriptor. The 'object' parameter is\n" 246 "\t\tinterperted depending on the '-t' option.\n" 247 "\n" 248 "\t\t-q\tQuiet mode. Only print out the handler number added.\n" 249 "\t\t-e\tInject a specific error. Must be either 'io' or\n" 250 "\t\t\t'checksum'. Default is 'io'.\n" 251 "\t\t-l\tInject error at a particular block level. Default is " 252 "0.\n" 253 "\t\t-m\tAutomatically remount underlying filesystem.\n" 254 "\t\t-r\tInject error over a particular logical range of an\n" 255 "\t\t\tobject. Will be translated to the appropriate blkid\n" 256 "\t\t\trange according to the object's properties.\n" 257 "\t\t-a\tFlush the ARC cache. Can be specified without any\n" 258 "\t\t\tassociated object.\n" 259 "\t\t-u\tUnload the associated pool. Can be specified with only\n" 260 "\t\t\ta pool object.\n" 261 "\t\t-f\tOnly inject errors a fraction of the time. Expressed as\n" 262 "\t\t\ta percentage between 1 and 100.\n" 263 "\n" 264 "\t-t data\t\tInject an error into the plain file contents of a\n" 265 "\t\t\tfile. The object must be specified as a complete path\n" 266 "\t\t\tto a file on a ZFS filesystem.\n" 267 "\n" 268 "\t-t dnode\tInject an error into the metadnode in the block\n" 269 "\t\t\tcorresponding to the dnode for a file or directory. The\n" 270 "\t\t\t'-r' option is incompatible with this mode. The object\n" 271 "\t\t\tis specified as a complete path to a file or directory\n" 272 "\t\t\ton a ZFS filesystem.\n" 273 "\n" 274 "\t-t <mos>\tInject errors into the MOS for objects of the given\n" 275 "\t\t\ttype. Valid types are: mos, mosdir, config, bplist,\n" 276 "\t\t\tspacemap, metaslab, errlog. The only valid <object> is\n" 277 "\t\t\tthe poolname.\n"); 278 } 279 280 static int 281 iter_handlers(int (*func)(int, const char *, zinject_record_t *, void *), 282 void *data) 283 { 284 zfs_cmd_t zc; 285 int ret; 286 287 zc.zc_guid = 0; 288 289 while (ioctl(zfs_fd, ZFS_IOC_INJECT_LIST_NEXT, &zc) == 0) 290 if ((ret = func((int)zc.zc_guid, zc.zc_name, 291 &zc.zc_inject_record, data)) != 0) 292 return (ret); 293 294 return (0); 295 } 296 297 static int 298 print_data_handler(int id, const char *pool, zinject_record_t *record, 299 void *data) 300 { 301 int *count = data; 302 303 if (record->zi_guid != 0 || record->zi_func[0] != '\0') 304 return (0); 305 306 if (*count == 0) { 307 (void) printf("%3s %-15s %-6s %-6s %-8s %3s %-15s\n", 308 "ID", "POOL", "OBJSET", "OBJECT", "TYPE", "LVL", "RANGE"); 309 (void) printf("--- --------------- ------ " 310 "------ -------- --- ---------------\n"); 311 } 312 313 *count += 1; 314 315 (void) printf("%3d %-15s %-6llu %-6llu %-8s %3d ", id, pool, 316 (u_longlong_t)record->zi_objset, (u_longlong_t)record->zi_object, 317 type_to_name(record->zi_type), record->zi_level); 318 319 if (record->zi_start == 0 && 320 record->zi_end == -1ULL) 321 (void) printf("all\n"); 322 else 323 (void) printf("[%llu, %llu]\n", (u_longlong_t)record->zi_start, 324 (u_longlong_t)record->zi_end); 325 326 return (0); 327 } 328 329 static int 330 print_device_handler(int id, const char *pool, zinject_record_t *record, 331 void *data) 332 { 333 int *count = data; 334 335 if (record->zi_guid == 0 || record->zi_func[0] != '\0') 336 return (0); 337 338 if (*count == 0) { 339 (void) printf("%3s %-15s %s\n", "ID", "POOL", "GUID"); 340 (void) printf("--- --------------- ----------------\n"); 341 } 342 343 *count += 1; 344 345 (void) printf("%3d %-15s %llx\n", id, pool, 346 (u_longlong_t)record->zi_guid); 347 348 return (0); 349 } 350 351 static int 352 print_panic_handler(int id, const char *pool, zinject_record_t *record, 353 void *data) 354 { 355 int *count = data; 356 357 if (record->zi_func[0] == '\0') 358 return (0); 359 360 if (*count == 0) { 361 (void) printf("%3s %-15s %s\n", "ID", "POOL", "FUNCTION"); 362 (void) printf("--- --------------- ----------------\n"); 363 } 364 365 *count += 1; 366 367 (void) printf("%3d %-15s %s\n", id, pool, record->zi_func); 368 369 return (0); 370 } 371 372 /* 373 * Print all registered error handlers. Returns the number of handlers 374 * registered. 375 */ 376 static int 377 print_all_handlers(void) 378 { 379 int count = 0; 380 381 (void) iter_handlers(print_device_handler, &count); 382 (void) printf("\n"); 383 count = 0; 384 (void) iter_handlers(print_data_handler, &count); 385 (void) printf("\n"); 386 count = 0; 387 (void) iter_handlers(print_panic_handler, &count); 388 389 return (count); 390 } 391 392 /* ARGSUSED */ 393 static int 394 cancel_one_handler(int id, const char *pool, zinject_record_t *record, 395 void *data) 396 { 397 zfs_cmd_t zc; 398 399 zc.zc_guid = (uint64_t)id; 400 401 if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) { 402 (void) fprintf(stderr, "failed to remove handler %d: %s\n", 403 id, strerror(errno)); 404 return (1); 405 } 406 407 return (0); 408 } 409 410 /* 411 * Remove all fault injection handlers. 412 */ 413 static int 414 cancel_all_handlers(void) 415 { 416 int ret = iter_handlers(cancel_one_handler, NULL); 417 418 (void) printf("removed all registered handlers\n"); 419 420 return (ret); 421 } 422 423 /* 424 * Remove a specific fault injection handler. 425 */ 426 static int 427 cancel_handler(int id) 428 { 429 zfs_cmd_t zc; 430 431 zc.zc_guid = (uint64_t)id; 432 433 if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) { 434 (void) fprintf(stderr, "failed to remove handler %d: %s\n", 435 id, strerror(errno)); 436 return (1); 437 } 438 439 (void) printf("removed handler %d\n", id); 440 441 return (0); 442 } 443 444 /* 445 * Register a new fault injection handler. 446 */ 447 static int 448 register_handler(const char *pool, int flags, zinject_record_t *record, 449 int quiet) 450 { 451 zfs_cmd_t zc; 452 453 (void) strcpy(zc.zc_name, pool); 454 zc.zc_inject_record = *record; 455 zc.zc_guid = flags; 456 457 if (ioctl(zfs_fd, ZFS_IOC_INJECT_FAULT, &zc) != 0) { 458 (void) fprintf(stderr, "failed to add handler: %s\n", 459 strerror(errno)); 460 return (1); 461 } 462 463 if (flags & ZINJECT_NULL) 464 return (0); 465 466 if (quiet) { 467 (void) printf("%llu\n", (u_longlong_t)zc.zc_guid); 468 } else { 469 (void) printf("Added handler %llu with the following " 470 "properties:\n", (u_longlong_t)zc.zc_guid); 471 (void) printf(" pool: %s\n", pool); 472 if (record->zi_guid) { 473 (void) printf(" vdev: %llx\n", 474 (u_longlong_t)record->zi_guid); 475 } else if (record->zi_func[0] != '\0') { 476 (void) printf(" panic function: %s\n", 477 record->zi_func); 478 } else { 479 (void) printf("objset: %llu\n", 480 (u_longlong_t)record->zi_objset); 481 (void) printf("object: %llu\n", 482 (u_longlong_t)record->zi_object); 483 (void) printf(" type: %llu\n", 484 (u_longlong_t)record->zi_type); 485 (void) printf(" level: %d\n", record->zi_level); 486 if (record->zi_start == 0 && 487 record->zi_end == -1ULL) 488 (void) printf(" range: all\n"); 489 else 490 (void) printf(" range: [%llu, %llu)\n", 491 (u_longlong_t)record->zi_start, 492 (u_longlong_t)record->zi_end); 493 } 494 } 495 496 return (0); 497 } 498 499 int 500 main(int argc, char **argv) 501 { 502 int c; 503 char *range = NULL; 504 char *cancel = NULL; 505 char *end; 506 char *raw = NULL; 507 char *device = NULL; 508 int level = 0; 509 int quiet = 0; 510 int error = 0; 511 int domount = 0; 512 err_type_t type = TYPE_INVAL; 513 err_type_t label = TYPE_INVAL; 514 zinject_record_t record = { 0 }; 515 char pool[MAXNAMELEN]; 516 char dataset[MAXNAMELEN]; 517 zfs_handle_t *zhp; 518 int ret; 519 int flags = 0; 520 521 if ((g_zfs = libzfs_init()) == NULL) { 522 (void) fprintf(stderr, "internal error: failed to " 523 "initialize ZFS library\n"); 524 return (1); 525 } 526 527 libzfs_print_on_error(g_zfs, B_TRUE); 528 529 if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0) { 530 (void) fprintf(stderr, "failed to open ZFS device\n"); 531 return (1); 532 } 533 534 if (argc == 1) { 535 /* 536 * No arguments. Print the available handlers. If there are no 537 * available handlers, direct the user to '-h' for help 538 * information. 539 */ 540 if (print_all_handlers() == 0) { 541 (void) printf("No handlers registered.\n"); 542 (void) printf("Run 'zinject -h' for usage " 543 "information.\n"); 544 } 545 546 return (0); 547 } 548 549 while ((c = getopt(argc, argv, ":ab:d:f:Fqhc:t:l:mr:e:uL:p:")) != -1) { 550 switch (c) { 551 case 'a': 552 flags |= ZINJECT_FLUSH_ARC; 553 break; 554 case 'b': 555 raw = optarg; 556 break; 557 case 'c': 558 cancel = optarg; 559 break; 560 case 'd': 561 device = optarg; 562 break; 563 case 'e': 564 if (strcasecmp(optarg, "io") == 0) { 565 error = EIO; 566 } else if (strcasecmp(optarg, "checksum") == 0) { 567 error = ECKSUM; 568 } else if (strcasecmp(optarg, "nxio") == 0) { 569 error = ENXIO; 570 } else { 571 (void) fprintf(stderr, "invalid error type " 572 "'%s': must be 'io', 'checksum' or " 573 "'nxio'\n", optarg); 574 usage(); 575 return (1); 576 } 577 break; 578 case 'f': 579 record.zi_freq = atoi(optarg); 580 if (record.zi_freq < 1 || record.zi_freq > 100) { 581 (void) fprintf(stderr, "frequency range must " 582 "be in the range (0, 100]\n"); 583 return (1); 584 } 585 break; 586 case 'F': 587 record.zi_failfast = B_TRUE; 588 break; 589 case 'h': 590 usage(); 591 return (0); 592 case 'l': 593 level = (int)strtol(optarg, &end, 10); 594 if (*end != '\0') { 595 (void) fprintf(stderr, "invalid level '%s': " 596 "must be an integer\n", optarg); 597 usage(); 598 return (1); 599 } 600 break; 601 case 'm': 602 domount = 1; 603 break; 604 case 'p': 605 (void) strlcpy(record.zi_func, optarg, 606 sizeof (record.zi_func)); 607 break; 608 case 'q': 609 quiet = 1; 610 break; 611 case 'r': 612 range = optarg; 613 break; 614 case 't': 615 if ((type = name_to_type(optarg)) == TYPE_INVAL && 616 !MOS_TYPE(type)) { 617 (void) fprintf(stderr, "invalid type '%s'\n", 618 optarg); 619 usage(); 620 return (1); 621 } 622 break; 623 case 'u': 624 flags |= ZINJECT_UNLOAD_SPA; 625 break; 626 case 'L': 627 if ((label = name_to_type(optarg)) == TYPE_INVAL && 628 !LABEL_TYPE(type)) { 629 (void) fprintf(stderr, "invalid label type " 630 "'%s'\n", optarg); 631 usage(); 632 return (1); 633 } 634 break; 635 case ':': 636 (void) fprintf(stderr, "option -%c requires an " 637 "operand\n", optopt); 638 usage(); 639 return (1); 640 case '?': 641 (void) fprintf(stderr, "invalid option '%c'\n", 642 optopt); 643 usage(); 644 return (2); 645 } 646 } 647 648 argc -= optind; 649 argv += optind; 650 651 if (cancel != NULL) { 652 /* 653 * '-c' is invalid with any other options. 654 */ 655 if (raw != NULL || range != NULL || type != TYPE_INVAL || 656 level != 0 || record.zi_func[0] != '\0') { 657 (void) fprintf(stderr, "cancel (-c) incompatible with " 658 "any other options\n"); 659 usage(); 660 return (2); 661 } 662 if (argc != 0) { 663 (void) fprintf(stderr, "extraneous argument to '-c'\n"); 664 usage(); 665 return (2); 666 } 667 668 if (strcmp(cancel, "all") == 0) { 669 return (cancel_all_handlers()); 670 } else { 671 int id = (int)strtol(cancel, &end, 10); 672 if (*end != '\0') { 673 (void) fprintf(stderr, "invalid handle id '%s':" 674 " must be an integer or 'all'\n", cancel); 675 usage(); 676 return (1); 677 } 678 return (cancel_handler(id)); 679 } 680 } 681 682 if (device != NULL) { 683 /* 684 * Device (-d) injection uses a completely different mechanism 685 * for doing injection, so handle it separately here. 686 */ 687 if (raw != NULL || range != NULL || type != TYPE_INVAL || 688 level != 0 || record.zi_func[0] != '\0') { 689 (void) fprintf(stderr, "device (-d) incompatible with " 690 "data error injection\n"); 691 usage(); 692 return (2); 693 } 694 695 if (argc != 1) { 696 (void) fprintf(stderr, "device (-d) injection requires " 697 "a single pool name\n"); 698 usage(); 699 return (2); 700 } 701 702 (void) strcpy(pool, argv[0]); 703 dataset[0] = '\0'; 704 705 if (error == ECKSUM) { 706 (void) fprintf(stderr, "device error type must be " 707 "'io' or 'nxio'\n"); 708 return (1); 709 } 710 711 if (translate_device(pool, device, label, &record) != 0) 712 return (1); 713 if (!error) 714 error = ENXIO; 715 } else if (raw != NULL) { 716 if (range != NULL || type != TYPE_INVAL || level != 0 || 717 record.zi_func[0] != '\0') { 718 (void) fprintf(stderr, "raw (-b) format with " 719 "any other options\n"); 720 usage(); 721 return (2); 722 } 723 724 if (argc != 1) { 725 (void) fprintf(stderr, "raw (-b) format expects a " 726 "single pool name\n"); 727 usage(); 728 return (2); 729 } 730 731 (void) strcpy(pool, argv[0]); 732 dataset[0] = '\0'; 733 734 if (error == ENXIO) { 735 (void) fprintf(stderr, "data error type must be " 736 "'checksum' or 'io'\n"); 737 return (1); 738 } 739 740 if (translate_raw(raw, &record) != 0) 741 return (1); 742 if (!error) 743 error = EIO; 744 } else if (record.zi_func[0] != '\0') { 745 if (raw != NULL || range != NULL || type != TYPE_INVAL || 746 level != 0 || device != NULL) { 747 (void) fprintf(stderr, "panic (-p) incompatible with " 748 "other options\n"); 749 usage(); 750 return (2); 751 } 752 753 if (argc != 1) { 754 (void) fprintf(stderr, "panic (-p) injection requires " 755 "a single pool name\n"); 756 usage(); 757 return (2); 758 } 759 760 (void) strcpy(pool, argv[0]); 761 dataset[0] = '\0'; 762 } else if (type == TYPE_INVAL) { 763 if (flags == 0) { 764 (void) fprintf(stderr, "at least one of '-b', '-d', " 765 "'-t', '-a', '-p', or '-u' must be specified\n"); 766 usage(); 767 return (2); 768 } 769 770 if (argc == 1 && (flags & ZINJECT_UNLOAD_SPA)) { 771 (void) strcpy(pool, argv[0]); 772 dataset[0] = '\0'; 773 } else if (argc != 0) { 774 (void) fprintf(stderr, "extraneous argument for " 775 "'-f'\n"); 776 usage(); 777 return (2); 778 } 779 780 flags |= ZINJECT_NULL; 781 } else { 782 if (argc != 1) { 783 (void) fprintf(stderr, "missing object\n"); 784 usage(); 785 return (2); 786 } 787 788 if (error == ENXIO) { 789 (void) fprintf(stderr, "data error type must be " 790 "'checksum' or 'io'\n"); 791 return (1); 792 } 793 794 if (translate_record(type, argv[0], range, level, &record, pool, 795 dataset) != 0) 796 return (1); 797 if (!error) 798 error = EIO; 799 } 800 801 /* 802 * If this is pool-wide metadata, unmount everything. The ioctl() will 803 * unload the pool, so that we trigger spa-wide reopen of metadata next 804 * time we access the pool. 805 */ 806 if (dataset[0] != '\0' && domount) { 807 if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL) 808 return (1); 809 810 if (zfs_unmount(zhp, NULL, 0) != 0) 811 return (1); 812 } 813 814 record.zi_error = error; 815 816 ret = register_handler(pool, flags, &record, quiet); 817 818 if (dataset[0] != '\0' && domount) 819 ret = (zfs_mount(zhp, NULL, 0) != 0); 820 821 libzfs_fini(g_zfs); 822 823 return (ret); 824 } 825