xref: /illumos-gate/usr/src/cmd/zinject/zinject.c (revision 6a72ec1a)
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