1ea8dc4b6Seschrock /*
2ea8dc4b6Seschrock * CDDL HEADER START
3ea8dc4b6Seschrock *
4ea8dc4b6Seschrock * The contents of this file are subject to the terms of the
5ea8dc4b6Seschrock * Common Development and Distribution License (the "License").
6ea8dc4b6Seschrock * You may not use this file except in compliance with the License.
7ea8dc4b6Seschrock *
8ea8dc4b6Seschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9ea8dc4b6Seschrock * or http://www.opensolaris.org/os/licensing.
10ea8dc4b6Seschrock * See the License for the specific language governing permissions
11ea8dc4b6Seschrock * and limitations under the License.
12ea8dc4b6Seschrock *
13ea8dc4b6Seschrock * When distributing Covered Code, include this CDDL HEADER in each
14ea8dc4b6Seschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15ea8dc4b6Seschrock * If applicable, add the following below this CDDL HEADER, with the
16ea8dc4b6Seschrock * fields enclosed by brackets "[]" replaced with your own identifying
17ea8dc4b6Seschrock * information: Portions Copyright [yyyy] [name of copyright owner]
18ea8dc4b6Seschrock *
19ea8dc4b6Seschrock * CDDL HEADER END
20ea8dc4b6Seschrock */
21ea8dc4b6Seschrock /*
2298d1cbfeSGeorge Wilson * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2397e81309SPrakash Surya * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
24b853d39aSDon Brady * Copyright (c) 2017, Intel Corporation.
25ea8dc4b6Seschrock */
26ea8dc4b6Seschrock
27ea8dc4b6Seschrock /*
28ea8dc4b6Seschrock * ZFS Fault Injector
29ea8dc4b6Seschrock *
30ea8dc4b6Seschrock * This userland component takes a set of options and uses libzpool to translate
31ea8dc4b6Seschrock * from a user-visible object type and name to an internal representation.
32ea8dc4b6Seschrock * There are two basic types of faults: device faults and data faults.
33ea8dc4b6Seschrock *
34ea8dc4b6Seschrock *
35ea8dc4b6Seschrock * DEVICE FAULTS
36ea8dc4b6Seschrock *
37ea8dc4b6Seschrock * Errors can be injected into a particular vdev using the '-d' option. This
38ea8dc4b6Seschrock * option takes a path or vdev GUID to uniquely identify the device within a
39ea8dc4b6Seschrock * pool. There are two types of errors that can be injected, EIO and ENXIO,
4021bf64a7Sgw * that can be controlled through the '-e' option. The default is ENXIO. For
41ea8dc4b6Seschrock * EIO failures, any attempt to read data from the device will return EIO, but
42ea8dc4b6Seschrock * subsequent attempt to reopen the device will succeed. For ENXIO failures,
43ea8dc4b6Seschrock * any attempt to read from the device will return EIO, but any attempt to
44ea8dc4b6Seschrock * reopen the device will also return ENXIO.
4521bf64a7Sgw * For label faults, the -L option must be specified. This allows faults
4698d1cbfeSGeorge Wilson * to be injected into either the nvlist, uberblock, pad1, or pad2 region
4798d1cbfeSGeorge Wilson * of all the labels for the specified device.
48ea8dc4b6Seschrock *
49ea8dc4b6Seschrock * This form of the command looks like:
50ea8dc4b6Seschrock *
5112a8814cSTom Caputi * zinject -d device [-e errno] [-L <uber | nvlist | pad1 | pad2>] pool
52ea8dc4b6Seschrock *
53ea8dc4b6Seschrock *
54ea8dc4b6Seschrock * DATA FAULTS
55ea8dc4b6Seschrock *
56ea8dc4b6Seschrock * We begin with a tuple of the form:
57ea8dc4b6Seschrock *
5812a8814cSTom Caputi * <type,level,range,object>
59ea8dc4b6Seschrock *
6012a8814cSTom Caputi * type A string describing the type of data to target. Each type
6112a8814cSTom Caputi * implicitly describes how to interpret 'object'. Currently,
6212a8814cSTom Caputi * the following values are supported:
63ea8dc4b6Seschrock *
6412a8814cSTom Caputi * data User data for a file
6512a8814cSTom Caputi * dnode Dnode for a file or directory
66ea8dc4b6Seschrock *
67ea8dc4b6Seschrock * The following MOS objects are special. Instead of injecting
68ea8dc4b6Seschrock * errors on a particular object or blkid, we inject errors across
69ea8dc4b6Seschrock * all objects of the given type.
70ea8dc4b6Seschrock *
7112a8814cSTom Caputi * mos Any data in the MOS
7212a8814cSTom Caputi * mosdir object directory
7312a8814cSTom Caputi * config pool configuration
7412a8814cSTom Caputi * bpobj blkptr list
7512a8814cSTom Caputi * spacemap spacemap
7612a8814cSTom Caputi * metaslab metaslab
7712a8814cSTom Caputi * errlog persistent error log
78ea8dc4b6Seschrock *
7912a8814cSTom Caputi * level Object level. Defaults to '0', not applicable to all types. If
8012a8814cSTom Caputi * a range is given, this corresponds to the indirect block
8112a8814cSTom Caputi * corresponding to the specific range.
82ea8dc4b6Seschrock *
83ea8dc4b6Seschrock * range A numerical range [start,end) within the object. Defaults to
84ea8dc4b6Seschrock * the full size of the file.
85ea8dc4b6Seschrock *
8612a8814cSTom Caputi * object A string describing the logical location of the object. For
8712a8814cSTom Caputi * files and directories (currently the only supported types),
8812a8814cSTom Caputi * this is the path of the object on disk.
89ea8dc4b6Seschrock *
90ea8dc4b6Seschrock * This is translated, via libzpool, into the following internal representation:
91ea8dc4b6Seschrock *
9212a8814cSTom Caputi * <type,objset,object,level,range>
93ea8dc4b6Seschrock *
94ea8dc4b6Seschrock * These types should be self-explanatory. This tuple is then passed to the
95ea8dc4b6Seschrock * kernel via a special ioctl() to initiate fault injection for the given
96ea8dc4b6Seschrock * object. Note that 'type' is not strictly necessary for fault injection, but
97ea8dc4b6Seschrock * is used when translating existing faults into a human-readable string.
98ea8dc4b6Seschrock *
99ea8dc4b6Seschrock *
100ea8dc4b6Seschrock * The command itself takes one of the forms:
101ea8dc4b6Seschrock *
10212a8814cSTom Caputi * zinject
10312a8814cSTom Caputi * zinject <-a | -u pool>
10412a8814cSTom Caputi * zinject -c <id|all>
10512a8814cSTom Caputi * zinject [-q] <-t type> [-f freq] [-u] [-a] [-m] [-e errno] [-l level]
106ea8dc4b6Seschrock * [-r range] <object>
10712a8814cSTom Caputi * zinject [-f freq] [-a] [-m] [-u] -b objset:object:level:start:end pool
108ea8dc4b6Seschrock *
109ea8dc4b6Seschrock * With no arguments, the command prints all currently registered injection
110ea8dc4b6Seschrock * handlers, with their numeric identifiers.
111ea8dc4b6Seschrock *
112ea8dc4b6Seschrock * The '-c' option will clear the given handler, or all handlers if 'all' is
113ea8dc4b6Seschrock * specified.
114ea8dc4b6Seschrock *
115ea8dc4b6Seschrock * The '-e' option takes a string describing the errno to simulate. This must
116eb633035STom Caputi * be one of 'io', 'checksum', or 'decrypt'. In most cases this will result
117eb633035STom Caputi * in the same behavior, but RAID-Z will produce a different set of ereports
118eb633035STom Caputi * for this situation.
119ea8dc4b6Seschrock *
120ea8dc4b6Seschrock * The '-a', '-u', and '-m' flags toggle internal flush behavior. If '-a' is
121ea8dc4b6Seschrock * specified, then the ARC cache is flushed appropriately. If '-u' is
122ea8dc4b6Seschrock * specified, then the underlying SPA is unloaded. Either of these flags can be
123ea8dc4b6Seschrock * specified independently of any other handlers. The '-m' flag automatically
124ea8dc4b6Seschrock * does an unmount and remount of the underlying dataset to aid in flushing the
125ea8dc4b6Seschrock * cache.
126ea8dc4b6Seschrock *
127ea8dc4b6Seschrock * The '-f' flag controls the frequency of errors injected, expressed as a
128b853d39aSDon Brady * real number percentage between 0.0001 and 100. The default is 100.
129ea8dc4b6Seschrock *
130ea8dc4b6Seschrock * The this form is responsible for actually injecting the handler into the
131ea8dc4b6Seschrock * framework. It takes the arguments described above, translates them to the
132ea8dc4b6Seschrock * internal tuple using libzpool, and then issues an ioctl() to register the
133ea8dc4b6Seschrock * handler.
134ea8dc4b6Seschrock *
135ea8dc4b6Seschrock * The final form can target a specific bookmark, regardless of whether a
136ea8dc4b6Seschrock * human-readable interface has been designed. It allows developers to specify
137ea8dc4b6Seschrock * a particular block by number.
138ea8dc4b6Seschrock */
139ea8dc4b6Seschrock
140ea8dc4b6Seschrock #include <errno.h>
141ea8dc4b6Seschrock #include <fcntl.h>
142ea8dc4b6Seschrock #include <stdio.h>
143ea8dc4b6Seschrock #include <stdlib.h>
144ea8dc4b6Seschrock #include <strings.h>
145ea8dc4b6Seschrock #include <unistd.h>
146ea8dc4b6Seschrock
147ea8dc4b6Seschrock #include <sys/fs/zfs.h>
148ea8dc4b6Seschrock #include <sys/mount.h>
149ea8dc4b6Seschrock
150ea8dc4b6Seschrock #include <libzfs.h>
151ea8dc4b6Seschrock
152ea8dc4b6Seschrock #undef verify /* both libzfs.h and zfs_context.h want to define this */
153ea8dc4b6Seschrock
154ea8dc4b6Seschrock #include "zinject.h"
155ea8dc4b6Seschrock
15699653d4eSeschrock libzfs_handle_t *g_zfs;
157ea8dc4b6Seschrock int zfs_fd;
158ea8dc4b6Seschrock
159ea8dc4b6Seschrock #define ECKSUM EBADE
160ea8dc4b6Seschrock
161ea8dc4b6Seschrock static const char *errtable[TYPE_INVAL] = {
162ea8dc4b6Seschrock "data",
163ea8dc4b6Seschrock "dnode",
164ea8dc4b6Seschrock "mos",
165ea8dc4b6Seschrock "mosdir",
166ea8dc4b6Seschrock "metaslab",
167ea8dc4b6Seschrock "config",
168cde58dbcSMatthew Ahrens "bpobj",
169ea8dc4b6Seschrock "spacemap",
17021bf64a7Sgw "errlog",
17121bf64a7Sgw "uber",
17298d1cbfeSGeorge Wilson "nvlist",
17398d1cbfeSGeorge Wilson "pad1",
17498d1cbfeSGeorge Wilson "pad2"
175ea8dc4b6Seschrock };
176ea8dc4b6Seschrock
177ea8dc4b6Seschrock static err_type_t
name_to_type(const char * arg)178ea8dc4b6Seschrock name_to_type(const char *arg)
179ea8dc4b6Seschrock {
180ea8dc4b6Seschrock int i;
181ea8dc4b6Seschrock for (i = 0; i < TYPE_INVAL; i++)
182ea8dc4b6Seschrock if (strcmp(errtable[i], arg) == 0)
183ea8dc4b6Seschrock return (i);
184ea8dc4b6Seschrock
185ea8dc4b6Seschrock return (TYPE_INVAL);
186ea8dc4b6Seschrock }
187ea8dc4b6Seschrock
188ea8dc4b6Seschrock static const char *
type_to_name(uint64_t type)189ea8dc4b6Seschrock type_to_name(uint64_t type)
190ea8dc4b6Seschrock {
191ea8dc4b6Seschrock switch (type) {
192ea8dc4b6Seschrock case DMU_OT_OBJECT_DIRECTORY:
193ea8dc4b6Seschrock return ("mosdir");
194ea8dc4b6Seschrock case DMU_OT_OBJECT_ARRAY:
195ea8dc4b6Seschrock return ("metaslab");
196ea8dc4b6Seschrock case DMU_OT_PACKED_NVLIST:
197ea8dc4b6Seschrock return ("config");
198cde58dbcSMatthew Ahrens case DMU_OT_BPOBJ:
199cde58dbcSMatthew Ahrens return ("bpobj");
200ea8dc4b6Seschrock case DMU_OT_SPACE_MAP:
201ea8dc4b6Seschrock return ("spacemap");
202ea8dc4b6Seschrock case DMU_OT_ERROR_LOG:
203ea8dc4b6Seschrock return ("errlog");
204ea8dc4b6Seschrock default:
205ea8dc4b6Seschrock return ("-");
206ea8dc4b6Seschrock }
207ea8dc4b6Seschrock }
208ea8dc4b6Seschrock
209ea8dc4b6Seschrock
210ea8dc4b6Seschrock /*
211ea8dc4b6Seschrock * Print usage message.
212ea8dc4b6Seschrock */
213ea8dc4b6Seschrock void
usage(void)214ea8dc4b6Seschrock usage(void)
215ea8dc4b6Seschrock {
216ea8dc4b6Seschrock (void) printf(
217ea8dc4b6Seschrock "usage:\n"
218ea8dc4b6Seschrock "\n"
219ea8dc4b6Seschrock "\tzinject\n"
220ea8dc4b6Seschrock "\n"
221ea8dc4b6Seschrock "\t\tList all active injection records.\n"
222ea8dc4b6Seschrock "\n"
223ea8dc4b6Seschrock "\tzinject -c <id|all>\n"
224ea8dc4b6Seschrock "\n"
225ea8dc4b6Seschrock "\t\tClear the particular record (if given a numeric ID), or\n"
226ea8dc4b6Seschrock "\t\tall records if 'all' is specificed.\n"
227ea8dc4b6Seschrock "\n"
22888ecc943SGeorge Wilson "\tzinject -p <function name> pool\n"
22997e81309SPrakash Surya "\n"
23088ecc943SGeorge Wilson "\t\tInject a panic fault at the specified function. Only \n"
23188ecc943SGeorge Wilson "\t\tfunctions which call spa_vdev_config_exit(), or \n"
23288ecc943SGeorge Wilson "\t\tspa_vdev_exit() will trigger a panic.\n"
23388ecc943SGeorge Wilson "\n"
23498d1cbfeSGeorge Wilson "\tzinject -d device [-e errno] [-L <nvlist|uber|pad1|pad2>] [-F]\n"
235b853d39aSDon Brady "\t [-T <read|write|free|claim|all>] [-f frequency] pool\n"
23697e81309SPrakash Surya "\n"
23721bf64a7Sgw "\t\tInject a fault into a particular device or the device's\n"
23898d1cbfeSGeorge Wilson "\t\tlabel. Label injection can either be 'nvlist', 'uber',\n "
23998d1cbfeSGeorge Wilson "\t\t'pad1', or 'pad2'.\n"
240cb04b873SMark J Musante "\t\t'errno' can be 'nxio' (the default), 'io', or 'dtl'.\n"
241b853d39aSDon Brady "\t\t'frequency' is a value between 0.0001 and 100.0 that limits\n"
242b853d39aSDon Brady "\t\tdevice error injection to a percentage of the IOs.\n"
243ea8dc4b6Seschrock "\n"
2448f18d1faSGeorge Wilson "\tzinject -d device -A <degrade|fault> pool\n"
24597e81309SPrakash Surya "\n"
2468f18d1faSGeorge Wilson "\t\tPerform a specific action on a particular device\n"
2478f18d1faSGeorge Wilson "\n"
24897e81309SPrakash Surya "\tzinject -d device -D latency:lanes pool\n"
24997e81309SPrakash Surya "\n"
25097e81309SPrakash Surya "\t\tAdd an artificial delay to IO requests on a particular\n"
25197e81309SPrakash Surya "\t\tdevice, such that the requests take a minimum of 'latency'\n"
25297e81309SPrakash Surya "\t\tmilliseconds to complete. Each delay has an associated\n"
25397e81309SPrakash Surya "\t\tnumber of 'lanes' which defines the number of concurrent\n"
25497e81309SPrakash Surya "\t\tIO requests that can be processed.\n"
25597e81309SPrakash Surya "\n"
25697e81309SPrakash Surya "\t\tFor example, with a single lane delay of 10 ms (-D 10:1),\n"
25797e81309SPrakash Surya "\t\tthe device will only be able to service a single IO request\n"
25897e81309SPrakash Surya "\t\tat a time with each request taking 10 ms to complete. So,\n"
25997e81309SPrakash Surya "\t\tif only a single request is submitted every 10 ms, the\n"
26097e81309SPrakash Surya "\t\taverage latency will be 10 ms; but if more than one request\n"
26197e81309SPrakash Surya "\t\tis submitted every 10 ms, the average latency will be more\n"
26297e81309SPrakash Surya "\t\tthan 10 ms.\n"
26397e81309SPrakash Surya "\n"
26497e81309SPrakash Surya "\t\tSimilarly, if a delay of 10 ms is specified to have two\n"
26597e81309SPrakash Surya "\t\tlanes (-D 10:2), then the device will be able to service\n"
26697e81309SPrakash Surya "\t\ttwo requests at a time, each with a minimum latency of\n"
26797e81309SPrakash Surya "\t\t10 ms. So, if two requests are submitted every 10 ms, then\n"
26897e81309SPrakash Surya "\t\tthe average latency will be 10 ms; but if more than two\n"
26997e81309SPrakash Surya "\t\trequests are submitted every 10 ms, the average latency\n"
27097e81309SPrakash Surya "\t\twill be more than 10 ms.\n"
27197e81309SPrakash Surya "\n"
27297e81309SPrakash Surya "\t\tAlso note, these delays are additive. So two invocations\n"
27397e81309SPrakash Surya "\t\tof '-D 10:1', is roughly equivalent to a single invocation\n"
27497e81309SPrakash Surya "\t\tof '-D 10:2'. This also means, one can specify multiple\n"
27597e81309SPrakash Surya "\t\tlanes with differing target latencies. For example, an\n"
27697e81309SPrakash Surya "\t\tinvocation of '-D 10:1' followed by '-D 25:2' will\n"
27797e81309SPrakash Surya "\t\tcreate 3 lanes on the device; one lane with a latency\n"
27897e81309SPrakash Surya "\t\tof 10 ms and two lanes with a 25 ms latency.\n"
27997e81309SPrakash Surya "\n"
280468c413aSTim Haley "\tzinject -I [-s <seconds> | -g <txgs>] pool\n"
28197e81309SPrakash Surya "\n"
282468c413aSTim Haley "\t\tCause the pool to stop writing blocks yet not\n"
283468c413aSTim Haley "\t\treport errors for a duration. Simulates buggy hardware\n"
284468c413aSTim Haley "\t\tthat fails to honor cache flush requests.\n"
285468c413aSTim Haley "\t\tDefault duration is 30 seconds. The machine is panicked\n"
286468c413aSTim Haley "\t\tat the end of the duration.\n"
287468c413aSTim Haley "\n"
288ea8dc4b6Seschrock "\tzinject -b objset:object:level:blkid pool\n"
289ea8dc4b6Seschrock "\n"
290ea8dc4b6Seschrock "\t\tInject an error into pool 'pool' with the numeric bookmark\n"
291ea8dc4b6Seschrock "\t\tspecified by the remaining tuple. Each number is in\n"
292ea8dc4b6Seschrock "\t\thexidecimal, and only one block can be specified.\n"
293ea8dc4b6Seschrock "\n"
29412a8814cSTom Caputi "\tzinject [-q] <-t type> [-C dvas] [-e errno] [-l level]\n"
29512a8814cSTom Caputi "\t\t[-r range] [-a] [-m] [-u] [-f freq] <object>\n"
296ea8dc4b6Seschrock "\n"
297ea8dc4b6Seschrock "\t\tInject an error into the object specified by the '-t' option\n"
298ea8dc4b6Seschrock "\t\tand the object descriptor. The 'object' parameter is\n"
299ea8dc4b6Seschrock "\t\tinterperted depending on the '-t' option.\n"
300ea8dc4b6Seschrock "\n"
301ea8dc4b6Seschrock "\t\t-q\tQuiet mode. Only print out the handler number added.\n"
302eb633035STom Caputi "\t\t-e\tInject a specific error. Must be one of 'io', "
303eb633035STom Caputi "'checksum',\n"
304eb633035STom Caputi "\t\t\t'decompress', or decrypt. Default is 'io'.\n"
30512a8814cSTom Caputi "\t\t-C\tInject the given error only into specific DVAs. The\n"
30612a8814cSTom Caputi "\t\t\tDVAs should be specified as a list of 0-indexed DVAs\n"
30712a8814cSTom Caputi "\t\t\tseparated by commas (ex. '0,2').\n"
308ea8dc4b6Seschrock "\t\t-l\tInject error at a particular block level. Default is "
309ea8dc4b6Seschrock "0.\n"
310ea8dc4b6Seschrock "\t\t-m\tAutomatically remount underlying filesystem.\n"
311ea8dc4b6Seschrock "\t\t-r\tInject error over a particular logical range of an\n"
312ea8dc4b6Seschrock "\t\t\tobject. Will be translated to the appropriate blkid\n"
313ea8dc4b6Seschrock "\t\t\trange according to the object's properties.\n"
314ea8dc4b6Seschrock "\t\t-a\tFlush the ARC cache. Can be specified without any\n"
315ea8dc4b6Seschrock "\t\t\tassociated object.\n"
316ea8dc4b6Seschrock "\t\t-u\tUnload the associated pool. Can be specified with only\n"
317ea8dc4b6Seschrock "\t\t\ta pool object.\n"
318ea8dc4b6Seschrock "\t\t-f\tOnly inject errors a fraction of the time. Expressed as\n"
319b853d39aSDon Brady "\t\t\ta percentage between 0.0001 and 100.\n"
320ea8dc4b6Seschrock "\n"
321ea8dc4b6Seschrock "\t-t data\t\tInject an error into the plain file contents of a\n"
322ea8dc4b6Seschrock "\t\t\tfile. The object must be specified as a complete path\n"
323ea8dc4b6Seschrock "\t\t\tto a file on a ZFS filesystem.\n"
324ea8dc4b6Seschrock "\n"
325ea8dc4b6Seschrock "\t-t dnode\tInject an error into the metadnode in the block\n"
326ea8dc4b6Seschrock "\t\t\tcorresponding to the dnode for a file or directory. The\n"
327ea8dc4b6Seschrock "\t\t\t'-r' option is incompatible with this mode. The object\n"
328ea8dc4b6Seschrock "\t\t\tis specified as a complete path to a file or directory\n"
329ea8dc4b6Seschrock "\t\t\ton a ZFS filesystem.\n"
330ea8dc4b6Seschrock "\n"
331ea8dc4b6Seschrock "\t-t <mos>\tInject errors into the MOS for objects of the given\n"
332cde58dbcSMatthew Ahrens "\t\t\ttype. Valid types are: mos, mosdir, config, bpobj,\n"
33355434c77Sek "\t\t\tspacemap, metaslab, errlog. The only valid <object> is\n"
33455434c77Sek "\t\t\tthe poolname.\n");
335ea8dc4b6Seschrock }
336ea8dc4b6Seschrock
337ea8dc4b6Seschrock static int
iter_handlers(int (* func)(int,const char *,zinject_record_t *,void *),void * data)338ea8dc4b6Seschrock iter_handlers(int (*func)(int, const char *, zinject_record_t *, void *),
339ea8dc4b6Seschrock void *data)
340ea8dc4b6Seschrock {
341f4c46b1eSYuri Pankov zfs_cmd_t zc = { 0 };
342ea8dc4b6Seschrock int ret;
343ea8dc4b6Seschrock
344ea8dc4b6Seschrock while (ioctl(zfs_fd, ZFS_IOC_INJECT_LIST_NEXT, &zc) == 0)
345ea8dc4b6Seschrock if ((ret = func((int)zc.zc_guid, zc.zc_name,
346ea8dc4b6Seschrock &zc.zc_inject_record, data)) != 0)
347ea8dc4b6Seschrock return (ret);
348ea8dc4b6Seschrock
34954a91118SChris Kirby if (errno != ENOENT) {
35054a91118SChris Kirby (void) fprintf(stderr, "Unable to list handlers: %s\n",
35154a91118SChris Kirby strerror(errno));
35254a91118SChris Kirby return (-1);
35354a91118SChris Kirby }
35454a91118SChris Kirby
355ea8dc4b6Seschrock return (0);
356ea8dc4b6Seschrock }
357ea8dc4b6Seschrock
358ea8dc4b6Seschrock static int
print_data_handler(int id,const char * pool,zinject_record_t * record,void * data)359ea8dc4b6Seschrock print_data_handler(int id, const char *pool, zinject_record_t *record,
360ea8dc4b6Seschrock void *data)
361ea8dc4b6Seschrock {
362ea8dc4b6Seschrock int *count = data;
363ea8dc4b6Seschrock
36488ecc943SGeorge Wilson if (record->zi_guid != 0 || record->zi_func[0] != '\0')
365ea8dc4b6Seschrock return (0);
366ea8dc4b6Seschrock
367ea8dc4b6Seschrock if (*count == 0) {
36812a8814cSTom Caputi (void) printf("%3s %-15s %-6s %-6s %-8s %3s %-4s ",
36912a8814cSTom Caputi "%-15s\n", "ID", "POOL", "OBJSET", "OBJECT", "TYPE",
37012a8814cSTom Caputi "LVL", "DVAs", "RANGE");
371ea8dc4b6Seschrock (void) printf("--- --------------- ------ "
37212a8814cSTom Caputi "------ -------- --- ---- ----------------\n");
373ea8dc4b6Seschrock }
374ea8dc4b6Seschrock
375ea8dc4b6Seschrock *count += 1;
376ea8dc4b6Seschrock
37712a8814cSTom Caputi (void) printf("%3d %-15s %-6llu %-6llu %-8s %-3d 0x%02x ",
37812a8814cSTom Caputi id, pool, (u_longlong_t)record->zi_objset,
37912a8814cSTom Caputi (u_longlong_t)record->zi_object, type_to_name(record->zi_type),
38012a8814cSTom Caputi record->zi_level, record->zi_dvas);
381ea8dc4b6Seschrock
382ea8dc4b6Seschrock if (record->zi_start == 0 &&
383ea8dc4b6Seschrock record->zi_end == -1ULL)
384ea8dc4b6Seschrock (void) printf("all\n");
385ea8dc4b6Seschrock else
386ea8dc4b6Seschrock (void) printf("[%llu, %llu]\n", (u_longlong_t)record->zi_start,
387ea8dc4b6Seschrock (u_longlong_t)record->zi_end);
388ea8dc4b6Seschrock
389ea8dc4b6Seschrock return (0);
390ea8dc4b6Seschrock }
391ea8dc4b6Seschrock
392ea8dc4b6Seschrock static int
print_device_handler(int id,const char * pool,zinject_record_t * record,void * data)393ea8dc4b6Seschrock print_device_handler(int id, const char *pool, zinject_record_t *record,
394ea8dc4b6Seschrock void *data)
395ea8dc4b6Seschrock {
396ea8dc4b6Seschrock int *count = data;
397ea8dc4b6Seschrock
39888ecc943SGeorge Wilson if (record->zi_guid == 0 || record->zi_func[0] != '\0')
399ea8dc4b6Seschrock return (0);
400ea8dc4b6Seschrock
40197e81309SPrakash Surya if (record->zi_cmd == ZINJECT_DELAY_IO)
40297e81309SPrakash Surya return (0);
40397e81309SPrakash Surya
404ea8dc4b6Seschrock if (*count == 0) {
405ea8dc4b6Seschrock (void) printf("%3s %-15s %s\n", "ID", "POOL", "GUID");
406ea8dc4b6Seschrock (void) printf("--- --------------- ----------------\n");
407ea8dc4b6Seschrock }
408ea8dc4b6Seschrock
409ea8dc4b6Seschrock *count += 1;
410ea8dc4b6Seschrock
411ea8dc4b6Seschrock (void) printf("%3d %-15s %llx\n", id, pool,
412ea8dc4b6Seschrock (u_longlong_t)record->zi_guid);
413ea8dc4b6Seschrock
414ea8dc4b6Seschrock return (0);
415ea8dc4b6Seschrock }
416ea8dc4b6Seschrock
41797e81309SPrakash Surya static int
print_delay_handler(int id,const char * pool,zinject_record_t * record,void * data)41897e81309SPrakash Surya print_delay_handler(int id, const char *pool, zinject_record_t *record,
41997e81309SPrakash Surya void *data)
42097e81309SPrakash Surya {
42197e81309SPrakash Surya int *count = data;
42297e81309SPrakash Surya
42397e81309SPrakash Surya if (record->zi_guid == 0 || record->zi_func[0] != '\0')
42497e81309SPrakash Surya return (0);
42597e81309SPrakash Surya
42697e81309SPrakash Surya if (record->zi_cmd != ZINJECT_DELAY_IO)
42797e81309SPrakash Surya return (0);
42897e81309SPrakash Surya
42997e81309SPrakash Surya if (*count == 0) {
43097e81309SPrakash Surya (void) printf("%3s %-15s %-15s %-15s %s\n",
43197e81309SPrakash Surya "ID", "POOL", "DELAY (ms)", "LANES", "GUID");
43297e81309SPrakash Surya (void) printf("--- --------------- --------------- "
43397e81309SPrakash Surya "--------------- ----------------\n");
43497e81309SPrakash Surya }
43597e81309SPrakash Surya
43697e81309SPrakash Surya *count += 1;
43797e81309SPrakash Surya
43897e81309SPrakash Surya (void) printf("%3d %-15s %-15llu %-15llu %llx\n", id, pool,
43997e81309SPrakash Surya (u_longlong_t)NSEC2MSEC(record->zi_timer),
44097e81309SPrakash Surya (u_longlong_t)record->zi_nlanes,
44197e81309SPrakash Surya (u_longlong_t)record->zi_guid);
44297e81309SPrakash Surya
44397e81309SPrakash Surya return (0);
44497e81309SPrakash Surya }
44597e81309SPrakash Surya
44688ecc943SGeorge Wilson static int
print_panic_handler(int id,const char * pool,zinject_record_t * record,void * data)44788ecc943SGeorge Wilson print_panic_handler(int id, const char *pool, zinject_record_t *record,
44888ecc943SGeorge Wilson void *data)
44988ecc943SGeorge Wilson {
45088ecc943SGeorge Wilson int *count = data;
45188ecc943SGeorge Wilson
45288ecc943SGeorge Wilson if (record->zi_func[0] == '\0')
45388ecc943SGeorge Wilson return (0);
45488ecc943SGeorge Wilson
45588ecc943SGeorge Wilson if (*count == 0) {
45688ecc943SGeorge Wilson (void) printf("%3s %-15s %s\n", "ID", "POOL", "FUNCTION");
45788ecc943SGeorge Wilson (void) printf("--- --------------- ----------------\n");
45888ecc943SGeorge Wilson }
45988ecc943SGeorge Wilson
46088ecc943SGeorge Wilson *count += 1;
46188ecc943SGeorge Wilson
46288ecc943SGeorge Wilson (void) printf("%3d %-15s %s\n", id, pool, record->zi_func);
46388ecc943SGeorge Wilson
46488ecc943SGeorge Wilson return (0);
46588ecc943SGeorge Wilson }
46688ecc943SGeorge Wilson
467ea8dc4b6Seschrock /*
468ea8dc4b6Seschrock * Print all registered error handlers. Returns the number of handlers
469ea8dc4b6Seschrock * registered.
470ea8dc4b6Seschrock */
471ea8dc4b6Seschrock static int
print_all_handlers(void)472ea8dc4b6Seschrock print_all_handlers(void)
473ea8dc4b6Seschrock {
474cb04b873SMark J Musante int count = 0, total = 0;
475ea8dc4b6Seschrock
476ea8dc4b6Seschrock (void) iter_handlers(print_device_handler, &count);
477cb04b873SMark J Musante if (count > 0) {
478cb04b873SMark J Musante total += count;
479cb04b873SMark J Musante (void) printf("\n");
480cb04b873SMark J Musante count = 0;
481cb04b873SMark J Musante }
482cb04b873SMark J Musante
48397e81309SPrakash Surya (void) iter_handlers(print_delay_handler, &count);
48497e81309SPrakash Surya if (count > 0) {
48597e81309SPrakash Surya total += count;
48697e81309SPrakash Surya (void) printf("\n");
48797e81309SPrakash Surya count = 0;
48897e81309SPrakash Surya }
48997e81309SPrakash Surya
490ea8dc4b6Seschrock (void) iter_handlers(print_data_handler, &count);
491cb04b873SMark J Musante if (count > 0) {
492cb04b873SMark J Musante total += count;
493cb04b873SMark J Musante (void) printf("\n");
494cb04b873SMark J Musante count = 0;
495cb04b873SMark J Musante }
496cb04b873SMark J Musante
49788ecc943SGeorge Wilson (void) iter_handlers(print_panic_handler, &count);
498ea8dc4b6Seschrock
499cb04b873SMark J Musante return (count + total);
500ea8dc4b6Seschrock }
501ea8dc4b6Seschrock
502ea8dc4b6Seschrock /* ARGSUSED */
503ea8dc4b6Seschrock static int
cancel_one_handler(int id,const char * pool,zinject_record_t * record,void * data)504ea8dc4b6Seschrock cancel_one_handler(int id, const char *pool, zinject_record_t *record,
505ea8dc4b6Seschrock void *data)
506ea8dc4b6Seschrock {
507f4c46b1eSYuri Pankov zfs_cmd_t zc = { 0 };
508ea8dc4b6Seschrock
509ea8dc4b6Seschrock zc.zc_guid = (uint64_t)id;
510ea8dc4b6Seschrock
511ea8dc4b6Seschrock if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
512ea8dc4b6Seschrock (void) fprintf(stderr, "failed to remove handler %d: %s\n",
513ea8dc4b6Seschrock id, strerror(errno));
514ea8dc4b6Seschrock return (1);
515ea8dc4b6Seschrock }
516ea8dc4b6Seschrock
517ea8dc4b6Seschrock return (0);
518ea8dc4b6Seschrock }
519ea8dc4b6Seschrock
520ea8dc4b6Seschrock /*
521ea8dc4b6Seschrock * Remove all fault injection handlers.
522ea8dc4b6Seschrock */
523ea8dc4b6Seschrock static int
cancel_all_handlers(void)524ea8dc4b6Seschrock cancel_all_handlers(void)
525ea8dc4b6Seschrock {
526ea8dc4b6Seschrock int ret = iter_handlers(cancel_one_handler, NULL);
527ea8dc4b6Seschrock
52854a91118SChris Kirby if (ret == 0)
52954a91118SChris Kirby (void) printf("removed all registered handlers\n");
530ea8dc4b6Seschrock
531ea8dc4b6Seschrock return (ret);
532ea8dc4b6Seschrock }
533ea8dc4b6Seschrock
534ea8dc4b6Seschrock /*
535ea8dc4b6Seschrock * Remove a specific fault injection handler.
536ea8dc4b6Seschrock */
537ea8dc4b6Seschrock static int
cancel_handler(int id)538ea8dc4b6Seschrock cancel_handler(int id)
539ea8dc4b6Seschrock {
540f4c46b1eSYuri Pankov zfs_cmd_t zc = { 0 };
541ea8dc4b6Seschrock
542ea8dc4b6Seschrock zc.zc_guid = (uint64_t)id;
543ea8dc4b6Seschrock
544ea8dc4b6Seschrock if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
545ea8dc4b6Seschrock (void) fprintf(stderr, "failed to remove handler %d: %s\n",
546ea8dc4b6Seschrock id, strerror(errno));
547ea8dc4b6Seschrock return (1);
548ea8dc4b6Seschrock }
549ea8dc4b6Seschrock
550ea8dc4b6Seschrock (void) printf("removed handler %d\n", id);
551ea8dc4b6Seschrock
552ea8dc4b6Seschrock return (0);
553ea8dc4b6Seschrock }
554ea8dc4b6Seschrock
555ea8dc4b6Seschrock /*
556ea8dc4b6Seschrock * Register a new fault injection handler.
557ea8dc4b6Seschrock */
558ea8dc4b6Seschrock static int
register_handler(const char * pool,int flags,zinject_record_t * record,int quiet)559ea8dc4b6Seschrock register_handler(const char *pool, int flags, zinject_record_t *record,
560ea8dc4b6Seschrock int quiet)
561ea8dc4b6Seschrock {
562f4c46b1eSYuri Pankov zfs_cmd_t zc = { 0 };
563ea8dc4b6Seschrock
564ea8dc4b6Seschrock (void) strcpy(zc.zc_name, pool);
565ea8dc4b6Seschrock zc.zc_inject_record = *record;
566ea8dc4b6Seschrock zc.zc_guid = flags;
567ea8dc4b6Seschrock
568ea8dc4b6Seschrock if (ioctl(zfs_fd, ZFS_IOC_INJECT_FAULT, &zc) != 0) {
569ea8dc4b6Seschrock (void) fprintf(stderr, "failed to add handler: %s\n",
570d8ab6e12SDon Brady errno == EDOM ? "block level exceeds max level of object" :
571ea8dc4b6Seschrock strerror(errno));
572ea8dc4b6Seschrock return (1);
573ea8dc4b6Seschrock }
574ea8dc4b6Seschrock
575ea8dc4b6Seschrock if (flags & ZINJECT_NULL)
576ea8dc4b6Seschrock return (0);
577ea8dc4b6Seschrock
578ea8dc4b6Seschrock if (quiet) {
579ea8dc4b6Seschrock (void) printf("%llu\n", (u_longlong_t)zc.zc_guid);
580ea8dc4b6Seschrock } else {
581ea8dc4b6Seschrock (void) printf("Added handler %llu with the following "
582ea8dc4b6Seschrock "properties:\n", (u_longlong_t)zc.zc_guid);
583ea8dc4b6Seschrock (void) printf(" pool: %s\n", pool);
584ea8dc4b6Seschrock if (record->zi_guid) {
585ea8dc4b6Seschrock (void) printf(" vdev: %llx\n",
586ea8dc4b6Seschrock (u_longlong_t)record->zi_guid);
58788ecc943SGeorge Wilson } else if (record->zi_func[0] != '\0') {
58888ecc943SGeorge Wilson (void) printf(" panic function: %s\n",
58988ecc943SGeorge Wilson record->zi_func);
590468c413aSTim Haley } else if (record->zi_duration > 0) {
591468c413aSTim Haley (void) printf(" time: %lld seconds\n",
592468c413aSTim Haley (u_longlong_t)record->zi_duration);
593468c413aSTim Haley } else if (record->zi_duration < 0) {
594468c413aSTim Haley (void) printf(" txgs: %lld \n",
595468c413aSTim Haley (u_longlong_t)-record->zi_duration);
596ea8dc4b6Seschrock } else {
597ea8dc4b6Seschrock (void) printf("objset: %llu\n",
598ea8dc4b6Seschrock (u_longlong_t)record->zi_objset);
599ea8dc4b6Seschrock (void) printf("object: %llu\n",
600ea8dc4b6Seschrock (u_longlong_t)record->zi_object);
601ea8dc4b6Seschrock (void) printf(" type: %llu\n",
602ea8dc4b6Seschrock (u_longlong_t)record->zi_type);
603ea8dc4b6Seschrock (void) printf(" level: %d\n", record->zi_level);
604ea8dc4b6Seschrock if (record->zi_start == 0 &&
605ea8dc4b6Seschrock record->zi_end == -1ULL)
606ea8dc4b6Seschrock (void) printf(" range: all\n");
607ea8dc4b6Seschrock else
608ea8dc4b6Seschrock (void) printf(" range: [%llu, %llu)\n",
609ea8dc4b6Seschrock (u_longlong_t)record->zi_start,
610ea8dc4b6Seschrock (u_longlong_t)record->zi_end);
61112a8814cSTom Caputi (void) printf(" dvas: 0x%x\n", record->zi_dvas);
612ea8dc4b6Seschrock }
613ea8dc4b6Seschrock }
614ea8dc4b6Seschrock
615ea8dc4b6Seschrock return (0);
616ea8dc4b6Seschrock }
617ea8dc4b6Seschrock
6188f18d1faSGeorge Wilson int
perform_action(const char * pool,zinject_record_t * record,int cmd)6198f18d1faSGeorge Wilson perform_action(const char *pool, zinject_record_t *record, int cmd)
6208f18d1faSGeorge Wilson {
621f4c46b1eSYuri Pankov zfs_cmd_t zc = { 0 };
6228f18d1faSGeorge Wilson
6238f18d1faSGeorge Wilson ASSERT(cmd == VDEV_STATE_DEGRADED || cmd == VDEV_STATE_FAULTED);
6248f18d1faSGeorge Wilson (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
6258f18d1faSGeorge Wilson zc.zc_guid = record->zi_guid;
6268f18d1faSGeorge Wilson zc.zc_cookie = cmd;
6278f18d1faSGeorge Wilson
6288f18d1faSGeorge Wilson if (ioctl(zfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
6298f18d1faSGeorge Wilson return (0);
6308f18d1faSGeorge Wilson
6318f18d1faSGeorge Wilson return (1);
6328f18d1faSGeorge Wilson }
6338f18d1faSGeorge Wilson
63497e81309SPrakash Surya static int
parse_delay(char * str,uint64_t * delay,uint64_t * nlanes)63597e81309SPrakash Surya parse_delay(char *str, uint64_t *delay, uint64_t *nlanes)
63697e81309SPrakash Surya {
63797e81309SPrakash Surya unsigned long scan_delay;
63897e81309SPrakash Surya unsigned long scan_nlanes;
63997e81309SPrakash Surya
64097e81309SPrakash Surya if (sscanf(str, "%lu:%lu", &scan_delay, &scan_nlanes) != 2)
64197e81309SPrakash Surya return (1);
64297e81309SPrakash Surya
64397e81309SPrakash Surya /*
64497e81309SPrakash Surya * We explicitly disallow a delay of zero here, because we key
64597e81309SPrakash Surya * off this value being non-zero in translate_device(), to
64697e81309SPrakash Surya * determine if the fault is a ZINJECT_DELAY_IO fault or not.
64797e81309SPrakash Surya */
64897e81309SPrakash Surya if (scan_delay == 0)
64997e81309SPrakash Surya return (1);
65097e81309SPrakash Surya
65197e81309SPrakash Surya /*
65297e81309SPrakash Surya * The units for the CLI delay parameter is milliseconds, but
65397e81309SPrakash Surya * the data passed to the kernel is interpreted as nanoseconds.
65497e81309SPrakash Surya * Thus we scale the milliseconds to nanoseconds here, and this
65597e81309SPrakash Surya * nanosecond value is used to pass the delay to the kernel.
65697e81309SPrakash Surya */
65797e81309SPrakash Surya *delay = MSEC2NSEC(scan_delay);
65897e81309SPrakash Surya *nlanes = scan_nlanes;
65997e81309SPrakash Surya
66097e81309SPrakash Surya return (0);
66197e81309SPrakash Surya }
66297e81309SPrakash Surya
663b853d39aSDon Brady static int
parse_frequency(const char * str,uint32_t * percent)664b853d39aSDon Brady parse_frequency(const char *str, uint32_t *percent)
665b853d39aSDon Brady {
666b853d39aSDon Brady double val;
667b853d39aSDon Brady char *post;
668b853d39aSDon Brady
669b853d39aSDon Brady val = strtod(str, &post);
670b853d39aSDon Brady if (post == NULL || *post != '\0')
671b853d39aSDon Brady return (EINVAL);
672b853d39aSDon Brady
673b853d39aSDon Brady /* valid range is [0.0001, 100.0] */
674b853d39aSDon Brady val /= 100.0f;
675b853d39aSDon Brady if (val < 0.000001f || val > 1.0f)
676b853d39aSDon Brady return (ERANGE);
677b853d39aSDon Brady
678b853d39aSDon Brady /* convert to an integer for use by kernel */
679b853d39aSDon Brady *percent = ((uint32_t)(val * ZI_PERCENTAGE_MAX));
680b853d39aSDon Brady
681b853d39aSDon Brady return (0);
682b853d39aSDon Brady }
683b853d39aSDon Brady
68412a8814cSTom Caputi /*
68512a8814cSTom Caputi * This function converts a string specifier for DVAs into a bit mask.
68612a8814cSTom Caputi * The dva's provided by the user should be 0 indexed and separated by
68712a8814cSTom Caputi * a comma. For example:
68812a8814cSTom Caputi * "1" -> 0b0010 (0x2)
68912a8814cSTom Caputi * "0,1" -> 0b0011 (0x3)
69012a8814cSTom Caputi * "0,1,2" -> 0b0111 (0x7)
69112a8814cSTom Caputi */
69212a8814cSTom Caputi static int
parse_dvas(const char * str,uint32_t * dvas_out)69312a8814cSTom Caputi parse_dvas(const char *str, uint32_t *dvas_out)
69412a8814cSTom Caputi {
69512a8814cSTom Caputi const char *c = str;
69612a8814cSTom Caputi uint32_t mask = 0;
69712a8814cSTom Caputi boolean_t need_delim = B_FALSE;
69812a8814cSTom Caputi
69912a8814cSTom Caputi /* max string length is 5 ("0,1,2") */
70012a8814cSTom Caputi if (strlen(str) > 5 || strlen(str) == 0)
70112a8814cSTom Caputi return (EINVAL);
70212a8814cSTom Caputi
70312a8814cSTom Caputi while (*c != '\0') {
70412a8814cSTom Caputi switch (*c) {
70512a8814cSTom Caputi case '0':
70612a8814cSTom Caputi case '1':
70712a8814cSTom Caputi case '2':
70812a8814cSTom Caputi /* check for pipe between DVAs */
70912a8814cSTom Caputi if (need_delim)
71012a8814cSTom Caputi return (EINVAL);
71112a8814cSTom Caputi
71212a8814cSTom Caputi /* check if this DVA has been set already */
71312a8814cSTom Caputi if (mask & (1 << ((*c) - '0')))
71412a8814cSTom Caputi return (EINVAL);
71512a8814cSTom Caputi
71612a8814cSTom Caputi mask |= (1 << ((*c) - '0'));
71712a8814cSTom Caputi need_delim = B_TRUE;
71812a8814cSTom Caputi break;
71912a8814cSTom Caputi case ',':
72012a8814cSTom Caputi need_delim = B_FALSE;
72112a8814cSTom Caputi break;
72212a8814cSTom Caputi default:
72312a8814cSTom Caputi /* check for invalid character */
72412a8814cSTom Caputi return (EINVAL);
72512a8814cSTom Caputi }
72612a8814cSTom Caputi c++;
72712a8814cSTom Caputi }
72812a8814cSTom Caputi
72912a8814cSTom Caputi /* check for dangling delimiter */
73012a8814cSTom Caputi if (!need_delim)
73112a8814cSTom Caputi return (EINVAL);
73212a8814cSTom Caputi
73312a8814cSTom Caputi *dvas_out = mask;
73412a8814cSTom Caputi return (0);
73512a8814cSTom Caputi }
73612a8814cSTom Caputi
737ea8dc4b6Seschrock int
main(int argc,char ** argv)738ea8dc4b6Seschrock main(int argc, char **argv)
739ea8dc4b6Seschrock {
740ea8dc4b6Seschrock int c;
741ea8dc4b6Seschrock char *range = NULL;
742ea8dc4b6Seschrock char *cancel = NULL;
743ea8dc4b6Seschrock char *end;
744ea8dc4b6Seschrock char *raw = NULL;
745ea8dc4b6Seschrock char *device = NULL;
746ea8dc4b6Seschrock int level = 0;
747ea8dc4b6Seschrock int quiet = 0;
748ea8dc4b6Seschrock int error = 0;
749ea8dc4b6Seschrock int domount = 0;
7508f18d1faSGeorge Wilson int io_type = ZIO_TYPES;
7518f18d1faSGeorge Wilson int action = VDEV_STATE_UNKNOWN;
752ea8dc4b6Seschrock err_type_t type = TYPE_INVAL;
75321bf64a7Sgw err_type_t label = TYPE_INVAL;
754ea8dc4b6Seschrock zinject_record_t record = { 0 };
755ea8dc4b6Seschrock char pool[MAXNAMELEN];
756ea8dc4b6Seschrock char dataset[MAXNAMELEN];
757ea8dc4b6Seschrock zfs_handle_t *zhp;
758468c413aSTim Haley int nowrites = 0;
759468c413aSTim Haley int dur_txg = 0;
760468c413aSTim Haley int dur_secs = 0;
761ea8dc4b6Seschrock int ret;
762ea8dc4b6Seschrock int flags = 0;
76312a8814cSTom Caputi uint32_t dvas = 0;
764ea8dc4b6Seschrock
76599653d4eSeschrock if ((g_zfs = libzfs_init()) == NULL) {
76699653d4eSeschrock (void) fprintf(stderr, "internal error: failed to "
76799653d4eSeschrock "initialize ZFS library\n");
76899653d4eSeschrock return (1);
76999653d4eSeschrock }
77099653d4eSeschrock
77199653d4eSeschrock libzfs_print_on_error(g_zfs, B_TRUE);
77299653d4eSeschrock
773ea8dc4b6Seschrock if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
774ea8dc4b6Seschrock (void) fprintf(stderr, "failed to open ZFS device\n");
7753382f241Sluozhengzheng libzfs_fini(g_zfs);
776ea8dc4b6Seschrock return (1);
777ea8dc4b6Seschrock }
778ea8dc4b6Seschrock
779ea8dc4b6Seschrock if (argc == 1) {
780ea8dc4b6Seschrock /*
781ea8dc4b6Seschrock * No arguments. Print the available handlers. If there are no
782ea8dc4b6Seschrock * available handlers, direct the user to '-h' for help
783ea8dc4b6Seschrock * information.
784ea8dc4b6Seschrock */
785ea8dc4b6Seschrock if (print_all_handlers() == 0) {
786ea8dc4b6Seschrock (void) printf("No handlers registered.\n");
787ea8dc4b6Seschrock (void) printf("Run 'zinject -h' for usage "
788ea8dc4b6Seschrock "information.\n");
789ea8dc4b6Seschrock }
790ea8dc4b6Seschrock
7913382f241Sluozhengzheng libzfs_fini(g_zfs);
792ea8dc4b6Seschrock return (0);
793ea8dc4b6Seschrock }
794ea8dc4b6Seschrock
7958f18d1faSGeorge Wilson while ((c = getopt(argc, argv,
79612a8814cSTom Caputi ":aA:b:C:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:")) != -1) {
797ea8dc4b6Seschrock switch (c) {
798ea8dc4b6Seschrock case 'a':
799ea8dc4b6Seschrock flags |= ZINJECT_FLUSH_ARC;
800ea8dc4b6Seschrock break;
8018f18d1faSGeorge Wilson case 'A':
8028f18d1faSGeorge Wilson if (strcasecmp(optarg, "degrade") == 0) {
8038f18d1faSGeorge Wilson action = VDEV_STATE_DEGRADED;
8048f18d1faSGeorge Wilson } else if (strcasecmp(optarg, "fault") == 0) {
8058f18d1faSGeorge Wilson action = VDEV_STATE_FAULTED;
8068f18d1faSGeorge Wilson } else {
8078f18d1faSGeorge Wilson (void) fprintf(stderr, "invalid action '%s': "
8088f18d1faSGeorge Wilson "must be 'degrade' or 'fault'\n", optarg);
8098f18d1faSGeorge Wilson usage();
8103382f241Sluozhengzheng libzfs_fini(g_zfs);
8118f18d1faSGeorge Wilson return (1);
8128f18d1faSGeorge Wilson }
8138f18d1faSGeorge Wilson break;
814ea8dc4b6Seschrock case 'b':
815ea8dc4b6Seschrock raw = optarg;
816ea8dc4b6Seschrock break;
817ea8dc4b6Seschrock case 'c':
818ea8dc4b6Seschrock cancel = optarg;
819ea8dc4b6Seschrock break;
82012a8814cSTom Caputi case 'C':
82112a8814cSTom Caputi ret = parse_dvas(optarg, &dvas);
82212a8814cSTom Caputi if (ret != 0) {
82312a8814cSTom Caputi (void) fprintf(stderr, "invalid DVA list '%s': "
82412a8814cSTom Caputi "DVAs should be 0 indexed and separated by "
82512a8814cSTom Caputi "commas.\n", optarg);
82612a8814cSTom Caputi usage();
82712a8814cSTom Caputi libzfs_fini(g_zfs);
82812a8814cSTom Caputi return (1);
82912a8814cSTom Caputi }
83012a8814cSTom Caputi break;
831ea8dc4b6Seschrock case 'd':
832ea8dc4b6Seschrock device = optarg;
833ea8dc4b6Seschrock break;
834283b8460SGeorge.Wilson case 'D':
83597e81309SPrakash Surya ret = parse_delay(optarg, &record.zi_timer,
83697e81309SPrakash Surya &record.zi_nlanes);
83797e81309SPrakash Surya if (ret != 0) {
838283b8460SGeorge.Wilson (void) fprintf(stderr, "invalid i/o delay "
839283b8460SGeorge.Wilson "value: '%s'\n", optarg);
840283b8460SGeorge.Wilson usage();
8413382f241Sluozhengzheng libzfs_fini(g_zfs);
842283b8460SGeorge.Wilson return (1);
843283b8460SGeorge.Wilson }
844283b8460SGeorge.Wilson break;
845ea8dc4b6Seschrock case 'e':
846ea8dc4b6Seschrock if (strcasecmp(optarg, "io") == 0) {
847ea8dc4b6Seschrock error = EIO;
848ea8dc4b6Seschrock } else if (strcasecmp(optarg, "checksum") == 0) {
849ea8dc4b6Seschrock error = ECKSUM;
850eb633035STom Caputi } else if (strcasecmp(optarg, "decrypt") == 0) {
851eb633035STom Caputi error = EACCES;
852ea8dc4b6Seschrock } else if (strcasecmp(optarg, "nxio") == 0) {
853ea8dc4b6Seschrock error = ENXIO;
854cb04b873SMark J Musante } else if (strcasecmp(optarg, "dtl") == 0) {
855cb04b873SMark J Musante error = ECHILD;
856ea8dc4b6Seschrock } else {
857ea8dc4b6Seschrock (void) fprintf(stderr, "invalid error type "
858ea8dc4b6Seschrock "'%s': must be 'io', 'checksum' or "
859ea8dc4b6Seschrock "'nxio'\n", optarg);
860ea8dc4b6Seschrock usage();
861ea8dc4b6Seschrock return (1);
862ea8dc4b6Seschrock }
863ea8dc4b6Seschrock break;
864ea8dc4b6Seschrock case 'f':
865b853d39aSDon Brady ret = parse_frequency(optarg, &record.zi_freq);
866b853d39aSDon Brady if (ret != 0) {
867b853d39aSDon Brady (void) fprintf(stderr, "%sfrequency value must "
868b853d39aSDon Brady "be in the range [0.0001, 100.0]\n",
869b853d39aSDon Brady ret == EINVAL ? "invalid value: " :
870b853d39aSDon Brady ret == ERANGE ? "out of range: " : "");
8713382f241Sluozhengzheng libzfs_fini(g_zfs);
872ea8dc4b6Seschrock return (1);
873ea8dc4b6Seschrock }
874ea8dc4b6Seschrock break;
8758956713aSEric Schrock case 'F':
8768956713aSEric Schrock record.zi_failfast = B_TRUE;
8778956713aSEric Schrock break;
878468c413aSTim Haley case 'g':
879468c413aSTim Haley dur_txg = 1;
880468c413aSTim Haley record.zi_duration = (int)strtol(optarg, &end, 10);
881468c413aSTim Haley if (record.zi_duration <= 0 || *end != '\0') {
882468c413aSTim Haley (void) fprintf(stderr, "invalid duration '%s': "
883468c413aSTim Haley "must be a positive integer\n", optarg);
884468c413aSTim Haley usage();
8853382f241Sluozhengzheng libzfs_fini(g_zfs);
886468c413aSTim Haley return (1);
887468c413aSTim Haley }
888468c413aSTim Haley /* store duration of txgs as its negative */
889468c413aSTim Haley record.zi_duration *= -1;
890468c413aSTim Haley break;
891ea8dc4b6Seschrock case 'h':
892ea8dc4b6Seschrock usage();
8933382f241Sluozhengzheng libzfs_fini(g_zfs);
894ea8dc4b6Seschrock return (0);
895468c413aSTim Haley case 'I':
896468c413aSTim Haley /* default duration, if one hasn't yet been defined */
897468c413aSTim Haley nowrites = 1;
898468c413aSTim Haley if (dur_secs == 0 && dur_txg == 0)
899468c413aSTim Haley record.zi_duration = 30;
900468c413aSTim Haley break;
901ea8dc4b6Seschrock case 'l':
902ea8dc4b6Seschrock level = (int)strtol(optarg, &end, 10);
903ea8dc4b6Seschrock if (*end != '\0') {
904ea8dc4b6Seschrock (void) fprintf(stderr, "invalid level '%s': "
905ea8dc4b6Seschrock "must be an integer\n", optarg);
906ea8dc4b6Seschrock usage();
9073382f241Sluozhengzheng libzfs_fini(g_zfs);
908ea8dc4b6Seschrock return (1);
909ea8dc4b6Seschrock }
910ea8dc4b6Seschrock break;
911ea8dc4b6Seschrock case 'm':
912ea8dc4b6Seschrock domount = 1;
913ea8dc4b6Seschrock break;
91488ecc943SGeorge Wilson case 'p':
91588ecc943SGeorge Wilson (void) strlcpy(record.zi_func, optarg,
91688ecc943SGeorge Wilson sizeof (record.zi_func));
917283b8460SGeorge.Wilson record.zi_cmd = ZINJECT_PANIC;
91888ecc943SGeorge Wilson break;
919ea8dc4b6Seschrock case 'q':
920ea8dc4b6Seschrock quiet = 1;
921ea8dc4b6Seschrock break;
922ea8dc4b6Seschrock case 'r':
923ea8dc4b6Seschrock range = optarg;
924d8ab6e12SDon Brady flags |= ZINJECT_CALC_RANGE;
925ea8dc4b6Seschrock break;
926468c413aSTim Haley case 's':
927468c413aSTim Haley dur_secs = 1;
928468c413aSTim Haley record.zi_duration = (int)strtol(optarg, &end, 10);
929468c413aSTim Haley if (record.zi_duration <= 0 || *end != '\0') {
930468c413aSTim Haley (void) fprintf(stderr, "invalid duration '%s': "
931468c413aSTim Haley "must be a positive integer\n", optarg);
932468c413aSTim Haley usage();
9333382f241Sluozhengzheng libzfs_fini(g_zfs);
934468c413aSTim Haley return (1);
935468c413aSTim Haley }
936468c413aSTim Haley break;
9378f18d1faSGeorge Wilson case 'T':
9388f18d1faSGeorge Wilson if (strcasecmp(optarg, "read") == 0) {
9398f18d1faSGeorge Wilson io_type = ZIO_TYPE_READ;
9408f18d1faSGeorge Wilson } else if (strcasecmp(optarg, "write") == 0) {
9418f18d1faSGeorge Wilson io_type = ZIO_TYPE_WRITE;
9428f18d1faSGeorge Wilson } else if (strcasecmp(optarg, "free") == 0) {
9438f18d1faSGeorge Wilson io_type = ZIO_TYPE_FREE;
9448f18d1faSGeorge Wilson } else if (strcasecmp(optarg, "claim") == 0) {
9458f18d1faSGeorge Wilson io_type = ZIO_TYPE_CLAIM;
9468f18d1faSGeorge Wilson } else if (strcasecmp(optarg, "all") == 0) {
9478f18d1faSGeorge Wilson io_type = ZIO_TYPES;
9488f18d1faSGeorge Wilson } else {
9498f18d1faSGeorge Wilson (void) fprintf(stderr, "invalid I/O type "
9508f18d1faSGeorge Wilson "'%s': must be 'read', 'write', 'free', "
9518f18d1faSGeorge Wilson "'claim' or 'all'\n", optarg);
9528f18d1faSGeorge Wilson usage();
9533382f241Sluozhengzheng libzfs_fini(g_zfs);
9548f18d1faSGeorge Wilson return (1);
9558f18d1faSGeorge Wilson }
9568f18d1faSGeorge Wilson break;
957ea8dc4b6Seschrock case 't':
95821bf64a7Sgw if ((type = name_to_type(optarg)) == TYPE_INVAL &&
95921bf64a7Sgw !MOS_TYPE(type)) {
960ea8dc4b6Seschrock (void) fprintf(stderr, "invalid type '%s'\n",
961ea8dc4b6Seschrock optarg);
962ea8dc4b6Seschrock usage();
9633382f241Sluozhengzheng libzfs_fini(g_zfs);
964ea8dc4b6Seschrock return (1);
965ea8dc4b6Seschrock }
966ea8dc4b6Seschrock break;
967ea8dc4b6Seschrock case 'u':
968ea8dc4b6Seschrock flags |= ZINJECT_UNLOAD_SPA;
969ea8dc4b6Seschrock break;
97021bf64a7Sgw case 'L':
97121bf64a7Sgw if ((label = name_to_type(optarg)) == TYPE_INVAL &&
97221bf64a7Sgw !LABEL_TYPE(type)) {
97321bf64a7Sgw (void) fprintf(stderr, "invalid label type "
97421bf64a7Sgw "'%s'\n", optarg);
97521bf64a7Sgw usage();
9763382f241Sluozhengzheng libzfs_fini(g_zfs);
97721bf64a7Sgw return (1);
97821bf64a7Sgw }
97921bf64a7Sgw break;
980ea8dc4b6Seschrock case ':':
981ea8dc4b6Seschrock (void) fprintf(stderr, "option -%c requires an "
982ea8dc4b6Seschrock "operand\n", optopt);
983ea8dc4b6Seschrock usage();
9843382f241Sluozhengzheng libzfs_fini(g_zfs);
985ea8dc4b6Seschrock return (1);
986ea8dc4b6Seschrock case '?':
987ea8dc4b6Seschrock (void) fprintf(stderr, "invalid option '%c'\n",
988ea8dc4b6Seschrock optopt);
989ea8dc4b6Seschrock usage();
9903382f241Sluozhengzheng libzfs_fini(g_zfs);
991ea8dc4b6Seschrock return (2);
992ea8dc4b6Seschrock }
993ea8dc4b6Seschrock }
994ea8dc4b6Seschrock
995ea8dc4b6Seschrock argc -= optind;
996ea8dc4b6Seschrock argv += optind;
997ea8dc4b6Seschrock
998283b8460SGeorge.Wilson if (record.zi_duration != 0)
999283b8460SGeorge.Wilson record.zi_cmd = ZINJECT_IGNORED_WRITES;
1000283b8460SGeorge.Wilson
1001ea8dc4b6Seschrock if (cancel != NULL) {
1002ea8dc4b6Seschrock /*
1003ea8dc4b6Seschrock * '-c' is invalid with any other options.
1004ea8dc4b6Seschrock */
1005ea8dc4b6Seschrock if (raw != NULL || range != NULL || type != TYPE_INVAL ||
100612a8814cSTom Caputi level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED ||
100712a8814cSTom Caputi record.zi_freq > 0 || dvas != 0) {
1008ea8dc4b6Seschrock (void) fprintf(stderr, "cancel (-c) incompatible with "
1009ea8dc4b6Seschrock "any other options\n");
1010ea8dc4b6Seschrock usage();
10113382f241Sluozhengzheng libzfs_fini(g_zfs);
1012ea8dc4b6Seschrock return (2);
1013ea8dc4b6Seschrock }
1014ea8dc4b6Seschrock if (argc != 0) {
1015ea8dc4b6Seschrock (void) fprintf(stderr, "extraneous argument to '-c'\n");
1016ea8dc4b6Seschrock usage();
10173382f241Sluozhengzheng libzfs_fini(g_zfs);
1018ea8dc4b6Seschrock return (2);
1019ea8dc4b6Seschrock }
1020ea8dc4b6Seschrock
1021ea8dc4b6Seschrock if (strcmp(cancel, "all") == 0) {
1022ea8dc4b6Seschrock return (cancel_all_handlers());
1023ea8dc4b6Seschrock } else {
1024ea8dc4b6Seschrock int id = (int)strtol(cancel, &end, 10);
1025ea8dc4b6Seschrock if (*end != '\0') {
1026ea8dc4b6Seschrock (void) fprintf(stderr, "invalid handle id '%s':"
1027ea8dc4b6Seschrock " must be an integer or 'all'\n", cancel);
1028ea8dc4b6Seschrock usage();
10293382f241Sluozhengzheng libzfs_fini(g_zfs);
1030ea8dc4b6Seschrock return (1);
1031ea8dc4b6Seschrock }
1032ea8dc4b6Seschrock return (cancel_handler(id));
1033ea8dc4b6Seschrock }
1034ea8dc4b6Seschrock }
1035ea8dc4b6Seschrock
1036ea8dc4b6Seschrock if (device != NULL) {
1037ea8dc4b6Seschrock /*
1038ea8dc4b6Seschrock * Device (-d) injection uses a completely different mechanism
1039ea8dc4b6Seschrock * for doing injection, so handle it separately here.
1040ea8dc4b6Seschrock */
1041ea8dc4b6Seschrock if (raw != NULL || range != NULL || type != TYPE_INVAL ||
104212a8814cSTom Caputi level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED ||
104312a8814cSTom Caputi dvas != 0) {
1044ea8dc4b6Seschrock (void) fprintf(stderr, "device (-d) incompatible with "
1045ea8dc4b6Seschrock "data error injection\n");
1046ea8dc4b6Seschrock usage();
10473382f241Sluozhengzheng libzfs_fini(g_zfs);
1048ea8dc4b6Seschrock return (2);
1049ea8dc4b6Seschrock }
1050ea8dc4b6Seschrock
1051ea8dc4b6Seschrock if (argc != 1) {
1052ea8dc4b6Seschrock (void) fprintf(stderr, "device (-d) injection requires "
1053ea8dc4b6Seschrock "a single pool name\n");
1054ea8dc4b6Seschrock usage();
10553382f241Sluozhengzheng libzfs_fini(g_zfs);
1056ea8dc4b6Seschrock return (2);
1057ea8dc4b6Seschrock }
1058ea8dc4b6Seschrock
10593382f241Sluozhengzheng (void) strlcpy(pool, argv[0], sizeof (pool));
1060ea8dc4b6Seschrock dataset[0] = '\0';
1061ea8dc4b6Seschrock
1062ea8dc4b6Seschrock if (error == ECKSUM) {
1063ea8dc4b6Seschrock (void) fprintf(stderr, "device error type must be "
1064ea8dc4b6Seschrock "'io' or 'nxio'\n");
10653382f241Sluozhengzheng libzfs_fini(g_zfs);
1066ea8dc4b6Seschrock return (1);
1067ea8dc4b6Seschrock }
1068ea8dc4b6Seschrock
10698f18d1faSGeorge Wilson record.zi_iotype = io_type;
10703382f241Sluozhengzheng if (translate_device(pool, device, label, &record) != 0) {
10713382f241Sluozhengzheng libzfs_fini(g_zfs);
1072ea8dc4b6Seschrock return (1);
10733382f241Sluozhengzheng }
1074ea8dc4b6Seschrock if (!error)
1075ea8dc4b6Seschrock error = ENXIO;
10768f18d1faSGeorge Wilson
10778f18d1faSGeorge Wilson if (action != VDEV_STATE_UNKNOWN)
10788f18d1faSGeorge Wilson return (perform_action(pool, &record, action));
10798f18d1faSGeorge Wilson
1080ea8dc4b6Seschrock } else if (raw != NULL) {
108188ecc943SGeorge Wilson if (range != NULL || type != TYPE_INVAL || level != 0 ||
108212a8814cSTom Caputi record.zi_cmd != ZINJECT_UNINITIALIZED ||
108312a8814cSTom Caputi record.zi_freq > 0 || dvas != 0) {
1084ea8dc4b6Seschrock (void) fprintf(stderr, "raw (-b) format with "
1085ea8dc4b6Seschrock "any other options\n");
1086ea8dc4b6Seschrock usage();
10873382f241Sluozhengzheng libzfs_fini(g_zfs);
1088ea8dc4b6Seschrock return (2);
1089ea8dc4b6Seschrock }
1090ea8dc4b6Seschrock
1091ea8dc4b6Seschrock if (argc != 1) {
1092ea8dc4b6Seschrock (void) fprintf(stderr, "raw (-b) format expects a "
1093ea8dc4b6Seschrock "single pool name\n");
1094ea8dc4b6Seschrock usage();
10953382f241Sluozhengzheng libzfs_fini(g_zfs);
1096ea8dc4b6Seschrock return (2);
1097ea8dc4b6Seschrock }
1098ea8dc4b6Seschrock
10993382f241Sluozhengzheng (void) strlcpy(pool, argv[0], sizeof (pool));
1100ea8dc4b6Seschrock dataset[0] = '\0';
1101ea8dc4b6Seschrock
1102ea8dc4b6Seschrock if (error == ENXIO) {
1103ea8dc4b6Seschrock (void) fprintf(stderr, "data error type must be "
1104ea8dc4b6Seschrock "'checksum' or 'io'\n");
11053382f241Sluozhengzheng libzfs_fini(g_zfs);
1106ea8dc4b6Seschrock return (1);
1107ea8dc4b6Seschrock }
1108ea8dc4b6Seschrock
1109283b8460SGeorge.Wilson record.zi_cmd = ZINJECT_DATA_FAULT;
11103382f241Sluozhengzheng if (translate_raw(raw, &record) != 0) {
11113382f241Sluozhengzheng libzfs_fini(g_zfs);
1112ea8dc4b6Seschrock return (1);
11133382f241Sluozhengzheng }
1114ea8dc4b6Seschrock if (!error)
1115ea8dc4b6Seschrock error = EIO;
1116283b8460SGeorge.Wilson } else if (record.zi_cmd == ZINJECT_PANIC) {
111788ecc943SGeorge Wilson if (raw != NULL || range != NULL || type != TYPE_INVAL ||
111812a8814cSTom Caputi level != 0 || device != NULL || record.zi_freq > 0 ||
111912a8814cSTom Caputi dvas != 0) {
112088ecc943SGeorge Wilson (void) fprintf(stderr, "panic (-p) incompatible with "
112188ecc943SGeorge Wilson "other options\n");
112288ecc943SGeorge Wilson usage();
11233382f241Sluozhengzheng libzfs_fini(g_zfs);
112488ecc943SGeorge Wilson return (2);
112588ecc943SGeorge Wilson }
112688ecc943SGeorge Wilson
11271195e687SMark J Musante if (argc < 1 || argc > 2) {
112888ecc943SGeorge Wilson (void) fprintf(stderr, "panic (-p) injection requires "
11291195e687SMark J Musante "a single pool name and an optional id\n");
113088ecc943SGeorge Wilson usage();
11313382f241Sluozhengzheng libzfs_fini(g_zfs);
113288ecc943SGeorge Wilson return (2);
113388ecc943SGeorge Wilson }
113488ecc943SGeorge Wilson
11353382f241Sluozhengzheng (void) strlcpy(pool, argv[0], sizeof (pool));
11361195e687SMark J Musante if (argv[1] != NULL)
11371195e687SMark J Musante record.zi_type = atoi(argv[1]);
1138468c413aSTim Haley dataset[0] = '\0';
1139283b8460SGeorge.Wilson } else if (record.zi_cmd == ZINJECT_IGNORED_WRITES) {
114012a8814cSTom Caputi if (raw != NULL || range != NULL || type != TYPE_INVAL ||
114112a8814cSTom Caputi level != 0 || record.zi_freq > 0 || dvas != 0) {
114212a8814cSTom Caputi (void) fprintf(stderr, "hardware failure (-I) "
114312a8814cSTom Caputi "incompatible with other options\n");
114412a8814cSTom Caputi usage();
114512a8814cSTom Caputi libzfs_fini(g_zfs);
114612a8814cSTom Caputi return (2);
114712a8814cSTom Caputi }
114812a8814cSTom Caputi
1149468c413aSTim Haley if (nowrites == 0) {
1150468c413aSTim Haley (void) fprintf(stderr, "-s or -g meaningless "
1151468c413aSTim Haley "without -I (ignore writes)\n");
1152468c413aSTim Haley usage();
11533382f241Sluozhengzheng libzfs_fini(g_zfs);
1154468c413aSTim Haley return (2);
1155468c413aSTim Haley } else if (dur_secs && dur_txg) {
1156468c413aSTim Haley (void) fprintf(stderr, "choose a duration either "
1157468c413aSTim Haley "in seconds (-s) or a number of txgs (-g) "
1158468c413aSTim Haley "but not both\n");
1159468c413aSTim Haley usage();
11603382f241Sluozhengzheng libzfs_fini(g_zfs);
1161468c413aSTim Haley return (2);
1162468c413aSTim Haley } else if (argc != 1) {
1163468c413aSTim Haley (void) fprintf(stderr, "ignore writes (-I) "
1164468c413aSTim Haley "injection requires a single pool name\n");
1165468c413aSTim Haley usage();
11663382f241Sluozhengzheng libzfs_fini(g_zfs);
1167468c413aSTim Haley return (2);
1168468c413aSTim Haley }
1169468c413aSTim Haley
11703382f241Sluozhengzheng (void) strlcpy(pool, argv[0], sizeof (pool));
117188ecc943SGeorge Wilson dataset[0] = '\0';
1172ea8dc4b6Seschrock } else if (type == TYPE_INVAL) {
1173ea8dc4b6Seschrock if (flags == 0) {
1174ea8dc4b6Seschrock (void) fprintf(stderr, "at least one of '-b', '-d', "
1175468c413aSTim Haley "'-t', '-a', '-p', '-I' or '-u' "
1176468c413aSTim Haley "must be specified\n");
1177ea8dc4b6Seschrock usage();
11783382f241Sluozhengzheng libzfs_fini(g_zfs);
1179ea8dc4b6Seschrock return (2);
1180ea8dc4b6Seschrock }
1181ea8dc4b6Seschrock
1182ea8dc4b6Seschrock if (argc == 1 && (flags & ZINJECT_UNLOAD_SPA)) {
11833382f241Sluozhengzheng (void) strlcpy(pool, argv[0], sizeof (pool));
1184ea8dc4b6Seschrock dataset[0] = '\0';
1185ea8dc4b6Seschrock } else if (argc != 0) {
1186ea8dc4b6Seschrock (void) fprintf(stderr, "extraneous argument for "
1187ea8dc4b6Seschrock "'-f'\n");
1188ea8dc4b6Seschrock usage();
11893382f241Sluozhengzheng libzfs_fini(g_zfs);
1190ea8dc4b6Seschrock return (2);
1191ea8dc4b6Seschrock }
1192ea8dc4b6Seschrock
1193ea8dc4b6Seschrock flags |= ZINJECT_NULL;
1194ea8dc4b6Seschrock } else {
1195ea8dc4b6Seschrock if (argc != 1) {
1196ea8dc4b6Seschrock (void) fprintf(stderr, "missing object\n");
1197ea8dc4b6Seschrock usage();
11983382f241Sluozhengzheng libzfs_fini(g_zfs);
1199ea8dc4b6Seschrock return (2);
1200ea8dc4b6Seschrock }
1201ea8dc4b6Seschrock
1202ea8dc4b6Seschrock if (error == ENXIO) {
1203ea8dc4b6Seschrock (void) fprintf(stderr, "data error type must be "
1204ea8dc4b6Seschrock "'checksum' or 'io'\n");
12053382f241Sluozhengzheng libzfs_fini(g_zfs);
1206ea8dc4b6Seschrock return (1);
1207ea8dc4b6Seschrock }
1208ea8dc4b6Seschrock
120912a8814cSTom Caputi if (dvas != 0) {
121012a8814cSTom Caputi if (error == EACCES || error == EINVAL) {
121112a8814cSTom Caputi (void) fprintf(stderr, "the '-C' option may "
121212a8814cSTom Caputi "not be used with logical data errors "
121312a8814cSTom Caputi "'decrypt' and 'decompress'\n");
1214*6a72ec1aSToomas Soome libzfs_fini(g_zfs);
1215*6a72ec1aSToomas Soome return (1);
1216eb633035STom Caputi }
1217*6a72ec1aSToomas Soome record.zi_dvas = dvas;
1218eb633035STom Caputi }
1219eb633035STom Caputi
1220eb633035STom Caputi if (error == EACCES) {
1221eb633035STom Caputi if (type != TYPE_DATA) {
1222eb633035STom Caputi (void) fprintf(stderr, "decryption errors "
1223eb633035STom Caputi "may only be injected for 'data' types\n");
122412a8814cSTom Caputi libzfs_fini(g_zfs);
122512a8814cSTom Caputi return (1);
122612a8814cSTom Caputi }
122712a8814cSTom Caputi
1228eb633035STom Caputi record.zi_cmd = ZINJECT_DECRYPT_FAULT;
1229eb633035STom Caputi /*
1230eb633035STom Caputi * Internally, ZFS actually uses ECKSUM for decryption
1231eb633035STom Caputi * errors since EACCES is used to indicate the key was
1232eb633035STom Caputi * not found.
1233eb633035STom Caputi */
1234eb633035STom Caputi error = ECKSUM;
1235*6a72ec1aSToomas Soome } else {
1236*6a72ec1aSToomas Soome record.zi_cmd = ZINJECT_DATA_FAULT;
123712a8814cSTom Caputi }
123812a8814cSTom Caputi
1239ea8dc4b6Seschrock if (translate_record(type, argv[0], range, level, &record, pool,
12403382f241Sluozhengzheng dataset) != 0) {
12413382f241Sluozhengzheng libzfs_fini(g_zfs);
1242ea8dc4b6Seschrock return (1);
12433382f241Sluozhengzheng }
1244ea8dc4b6Seschrock if (!error)
1245ea8dc4b6Seschrock error = EIO;
1246ea8dc4b6Seschrock }
1247ea8dc4b6Seschrock
1248ea8dc4b6Seschrock /*
1249ea8dc4b6Seschrock * If this is pool-wide metadata, unmount everything. The ioctl() will
1250ea8dc4b6Seschrock * unload the pool, so that we trigger spa-wide reopen of metadata next
1251ea8dc4b6Seschrock * time we access the pool.
1252ea8dc4b6Seschrock */
1253ea8dc4b6Seschrock if (dataset[0] != '\0' && domount) {
12543382f241Sluozhengzheng if ((zhp = zfs_open(g_zfs, dataset,
12553382f241Sluozhengzheng ZFS_TYPE_DATASET)) == NULL) {
12563382f241Sluozhengzheng libzfs_fini(g_zfs);
1257ea8dc4b6Seschrock return (1);
12583382f241Sluozhengzheng }
1259ea8dc4b6Seschrock
12603382f241Sluozhengzheng if (zfs_unmount(zhp, NULL, 0) != 0) {
12613382f241Sluozhengzheng libzfs_fini(g_zfs);
1262ea8dc4b6Seschrock return (1);
12633382f241Sluozhengzheng }
1264ea8dc4b6Seschrock }
1265ea8dc4b6Seschrock
1266ea8dc4b6Seschrock record.zi_error = error;
1267ea8dc4b6Seschrock
1268ea8dc4b6Seschrock ret = register_handler(pool, flags, &record, quiet);
1269ea8dc4b6Seschrock
1270ea8dc4b6Seschrock if (dataset[0] != '\0' && domount)
1271ea8dc4b6Seschrock ret = (zfs_mount(zhp, NULL, 0) != 0);
1272ea8dc4b6Seschrock
127399653d4eSeschrock libzfs_fini(g_zfs);
127499653d4eSeschrock
1275ea8dc4b6Seschrock return (ret);
1276ea8dc4b6Seschrock }
1277