xref: /freebsd-src/sys/contrib/openzfs/cmd/zinject/zinject.c (revision 5289625dfecb962e0410dfafc403aced3b9a2e4b)
1eda14cbcSMatt Macy /*
2eda14cbcSMatt Macy  * CDDL HEADER START
3eda14cbcSMatt Macy  *
4eda14cbcSMatt Macy  * The contents of this file are subject to the terms of the
5eda14cbcSMatt Macy  * Common Development and Distribution License (the "License").
6eda14cbcSMatt Macy  * You may not use this file except in compliance with the License.
7eda14cbcSMatt Macy  *
8eda14cbcSMatt Macy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9271171e0SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
10eda14cbcSMatt Macy  * See the License for the specific language governing permissions
11eda14cbcSMatt Macy  * and limitations under the License.
12eda14cbcSMatt Macy  *
13eda14cbcSMatt Macy  * When distributing Covered Code, include this CDDL HEADER in each
14eda14cbcSMatt Macy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15eda14cbcSMatt Macy  * If applicable, add the following below this CDDL HEADER, with the
16eda14cbcSMatt Macy  * fields enclosed by brackets "[]" replaced with your own identifying
17eda14cbcSMatt Macy  * information: Portions Copyright [yyyy] [name of copyright owner]
18eda14cbcSMatt Macy  *
19eda14cbcSMatt Macy  * CDDL HEADER END
20eda14cbcSMatt Macy  */
21eda14cbcSMatt Macy /*
22eda14cbcSMatt Macy  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23eda14cbcSMatt Macy  * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
24eda14cbcSMatt Macy  * Copyright (c) 2017, Intel Corporation.
25c6767dc1SMartin Matuska  * Copyright (c) 2023-2025, Klara, Inc.
26eda14cbcSMatt Macy  */
27eda14cbcSMatt Macy 
28eda14cbcSMatt Macy /*
29eda14cbcSMatt Macy  * ZFS Fault Injector
30eda14cbcSMatt Macy  *
31eda14cbcSMatt Macy  * This userland component takes a set of options and uses libzpool to translate
32eda14cbcSMatt Macy  * from a user-visible object type and name to an internal representation.
33eda14cbcSMatt Macy  * There are two basic types of faults: device faults and data faults.
34eda14cbcSMatt Macy  *
35eda14cbcSMatt Macy  *
36eda14cbcSMatt Macy  * DEVICE FAULTS
37eda14cbcSMatt Macy  *
38eda14cbcSMatt Macy  * Errors can be injected into a particular vdev using the '-d' option.  This
39eda14cbcSMatt Macy  * option takes a path or vdev GUID to uniquely identify the device within a
40eda14cbcSMatt Macy  * pool.  There are four types of errors that can be injected, IO, ENXIO,
41eda14cbcSMatt Macy  * ECHILD, and EILSEQ.  These can be controlled through the '-e' option and the
42eda14cbcSMatt Macy  * default is ENXIO.  For EIO failures, any attempt to read data from the device
43eda14cbcSMatt Macy  * will return EIO, but a subsequent attempt to reopen the device will succeed.
44eda14cbcSMatt Macy  * For ENXIO failures, any attempt to read from the device will return EIO, but
45eda14cbcSMatt Macy  * any attempt to reopen the device will also return ENXIO.  The EILSEQ failures
46eda14cbcSMatt Macy  * only apply to read operations (-T read) and will flip a bit after the device
47eda14cbcSMatt Macy  * has read the original data.
48eda14cbcSMatt Macy  *
49eda14cbcSMatt Macy  * For label faults, the -L option must be specified. This allows faults
50eda14cbcSMatt Macy  * to be injected into either the nvlist, uberblock, pad1, or pad2 region
51eda14cbcSMatt Macy  * of all the labels for the specified device.
52eda14cbcSMatt Macy  *
53eda14cbcSMatt Macy  * This form of the command looks like:
54eda14cbcSMatt Macy  *
55eda14cbcSMatt Macy  * 	zinject -d device [-e errno] [-L <uber | nvlist | pad1 | pad2>] pool
56eda14cbcSMatt Macy  *
57eda14cbcSMatt Macy  *
58eda14cbcSMatt Macy  * DATA FAULTS
59eda14cbcSMatt Macy  *
60eda14cbcSMatt Macy  * We begin with a tuple of the form:
61eda14cbcSMatt Macy  *
62eda14cbcSMatt Macy  * 	<type,level,range,object>
63eda14cbcSMatt Macy  *
64eda14cbcSMatt Macy  * 	type	A string describing the type of data to target.  Each type
65eda14cbcSMatt Macy  * 		implicitly describes how to interpret 'object'. Currently,
66eda14cbcSMatt Macy  * 		the following values are supported:
67eda14cbcSMatt Macy  *
68eda14cbcSMatt Macy  * 		data		User data for a file
69eda14cbcSMatt Macy  * 		dnode		Dnode for a file or directory
70eda14cbcSMatt Macy  *
71eda14cbcSMatt Macy  *		The following MOS objects are special.  Instead of injecting
72eda14cbcSMatt Macy  *		errors on a particular object or blkid, we inject errors across
73eda14cbcSMatt Macy  *		all objects of the given type.
74eda14cbcSMatt Macy  *
75eda14cbcSMatt Macy  * 		mos		Any data in the MOS
76eda14cbcSMatt Macy  * 		mosdir		object directory
77eda14cbcSMatt Macy  * 		config		pool configuration
78eda14cbcSMatt Macy  * 		bpobj		blkptr list
79eda14cbcSMatt Macy  * 		spacemap	spacemap
80eda14cbcSMatt Macy  * 		metaslab	metaslab
81eda14cbcSMatt Macy  * 		errlog		persistent error log
82eda14cbcSMatt Macy  *
83eda14cbcSMatt Macy  * 	level	Object level.  Defaults to '0', not applicable to all types.  If
84eda14cbcSMatt Macy  * 		a range is given, this corresponds to the indirect block
85eda14cbcSMatt Macy  * 		corresponding to the specific range.
86eda14cbcSMatt Macy  *
87eda14cbcSMatt Macy  *	range	A numerical range [start,end) within the object.  Defaults to
88eda14cbcSMatt Macy  *		the full size of the file.
89eda14cbcSMatt Macy  *
90eda14cbcSMatt Macy  * 	object	A string describing the logical location of the object.  For
91eda14cbcSMatt Macy  * 		files and directories (currently the only supported types),
92eda14cbcSMatt Macy  * 		this is the path of the object on disk.
93eda14cbcSMatt Macy  *
94eda14cbcSMatt Macy  * This is translated, via libzpool, into the following internal representation:
95eda14cbcSMatt Macy  *
96eda14cbcSMatt Macy  * 	<type,objset,object,level,range>
97eda14cbcSMatt Macy  *
98eda14cbcSMatt Macy  * These types should be self-explanatory.  This tuple is then passed to the
99eda14cbcSMatt Macy  * kernel via a special ioctl() to initiate fault injection for the given
100eda14cbcSMatt Macy  * object.  Note that 'type' is not strictly necessary for fault injection, but
101eda14cbcSMatt Macy  * is used when translating existing faults into a human-readable string.
102eda14cbcSMatt Macy  *
103eda14cbcSMatt Macy  *
104eda14cbcSMatt Macy  * The command itself takes one of the forms:
105eda14cbcSMatt Macy  *
106eda14cbcSMatt Macy  * 	zinject
107eda14cbcSMatt Macy  * 	zinject <-a | -u pool>
108eda14cbcSMatt Macy  * 	zinject -c <id|all>
109eda14cbcSMatt Macy  * 	zinject [-q] <-t type> [-f freq] [-u] [-a] [-m] [-e errno] [-l level]
110eda14cbcSMatt Macy  *	    [-r range] <object>
111eda14cbcSMatt Macy  * 	zinject [-f freq] [-a] [-m] [-u] -b objset:object:level:start:end pool
112eda14cbcSMatt Macy  *
113eda14cbcSMatt Macy  * With no arguments, the command prints all currently registered injection
114eda14cbcSMatt Macy  * handlers, with their numeric identifiers.
115eda14cbcSMatt Macy  *
116eda14cbcSMatt Macy  * The '-c' option will clear the given handler, or all handlers if 'all' is
117eda14cbcSMatt Macy  * specified.
118eda14cbcSMatt Macy  *
119eda14cbcSMatt Macy  * The '-e' option takes a string describing the errno to simulate.  This must
120eda14cbcSMatt Macy  * be one of 'io', 'checksum', 'decompress', or 'decrypt'.  In most cases this
121eda14cbcSMatt Macy  * will result in the same behavior, but RAID-Z will produce a different set of
122eda14cbcSMatt Macy  * ereports for this situation.
123eda14cbcSMatt Macy  *
124eda14cbcSMatt Macy  * The '-a', '-u', and '-m' flags toggle internal flush behavior.  If '-a' is
125eda14cbcSMatt Macy  * specified, then the ARC cache is flushed appropriately.  If '-u' is
126eda14cbcSMatt Macy  * specified, then the underlying SPA is unloaded.  Either of these flags can be
127eda14cbcSMatt Macy  * specified independently of any other handlers.  The '-m' flag automatically
128eda14cbcSMatt Macy  * does an unmount and remount of the underlying dataset to aid in flushing the
129eda14cbcSMatt Macy  * cache.
130eda14cbcSMatt Macy  *
131eda14cbcSMatt Macy  * The '-f' flag controls the frequency of errors injected, expressed as a
132eda14cbcSMatt Macy  * real number percentage between 0.0001 and 100.  The default is 100.
133eda14cbcSMatt Macy  *
134eda14cbcSMatt Macy  * The this form is responsible for actually injecting the handler into the
135eda14cbcSMatt Macy  * framework.  It takes the arguments described above, translates them to the
136eda14cbcSMatt Macy  * internal tuple using libzpool, and then issues an ioctl() to register the
137eda14cbcSMatt Macy  * handler.
138eda14cbcSMatt Macy  *
139eda14cbcSMatt Macy  * The final form can target a specific bookmark, regardless of whether a
140eda14cbcSMatt Macy  * human-readable interface has been designed.  It allows developers to specify
141eda14cbcSMatt Macy  * a particular block by number.
142eda14cbcSMatt Macy  */
143eda14cbcSMatt Macy 
144eda14cbcSMatt Macy #include <errno.h>
145eda14cbcSMatt Macy #include <fcntl.h>
146eda14cbcSMatt Macy #include <stdio.h>
147eda14cbcSMatt Macy #include <stdlib.h>
148da5137abSMartin Matuska #include <string.h>
149eda14cbcSMatt Macy #include <strings.h>
150eda14cbcSMatt Macy #include <unistd.h>
151eda14cbcSMatt Macy 
152eda14cbcSMatt Macy #include <sys/fs/zfs.h>
153eda14cbcSMatt Macy #include <sys/mount.h>
154eda14cbcSMatt Macy 
155eda14cbcSMatt Macy #include <libzfs.h>
156eda14cbcSMatt Macy 
157eda14cbcSMatt Macy #undef verify	/* both libzfs.h and zfs_context.h want to define this */
158eda14cbcSMatt Macy 
159eda14cbcSMatt Macy #include "zinject.h"
160eda14cbcSMatt Macy 
161eda14cbcSMatt Macy libzfs_handle_t *g_zfs;
162eda14cbcSMatt Macy int zfs_fd;
163eda14cbcSMatt Macy 
164da5137abSMartin Matuska static const char *const errtable[TYPE_INVAL] = {
165eda14cbcSMatt Macy 	"data",
166eda14cbcSMatt Macy 	"dnode",
167eda14cbcSMatt Macy 	"mos",
168eda14cbcSMatt Macy 	"mosdir",
169eda14cbcSMatt Macy 	"metaslab",
170eda14cbcSMatt Macy 	"config",
171eda14cbcSMatt Macy 	"bpobj",
172eda14cbcSMatt Macy 	"spacemap",
173eda14cbcSMatt Macy 	"errlog",
174eda14cbcSMatt Macy 	"uber",
175eda14cbcSMatt Macy 	"nvlist",
176eda14cbcSMatt Macy 	"pad1",
177eda14cbcSMatt Macy 	"pad2"
178eda14cbcSMatt Macy };
179eda14cbcSMatt Macy 
180eda14cbcSMatt Macy static err_type_t
181eda14cbcSMatt Macy name_to_type(const char *arg)
182eda14cbcSMatt Macy {
183eda14cbcSMatt Macy 	int i;
184eda14cbcSMatt Macy 	for (i = 0; i < TYPE_INVAL; i++)
185eda14cbcSMatt Macy 		if (strcmp(errtable[i], arg) == 0)
186eda14cbcSMatt Macy 			return (i);
187eda14cbcSMatt Macy 
188eda14cbcSMatt Macy 	return (TYPE_INVAL);
189eda14cbcSMatt Macy }
190eda14cbcSMatt Macy 
191eda14cbcSMatt Macy static const char *
192eda14cbcSMatt Macy type_to_name(uint64_t type)
193eda14cbcSMatt Macy {
194eda14cbcSMatt Macy 	switch (type) {
195eda14cbcSMatt Macy 	case DMU_OT_OBJECT_DIRECTORY:
196eda14cbcSMatt Macy 		return ("mosdir");
197eda14cbcSMatt Macy 	case DMU_OT_OBJECT_ARRAY:
198eda14cbcSMatt Macy 		return ("metaslab");
199eda14cbcSMatt Macy 	case DMU_OT_PACKED_NVLIST:
200eda14cbcSMatt Macy 		return ("config");
201eda14cbcSMatt Macy 	case DMU_OT_BPOBJ:
202eda14cbcSMatt Macy 		return ("bpobj");
203eda14cbcSMatt Macy 	case DMU_OT_SPACE_MAP:
204eda14cbcSMatt Macy 		return ("spacemap");
205eda14cbcSMatt Macy 	case DMU_OT_ERROR_LOG:
206eda14cbcSMatt Macy 		return ("errlog");
207eda14cbcSMatt Macy 	default:
208eda14cbcSMatt Macy 		return ("-");
209eda14cbcSMatt Macy 	}
210eda14cbcSMatt Macy }
211eda14cbcSMatt Macy 
2121719886fSMartin Matuska struct errstr {
2131719886fSMartin Matuska 	int		err;
2141719886fSMartin Matuska 	const char	*str;
2151719886fSMartin Matuska };
2161719886fSMartin Matuska static const struct errstr errstrtable[] = {
2171719886fSMartin Matuska 	{ EIO,		"io" },
2181719886fSMartin Matuska 	{ ECKSUM,	"checksum" },
2191719886fSMartin Matuska 	{ EINVAL,	"decompress" },
2201719886fSMartin Matuska 	{ EACCES,	"decrypt" },
2211719886fSMartin Matuska 	{ ENXIO,	"nxio" },
2221719886fSMartin Matuska 	{ ECHILD,	"dtl" },
2231719886fSMartin Matuska 	{ EILSEQ,	"corrupt" },
2241719886fSMartin Matuska 	{ ENOSYS,	"noop" },
2251719886fSMartin Matuska 	{ 0, NULL },
2261719886fSMartin Matuska };
2271719886fSMartin Matuska 
2281719886fSMartin Matuska static int
2291719886fSMartin Matuska str_to_err(const char *str)
2301719886fSMartin Matuska {
2311719886fSMartin Matuska 	for (int i = 0; errstrtable[i].str != NULL; i++)
2321719886fSMartin Matuska 		if (strcasecmp(errstrtable[i].str, str) == 0)
2331719886fSMartin Matuska 			return (errstrtable[i].err);
2341719886fSMartin Matuska 	return (-1);
2351719886fSMartin Matuska }
2361719886fSMartin Matuska static const char *
2371719886fSMartin Matuska err_to_str(int err)
2381719886fSMartin Matuska {
2391719886fSMartin Matuska 	for (int i = 0; errstrtable[i].str != NULL; i++)
2401719886fSMartin Matuska 		if (errstrtable[i].err == err)
2411719886fSMartin Matuska 			return (errstrtable[i].str);
2421719886fSMartin Matuska 	return ("[unknown]");
2431719886fSMartin Matuska }
244eda14cbcSMatt Macy 
245c6767dc1SMartin Matuska static const char *const iotypestrtable[ZINJECT_IOTYPES] = {
246c6767dc1SMartin Matuska 	[ZINJECT_IOTYPE_NULL]	= "null",
247c6767dc1SMartin Matuska 	[ZINJECT_IOTYPE_READ]	= "read",
248c6767dc1SMartin Matuska 	[ZINJECT_IOTYPE_WRITE]	= "write",
249c6767dc1SMartin Matuska 	[ZINJECT_IOTYPE_FREE]	= "free",
250c6767dc1SMartin Matuska 	[ZINJECT_IOTYPE_CLAIM]	= "claim",
251c6767dc1SMartin Matuska 	[ZINJECT_IOTYPE_FLUSH]	= "flush",
252c6767dc1SMartin Matuska 	[ZINJECT_IOTYPE_TRIM]	= "trim",
253c6767dc1SMartin Matuska 	[ZINJECT_IOTYPE_ALL]	= "all",
254c6767dc1SMartin Matuska 	[ZINJECT_IOTYPE_PROBE]	= "probe",
255c6767dc1SMartin Matuska };
256c6767dc1SMartin Matuska 
257c6767dc1SMartin Matuska static zinject_iotype_t
258c6767dc1SMartin Matuska str_to_iotype(const char *arg)
259c6767dc1SMartin Matuska {
260c6767dc1SMartin Matuska 	for (uint_t iotype = 0; iotype < ZINJECT_IOTYPES; iotype++)
261c6767dc1SMartin Matuska 		if (iotypestrtable[iotype] != NULL &&
262c6767dc1SMartin Matuska 		    strcasecmp(iotypestrtable[iotype], arg) == 0)
263c6767dc1SMartin Matuska 			return (iotype);
264c6767dc1SMartin Matuska 	return (ZINJECT_IOTYPES);
265c6767dc1SMartin Matuska }
266c6767dc1SMartin Matuska 
267c6767dc1SMartin Matuska static const char *
268c6767dc1SMartin Matuska iotype_to_str(zinject_iotype_t iotype)
269c6767dc1SMartin Matuska {
270c6767dc1SMartin Matuska 	if (iotype >= ZINJECT_IOTYPES || iotypestrtable[iotype] == NULL)
271c6767dc1SMartin Matuska 		return ("[unknown]");
272c6767dc1SMartin Matuska 	return (iotypestrtable[iotype]);
273c6767dc1SMartin Matuska }
274c6767dc1SMartin Matuska 
275eda14cbcSMatt Macy /*
276eda14cbcSMatt Macy  * Print usage message.
277eda14cbcSMatt Macy  */
278eda14cbcSMatt Macy void
279eda14cbcSMatt Macy usage(void)
280eda14cbcSMatt Macy {
281eda14cbcSMatt Macy 	(void) printf(
282eda14cbcSMatt Macy 	    "usage:\n"
283eda14cbcSMatt Macy 	    "\n"
284eda14cbcSMatt Macy 	    "\tzinject\n"
285eda14cbcSMatt Macy 	    "\n"
286eda14cbcSMatt Macy 	    "\t\tList all active injection records.\n"
287eda14cbcSMatt Macy 	    "\n"
288eda14cbcSMatt Macy 	    "\tzinject -c <id|all>\n"
289eda14cbcSMatt Macy 	    "\n"
290eda14cbcSMatt Macy 	    "\t\tClear the particular record (if given a numeric ID), or\n"
291eda14cbcSMatt Macy 	    "\t\tall records if 'all' is specified.\n"
292eda14cbcSMatt Macy 	    "\n"
293eda14cbcSMatt Macy 	    "\tzinject -p <function name> pool\n"
294eda14cbcSMatt Macy 	    "\t\tInject a panic fault at the specified function. Only \n"
295eda14cbcSMatt Macy 	    "\t\tfunctions which call spa_vdev_config_exit(), or \n"
296eda14cbcSMatt Macy 	    "\t\tspa_vdev_exit() will trigger a panic.\n"
297eda14cbcSMatt Macy 	    "\n"
298eda14cbcSMatt Macy 	    "\tzinject -d device [-e errno] [-L <nvlist|uber|pad1|pad2>] [-F]\n"
2991719886fSMartin Matuska 	    "\t\t[-T <read|write|free|claim|flush|all>] [-f frequency] pool\n\n"
300eda14cbcSMatt Macy 	    "\t\tInject a fault into a particular device or the device's\n"
301eda14cbcSMatt Macy 	    "\t\tlabel.  Label injection can either be 'nvlist', 'uber',\n "
302eda14cbcSMatt Macy 	    "\t\t'pad1', or 'pad2'.\n"
3031719886fSMartin Matuska 	    "\t\t'errno' can be 'nxio' (the default), 'io', 'dtl',\n"
3041719886fSMartin Matuska 	    "\t\t'corrupt' (bit flip), or 'noop' (successfully do nothing).\n"
305eda14cbcSMatt Macy 	    "\t\t'frequency' is a value between 0.0001 and 100.0 that limits\n"
306eda14cbcSMatt Macy 	    "\t\tdevice error injection to a percentage of the IOs.\n"
307eda14cbcSMatt Macy 	    "\n"
308eda14cbcSMatt Macy 	    "\tzinject -d device -A <degrade|fault> -D <delay secs> pool\n"
309eda14cbcSMatt Macy 	    "\t\tPerform a specific action on a particular device.\n"
310eda14cbcSMatt Macy 	    "\n"
311eda14cbcSMatt Macy 	    "\tzinject -d device -D latency:lanes pool\n"
312eda14cbcSMatt Macy 	    "\n"
313eda14cbcSMatt Macy 	    "\t\tAdd an artificial delay to IO requests on a particular\n"
314eda14cbcSMatt Macy 	    "\t\tdevice, such that the requests take a minimum of 'latency'\n"
315eda14cbcSMatt Macy 	    "\t\tmilliseconds to complete. Each delay has an associated\n"
316eda14cbcSMatt Macy 	    "\t\tnumber of 'lanes' which defines the number of concurrent\n"
317eda14cbcSMatt Macy 	    "\t\tIO requests that can be processed.\n"
318eda14cbcSMatt Macy 	    "\n"
319eda14cbcSMatt Macy 	    "\t\tFor example, with a single lane delay of 10 ms (-D 10:1),\n"
320eda14cbcSMatt Macy 	    "\t\tthe device will only be able to service a single IO request\n"
321eda14cbcSMatt Macy 	    "\t\tat a time with each request taking 10 ms to complete. So,\n"
322eda14cbcSMatt Macy 	    "\t\tif only a single request is submitted every 10 ms, the\n"
323eda14cbcSMatt Macy 	    "\t\taverage latency will be 10 ms; but if more than one request\n"
324eda14cbcSMatt Macy 	    "\t\tis submitted every 10 ms, the average latency will be more\n"
325eda14cbcSMatt Macy 	    "\t\tthan 10 ms.\n"
326eda14cbcSMatt Macy 	    "\n"
327eda14cbcSMatt Macy 	    "\t\tSimilarly, if a delay of 10 ms is specified to have two\n"
328eda14cbcSMatt Macy 	    "\t\tlanes (-D 10:2), then the device will be able to service\n"
329eda14cbcSMatt Macy 	    "\t\ttwo requests at a time, each with a minimum latency of\n"
330eda14cbcSMatt Macy 	    "\t\t10 ms. So, if two requests are submitted every 10 ms, then\n"
331eda14cbcSMatt Macy 	    "\t\tthe average latency will be 10 ms; but if more than two\n"
332eda14cbcSMatt Macy 	    "\t\trequests are submitted every 10 ms, the average latency\n"
333eda14cbcSMatt Macy 	    "\t\twill be more than 10 ms.\n"
334eda14cbcSMatt Macy 	    "\n"
335eda14cbcSMatt Macy 	    "\t\tAlso note, these delays are additive. So two invocations\n"
336eda14cbcSMatt Macy 	    "\t\tof '-D 10:1', is roughly equivalent to a single invocation\n"
337eda14cbcSMatt Macy 	    "\t\tof '-D 10:2'. This also means, one can specify multiple\n"
338eda14cbcSMatt Macy 	    "\t\tlanes with differing target latencies. For example, an\n"
339eda14cbcSMatt Macy 	    "\t\tinvocation of '-D 10:1' followed by '-D 25:2' will\n"
340eda14cbcSMatt Macy 	    "\t\tcreate 3 lanes on the device; one lane with a latency\n"
341eda14cbcSMatt Macy 	    "\t\tof 10 ms and two lanes with a 25 ms latency.\n"
342eda14cbcSMatt Macy 	    "\n"
3430d4ad640SMartin Matuska 	    "\tzinject -P import|export -s <seconds> pool\n"
3440d4ad640SMartin Matuska 	    "\t\tAdd an artificial delay to a future pool import or export,\n"
3450d4ad640SMartin Matuska 	    "\t\tsuch that the operation takes a minimum of supplied seconds\n"
3460d4ad640SMartin Matuska 	    "\t\tto complete.\n"
3470d4ad640SMartin Matuska 	    "\n"
348eda14cbcSMatt Macy 	    "\tzinject -I [-s <seconds> | -g <txgs>] pool\n"
349eda14cbcSMatt Macy 	    "\t\tCause the pool to stop writing blocks yet not\n"
350eda14cbcSMatt Macy 	    "\t\treport errors for a duration.  Simulates buggy hardware\n"
351eda14cbcSMatt Macy 	    "\t\tthat fails to honor cache flush requests.\n"
352eda14cbcSMatt Macy 	    "\t\tDefault duration is 30 seconds.  The machine is panicked\n"
353eda14cbcSMatt Macy 	    "\t\tat the end of the duration.\n"
354eda14cbcSMatt Macy 	    "\n"
355eda14cbcSMatt Macy 	    "\tzinject -b objset:object:level:blkid pool\n"
356eda14cbcSMatt Macy 	    "\n"
357eda14cbcSMatt Macy 	    "\t\tInject an error into pool 'pool' with the numeric bookmark\n"
358eda14cbcSMatt Macy 	    "\t\tspecified by the remaining tuple.  Each number is in\n"
359eda14cbcSMatt Macy 	    "\t\thexadecimal, and only one block can be specified.\n"
360eda14cbcSMatt Macy 	    "\n"
361eda14cbcSMatt Macy 	    "\tzinject [-q] <-t type> [-C dvas] [-e errno] [-l level]\n"
362eda14cbcSMatt Macy 	    "\t\t[-r range] [-a] [-m] [-u] [-f freq] <object>\n"
363eda14cbcSMatt Macy 	    "\n"
364eda14cbcSMatt Macy 	    "\t\tInject an error into the object specified by the '-t' option\n"
365eda14cbcSMatt Macy 	    "\t\tand the object descriptor.  The 'object' parameter is\n"
366eda14cbcSMatt Macy 	    "\t\tinterpreted depending on the '-t' option.\n"
367eda14cbcSMatt Macy 	    "\n"
368eda14cbcSMatt Macy 	    "\t\t-q\tQuiet mode.  Only print out the handler number added.\n"
369eda14cbcSMatt Macy 	    "\t\t-e\tInject a specific error.  Must be one of 'io',\n"
370eda14cbcSMatt Macy 	    "\t\t\t'checksum', 'decompress', or 'decrypt'.  Default is 'io'.\n"
371eda14cbcSMatt Macy 	    "\t\t-C\tInject the given error only into specific DVAs. The\n"
372eda14cbcSMatt Macy 	    "\t\t\tDVAs should be specified as a list of 0-indexed DVAs\n"
373eda14cbcSMatt Macy 	    "\t\t\tseparated by commas (ex. '0,2').\n"
374eda14cbcSMatt Macy 	    "\t\t-l\tInject error at a particular block level. Default is "
375eda14cbcSMatt Macy 	    "0.\n"
376eda14cbcSMatt Macy 	    "\t\t-m\tAutomatically remount underlying filesystem.\n"
377eda14cbcSMatt Macy 	    "\t\t-r\tInject error over a particular logical range of an\n"
378eda14cbcSMatt Macy 	    "\t\t\tobject.  Will be translated to the appropriate blkid\n"
379eda14cbcSMatt Macy 	    "\t\t\trange according to the object's properties.\n"
380eda14cbcSMatt Macy 	    "\t\t-a\tFlush the ARC cache.  Can be specified without any\n"
381eda14cbcSMatt Macy 	    "\t\t\tassociated object.\n"
382eda14cbcSMatt Macy 	    "\t\t-u\tUnload the associated pool.  Can be specified with only\n"
383eda14cbcSMatt Macy 	    "\t\t\ta pool object.\n"
384eda14cbcSMatt Macy 	    "\t\t-f\tOnly inject errors a fraction of the time.  Expressed as\n"
385eda14cbcSMatt Macy 	    "\t\t\ta percentage between 0.0001 and 100.\n"
386eda14cbcSMatt Macy 	    "\n"
387eda14cbcSMatt Macy 	    "\t-t data\t\tInject an error into the plain file contents of a\n"
388eda14cbcSMatt Macy 	    "\t\t\tfile.  The object must be specified as a complete path\n"
389eda14cbcSMatt Macy 	    "\t\t\tto a file on a ZFS filesystem.\n"
390eda14cbcSMatt Macy 	    "\n"
391eda14cbcSMatt Macy 	    "\t-t dnode\tInject an error into the metadnode in the block\n"
392eda14cbcSMatt Macy 	    "\t\t\tcorresponding to the dnode for a file or directory.  The\n"
393eda14cbcSMatt Macy 	    "\t\t\t'-r' option is incompatible with this mode.  The object\n"
394eda14cbcSMatt Macy 	    "\t\t\tis specified as a complete path to a file or directory\n"
395eda14cbcSMatt Macy 	    "\t\t\ton a ZFS filesystem.\n"
396eda14cbcSMatt Macy 	    "\n"
397eda14cbcSMatt Macy 	    "\t-t <mos>\tInject errors into the MOS for objects of the given\n"
398eda14cbcSMatt Macy 	    "\t\t\ttype.  Valid types are: mos, mosdir, config, bpobj,\n"
399eda14cbcSMatt Macy 	    "\t\t\tspacemap, metaslab, errlog.  The only valid <object> is\n"
400eda14cbcSMatt Macy 	    "\t\t\tthe poolname.\n");
401eda14cbcSMatt Macy }
402eda14cbcSMatt Macy 
403eda14cbcSMatt Macy static int
404eda14cbcSMatt Macy iter_handlers(int (*func)(int, const char *, zinject_record_t *, void *),
405eda14cbcSMatt Macy     void *data)
406eda14cbcSMatt Macy {
407eda14cbcSMatt Macy 	zfs_cmd_t zc = {"\0"};
408eda14cbcSMatt Macy 	int ret;
409eda14cbcSMatt Macy 
410eda14cbcSMatt Macy 	while (zfs_ioctl(g_zfs, ZFS_IOC_INJECT_LIST_NEXT, &zc) == 0)
411eda14cbcSMatt Macy 		if ((ret = func((int)zc.zc_guid, zc.zc_name,
412eda14cbcSMatt Macy 		    &zc.zc_inject_record, data)) != 0)
413eda14cbcSMatt Macy 			return (ret);
414eda14cbcSMatt Macy 
415eda14cbcSMatt Macy 	if (errno != ENOENT) {
416eda14cbcSMatt Macy 		(void) fprintf(stderr, "Unable to list handlers: %s\n",
417eda14cbcSMatt Macy 		    strerror(errno));
418eda14cbcSMatt Macy 		return (-1);
419eda14cbcSMatt Macy 	}
420eda14cbcSMatt Macy 
421eda14cbcSMatt Macy 	return (0);
422eda14cbcSMatt Macy }
423eda14cbcSMatt Macy 
424eda14cbcSMatt Macy static int
425eda14cbcSMatt Macy print_data_handler(int id, const char *pool, zinject_record_t *record,
426eda14cbcSMatt Macy     void *data)
427eda14cbcSMatt Macy {
428eda14cbcSMatt Macy 	int *count = data;
429eda14cbcSMatt Macy 
4300d4ad640SMartin Matuska 	if (record->zi_guid != 0 || record->zi_func[0] != '\0' ||
4310d4ad640SMartin Matuska 	    record->zi_duration != 0) {
432eda14cbcSMatt Macy 		return (0);
4330d4ad640SMartin Matuska 	}
434eda14cbcSMatt Macy 
435eda14cbcSMatt Macy 	if (*count == 0) {
436eda14cbcSMatt Macy 		(void) printf("%3s  %-15s  %-6s  %-6s  %-8s  %3s  %-4s  "
437c6767dc1SMartin Matuska 		    "%-15s  %-6s  %-15s\n", "ID", "POOL", "OBJSET", "OBJECT",
438c6767dc1SMartin Matuska 		    "TYPE", "LVL", "DVAs", "RANGE", "MATCH", "INJECT");
439eda14cbcSMatt Macy 		(void) printf("---  ---------------  ------  "
440c6767dc1SMartin Matuska 		    "------  --------  ---  ----  ---------------  "
441c6767dc1SMartin Matuska 		    "------  ------\n");
442eda14cbcSMatt Macy 	}
443eda14cbcSMatt Macy 
444eda14cbcSMatt Macy 	*count += 1;
445eda14cbcSMatt Macy 
446c6767dc1SMartin Matuska 	char rangebuf[32];
447c6767dc1SMartin Matuska 	if (record->zi_start == 0 && record->zi_end == -1ULL)
448c6767dc1SMartin Matuska 		snprintf(rangebuf, sizeof (rangebuf), "all");
449eda14cbcSMatt Macy 	else
450c6767dc1SMartin Matuska 		snprintf(rangebuf, sizeof (rangebuf), "[%llu, %llu]",
451c6767dc1SMartin Matuska 		    (u_longlong_t)record->zi_start,
452eda14cbcSMatt Macy 		    (u_longlong_t)record->zi_end);
453eda14cbcSMatt Macy 
454c6767dc1SMartin Matuska 
455c6767dc1SMartin Matuska 	(void) printf("%3d  %-15s  %-6llu  %-6llu  %-8s  %-3d  0x%02x  %-15s  "
456*5289625dSMark Johnston 	    "%6llu  %6llu\n", id, pool, (u_longlong_t)record->zi_objset,
457c6767dc1SMartin Matuska 	    (u_longlong_t)record->zi_object, type_to_name(record->zi_type),
458c6767dc1SMartin Matuska 	    record->zi_level, record->zi_dvas, rangebuf,
459*5289625dSMark Johnston 	    (u_longlong_t)record->zi_match_count,
460*5289625dSMark Johnston 	    (u_longlong_t)record->zi_inject_count);
461c6767dc1SMartin Matuska 
462eda14cbcSMatt Macy 	return (0);
463eda14cbcSMatt Macy }
464eda14cbcSMatt Macy 
465eda14cbcSMatt Macy static int
466eda14cbcSMatt Macy print_device_handler(int id, const char *pool, zinject_record_t *record,
467eda14cbcSMatt Macy     void *data)
468eda14cbcSMatt Macy {
469eda14cbcSMatt Macy 	int *count = data;
470eda14cbcSMatt Macy 
471eda14cbcSMatt Macy 	if (record->zi_guid == 0 || record->zi_func[0] != '\0')
472eda14cbcSMatt Macy 		return (0);
473eda14cbcSMatt Macy 
474eda14cbcSMatt Macy 	if (record->zi_cmd == ZINJECT_DELAY_IO)
475eda14cbcSMatt Macy 		return (0);
476eda14cbcSMatt Macy 
477eda14cbcSMatt Macy 	if (*count == 0) {
478c6767dc1SMartin Matuska 		(void) printf("%3s  %-15s  %-16s  %-5s  %-10s  %-9s  "
479c6767dc1SMartin Matuska 		    "%-6s  %-6s\n",
480c6767dc1SMartin Matuska 		    "ID", "POOL", "GUID", "TYPE", "ERROR", "FREQ",
481c6767dc1SMartin Matuska 		    "MATCH", "INJECT");
4821719886fSMartin Matuska 		(void) printf(
4831719886fSMartin Matuska 		    "---  ---------------  ----------------  "
484c6767dc1SMartin Matuska 		    "-----  ----------  ---------  "
485c6767dc1SMartin Matuska 		    "------  ------\n");
486eda14cbcSMatt Macy 	}
487eda14cbcSMatt Macy 
488eda14cbcSMatt Macy 	*count += 1;
489eda14cbcSMatt Macy 
4901719886fSMartin Matuska 	double freq = record->zi_freq == 0 ? 100.0f :
4911719886fSMartin Matuska 	    (((double)record->zi_freq) / ZI_PERCENTAGE_MAX) * 100.0f;
4921719886fSMartin Matuska 
493c6767dc1SMartin Matuska 	(void) printf("%3d  %-15s  %llx  %-5s  %-10s  %8.4f%%  "
494*5289625dSMark Johnston 	    "%6llu  %6llu\n", id, pool, (u_longlong_t)record->zi_guid,
495c6767dc1SMartin Matuska 	    iotype_to_str(record->zi_iotype), err_to_str(record->zi_error),
496*5289625dSMark Johnston 	    freq, (u_longlong_t)record->zi_match_count,
497*5289625dSMark Johnston 	    (u_longlong_t)record->zi_inject_count);
498eda14cbcSMatt Macy 
499eda14cbcSMatt Macy 	return (0);
500eda14cbcSMatt Macy }
501eda14cbcSMatt Macy 
502eda14cbcSMatt Macy static int
503eda14cbcSMatt Macy print_delay_handler(int id, const char *pool, zinject_record_t *record,
504eda14cbcSMatt Macy     void *data)
505eda14cbcSMatt Macy {
506eda14cbcSMatt Macy 	int *count = data;
507eda14cbcSMatt Macy 
508eda14cbcSMatt Macy 	if (record->zi_guid == 0 || record->zi_func[0] != '\0')
509eda14cbcSMatt Macy 		return (0);
510eda14cbcSMatt Macy 
511eda14cbcSMatt Macy 	if (record->zi_cmd != ZINJECT_DELAY_IO)
512eda14cbcSMatt Macy 		return (0);
513eda14cbcSMatt Macy 
514eda14cbcSMatt Macy 	if (*count == 0) {
515c6767dc1SMartin Matuska 		(void) printf("%3s  %-15s  %-16s  %-10s  %-5s  %-9s  "
516c6767dc1SMartin Matuska 		    "%-6s  %-6s\n",
517c6767dc1SMartin Matuska 		    "ID", "POOL", "GUID", "DELAY (ms)", "LANES", "FREQ",
518c6767dc1SMartin Matuska 		    "MATCH", "INJECT");
519c6767dc1SMartin Matuska 		(void) printf("---  ---------------  ----------------  "
520c6767dc1SMartin Matuska 		    "----------  -----  ---------  "
521c6767dc1SMartin Matuska 		    "------  ------\n");
522eda14cbcSMatt Macy 	}
523eda14cbcSMatt Macy 
524eda14cbcSMatt Macy 	*count += 1;
525eda14cbcSMatt Macy 
526c6767dc1SMartin Matuska 	double freq = record->zi_freq == 0 ? 100.0f :
527c6767dc1SMartin Matuska 	    (((double)record->zi_freq) / ZI_PERCENTAGE_MAX) * 100.0f;
528c6767dc1SMartin Matuska 
529c6767dc1SMartin Matuska 	(void) printf("%3d  %-15s  %llx  %10llu  %5llu  %8.4f%%  "
530*5289625dSMark Johnston 	    "%6llu  %6llu\n", id, pool, (u_longlong_t)record->zi_guid,
531eda14cbcSMatt Macy 	    (u_longlong_t)NSEC2MSEC(record->zi_timer),
532*5289625dSMark Johnston 	    (u_longlong_t)record->zi_nlanes, freq,
533*5289625dSMark Johnston 	    (u_longlong_t)record->zi_match_count,
534*5289625dSMark Johnston 	    (u_longlong_t)record->zi_inject_count);
535eda14cbcSMatt Macy 
536eda14cbcSMatt Macy 	return (0);
537eda14cbcSMatt Macy }
538eda14cbcSMatt Macy 
539eda14cbcSMatt Macy static int
540eda14cbcSMatt Macy print_panic_handler(int id, const char *pool, zinject_record_t *record,
541eda14cbcSMatt Macy     void *data)
542eda14cbcSMatt Macy {
543eda14cbcSMatt Macy 	int *count = data;
544eda14cbcSMatt Macy 
545eda14cbcSMatt Macy 	if (record->zi_func[0] == '\0')
546eda14cbcSMatt Macy 		return (0);
547eda14cbcSMatt Macy 
548eda14cbcSMatt Macy 	if (*count == 0) {
549eda14cbcSMatt Macy 		(void) printf("%3s  %-15s  %s\n", "ID", "POOL", "FUNCTION");
550eda14cbcSMatt Macy 		(void) printf("---  ---------------  ----------------\n");
551eda14cbcSMatt Macy 	}
552eda14cbcSMatt Macy 
553eda14cbcSMatt Macy 	*count += 1;
554eda14cbcSMatt Macy 
555eda14cbcSMatt Macy 	(void) printf("%3d  %-15s  %s\n", id, pool, record->zi_func);
556eda14cbcSMatt Macy 
557eda14cbcSMatt Macy 	return (0);
558eda14cbcSMatt Macy }
559eda14cbcSMatt Macy 
5600d4ad640SMartin Matuska static int
5610d4ad640SMartin Matuska print_pool_delay_handler(int id, const char *pool, zinject_record_t *record,
5620d4ad640SMartin Matuska     void *data)
5630d4ad640SMartin Matuska {
5640d4ad640SMartin Matuska 	int *count = data;
5650d4ad640SMartin Matuska 
5660d4ad640SMartin Matuska 	if (record->zi_cmd != ZINJECT_DELAY_IMPORT &&
5670d4ad640SMartin Matuska 	    record->zi_cmd != ZINJECT_DELAY_EXPORT) {
5680d4ad640SMartin Matuska 		return (0);
5690d4ad640SMartin Matuska 	}
5700d4ad640SMartin Matuska 
5710d4ad640SMartin Matuska 	if (*count == 0) {
5720d4ad640SMartin Matuska 		(void) printf("%3s  %-19s  %-11s  %s\n",
5730d4ad640SMartin Matuska 		    "ID", "POOL", "DELAY (sec)", "COMMAND");
5740d4ad640SMartin Matuska 		(void) printf("---  -------------------  -----------"
5750d4ad640SMartin Matuska 		    "  -------\n");
5760d4ad640SMartin Matuska 	}
5770d4ad640SMartin Matuska 
5780d4ad640SMartin Matuska 	*count += 1;
5790d4ad640SMartin Matuska 
5800d4ad640SMartin Matuska 	(void) printf("%3d  %-19s  %-11llu  %s\n",
5810d4ad640SMartin Matuska 	    id, pool, (u_longlong_t)record->zi_duration,
5820d4ad640SMartin Matuska 	    record->zi_cmd == ZINJECT_DELAY_IMPORT ? "import": "export");
5830d4ad640SMartin Matuska 
5840d4ad640SMartin Matuska 	return (0);
5850d4ad640SMartin Matuska }
5860d4ad640SMartin Matuska 
587eda14cbcSMatt Macy /*
588eda14cbcSMatt Macy  * Print all registered error handlers.  Returns the number of handlers
589eda14cbcSMatt Macy  * registered.
590eda14cbcSMatt Macy  */
591eda14cbcSMatt Macy static int
592eda14cbcSMatt Macy print_all_handlers(void)
593eda14cbcSMatt Macy {
594eda14cbcSMatt Macy 	int count = 0, total = 0;
595eda14cbcSMatt Macy 
596eda14cbcSMatt Macy 	(void) iter_handlers(print_device_handler, &count);
597eda14cbcSMatt Macy 	if (count > 0) {
598eda14cbcSMatt Macy 		total += count;
599eda14cbcSMatt Macy 		(void) printf("\n");
600eda14cbcSMatt Macy 		count = 0;
601eda14cbcSMatt Macy 	}
602eda14cbcSMatt Macy 
603eda14cbcSMatt Macy 	(void) iter_handlers(print_delay_handler, &count);
604eda14cbcSMatt Macy 	if (count > 0) {
605eda14cbcSMatt Macy 		total += count;
606eda14cbcSMatt Macy 		(void) printf("\n");
607eda14cbcSMatt Macy 		count = 0;
608eda14cbcSMatt Macy 	}
609eda14cbcSMatt Macy 
610eda14cbcSMatt Macy 	(void) iter_handlers(print_data_handler, &count);
611eda14cbcSMatt Macy 	if (count > 0) {
612eda14cbcSMatt Macy 		total += count;
613eda14cbcSMatt Macy 		(void) printf("\n");
614eda14cbcSMatt Macy 		count = 0;
615eda14cbcSMatt Macy 	}
616eda14cbcSMatt Macy 
6170d4ad640SMartin Matuska 	(void) iter_handlers(print_pool_delay_handler, &count);
6180d4ad640SMartin Matuska 	if (count > 0) {
6190d4ad640SMartin Matuska 		total += count;
6200d4ad640SMartin Matuska 		(void) printf("\n");
6210d4ad640SMartin Matuska 		count = 0;
6220d4ad640SMartin Matuska 	}
6230d4ad640SMartin Matuska 
624eda14cbcSMatt Macy 	(void) iter_handlers(print_panic_handler, &count);
625eda14cbcSMatt Macy 
626eda14cbcSMatt Macy 	return (count + total);
627eda14cbcSMatt Macy }
628eda14cbcSMatt Macy 
629eda14cbcSMatt Macy static int
630eda14cbcSMatt Macy cancel_one_handler(int id, const char *pool, zinject_record_t *record,
631eda14cbcSMatt Macy     void *data)
632eda14cbcSMatt Macy {
633e92ffd9bSMartin Matuska 	(void) pool, (void) record, (void) data;
634eda14cbcSMatt Macy 	zfs_cmd_t zc = {"\0"};
635eda14cbcSMatt Macy 
636eda14cbcSMatt Macy 	zc.zc_guid = (uint64_t)id;
637eda14cbcSMatt Macy 
638eda14cbcSMatt Macy 	if (zfs_ioctl(g_zfs, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
639eda14cbcSMatt Macy 		(void) fprintf(stderr, "failed to remove handler %d: %s\n",
640eda14cbcSMatt Macy 		    id, strerror(errno));
641eda14cbcSMatt Macy 		return (1);
642eda14cbcSMatt Macy 	}
643eda14cbcSMatt Macy 
644eda14cbcSMatt Macy 	return (0);
645eda14cbcSMatt Macy }
646eda14cbcSMatt Macy 
647eda14cbcSMatt Macy /*
648eda14cbcSMatt Macy  * Remove all fault injection handlers.
649eda14cbcSMatt Macy  */
650eda14cbcSMatt Macy static int
651eda14cbcSMatt Macy cancel_all_handlers(void)
652eda14cbcSMatt Macy {
653eda14cbcSMatt Macy 	int ret = iter_handlers(cancel_one_handler, NULL);
654eda14cbcSMatt Macy 
655eda14cbcSMatt Macy 	if (ret == 0)
656eda14cbcSMatt Macy 		(void) printf("removed all registered handlers\n");
657eda14cbcSMatt Macy 
658eda14cbcSMatt Macy 	return (ret);
659eda14cbcSMatt Macy }
660eda14cbcSMatt Macy 
661eda14cbcSMatt Macy /*
662eda14cbcSMatt Macy  * Remove a specific fault injection handler.
663eda14cbcSMatt Macy  */
664eda14cbcSMatt Macy static int
665eda14cbcSMatt Macy cancel_handler(int id)
666eda14cbcSMatt Macy {
667eda14cbcSMatt Macy 	zfs_cmd_t zc = {"\0"};
668eda14cbcSMatt Macy 
669eda14cbcSMatt Macy 	zc.zc_guid = (uint64_t)id;
670eda14cbcSMatt Macy 
671eda14cbcSMatt Macy 	if (zfs_ioctl(g_zfs, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
672eda14cbcSMatt Macy 		(void) fprintf(stderr, "failed to remove handler %d: %s\n",
673eda14cbcSMatt Macy 		    id, strerror(errno));
674eda14cbcSMatt Macy 		return (1);
675eda14cbcSMatt Macy 	}
676eda14cbcSMatt Macy 
677eda14cbcSMatt Macy 	(void) printf("removed handler %d\n", id);
678eda14cbcSMatt Macy 
679eda14cbcSMatt Macy 	return (0);
680eda14cbcSMatt Macy }
681eda14cbcSMatt Macy 
682eda14cbcSMatt Macy /*
683eda14cbcSMatt Macy  * Register a new fault injection handler.
684eda14cbcSMatt Macy  */
685eda14cbcSMatt Macy static int
686eda14cbcSMatt Macy register_handler(const char *pool, int flags, zinject_record_t *record,
687eda14cbcSMatt Macy     int quiet)
688eda14cbcSMatt Macy {
689eda14cbcSMatt Macy 	zfs_cmd_t zc = {"\0"};
690eda14cbcSMatt Macy 
691eda14cbcSMatt Macy 	(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
692eda14cbcSMatt Macy 	zc.zc_inject_record = *record;
693eda14cbcSMatt Macy 	zc.zc_guid = flags;
694eda14cbcSMatt Macy 
695eda14cbcSMatt Macy 	if (zfs_ioctl(g_zfs, ZFS_IOC_INJECT_FAULT, &zc) != 0) {
6960d4ad640SMartin Matuska 		const char *errmsg = strerror(errno);
6970d4ad640SMartin Matuska 
6980d4ad640SMartin Matuska 		switch (errno) {
6990d4ad640SMartin Matuska 		case EDOM:
7000d4ad640SMartin Matuska 			errmsg = "block level exceeds max level of object";
7010d4ad640SMartin Matuska 			break;
7020d4ad640SMartin Matuska 		case EEXIST:
7030d4ad640SMartin Matuska 			if (record->zi_cmd == ZINJECT_DELAY_IMPORT)
7040d4ad640SMartin Matuska 				errmsg = "pool already imported";
7050d4ad640SMartin Matuska 			if (record->zi_cmd == ZINJECT_DELAY_EXPORT)
7060d4ad640SMartin Matuska 				errmsg = "a handler already exists";
7070d4ad640SMartin Matuska 			break;
7080d4ad640SMartin Matuska 		case ENOENT:
7090d4ad640SMartin Matuska 			/* import delay injector running on older zfs module */
7100d4ad640SMartin Matuska 			if (record->zi_cmd == ZINJECT_DELAY_IMPORT)
7110d4ad640SMartin Matuska 				errmsg = "import delay injector not supported";
7120d4ad640SMartin Matuska 			break;
7130d4ad640SMartin Matuska 		default:
7140d4ad640SMartin Matuska 			break;
7150d4ad640SMartin Matuska 		}
7160d4ad640SMartin Matuska 		(void) fprintf(stderr, "failed to add handler: %s\n", errmsg);
717eda14cbcSMatt Macy 		return (1);
718eda14cbcSMatt Macy 	}
719eda14cbcSMatt Macy 
720eda14cbcSMatt Macy 	if (flags & ZINJECT_NULL)
721eda14cbcSMatt Macy 		return (0);
722eda14cbcSMatt Macy 
723eda14cbcSMatt Macy 	if (quiet) {
724eda14cbcSMatt Macy 		(void) printf("%llu\n", (u_longlong_t)zc.zc_guid);
725eda14cbcSMatt Macy 	} else {
726eda14cbcSMatt Macy 		(void) printf("Added handler %llu with the following "
727eda14cbcSMatt Macy 		    "properties:\n", (u_longlong_t)zc.zc_guid);
728eda14cbcSMatt Macy 		(void) printf("  pool: %s\n", pool);
729eda14cbcSMatt Macy 		if (record->zi_guid) {
730eda14cbcSMatt Macy 			(void) printf("  vdev: %llx\n",
731eda14cbcSMatt Macy 			    (u_longlong_t)record->zi_guid);
732eda14cbcSMatt Macy 		} else if (record->zi_func[0] != '\0') {
733eda14cbcSMatt Macy 			(void) printf("  panic function: %s\n",
734eda14cbcSMatt Macy 			    record->zi_func);
735eda14cbcSMatt Macy 		} else if (record->zi_duration > 0) {
736eda14cbcSMatt Macy 			(void) printf(" time: %lld seconds\n",
737eda14cbcSMatt Macy 			    (u_longlong_t)record->zi_duration);
738eda14cbcSMatt Macy 		} else if (record->zi_duration < 0) {
739eda14cbcSMatt Macy 			(void) printf(" txgs: %lld \n",
740eda14cbcSMatt Macy 			    (u_longlong_t)-record->zi_duration);
7410d4ad640SMartin Matuska 		} else if (record->zi_timer > 0) {
7420d4ad640SMartin Matuska 			(void) printf(" timer: %lld ms\n",
7430d4ad640SMartin Matuska 			    (u_longlong_t)NSEC2MSEC(record->zi_timer));
744eda14cbcSMatt Macy 		} else {
745eda14cbcSMatt Macy 			(void) printf("objset: %llu\n",
746eda14cbcSMatt Macy 			    (u_longlong_t)record->zi_objset);
747eda14cbcSMatt Macy 			(void) printf("object: %llu\n",
748eda14cbcSMatt Macy 			    (u_longlong_t)record->zi_object);
749eda14cbcSMatt Macy 			(void) printf("  type: %llu\n",
750eda14cbcSMatt Macy 			    (u_longlong_t)record->zi_type);
751eda14cbcSMatt Macy 			(void) printf(" level: %d\n", record->zi_level);
752eda14cbcSMatt Macy 			if (record->zi_start == 0 &&
753eda14cbcSMatt Macy 			    record->zi_end == -1ULL)
754eda14cbcSMatt Macy 				(void) printf(" range: all\n");
755eda14cbcSMatt Macy 			else
756eda14cbcSMatt Macy 				(void) printf(" range: [%llu, %llu)\n",
757eda14cbcSMatt Macy 				    (u_longlong_t)record->zi_start,
758eda14cbcSMatt Macy 				    (u_longlong_t)record->zi_end);
759eda14cbcSMatt Macy 			(void) printf("  dvas: 0x%x\n", record->zi_dvas);
760eda14cbcSMatt Macy 		}
761eda14cbcSMatt Macy 	}
762eda14cbcSMatt Macy 
763eda14cbcSMatt Macy 	return (0);
764eda14cbcSMatt Macy }
765eda14cbcSMatt Macy 
766eda14cbcSMatt Macy static int
767eda14cbcSMatt Macy perform_action(const char *pool, zinject_record_t *record, int cmd)
768eda14cbcSMatt Macy {
769eda14cbcSMatt Macy 	zfs_cmd_t zc = {"\0"};
770eda14cbcSMatt Macy 
771eda14cbcSMatt Macy 	ASSERT(cmd == VDEV_STATE_DEGRADED || cmd == VDEV_STATE_FAULTED);
772eda14cbcSMatt Macy 	(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
773eda14cbcSMatt Macy 	zc.zc_guid = record->zi_guid;
774eda14cbcSMatt Macy 	zc.zc_cookie = cmd;
775eda14cbcSMatt Macy 
776eda14cbcSMatt Macy 	if (zfs_ioctl(g_zfs, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
777eda14cbcSMatt Macy 		return (0);
778eda14cbcSMatt Macy 
779eda14cbcSMatt Macy 	return (1);
780eda14cbcSMatt Macy }
781eda14cbcSMatt Macy 
782eda14cbcSMatt Macy static int
783eda14cbcSMatt Macy parse_delay(char *str, uint64_t *delay, uint64_t *nlanes)
784eda14cbcSMatt Macy {
785eda14cbcSMatt Macy 	unsigned long scan_delay;
786eda14cbcSMatt Macy 	unsigned long scan_nlanes;
787eda14cbcSMatt Macy 
788eda14cbcSMatt Macy 	if (sscanf(str, "%lu:%lu", &scan_delay, &scan_nlanes) != 2)
789eda14cbcSMatt Macy 		return (1);
790eda14cbcSMatt Macy 
791eda14cbcSMatt Macy 	/*
792eda14cbcSMatt Macy 	 * We explicitly disallow a delay of zero here, because we key
793eda14cbcSMatt Macy 	 * off this value being non-zero in translate_device(), to
794eda14cbcSMatt Macy 	 * determine if the fault is a ZINJECT_DELAY_IO fault or not.
795eda14cbcSMatt Macy 	 */
796eda14cbcSMatt Macy 	if (scan_delay == 0)
797eda14cbcSMatt Macy 		return (1);
798eda14cbcSMatt Macy 
799eda14cbcSMatt Macy 	/*
800eda14cbcSMatt Macy 	 * The units for the CLI delay parameter is milliseconds, but
801eda14cbcSMatt Macy 	 * the data passed to the kernel is interpreted as nanoseconds.
802eda14cbcSMatt Macy 	 * Thus we scale the milliseconds to nanoseconds here, and this
803eda14cbcSMatt Macy 	 * nanosecond value is used to pass the delay to the kernel.
804eda14cbcSMatt Macy 	 */
805eda14cbcSMatt Macy 	*delay = MSEC2NSEC(scan_delay);
806eda14cbcSMatt Macy 	*nlanes = scan_nlanes;
807eda14cbcSMatt Macy 
808eda14cbcSMatt Macy 	return (0);
809eda14cbcSMatt Macy }
810eda14cbcSMatt Macy 
811eda14cbcSMatt Macy static int
812eda14cbcSMatt Macy parse_frequency(const char *str, uint32_t *percent)
813eda14cbcSMatt Macy {
814eda14cbcSMatt Macy 	double val;
815eda14cbcSMatt Macy 	char *post;
816eda14cbcSMatt Macy 
817eda14cbcSMatt Macy 	val = strtod(str, &post);
818eda14cbcSMatt Macy 	if (post == NULL || *post != '\0')
819eda14cbcSMatt Macy 		return (EINVAL);
820eda14cbcSMatt Macy 
821eda14cbcSMatt Macy 	/* valid range is [0.0001, 100.0] */
822eda14cbcSMatt Macy 	val /= 100.0f;
823eda14cbcSMatt Macy 	if (val < 0.000001f || val > 1.0f)
824eda14cbcSMatt Macy 		return (ERANGE);
825eda14cbcSMatt Macy 
826eda14cbcSMatt Macy 	/* convert to an integer for use by kernel */
827eda14cbcSMatt Macy 	*percent = ((uint32_t)(val * ZI_PERCENTAGE_MAX));
828eda14cbcSMatt Macy 
829eda14cbcSMatt Macy 	return (0);
830eda14cbcSMatt Macy }
831eda14cbcSMatt Macy 
832eda14cbcSMatt Macy /*
833eda14cbcSMatt Macy  * This function converts a string specifier for DVAs into a bit mask.
834eda14cbcSMatt Macy  * The dva's provided by the user should be 0 indexed and separated by
835eda14cbcSMatt Macy  * a comma. For example:
836eda14cbcSMatt Macy  *	"1"	-> 0b0010  (0x2)
837eda14cbcSMatt Macy  *	"0,1"	-> 0b0011  (0x3)
838eda14cbcSMatt Macy  *	"0,1,2"	-> 0b0111  (0x7)
839eda14cbcSMatt Macy  */
840eda14cbcSMatt Macy static int
841eda14cbcSMatt Macy parse_dvas(const char *str, uint32_t *dvas_out)
842eda14cbcSMatt Macy {
843eda14cbcSMatt Macy 	const char *c = str;
844eda14cbcSMatt Macy 	uint32_t mask = 0;
845eda14cbcSMatt Macy 	boolean_t need_delim = B_FALSE;
846eda14cbcSMatt Macy 
847eda14cbcSMatt Macy 	/* max string length is 5 ("0,1,2") */
848eda14cbcSMatt Macy 	if (strlen(str) > 5 || strlen(str) == 0)
849eda14cbcSMatt Macy 		return (EINVAL);
850eda14cbcSMatt Macy 
851eda14cbcSMatt Macy 	while (*c != '\0') {
852eda14cbcSMatt Macy 		switch (*c) {
853eda14cbcSMatt Macy 		case '0':
854eda14cbcSMatt Macy 		case '1':
855eda14cbcSMatt Macy 		case '2':
856eda14cbcSMatt Macy 			/* check for pipe between DVAs */
857eda14cbcSMatt Macy 			if (need_delim)
858eda14cbcSMatt Macy 				return (EINVAL);
859eda14cbcSMatt Macy 
860eda14cbcSMatt Macy 			/* check if this DVA has been set already */
861eda14cbcSMatt Macy 			if (mask & (1 << ((*c) - '0')))
862eda14cbcSMatt Macy 				return (EINVAL);
863eda14cbcSMatt Macy 
864eda14cbcSMatt Macy 			mask |= (1 << ((*c) - '0'));
865eda14cbcSMatt Macy 			need_delim = B_TRUE;
866eda14cbcSMatt Macy 			break;
867eda14cbcSMatt Macy 		case ',':
868eda14cbcSMatt Macy 			need_delim = B_FALSE;
869eda14cbcSMatt Macy 			break;
870eda14cbcSMatt Macy 		default:
871eda14cbcSMatt Macy 			/* check for invalid character */
872eda14cbcSMatt Macy 			return (EINVAL);
873eda14cbcSMatt Macy 		}
874eda14cbcSMatt Macy 		c++;
875eda14cbcSMatt Macy 	}
876eda14cbcSMatt Macy 
877eda14cbcSMatt Macy 	/* check for dangling delimiter */
878eda14cbcSMatt Macy 	if (!need_delim)
879eda14cbcSMatt Macy 		return (EINVAL);
880eda14cbcSMatt Macy 
881eda14cbcSMatt Macy 	*dvas_out = mask;
882eda14cbcSMatt Macy 	return (0);
883eda14cbcSMatt Macy }
884eda14cbcSMatt Macy 
885eda14cbcSMatt Macy int
886eda14cbcSMatt Macy main(int argc, char **argv)
887eda14cbcSMatt Macy {
888eda14cbcSMatt Macy 	int c;
889eda14cbcSMatt Macy 	char *range = NULL;
890eda14cbcSMatt Macy 	char *cancel = NULL;
891eda14cbcSMatt Macy 	char *end;
892eda14cbcSMatt Macy 	char *raw = NULL;
893eda14cbcSMatt Macy 	char *device = NULL;
894eda14cbcSMatt Macy 	int level = 0;
895eda14cbcSMatt Macy 	int quiet = 0;
896eda14cbcSMatt Macy 	int error = 0;
897eda14cbcSMatt Macy 	int domount = 0;
898c6767dc1SMartin Matuska 	int io_type = ZINJECT_IOTYPE_ALL;
899eda14cbcSMatt Macy 	int action = VDEV_STATE_UNKNOWN;
900eda14cbcSMatt Macy 	err_type_t type = TYPE_INVAL;
901eda14cbcSMatt Macy 	err_type_t label = TYPE_INVAL;
902eda14cbcSMatt Macy 	zinject_record_t record = { 0 };
903eda14cbcSMatt Macy 	char pool[MAXNAMELEN] = "";
904eda14cbcSMatt Macy 	char dataset[MAXNAMELEN] = "";
905eda14cbcSMatt Macy 	zfs_handle_t *zhp = NULL;
906eda14cbcSMatt Macy 	int nowrites = 0;
907eda14cbcSMatt Macy 	int dur_txg = 0;
908eda14cbcSMatt Macy 	int dur_secs = 0;
909eda14cbcSMatt Macy 	int ret;
910eda14cbcSMatt Macy 	int flags = 0;
911eda14cbcSMatt Macy 	uint32_t dvas = 0;
912eda14cbcSMatt Macy 
913eda14cbcSMatt Macy 	if ((g_zfs = libzfs_init()) == NULL) {
914eda14cbcSMatt Macy 		(void) fprintf(stderr, "%s\n", libzfs_error_init(errno));
915eda14cbcSMatt Macy 		return (1);
916eda14cbcSMatt Macy 	}
917eda14cbcSMatt Macy 
918eda14cbcSMatt Macy 	libzfs_print_on_error(g_zfs, B_TRUE);
919eda14cbcSMatt Macy 
920eda14cbcSMatt Macy 	if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
921eda14cbcSMatt Macy 		(void) fprintf(stderr, "failed to open ZFS device\n");
922eda14cbcSMatt Macy 		libzfs_fini(g_zfs);
923eda14cbcSMatt Macy 		return (1);
924eda14cbcSMatt Macy 	}
925eda14cbcSMatt Macy 
926eda14cbcSMatt Macy 	if (argc == 1) {
927eda14cbcSMatt Macy 		/*
928eda14cbcSMatt Macy 		 * No arguments.  Print the available handlers.  If there are no
929eda14cbcSMatt Macy 		 * available handlers, direct the user to '-h' for help
930eda14cbcSMatt Macy 		 * information.
931eda14cbcSMatt Macy 		 */
932eda14cbcSMatt Macy 		if (print_all_handlers() == 0) {
933eda14cbcSMatt Macy 			(void) printf("No handlers registered.\n");
934eda14cbcSMatt Macy 			(void) printf("Run 'zinject -h' for usage "
935eda14cbcSMatt Macy 			    "information.\n");
936eda14cbcSMatt Macy 		}
937eda14cbcSMatt Macy 		libzfs_fini(g_zfs);
938eda14cbcSMatt Macy 		return (0);
939eda14cbcSMatt Macy 	}
940eda14cbcSMatt Macy 
941eda14cbcSMatt Macy 	while ((c = getopt(argc, argv,
9420d4ad640SMartin Matuska 	    ":aA:b:C:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:P:")) != -1) {
943eda14cbcSMatt Macy 		switch (c) {
944eda14cbcSMatt Macy 		case 'a':
945eda14cbcSMatt Macy 			flags |= ZINJECT_FLUSH_ARC;
946eda14cbcSMatt Macy 			break;
947eda14cbcSMatt Macy 		case 'A':
948eda14cbcSMatt Macy 			if (strcasecmp(optarg, "degrade") == 0) {
949eda14cbcSMatt Macy 				action = VDEV_STATE_DEGRADED;
950eda14cbcSMatt Macy 			} else if (strcasecmp(optarg, "fault") == 0) {
951eda14cbcSMatt Macy 				action = VDEV_STATE_FAULTED;
952eda14cbcSMatt Macy 			} else {
953eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid action '%s': "
954eda14cbcSMatt Macy 				    "must be 'degrade' or 'fault'\n", optarg);
955eda14cbcSMatt Macy 				usage();
956eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
957eda14cbcSMatt Macy 				return (1);
958eda14cbcSMatt Macy 			}
959eda14cbcSMatt Macy 			break;
960eda14cbcSMatt Macy 		case 'b':
961eda14cbcSMatt Macy 			raw = optarg;
962eda14cbcSMatt Macy 			break;
963eda14cbcSMatt Macy 		case 'c':
964eda14cbcSMatt Macy 			cancel = optarg;
965eda14cbcSMatt Macy 			break;
966eda14cbcSMatt Macy 		case 'C':
967eda14cbcSMatt Macy 			ret = parse_dvas(optarg, &dvas);
968eda14cbcSMatt Macy 			if (ret != 0) {
969eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid DVA list '%s': "
970eda14cbcSMatt Macy 				    "DVAs should be 0 indexed and separated by "
971eda14cbcSMatt Macy 				    "commas.\n", optarg);
972eda14cbcSMatt Macy 				usage();
973eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
974eda14cbcSMatt Macy 				return (1);
975eda14cbcSMatt Macy 			}
976eda14cbcSMatt Macy 			break;
977eda14cbcSMatt Macy 		case 'd':
978eda14cbcSMatt Macy 			device = optarg;
979eda14cbcSMatt Macy 			break;
980eda14cbcSMatt Macy 		case 'D':
981eda14cbcSMatt Macy 			errno = 0;
982eda14cbcSMatt Macy 			ret = parse_delay(optarg, &record.zi_timer,
983eda14cbcSMatt Macy 			    &record.zi_nlanes);
984eda14cbcSMatt Macy 			if (ret != 0) {
985eda14cbcSMatt Macy 
986eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid i/o delay "
987eda14cbcSMatt Macy 				    "value: '%s'\n", optarg);
988eda14cbcSMatt Macy 				usage();
989eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
990eda14cbcSMatt Macy 				return (1);
991eda14cbcSMatt Macy 			}
992eda14cbcSMatt Macy 			break;
993eda14cbcSMatt Macy 		case 'e':
9941719886fSMartin Matuska 			error = str_to_err(optarg);
9951719886fSMartin Matuska 			if (error < 0) {
996eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid error type "
9971719886fSMartin Matuska 				    "'%s': must be one of: io decompress "
9981719886fSMartin Matuska 				    "decrypt nxio dtl corrupt noop\n",
9991719886fSMartin Matuska 				    optarg);
1000eda14cbcSMatt Macy 				usage();
1001eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
1002eda14cbcSMatt Macy 				return (1);
1003eda14cbcSMatt Macy 			}
1004eda14cbcSMatt Macy 			break;
1005eda14cbcSMatt Macy 		case 'f':
1006eda14cbcSMatt Macy 			ret = parse_frequency(optarg, &record.zi_freq);
1007eda14cbcSMatt Macy 			if (ret != 0) {
1008eda14cbcSMatt Macy 				(void) fprintf(stderr, "%sfrequency value must "
1009eda14cbcSMatt Macy 				    "be in the range [0.0001, 100.0]\n",
1010eda14cbcSMatt Macy 				    ret == EINVAL ? "invalid value: " :
1011eda14cbcSMatt Macy 				    ret == ERANGE ? "out of range: " : "");
1012eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
1013eda14cbcSMatt Macy 				return (1);
1014eda14cbcSMatt Macy 			}
1015eda14cbcSMatt Macy 			break;
1016eda14cbcSMatt Macy 		case 'F':
1017eda14cbcSMatt Macy 			record.zi_failfast = B_TRUE;
1018eda14cbcSMatt Macy 			break;
1019eda14cbcSMatt Macy 		case 'g':
1020eda14cbcSMatt Macy 			dur_txg = 1;
1021eda14cbcSMatt Macy 			record.zi_duration = (int)strtol(optarg, &end, 10);
1022eda14cbcSMatt Macy 			if (record.zi_duration <= 0 || *end != '\0') {
1023eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid duration '%s': "
1024eda14cbcSMatt Macy 				    "must be a positive integer\n", optarg);
1025eda14cbcSMatt Macy 				usage();
1026eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
1027eda14cbcSMatt Macy 				return (1);
1028eda14cbcSMatt Macy 			}
1029eda14cbcSMatt Macy 			/* store duration of txgs as its negative */
1030eda14cbcSMatt Macy 			record.zi_duration *= -1;
1031eda14cbcSMatt Macy 			break;
1032eda14cbcSMatt Macy 		case 'h':
1033eda14cbcSMatt Macy 			usage();
1034eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1035eda14cbcSMatt Macy 			return (0);
1036eda14cbcSMatt Macy 		case 'I':
1037eda14cbcSMatt Macy 			/* default duration, if one hasn't yet been defined */
1038eda14cbcSMatt Macy 			nowrites = 1;
1039eda14cbcSMatt Macy 			if (dur_secs == 0 && dur_txg == 0)
1040eda14cbcSMatt Macy 				record.zi_duration = 30;
1041eda14cbcSMatt Macy 			break;
1042eda14cbcSMatt Macy 		case 'l':
1043eda14cbcSMatt Macy 			level = (int)strtol(optarg, &end, 10);
1044eda14cbcSMatt Macy 			if (*end != '\0') {
1045eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid level '%s': "
1046eda14cbcSMatt Macy 				    "must be an integer\n", optarg);
1047eda14cbcSMatt Macy 				usage();
1048eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
1049eda14cbcSMatt Macy 				return (1);
1050eda14cbcSMatt Macy 			}
1051eda14cbcSMatt Macy 			break;
1052eda14cbcSMatt Macy 		case 'm':
1053eda14cbcSMatt Macy 			domount = 1;
1054eda14cbcSMatt Macy 			break;
1055eda14cbcSMatt Macy 		case 'p':
1056eda14cbcSMatt Macy 			(void) strlcpy(record.zi_func, optarg,
1057eda14cbcSMatt Macy 			    sizeof (record.zi_func));
1058eda14cbcSMatt Macy 			record.zi_cmd = ZINJECT_PANIC;
1059eda14cbcSMatt Macy 			break;
10600d4ad640SMartin Matuska 		case 'P':
10610d4ad640SMartin Matuska 			if (strcasecmp(optarg, "import") == 0) {
10620d4ad640SMartin Matuska 				record.zi_cmd = ZINJECT_DELAY_IMPORT;
10630d4ad640SMartin Matuska 			} else if (strcasecmp(optarg, "export") == 0) {
10640d4ad640SMartin Matuska 				record.zi_cmd = ZINJECT_DELAY_EXPORT;
10650d4ad640SMartin Matuska 			} else {
10660d4ad640SMartin Matuska 				(void) fprintf(stderr, "invalid command '%s': "
10670d4ad640SMartin Matuska 				    "must be 'import' or 'export'\n", optarg);
10680d4ad640SMartin Matuska 				usage();
10690d4ad640SMartin Matuska 				libzfs_fini(g_zfs);
10700d4ad640SMartin Matuska 				return (1);
10710d4ad640SMartin Matuska 			}
10720d4ad640SMartin Matuska 			break;
1073eda14cbcSMatt Macy 		case 'q':
1074eda14cbcSMatt Macy 			quiet = 1;
1075eda14cbcSMatt Macy 			break;
1076eda14cbcSMatt Macy 		case 'r':
1077eda14cbcSMatt Macy 			range = optarg;
1078eda14cbcSMatt Macy 			flags |= ZINJECT_CALC_RANGE;
1079eda14cbcSMatt Macy 			break;
1080eda14cbcSMatt Macy 		case 's':
1081eda14cbcSMatt Macy 			dur_secs = 1;
1082eda14cbcSMatt Macy 			record.zi_duration = (int)strtol(optarg, &end, 10);
1083eda14cbcSMatt Macy 			if (record.zi_duration <= 0 || *end != '\0') {
1084eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid duration '%s': "
1085eda14cbcSMatt Macy 				    "must be a positive integer\n", optarg);
1086eda14cbcSMatt Macy 				usage();
1087eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
1088eda14cbcSMatt Macy 				return (1);
1089eda14cbcSMatt Macy 			}
1090eda14cbcSMatt Macy 			break;
1091eda14cbcSMatt Macy 		case 'T':
1092c6767dc1SMartin Matuska 			io_type = str_to_iotype(optarg);
1093c6767dc1SMartin Matuska 			if (io_type == ZINJECT_IOTYPES) {
1094eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid I/O type "
1095eda14cbcSMatt Macy 				    "'%s': must be 'read', 'write', 'free', "
10961719886fSMartin Matuska 				    "'claim', 'flush' or 'all'\n", optarg);
1097eda14cbcSMatt Macy 				usage();
1098eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
1099eda14cbcSMatt Macy 				return (1);
1100eda14cbcSMatt Macy 			}
1101eda14cbcSMatt Macy 			break;
1102eda14cbcSMatt Macy 		case 't':
1103eda14cbcSMatt Macy 			if ((type = name_to_type(optarg)) == TYPE_INVAL &&
1104eda14cbcSMatt Macy 			    !MOS_TYPE(type)) {
1105eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid type '%s'\n",
1106eda14cbcSMatt Macy 				    optarg);
1107eda14cbcSMatt Macy 				usage();
1108eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
1109eda14cbcSMatt Macy 				return (1);
1110eda14cbcSMatt Macy 			}
1111eda14cbcSMatt Macy 			break;
1112eda14cbcSMatt Macy 		case 'u':
1113eda14cbcSMatt Macy 			flags |= ZINJECT_UNLOAD_SPA;
1114eda14cbcSMatt Macy 			break;
1115eda14cbcSMatt Macy 		case 'L':
1116eda14cbcSMatt Macy 			if ((label = name_to_type(optarg)) == TYPE_INVAL &&
1117eda14cbcSMatt Macy 			    !LABEL_TYPE(type)) {
1118eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid label type "
1119eda14cbcSMatt Macy 				    "'%s'\n", optarg);
1120eda14cbcSMatt Macy 				usage();
1121eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
1122eda14cbcSMatt Macy 				return (1);
1123eda14cbcSMatt Macy 			}
1124eda14cbcSMatt Macy 			break;
1125eda14cbcSMatt Macy 		case ':':
1126eda14cbcSMatt Macy 			(void) fprintf(stderr, "option -%c requires an "
1127eda14cbcSMatt Macy 			    "operand\n", optopt);
1128eda14cbcSMatt Macy 			usage();
1129eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1130eda14cbcSMatt Macy 			return (1);
1131eda14cbcSMatt Macy 		case '?':
1132eda14cbcSMatt Macy 			(void) fprintf(stderr, "invalid option '%c'\n",
1133eda14cbcSMatt Macy 			    optopt);
1134eda14cbcSMatt Macy 			usage();
1135eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1136eda14cbcSMatt Macy 			return (2);
1137eda14cbcSMatt Macy 		}
1138eda14cbcSMatt Macy 	}
1139eda14cbcSMatt Macy 
1140eda14cbcSMatt Macy 	argc -= optind;
1141eda14cbcSMatt Macy 	argv += optind;
1142eda14cbcSMatt Macy 
11430d4ad640SMartin Matuska 	if (record.zi_duration != 0 && record.zi_cmd == 0)
1144eda14cbcSMatt Macy 		record.zi_cmd = ZINJECT_IGNORED_WRITES;
1145eda14cbcSMatt Macy 
1146eda14cbcSMatt Macy 	if (cancel != NULL) {
1147eda14cbcSMatt Macy 		/*
1148eda14cbcSMatt Macy 		 * '-c' is invalid with any other options.
1149eda14cbcSMatt Macy 		 */
1150eda14cbcSMatt Macy 		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
1151eda14cbcSMatt Macy 		    level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED ||
1152eda14cbcSMatt Macy 		    record.zi_freq > 0 || dvas != 0) {
1153eda14cbcSMatt Macy 			(void) fprintf(stderr, "cancel (-c) incompatible with "
1154eda14cbcSMatt Macy 			    "any other options\n");
1155eda14cbcSMatt Macy 			usage();
1156eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1157eda14cbcSMatt Macy 			return (2);
1158eda14cbcSMatt Macy 		}
1159eda14cbcSMatt Macy 		if (argc != 0) {
1160eda14cbcSMatt Macy 			(void) fprintf(stderr, "extraneous argument to '-c'\n");
1161eda14cbcSMatt Macy 			usage();
1162eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1163eda14cbcSMatt Macy 			return (2);
1164eda14cbcSMatt Macy 		}
1165eda14cbcSMatt Macy 
1166eda14cbcSMatt Macy 		if (strcmp(cancel, "all") == 0) {
1167eda14cbcSMatt Macy 			return (cancel_all_handlers());
1168eda14cbcSMatt Macy 		} else {
1169eda14cbcSMatt Macy 			int id = (int)strtol(cancel, &end, 10);
1170eda14cbcSMatt Macy 			if (*end != '\0') {
1171eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid handle id '%s':"
1172eda14cbcSMatt Macy 				    " must be an integer or 'all'\n", cancel);
1173eda14cbcSMatt Macy 				usage();
1174eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
1175eda14cbcSMatt Macy 				return (1);
1176eda14cbcSMatt Macy 			}
1177eda14cbcSMatt Macy 			return (cancel_handler(id));
1178eda14cbcSMatt Macy 		}
1179eda14cbcSMatt Macy 	}
1180eda14cbcSMatt Macy 
1181eda14cbcSMatt Macy 	if (device != NULL) {
1182eda14cbcSMatt Macy 		/*
1183eda14cbcSMatt Macy 		 * Device (-d) injection uses a completely different mechanism
1184eda14cbcSMatt Macy 		 * for doing injection, so handle it separately here.
1185eda14cbcSMatt Macy 		 */
1186eda14cbcSMatt Macy 		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
1187eda14cbcSMatt Macy 		    level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED ||
1188eda14cbcSMatt Macy 		    dvas != 0) {
1189eda14cbcSMatt Macy 			(void) fprintf(stderr, "device (-d) incompatible with "
1190eda14cbcSMatt Macy 			    "data error injection\n");
1191eda14cbcSMatt Macy 			usage();
1192eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1193eda14cbcSMatt Macy 			return (2);
1194eda14cbcSMatt Macy 		}
1195eda14cbcSMatt Macy 
1196eda14cbcSMatt Macy 		if (argc != 1) {
1197eda14cbcSMatt Macy 			(void) fprintf(stderr, "device (-d) injection requires "
1198eda14cbcSMatt Macy 			    "a single pool name\n");
1199eda14cbcSMatt Macy 			usage();
1200eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1201eda14cbcSMatt Macy 			return (2);
1202eda14cbcSMatt Macy 		}
1203eda14cbcSMatt Macy 
1204eda14cbcSMatt Macy 		(void) strlcpy(pool, argv[0], sizeof (pool));
1205eda14cbcSMatt Macy 		dataset[0] = '\0';
1206eda14cbcSMatt Macy 
1207eda14cbcSMatt Macy 		if (error == ECKSUM) {
1208eda14cbcSMatt Macy 			(void) fprintf(stderr, "device error type must be "
1209eda14cbcSMatt Macy 			    "'io', 'nxio' or 'corrupt'\n");
1210eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1211eda14cbcSMatt Macy 			return (1);
1212eda14cbcSMatt Macy 		}
1213eda14cbcSMatt Macy 
1214eda14cbcSMatt Macy 		if (error == EILSEQ &&
1215c6767dc1SMartin Matuska 		    (record.zi_freq == 0 || io_type != ZINJECT_IOTYPE_READ)) {
1216eda14cbcSMatt Macy 			(void) fprintf(stderr, "device corrupt errors require "
1217eda14cbcSMatt Macy 			    "io type read and a frequency value\n");
1218eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1219eda14cbcSMatt Macy 			return (1);
1220eda14cbcSMatt Macy 		}
1221eda14cbcSMatt Macy 
1222eda14cbcSMatt Macy 		record.zi_iotype = io_type;
1223eda14cbcSMatt Macy 		if (translate_device(pool, device, label, &record) != 0) {
1224eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1225eda14cbcSMatt Macy 			return (1);
1226eda14cbcSMatt Macy 		}
1227e2257b31SMartin Matuska 
1228e2257b31SMartin Matuska 		if (record.zi_nlanes) {
1229e2257b31SMartin Matuska 			switch (io_type) {
1230c6767dc1SMartin Matuska 			case ZINJECT_IOTYPE_READ:
1231c6767dc1SMartin Matuska 			case ZINJECT_IOTYPE_WRITE:
1232c6767dc1SMartin Matuska 			case ZINJECT_IOTYPE_ALL:
1233e2257b31SMartin Matuska 				break;
1234e2257b31SMartin Matuska 			default:
1235e2257b31SMartin Matuska 				(void) fprintf(stderr, "I/O type for a delay "
1236e2257b31SMartin Matuska 				    "must be 'read' or 'write'\n");
1237e2257b31SMartin Matuska 				usage();
1238e2257b31SMartin Matuska 				libzfs_fini(g_zfs);
1239e2257b31SMartin Matuska 				return (1);
1240e2257b31SMartin Matuska 			}
1241e2257b31SMartin Matuska 		}
1242e2257b31SMartin Matuska 
1243eda14cbcSMatt Macy 		if (!error)
1244eda14cbcSMatt Macy 			error = ENXIO;
1245eda14cbcSMatt Macy 
1246eda14cbcSMatt Macy 		if (action != VDEV_STATE_UNKNOWN)
1247eda14cbcSMatt Macy 			return (perform_action(pool, &record, action));
1248eda14cbcSMatt Macy 
1249eda14cbcSMatt Macy 	} else if (raw != NULL) {
1250eda14cbcSMatt Macy 		if (range != NULL || type != TYPE_INVAL || level != 0 ||
1251eda14cbcSMatt Macy 		    record.zi_cmd != ZINJECT_UNINITIALIZED ||
1252eda14cbcSMatt Macy 		    record.zi_freq > 0 || dvas != 0) {
1253eda14cbcSMatt Macy 			(void) fprintf(stderr, "raw (-b) format with "
1254eda14cbcSMatt Macy 			    "any other options\n");
1255eda14cbcSMatt Macy 			usage();
1256eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1257eda14cbcSMatt Macy 			return (2);
1258eda14cbcSMatt Macy 		}
1259eda14cbcSMatt Macy 
1260eda14cbcSMatt Macy 		if (argc != 1) {
1261eda14cbcSMatt Macy 			(void) fprintf(stderr, "raw (-b) format expects a "
1262eda14cbcSMatt Macy 			    "single pool name\n");
1263eda14cbcSMatt Macy 			usage();
1264eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1265eda14cbcSMatt Macy 			return (2);
1266eda14cbcSMatt Macy 		}
1267eda14cbcSMatt Macy 
1268eda14cbcSMatt Macy 		(void) strlcpy(pool, argv[0], sizeof (pool));
1269eda14cbcSMatt Macy 		dataset[0] = '\0';
1270eda14cbcSMatt Macy 
1271eda14cbcSMatt Macy 		if (error == ENXIO) {
1272eda14cbcSMatt Macy 			(void) fprintf(stderr, "data error type must be "
1273eda14cbcSMatt Macy 			    "'checksum' or 'io'\n");
1274eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1275eda14cbcSMatt Macy 			return (1);
1276eda14cbcSMatt Macy 		}
1277eda14cbcSMatt Macy 
1278eda14cbcSMatt Macy 		record.zi_cmd = ZINJECT_DATA_FAULT;
1279eda14cbcSMatt Macy 		if (translate_raw(raw, &record) != 0) {
1280eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1281eda14cbcSMatt Macy 			return (1);
1282eda14cbcSMatt Macy 		}
1283eda14cbcSMatt Macy 		if (!error)
1284eda14cbcSMatt Macy 			error = EIO;
1285eda14cbcSMatt Macy 	} else if (record.zi_cmd == ZINJECT_PANIC) {
1286eda14cbcSMatt Macy 		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
1287eda14cbcSMatt Macy 		    level != 0 || device != NULL || record.zi_freq > 0 ||
1288eda14cbcSMatt Macy 		    dvas != 0) {
12890d4ad640SMartin Matuska 			(void) fprintf(stderr, "%s incompatible with other "
12900d4ad640SMartin Matuska 			    "options\n", "import|export delay (-P)");
1291eda14cbcSMatt Macy 			usage();
1292eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1293eda14cbcSMatt Macy 			return (2);
1294eda14cbcSMatt Macy 		}
1295eda14cbcSMatt Macy 
1296eda14cbcSMatt Macy 		if (argc < 1 || argc > 2) {
1297eda14cbcSMatt Macy 			(void) fprintf(stderr, "panic (-p) injection requires "
1298eda14cbcSMatt Macy 			    "a single pool name and an optional id\n");
1299eda14cbcSMatt Macy 			usage();
1300eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1301eda14cbcSMatt Macy 			return (2);
1302eda14cbcSMatt Macy 		}
1303eda14cbcSMatt Macy 
1304eda14cbcSMatt Macy 		(void) strlcpy(pool, argv[0], sizeof (pool));
1305eda14cbcSMatt Macy 		if (argv[1] != NULL)
1306eda14cbcSMatt Macy 			record.zi_type = atoi(argv[1]);
1307eda14cbcSMatt Macy 		dataset[0] = '\0';
13080d4ad640SMartin Matuska 	} else if (record.zi_cmd == ZINJECT_DELAY_IMPORT ||
13090d4ad640SMartin Matuska 	    record.zi_cmd == ZINJECT_DELAY_EXPORT) {
13100d4ad640SMartin Matuska 		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
13110d4ad640SMartin Matuska 		    level != 0 || device != NULL || record.zi_freq > 0 ||
13120d4ad640SMartin Matuska 		    dvas != 0) {
13130d4ad640SMartin Matuska 			(void) fprintf(stderr, "%s incompatible with other "
13140d4ad640SMartin Matuska 			    "options\n", "import|export delay (-P)");
13150d4ad640SMartin Matuska 			usage();
13160d4ad640SMartin Matuska 			libzfs_fini(g_zfs);
13170d4ad640SMartin Matuska 			return (2);
13180d4ad640SMartin Matuska 		}
13190d4ad640SMartin Matuska 
13200d4ad640SMartin Matuska 		if (argc != 1 || record.zi_duration <= 0) {
13210d4ad640SMartin Matuska 			(void) fprintf(stderr, "import|export delay (-P) "
13220d4ad640SMartin Matuska 			    "injection requires a duration (-s) and a single "
13230d4ad640SMartin Matuska 			    "pool name\n");
13240d4ad640SMartin Matuska 			usage();
13250d4ad640SMartin Matuska 			libzfs_fini(g_zfs);
13260d4ad640SMartin Matuska 			return (2);
13270d4ad640SMartin Matuska 		}
13280d4ad640SMartin Matuska 
13290d4ad640SMartin Matuska 		(void) strlcpy(pool, argv[0], sizeof (pool));
1330eda14cbcSMatt Macy 	} else if (record.zi_cmd == ZINJECT_IGNORED_WRITES) {
1331eda14cbcSMatt Macy 		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
1332eda14cbcSMatt Macy 		    level != 0 || record.zi_freq > 0 || dvas != 0) {
1333eda14cbcSMatt Macy 			(void) fprintf(stderr, "hardware failure (-I) "
1334eda14cbcSMatt Macy 			    "incompatible with other options\n");
1335eda14cbcSMatt Macy 			usage();
1336eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1337eda14cbcSMatt Macy 			return (2);
1338eda14cbcSMatt Macy 		}
1339eda14cbcSMatt Macy 
1340eda14cbcSMatt Macy 		if (nowrites == 0) {
1341eda14cbcSMatt Macy 			(void) fprintf(stderr, "-s or -g meaningless "
1342eda14cbcSMatt Macy 			    "without -I (ignore writes)\n");
1343eda14cbcSMatt Macy 			usage();
1344eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1345eda14cbcSMatt Macy 			return (2);
1346eda14cbcSMatt Macy 		} else if (dur_secs && dur_txg) {
1347eda14cbcSMatt Macy 			(void) fprintf(stderr, "choose a duration either "
1348eda14cbcSMatt Macy 			    "in seconds (-s) or a number of txgs (-g) "
1349eda14cbcSMatt Macy 			    "but not both\n");
1350eda14cbcSMatt Macy 			usage();
1351eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1352eda14cbcSMatt Macy 			return (2);
1353eda14cbcSMatt Macy 		} else if (argc != 1) {
1354eda14cbcSMatt Macy 			(void) fprintf(stderr, "ignore writes (-I) "
1355eda14cbcSMatt Macy 			    "injection requires a single pool name\n");
1356eda14cbcSMatt Macy 			usage();
1357eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1358eda14cbcSMatt Macy 			return (2);
1359eda14cbcSMatt Macy 		}
1360eda14cbcSMatt Macy 
1361eda14cbcSMatt Macy 		(void) strlcpy(pool, argv[0], sizeof (pool));
1362eda14cbcSMatt Macy 		dataset[0] = '\0';
1363eda14cbcSMatt Macy 	} else if (type == TYPE_INVAL) {
1364eda14cbcSMatt Macy 		if (flags == 0) {
1365eda14cbcSMatt Macy 			(void) fprintf(stderr, "at least one of '-b', '-d', "
1366eda14cbcSMatt Macy 			    "'-t', '-a', '-p', '-I' or '-u' "
1367eda14cbcSMatt Macy 			    "must be specified\n");
1368eda14cbcSMatt Macy 			usage();
1369eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1370eda14cbcSMatt Macy 			return (2);
1371eda14cbcSMatt Macy 		}
1372eda14cbcSMatt Macy 
1373eda14cbcSMatt Macy 		if (argc == 1 && (flags & ZINJECT_UNLOAD_SPA)) {
1374eda14cbcSMatt Macy 			(void) strlcpy(pool, argv[0], sizeof (pool));
1375eda14cbcSMatt Macy 			dataset[0] = '\0';
1376eda14cbcSMatt Macy 		} else if (argc != 0) {
1377eda14cbcSMatt Macy 			(void) fprintf(stderr, "extraneous argument for "
1378eda14cbcSMatt Macy 			    "'-f'\n");
1379eda14cbcSMatt Macy 			usage();
1380eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1381eda14cbcSMatt Macy 			return (2);
1382eda14cbcSMatt Macy 		}
1383eda14cbcSMatt Macy 
1384eda14cbcSMatt Macy 		flags |= ZINJECT_NULL;
1385eda14cbcSMatt Macy 	} else {
1386eda14cbcSMatt Macy 		if (argc != 1) {
1387eda14cbcSMatt Macy 			(void) fprintf(stderr, "missing object\n");
1388eda14cbcSMatt Macy 			usage();
1389eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1390eda14cbcSMatt Macy 			return (2);
1391eda14cbcSMatt Macy 		}
1392eda14cbcSMatt Macy 
1393eda14cbcSMatt Macy 		if (error == ENXIO || error == EILSEQ) {
1394eda14cbcSMatt Macy 			(void) fprintf(stderr, "data error type must be "
1395eda14cbcSMatt Macy 			    "'checksum' or 'io'\n");
1396eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1397eda14cbcSMatt Macy 			return (1);
1398eda14cbcSMatt Macy 		}
1399eda14cbcSMatt Macy 
1400eda14cbcSMatt Macy 		if (dvas != 0) {
1401eda14cbcSMatt Macy 			if (error == EACCES || error == EINVAL) {
1402eda14cbcSMatt Macy 				(void) fprintf(stderr, "the '-C' option may "
1403eda14cbcSMatt Macy 				    "not be used with logical data errors "
1404eda14cbcSMatt Macy 				    "'decrypt' and 'decompress'\n");
1405eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
1406eda14cbcSMatt Macy 				return (1);
1407eda14cbcSMatt Macy 			}
1408eda14cbcSMatt Macy 
1409eda14cbcSMatt Macy 			record.zi_dvas = dvas;
1410eda14cbcSMatt Macy 		}
1411eda14cbcSMatt Macy 
1412eda14cbcSMatt Macy 		if (error == EACCES) {
1413eda14cbcSMatt Macy 			if (type != TYPE_DATA) {
1414eda14cbcSMatt Macy 				(void) fprintf(stderr, "decryption errors "
1415eda14cbcSMatt Macy 				    "may only be injected for 'data' types\n");
1416eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
1417eda14cbcSMatt Macy 				return (1);
1418eda14cbcSMatt Macy 			}
1419eda14cbcSMatt Macy 
1420eda14cbcSMatt Macy 			record.zi_cmd = ZINJECT_DECRYPT_FAULT;
1421eda14cbcSMatt Macy 			/*
1422eda14cbcSMatt Macy 			 * Internally, ZFS actually uses ECKSUM for decryption
1423eda14cbcSMatt Macy 			 * errors since EACCES is used to indicate the key was
1424eda14cbcSMatt Macy 			 * not found.
1425eda14cbcSMatt Macy 			 */
1426eda14cbcSMatt Macy 			error = ECKSUM;
1427eda14cbcSMatt Macy 		} else {
1428eda14cbcSMatt Macy 			record.zi_cmd = ZINJECT_DATA_FAULT;
1429eda14cbcSMatt Macy 		}
1430eda14cbcSMatt Macy 
1431eda14cbcSMatt Macy 		if (translate_record(type, argv[0], range, level, &record, pool,
1432eda14cbcSMatt Macy 		    dataset) != 0) {
1433eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1434eda14cbcSMatt Macy 			return (1);
1435eda14cbcSMatt Macy 		}
1436eda14cbcSMatt Macy 		if (!error)
1437eda14cbcSMatt Macy 			error = EIO;
1438eda14cbcSMatt Macy 	}
1439eda14cbcSMatt Macy 
1440eda14cbcSMatt Macy 	/*
1441eda14cbcSMatt Macy 	 * If this is pool-wide metadata, unmount everything.  The ioctl() will
1442eda14cbcSMatt Macy 	 * unload the pool, so that we trigger spa-wide reopen of metadata next
1443eda14cbcSMatt Macy 	 * time we access the pool.
1444eda14cbcSMatt Macy 	 */
1445eda14cbcSMatt Macy 	if (dataset[0] != '\0' && domount) {
1446eda14cbcSMatt Macy 		if ((zhp = zfs_open(g_zfs, dataset,
1447eda14cbcSMatt Macy 		    ZFS_TYPE_DATASET)) == NULL) {
1448eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1449eda14cbcSMatt Macy 			return (1);
1450eda14cbcSMatt Macy 		}
1451eda14cbcSMatt Macy 		if (zfs_unmount(zhp, NULL, 0) != 0) {
1452eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1453eda14cbcSMatt Macy 			return (1);
1454eda14cbcSMatt Macy 		}
1455eda14cbcSMatt Macy 	}
1456eda14cbcSMatt Macy 
1457eda14cbcSMatt Macy 	record.zi_error = error;
1458eda14cbcSMatt Macy 
1459eda14cbcSMatt Macy 	ret = register_handler(pool, flags, &record, quiet);
1460eda14cbcSMatt Macy 
1461eda14cbcSMatt Macy 	if (dataset[0] != '\0' && domount)
1462eda14cbcSMatt Macy 		ret = (zfs_mount(zhp, NULL, 0) != 0);
1463eda14cbcSMatt Macy 
1464eda14cbcSMatt Macy 	libzfs_fini(g_zfs);
1465eda14cbcSMatt Macy 
1466eda14cbcSMatt Macy 	return (ret);
1467eda14cbcSMatt Macy }
1468