]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - cddl/contrib/opensolaris/cmd/zinject/zinject.c
MFC r296510, r296563, r296567: MFV r296505:
[FreeBSD/stable/10.git] / cddl / contrib / opensolaris / cmd / zinject / zinject.c
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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
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, uberblock, pad1, or pad2 region
46  * of all the labels for the specified device.
47  *
48  * This form of the command looks like:
49  *
50  *      zinject -d device [-e errno] [-L <uber | nvlist | pad1 | pad2>] 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  *              bpobj           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/param.h>
148 #include <sys/mount.h>
149
150 #include <libzfs.h>
151 #include <libzfs_compat.h>
152
153 #undef verify   /* both libzfs.h and zfs_context.h want to define this */
154
155 #include "zinject.h"
156
157 libzfs_handle_t *g_zfs;
158 int zfs_fd;
159
160 #ifndef ECKSUM
161 #define ECKSUM  EBADE
162 #endif
163
164 static const char *errtable[TYPE_INVAL] = {
165         "data",
166         "dnode",
167         "mos",
168         "mosdir",
169         "metaslab",
170         "config",
171         "bpobj",
172         "spacemap",
173         "errlog",
174         "uber",
175         "nvlist",
176         "pad1",
177         "pad2"
178 };
179
180 static err_type_t
181 name_to_type(const char *arg)
182 {
183         int i;
184         for (i = 0; i < TYPE_INVAL; i++)
185                 if (strcmp(errtable[i], arg) == 0)
186                         return (i);
187
188         return (TYPE_INVAL);
189 }
190
191 static const char *
192 type_to_name(uint64_t type)
193 {
194         switch (type) {
195         case DMU_OT_OBJECT_DIRECTORY:
196                 return ("mosdir");
197         case DMU_OT_OBJECT_ARRAY:
198                 return ("metaslab");
199         case DMU_OT_PACKED_NVLIST:
200                 return ("config");
201         case DMU_OT_BPOBJ:
202                 return ("bpobj");
203         case DMU_OT_SPACE_MAP:
204                 return ("spacemap");
205         case DMU_OT_ERROR_LOG:
206                 return ("errlog");
207         default:
208                 return ("-");
209         }
210 }
211
212
213 /*
214  * Print usage message.
215  */
216 void
217 usage(void)
218 {
219         (void) printf(
220             "usage:\n"
221             "\n"
222             "\tzinject\n"
223             "\n"
224             "\t\tList all active injection records.\n"
225             "\n"
226             "\tzinject -c <id|all>\n"
227             "\n"
228             "\t\tClear the particular record (if given a numeric ID), or\n"
229             "\t\tall records if 'all' is specificed.\n"
230             "\n"
231             "\tzinject -p <function name> pool\n"
232             "\n"
233             "\t\tInject a panic fault at the specified function. Only \n"
234             "\t\tfunctions which call spa_vdev_config_exit(), or \n"
235             "\t\tspa_vdev_exit() will trigger a panic.\n"
236             "\n"
237             "\tzinject -d device [-e errno] [-L <nvlist|uber|pad1|pad2>] [-F]\n"
238             "\t    [-T <read|write|free|claim|all> pool\n"
239             "\n"
240             "\t\tInject a fault into a particular device or the device's\n"
241             "\t\tlabel.  Label injection can either be 'nvlist', 'uber',\n "
242             "\t\t'pad1', or 'pad2'.\n"
243             "\t\t'errno' can be 'nxio' (the default), 'io', or 'dtl'.\n"
244             "\n"
245             "\tzinject -d device -A <degrade|fault> pool\n"
246             "\n"
247             "\t\tPerform a specific action on a particular device\n"
248             "\n"
249             "\tzinject -d device -D latency:lanes pool\n"
250             "\n"
251             "\t\tAdd an artificial delay to IO requests on a particular\n"
252             "\t\tdevice, such that the requests take a minimum of 'latency'\n"
253             "\t\tmilliseconds to complete. Each delay has an associated\n"
254             "\t\tnumber of 'lanes' which defines the number of concurrent\n"
255             "\t\tIO requests that can be processed.\n"
256             "\n"
257             "\t\tFor example, with a single lane delay of 10 ms (-D 10:1),\n"
258             "\t\tthe device will only be able to service a single IO request\n"
259             "\t\tat a time with each request taking 10 ms to complete. So,\n"
260             "\t\tif only a single request is submitted every 10 ms, the\n"
261             "\t\taverage latency will be 10 ms; but if more than one request\n"
262             "\t\tis submitted every 10 ms, the average latency will be more\n"
263             "\t\tthan 10 ms.\n"
264             "\n"
265             "\t\tSimilarly, if a delay of 10 ms is specified to have two\n"
266             "\t\tlanes (-D 10:2), then the device will be able to service\n"
267             "\t\ttwo requests at a time, each with a minimum latency of\n"
268             "\t\t10 ms. So, if two requests are submitted every 10 ms, then\n"
269             "\t\tthe average latency will be 10 ms; but if more than two\n"
270             "\t\trequests are submitted every 10 ms, the average latency\n"
271             "\t\twill be more than 10 ms.\n"
272             "\n"
273             "\t\tAlso note, these delays are additive. So two invocations\n"
274             "\t\tof '-D 10:1', is roughly equivalent to a single invocation\n"
275             "\t\tof '-D 10:2'. This also means, one can specify multiple\n"
276             "\t\tlanes with differing target latencies. For example, an\n"
277             "\t\tinvocation of '-D 10:1' followed by '-D 25:2' will\n"
278             "\t\tcreate 3 lanes on the device; one lane with a latency\n"
279             "\t\tof 10 ms and two lanes with a 25 ms latency.\n"
280             "\n"
281             "\tzinject -I [-s <seconds> | -g <txgs>] pool\n"
282             "\n"
283             "\t\tCause the pool to stop writing blocks yet not\n"
284             "\t\treport errors for a duration.  Simulates buggy hardware\n"
285             "\t\tthat fails to honor cache flush requests.\n"
286             "\t\tDefault duration is 30 seconds.  The machine is panicked\n"
287             "\t\tat the end of the duration.\n"
288             "\n"
289             "\tzinject -b objset:object:level:blkid pool\n"
290             "\n"
291             "\t\tInject an error into pool 'pool' with the numeric bookmark\n"
292             "\t\tspecified by the remaining tuple.  Each number is in\n"
293             "\t\thexidecimal, and only one block can be specified.\n"
294             "\n"
295             "\tzinject [-q] <-t type> [-e errno] [-l level] [-r range]\n"
296             "\t    [-a] [-m] [-u] [-f freq] <object>\n"
297             "\n"
298             "\t\tInject an error into the object specified by the '-t' option\n"
299             "\t\tand the object descriptor.  The 'object' parameter is\n"
300             "\t\tinterperted depending on the '-t' option.\n"
301             "\n"
302             "\t\t-q\tQuiet mode.  Only print out the handler number added.\n"
303             "\t\t-e\tInject a specific error.  Must be either 'io' or\n"
304             "\t\t\t'checksum'.  Default is 'io'.\n"
305             "\t\t-l\tInject error at a particular block level. Default is "
306             "0.\n"
307             "\t\t-m\tAutomatically remount underlying filesystem.\n"
308             "\t\t-r\tInject error over a particular logical range of an\n"
309             "\t\t\tobject.  Will be translated to the appropriate blkid\n"
310             "\t\t\trange according to the object's properties.\n"
311             "\t\t-a\tFlush the ARC cache.  Can be specified without any\n"
312             "\t\t\tassociated object.\n"
313             "\t\t-u\tUnload the associated pool.  Can be specified with only\n"
314             "\t\t\ta pool object.\n"
315             "\t\t-f\tOnly inject errors a fraction of the time.  Expressed as\n"
316             "\t\t\ta percentage between 1 and 100.\n"
317             "\n"
318             "\t-t data\t\tInject an error into the plain file contents of a\n"
319             "\t\t\tfile.  The object must be specified as a complete path\n"
320             "\t\t\tto a file on a ZFS filesystem.\n"
321             "\n"
322             "\t-t dnode\tInject an error into the metadnode in the block\n"
323             "\t\t\tcorresponding to the dnode for a file or directory.  The\n"
324             "\t\t\t'-r' option is incompatible with this mode.  The object\n"
325             "\t\t\tis specified as a complete path to a file or directory\n"
326             "\t\t\ton a ZFS filesystem.\n"
327             "\n"
328             "\t-t <mos>\tInject errors into the MOS for objects of the given\n"
329             "\t\t\ttype.  Valid types are: mos, mosdir, config, bpobj,\n"
330             "\t\t\tspacemap, metaslab, errlog.  The only valid <object> is\n"
331             "\t\t\tthe poolname.\n");
332 }
333
334 static int
335 iter_handlers(int (*func)(int, const char *, zinject_record_t *, void *),
336     void *data)
337 {
338         zfs_cmd_t zc = { 0 };
339         int ret;
340
341         while (ioctl(zfs_fd, ZFS_IOC_INJECT_LIST_NEXT, &zc) == 0)
342                 if ((ret = func((int)zc.zc_guid, zc.zc_name,
343                     &zc.zc_inject_record, data)) != 0)
344                         return (ret);
345
346         if (errno != ENOENT) {
347                 (void) fprintf(stderr, "Unable to list handlers: %s\n",
348                     strerror(errno));
349                 return (-1);
350         }
351
352         return (0);
353 }
354
355 static int
356 print_data_handler(int id, const char *pool, zinject_record_t *record,
357     void *data)
358 {
359         int *count = data;
360
361         if (record->zi_guid != 0 || record->zi_func[0] != '\0')
362                 return (0);
363
364         if (*count == 0) {
365                 (void) printf("%3s  %-15s  %-6s  %-6s  %-8s  %3s  %-15s\n",
366                     "ID", "POOL", "OBJSET", "OBJECT", "TYPE", "LVL",  "RANGE");
367                 (void) printf("---  ---------------  ------  "
368                     "------  --------  ---  ---------------\n");
369         }
370
371         *count += 1;
372
373         (void) printf("%3d  %-15s  %-6llu  %-6llu  %-8s  %3d  ", id, pool,
374             (u_longlong_t)record->zi_objset, (u_longlong_t)record->zi_object,
375             type_to_name(record->zi_type), record->zi_level);
376
377         if (record->zi_start == 0 &&
378             record->zi_end == -1ULL)
379                 (void) printf("all\n");
380         else
381                 (void) printf("[%llu, %llu]\n", (u_longlong_t)record->zi_start,
382                     (u_longlong_t)record->zi_end);
383
384         return (0);
385 }
386
387 static int
388 print_device_handler(int id, const char *pool, zinject_record_t *record,
389     void *data)
390 {
391         int *count = data;
392
393         if (record->zi_guid == 0 || record->zi_func[0] != '\0')
394                 return (0);
395
396         if (record->zi_cmd == ZINJECT_DELAY_IO)
397                 return (0);
398
399         if (*count == 0) {
400                 (void) printf("%3s  %-15s  %s\n", "ID", "POOL", "GUID");
401                 (void) printf("---  ---------------  ----------------\n");
402         }
403
404         *count += 1;
405
406         (void) printf("%3d  %-15s  %llx\n", id, pool,
407             (u_longlong_t)record->zi_guid);
408
409         return (0);
410 }
411
412 static int
413 print_delay_handler(int id, const char *pool, zinject_record_t *record,
414     void *data)
415 {
416         int *count = data;
417
418         if (record->zi_guid == 0 || record->zi_func[0] != '\0')
419                 return (0);
420
421         if (record->zi_cmd != ZINJECT_DELAY_IO)
422                 return (0);
423
424         if (*count == 0) {
425                 (void) printf("%3s  %-15s  %-15s  %-15s  %s\n",
426                     "ID", "POOL", "DELAY (ms)", "LANES", "GUID");
427                 (void) printf("---  ---------------  ---------------  "
428                     "---------------  ----------------\n");
429         }
430
431         *count += 1;
432
433         (void) printf("%3d  %-15s  %-15llu  %-15llu  %llx\n", id, pool,
434             (u_longlong_t)NSEC2MSEC(record->zi_timer),
435             (u_longlong_t)record->zi_nlanes,
436             (u_longlong_t)record->zi_guid);
437
438         return (0);
439 }
440
441 static int
442 print_panic_handler(int id, const char *pool, zinject_record_t *record,
443     void *data)
444 {
445         int *count = data;
446
447         if (record->zi_func[0] == '\0')
448                 return (0);
449
450         if (*count == 0) {
451                 (void) printf("%3s  %-15s  %s\n", "ID", "POOL", "FUNCTION");
452                 (void) printf("---  ---------------  ----------------\n");
453         }
454
455         *count += 1;
456
457         (void) printf("%3d  %-15s  %s\n", id, pool, record->zi_func);
458
459         return (0);
460 }
461
462 /*
463  * Print all registered error handlers.  Returns the number of handlers
464  * registered.
465  */
466 static int
467 print_all_handlers(void)
468 {
469         int count = 0, total = 0;
470
471         (void) iter_handlers(print_device_handler, &count);
472         if (count > 0) {
473                 total += count;
474                 (void) printf("\n");
475                 count = 0;
476         }
477
478         (void) iter_handlers(print_delay_handler, &count);
479         if (count > 0) {
480                 total += count;
481                 (void) printf("\n");
482                 count = 0;
483         }
484
485         (void) iter_handlers(print_data_handler, &count);
486         if (count > 0) {
487                 total += count;
488                 (void) printf("\n");
489                 count = 0;
490         }
491
492         (void) iter_handlers(print_panic_handler, &count);
493
494         return (count + total);
495 }
496
497 /* ARGSUSED */
498 static int
499 cancel_one_handler(int id, const char *pool, zinject_record_t *record,
500     void *data)
501 {
502         zfs_cmd_t zc = { 0 };
503
504         zc.zc_guid = (uint64_t)id;
505
506         if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
507                 (void) fprintf(stderr, "failed to remove handler %d: %s\n",
508                     id, strerror(errno));
509                 return (1);
510         }
511
512         return (0);
513 }
514
515 /*
516  * Remove all fault injection handlers.
517  */
518 static int
519 cancel_all_handlers(void)
520 {
521         int ret = iter_handlers(cancel_one_handler, NULL);
522
523         if (ret == 0)
524                 (void) printf("removed all registered handlers\n");
525
526         return (ret);
527 }
528
529 /*
530  * Remove a specific fault injection handler.
531  */
532 static int
533 cancel_handler(int id)
534 {
535         zfs_cmd_t zc = { 0 };
536
537         zc.zc_guid = (uint64_t)id;
538
539         if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
540                 (void) fprintf(stderr, "failed to remove handler %d: %s\n",
541                     id, strerror(errno));
542                 return (1);
543         }
544
545         (void) printf("removed handler %d\n", id);
546
547         return (0);
548 }
549
550 /*
551  * Register a new fault injection handler.
552  */
553 static int
554 register_handler(const char *pool, int flags, zinject_record_t *record,
555     int quiet)
556 {
557         zfs_cmd_t zc = { 0 };
558
559         (void) strcpy(zc.zc_name, pool);
560         zc.zc_inject_record = *record;
561         zc.zc_guid = flags;
562
563         if (ioctl(zfs_fd, ZFS_IOC_INJECT_FAULT, &zc) != 0) {
564                 (void) fprintf(stderr, "failed to add handler: %s\n",
565                     strerror(errno));
566                 return (1);
567         }
568
569         if (flags & ZINJECT_NULL)
570                 return (0);
571
572         if (quiet) {
573                 (void) printf("%llu\n", (u_longlong_t)zc.zc_guid);
574         } else {
575                 (void) printf("Added handler %llu with the following "
576                     "properties:\n", (u_longlong_t)zc.zc_guid);
577                 (void) printf("  pool: %s\n", pool);
578                 if (record->zi_guid) {
579                         (void) printf("  vdev: %llx\n",
580                             (u_longlong_t)record->zi_guid);
581                 } else if (record->zi_func[0] != '\0') {
582                         (void) printf("  panic function: %s\n",
583                             record->zi_func);
584                 } else if (record->zi_duration > 0) {
585                         (void) printf(" time: %lld seconds\n",
586                             (u_longlong_t)record->zi_duration);
587                 } else if (record->zi_duration < 0) {
588                         (void) printf(" txgs: %lld \n",
589                             (u_longlong_t)-record->zi_duration);
590                 } else {
591                         (void) printf("objset: %llu\n",
592                             (u_longlong_t)record->zi_objset);
593                         (void) printf("object: %llu\n",
594                             (u_longlong_t)record->zi_object);
595                         (void) printf("  type: %llu\n",
596                             (u_longlong_t)record->zi_type);
597                         (void) printf(" level: %d\n", record->zi_level);
598                         if (record->zi_start == 0 &&
599                             record->zi_end == -1ULL)
600                                 (void) printf(" range: all\n");
601                         else
602                                 (void) printf(" range: [%llu, %llu)\n",
603                                     (u_longlong_t)record->zi_start,
604                                     (u_longlong_t)record->zi_end);
605                 }
606         }
607
608         return (0);
609 }
610
611 int
612 perform_action(const char *pool, zinject_record_t *record, int cmd)
613 {
614         zfs_cmd_t zc = { 0 };
615
616         ASSERT(cmd == VDEV_STATE_DEGRADED || cmd == VDEV_STATE_FAULTED);
617         (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
618         zc.zc_guid = record->zi_guid;
619         zc.zc_cookie = cmd;
620
621         if (ioctl(zfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
622                 return (0);
623
624         return (1);
625 }
626
627 static int
628 parse_delay(char *str, uint64_t *delay, uint64_t *nlanes)
629 {
630         unsigned long scan_delay;
631         unsigned long scan_nlanes;
632
633         if (sscanf(str, "%lu:%lu", &scan_delay, &scan_nlanes) != 2)
634                 return (1);
635
636         /*
637          * We explicitly disallow a delay of zero here, because we key
638          * off this value being non-zero in translate_device(), to
639          * determine if the fault is a ZINJECT_DELAY_IO fault or not.
640          */
641         if (scan_delay == 0)
642                 return (1);
643
644         /*
645          * The units for the CLI delay parameter is milliseconds, but
646          * the data passed to the kernel is interpreted as nanoseconds.
647          * Thus we scale the milliseconds to nanoseconds here, and this
648          * nanosecond value is used to pass the delay to the kernel.
649          */
650         *delay = MSEC2NSEC(scan_delay);
651         *nlanes = scan_nlanes;
652
653         return (0);
654 }
655
656 int
657 main(int argc, char **argv)
658 {
659         int c;
660         char *range = NULL;
661         char *cancel = NULL;
662         char *end;
663         char *raw = NULL;
664         char *device = NULL;
665         int level = 0;
666         int quiet = 0;
667         int error = 0;
668         int domount = 0;
669         int io_type = ZIO_TYPES;
670         int action = VDEV_STATE_UNKNOWN;
671         err_type_t type = TYPE_INVAL;
672         err_type_t label = TYPE_INVAL;
673         zinject_record_t record = { 0 };
674         char pool[MAXNAMELEN];
675         char dataset[MAXNAMELEN];
676         zfs_handle_t *zhp;
677         int nowrites = 0;
678         int dur_txg = 0;
679         int dur_secs = 0;
680         int ret;
681         int flags = 0;
682
683         if ((g_zfs = libzfs_init()) == NULL) {
684                 (void) fprintf(stderr, "internal error: failed to "
685                     "initialize ZFS library\n");
686                 return (1);
687         }
688
689         libzfs_print_on_error(g_zfs, B_TRUE);
690
691         if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
692                 (void) fprintf(stderr, "failed to open ZFS device\n");
693                 return (1);
694         }
695
696         if (argc == 1) {
697                 /*
698                  * No arguments.  Print the available handlers.  If there are no
699                  * available handlers, direct the user to '-h' for help
700                  * information.
701                  */
702                 if (print_all_handlers() == 0) {
703                         (void) printf("No handlers registered.\n");
704                         (void) printf("Run 'zinject -h' for usage "
705                             "information.\n");
706                 }
707
708                 return (0);
709         }
710
711         while ((c = getopt(argc, argv,
712             ":aA:b:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:")) != -1) {
713                 switch (c) {
714                 case 'a':
715                         flags |= ZINJECT_FLUSH_ARC;
716                         break;
717                 case 'A':
718                         if (strcasecmp(optarg, "degrade") == 0) {
719                                 action = VDEV_STATE_DEGRADED;
720                         } else if (strcasecmp(optarg, "fault") == 0) {
721                                 action = VDEV_STATE_FAULTED;
722                         } else {
723                                 (void) fprintf(stderr, "invalid action '%s': "
724                                     "must be 'degrade' or 'fault'\n", optarg);
725                                 usage();
726                                 return (1);
727                         }
728                         break;
729                 case 'b':
730                         raw = optarg;
731                         break;
732                 case 'c':
733                         cancel = optarg;
734                         break;
735                 case 'd':
736                         device = optarg;
737                         break;
738                 case 'D':
739                         ret = parse_delay(optarg, &record.zi_timer,
740                             &record.zi_nlanes);
741                         if (ret != 0) {
742                                 (void) fprintf(stderr, "invalid i/o delay "
743                                     "value: '%s'\n", optarg);
744                                 usage();
745                                 return (1);
746                         }
747                         break;
748                 case 'e':
749                         if (strcasecmp(optarg, "io") == 0) {
750                                 error = EIO;
751                         } else if (strcasecmp(optarg, "checksum") == 0) {
752                                 error = ECKSUM;
753                         } else if (strcasecmp(optarg, "nxio") == 0) {
754                                 error = ENXIO;
755                         } else if (strcasecmp(optarg, "dtl") == 0) {
756                                 error = ECHILD;
757                         } else {
758                                 (void) fprintf(stderr, "invalid error type "
759                                     "'%s': must be 'io', 'checksum' or "
760                                     "'nxio'\n", optarg);
761                                 usage();
762                                 return (1);
763                         }
764                         break;
765                 case 'f':
766                         record.zi_freq = atoi(optarg);
767                         if (record.zi_freq < 1 || record.zi_freq > 100) {
768                                 (void) fprintf(stderr, "frequency range must "
769                                     "be in the range (0, 100]\n");
770                                 return (1);
771                         }
772                         break;
773                 case 'F':
774                         record.zi_failfast = B_TRUE;
775                         break;
776                 case 'g':
777                         dur_txg = 1;
778                         record.zi_duration = (int)strtol(optarg, &end, 10);
779                         if (record.zi_duration <= 0 || *end != '\0') {
780                                 (void) fprintf(stderr, "invalid duration '%s': "
781                                     "must be a positive integer\n", optarg);
782                                 usage();
783                                 return (1);
784                         }
785                         /* store duration of txgs as its negative */
786                         record.zi_duration *= -1;
787                         break;
788                 case 'h':
789                         usage();
790                         return (0);
791                 case 'I':
792                         /* default duration, if one hasn't yet been defined */
793                         nowrites = 1;
794                         if (dur_secs == 0 && dur_txg == 0)
795                                 record.zi_duration = 30;
796                         break;
797                 case 'l':
798                         level = (int)strtol(optarg, &end, 10);
799                         if (*end != '\0') {
800                                 (void) fprintf(stderr, "invalid level '%s': "
801                                     "must be an integer\n", optarg);
802                                 usage();
803                                 return (1);
804                         }
805                         break;
806                 case 'm':
807                         domount = 1;
808                         break;
809                 case 'p':
810                         (void) strlcpy(record.zi_func, optarg,
811                             sizeof (record.zi_func));
812                         record.zi_cmd = ZINJECT_PANIC;
813                         break;
814                 case 'q':
815                         quiet = 1;
816                         break;
817                 case 'r':
818                         range = optarg;
819                         break;
820                 case 's':
821                         dur_secs = 1;
822                         record.zi_duration = (int)strtol(optarg, &end, 10);
823                         if (record.zi_duration <= 0 || *end != '\0') {
824                                 (void) fprintf(stderr, "invalid duration '%s': "
825                                     "must be a positive integer\n", optarg);
826                                 usage();
827                                 return (1);
828                         }
829                         break;
830                 case 'T':
831                         if (strcasecmp(optarg, "read") == 0) {
832                                 io_type = ZIO_TYPE_READ;
833                         } else if (strcasecmp(optarg, "write") == 0) {
834                                 io_type = ZIO_TYPE_WRITE;
835                         } else if (strcasecmp(optarg, "free") == 0) {
836                                 io_type = ZIO_TYPE_FREE;
837                         } else if (strcasecmp(optarg, "claim") == 0) {
838                                 io_type = ZIO_TYPE_CLAIM;
839                         } else if (strcasecmp(optarg, "all") == 0) {
840                                 io_type = ZIO_TYPES;
841                         } else {
842                                 (void) fprintf(stderr, "invalid I/O type "
843                                     "'%s': must be 'read', 'write', 'free', "
844                                     "'claim' or 'all'\n", optarg);
845                                 usage();
846                                 return (1);
847                         }
848                         break;
849                 case 't':
850                         if ((type = name_to_type(optarg)) == TYPE_INVAL &&
851                             !MOS_TYPE(type)) {
852                                 (void) fprintf(stderr, "invalid type '%s'\n",
853                                     optarg);
854                                 usage();
855                                 return (1);
856                         }
857                         break;
858                 case 'u':
859                         flags |= ZINJECT_UNLOAD_SPA;
860                         break;
861                 case 'L':
862                         if ((label = name_to_type(optarg)) == TYPE_INVAL &&
863                             !LABEL_TYPE(type)) {
864                                 (void) fprintf(stderr, "invalid label type "
865                                     "'%s'\n", optarg);
866                                 usage();
867                                 return (1);
868                         }
869                         break;
870                 case ':':
871                         (void) fprintf(stderr, "option -%c requires an "
872                             "operand\n", optopt);
873                         usage();
874                         return (1);
875                 case '?':
876                         (void) fprintf(stderr, "invalid option '%c'\n",
877                             optopt);
878                         usage();
879                         return (2);
880                 }
881         }
882
883         argc -= optind;
884         argv += optind;
885
886         if (record.zi_duration != 0)
887                 record.zi_cmd = ZINJECT_IGNORED_WRITES;
888
889         if (cancel != NULL) {
890                 /*
891                  * '-c' is invalid with any other options.
892                  */
893                 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
894                     level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
895                         (void) fprintf(stderr, "cancel (-c) incompatible with "
896                             "any other options\n");
897                         usage();
898                         return (2);
899                 }
900                 if (argc != 0) {
901                         (void) fprintf(stderr, "extraneous argument to '-c'\n");
902                         usage();
903                         return (2);
904                 }
905
906                 if (strcmp(cancel, "all") == 0) {
907                         return (cancel_all_handlers());
908                 } else {
909                         int id = (int)strtol(cancel, &end, 10);
910                         if (*end != '\0') {
911                                 (void) fprintf(stderr, "invalid handle id '%s':"
912                                     " must be an integer or 'all'\n", cancel);
913                                 usage();
914                                 return (1);
915                         }
916                         return (cancel_handler(id));
917                 }
918         }
919
920         if (device != NULL) {
921                 /*
922                  * Device (-d) injection uses a completely different mechanism
923                  * for doing injection, so handle it separately here.
924                  */
925                 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
926                     level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
927                         (void) fprintf(stderr, "device (-d) incompatible with "
928                             "data error injection\n");
929                         usage();
930                         return (2);
931                 }
932
933                 if (argc != 1) {
934                         (void) fprintf(stderr, "device (-d) injection requires "
935                             "a single pool name\n");
936                         usage();
937                         return (2);
938                 }
939
940                 (void) strcpy(pool, argv[0]);
941                 dataset[0] = '\0';
942
943                 if (error == ECKSUM) {
944                         (void) fprintf(stderr, "device error type must be "
945                             "'io' or 'nxio'\n");
946                         return (1);
947                 }
948
949                 record.zi_iotype = io_type;
950                 if (translate_device(pool, device, label, &record) != 0)
951                         return (1);
952                 if (!error)
953                         error = ENXIO;
954
955                 if (action != VDEV_STATE_UNKNOWN)
956                         return (perform_action(pool, &record, action));
957
958         } else if (raw != NULL) {
959                 if (range != NULL || type != TYPE_INVAL || level != 0 ||
960                     record.zi_cmd != ZINJECT_UNINITIALIZED) {
961                         (void) fprintf(stderr, "raw (-b) format with "
962                             "any other options\n");
963                         usage();
964                         return (2);
965                 }
966
967                 if (argc != 1) {
968                         (void) fprintf(stderr, "raw (-b) format expects a "
969                             "single pool name\n");
970                         usage();
971                         return (2);
972                 }
973
974                 (void) strcpy(pool, argv[0]);
975                 dataset[0] = '\0';
976
977                 if (error == ENXIO) {
978                         (void) fprintf(stderr, "data error type must be "
979                             "'checksum' or 'io'\n");
980                         return (1);
981                 }
982
983                 record.zi_cmd = ZINJECT_DATA_FAULT;
984                 if (translate_raw(raw, &record) != 0)
985                         return (1);
986                 if (!error)
987                         error = EIO;
988         } else if (record.zi_cmd == ZINJECT_PANIC) {
989                 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
990                     level != 0 || device != NULL) {
991                         (void) fprintf(stderr, "panic (-p) incompatible with "
992                             "other options\n");
993                         usage();
994                         return (2);
995                 }
996
997                 if (argc < 1 || argc > 2) {
998                         (void) fprintf(stderr, "panic (-p) injection requires "
999                             "a single pool name and an optional id\n");
1000                         usage();
1001                         return (2);
1002                 }
1003
1004                 (void) strcpy(pool, argv[0]);
1005                 if (argv[1] != NULL)
1006                         record.zi_type = atoi(argv[1]);
1007                 dataset[0] = '\0';
1008         } else if (record.zi_cmd == ZINJECT_IGNORED_WRITES) {
1009                 if (nowrites == 0) {
1010                         (void) fprintf(stderr, "-s or -g meaningless "
1011                             "without -I (ignore writes)\n");
1012                         usage();
1013                         return (2);
1014                 } else if (dur_secs && dur_txg) {
1015                         (void) fprintf(stderr, "choose a duration either "
1016                             "in seconds (-s) or a number of txgs (-g) "
1017                             "but not both\n");
1018                         usage();
1019                         return (2);
1020                 } else if (argc != 1) {
1021                         (void) fprintf(stderr, "ignore writes (-I) "
1022                             "injection requires a single pool name\n");
1023                         usage();
1024                         return (2);
1025                 }
1026
1027                 (void) strcpy(pool, argv[0]);
1028                 dataset[0] = '\0';
1029         } else if (type == TYPE_INVAL) {
1030                 if (flags == 0) {
1031                         (void) fprintf(stderr, "at least one of '-b', '-d', "
1032                             "'-t', '-a', '-p', '-I' or '-u' "
1033                             "must be specified\n");
1034                         usage();
1035                         return (2);
1036                 }
1037
1038                 if (argc == 1 && (flags & ZINJECT_UNLOAD_SPA)) {
1039                         (void) strcpy(pool, argv[0]);
1040                         dataset[0] = '\0';
1041                 } else if (argc != 0) {
1042                         (void) fprintf(stderr, "extraneous argument for "
1043                             "'-f'\n");
1044                         usage();
1045                         return (2);
1046                 }
1047
1048                 flags |= ZINJECT_NULL;
1049         } else {
1050                 if (argc != 1) {
1051                         (void) fprintf(stderr, "missing object\n");
1052                         usage();
1053                         return (2);
1054                 }
1055
1056                 if (error == ENXIO) {
1057                         (void) fprintf(stderr, "data error type must be "
1058                             "'checksum' or 'io'\n");
1059                         return (1);
1060                 }
1061
1062                 record.zi_cmd = ZINJECT_DATA_FAULT;
1063                 if (translate_record(type, argv[0], range, level, &record, pool,
1064                     dataset) != 0)
1065                         return (1);
1066                 if (!error)
1067                         error = EIO;
1068         }
1069
1070         /*
1071          * If this is pool-wide metadata, unmount everything.  The ioctl() will
1072          * unload the pool, so that we trigger spa-wide reopen of metadata next
1073          * time we access the pool.
1074          */
1075         if (dataset[0] != '\0' && domount) {
1076                 if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL)
1077                         return (1);
1078
1079                 if (zfs_unmount(zhp, NULL, 0) != 0)
1080                         return (1);
1081         }
1082
1083         record.zi_error = error;
1084
1085         ret = register_handler(pool, flags, &record, quiet);
1086
1087         if (dataset[0] != '\0' && domount)
1088                 ret = (zfs_mount(zhp, NULL, 0) != 0);
1089
1090         libzfs_fini(g_zfs);
1091
1092         return (ret);
1093 }