xref: /freebsd-src/sys/contrib/openzfs/cmd/zinject/zinject.c (revision eda14cbc264d6969b02f2b1994cef11148e914f1)
1*eda14cbcSMatt Macy /*
2*eda14cbcSMatt Macy  * CDDL HEADER START
3*eda14cbcSMatt Macy  *
4*eda14cbcSMatt Macy  * The contents of this file are subject to the terms of the
5*eda14cbcSMatt Macy  * Common Development and Distribution License (the "License").
6*eda14cbcSMatt Macy  * You may not use this file except in compliance with the License.
7*eda14cbcSMatt Macy  *
8*eda14cbcSMatt Macy  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*eda14cbcSMatt Macy  * or http://www.opensolaris.org/os/licensing.
10*eda14cbcSMatt Macy  * See the License for the specific language governing permissions
11*eda14cbcSMatt Macy  * and limitations under the License.
12*eda14cbcSMatt Macy  *
13*eda14cbcSMatt Macy  * When distributing Covered Code, include this CDDL HEADER in each
14*eda14cbcSMatt Macy  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*eda14cbcSMatt Macy  * If applicable, add the following below this CDDL HEADER, with the
16*eda14cbcSMatt Macy  * fields enclosed by brackets "[]" replaced with your own identifying
17*eda14cbcSMatt Macy  * information: Portions Copyright [yyyy] [name of copyright owner]
18*eda14cbcSMatt Macy  *
19*eda14cbcSMatt Macy  * CDDL HEADER END
20*eda14cbcSMatt Macy  */
21*eda14cbcSMatt Macy /*
22*eda14cbcSMatt Macy  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23*eda14cbcSMatt Macy  * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
24*eda14cbcSMatt Macy  * Copyright (c) 2017, Intel Corporation.
25*eda14cbcSMatt Macy  */
26*eda14cbcSMatt Macy 
27*eda14cbcSMatt Macy /*
28*eda14cbcSMatt Macy  * ZFS Fault Injector
29*eda14cbcSMatt Macy  *
30*eda14cbcSMatt Macy  * This userland component takes a set of options and uses libzpool to translate
31*eda14cbcSMatt Macy  * from a user-visible object type and name to an internal representation.
32*eda14cbcSMatt Macy  * There are two basic types of faults: device faults and data faults.
33*eda14cbcSMatt Macy  *
34*eda14cbcSMatt Macy  *
35*eda14cbcSMatt Macy  * DEVICE FAULTS
36*eda14cbcSMatt Macy  *
37*eda14cbcSMatt Macy  * Errors can be injected into a particular vdev using the '-d' option.  This
38*eda14cbcSMatt Macy  * option takes a path or vdev GUID to uniquely identify the device within a
39*eda14cbcSMatt Macy  * pool.  There are four types of errors that can be injected, IO, ENXIO,
40*eda14cbcSMatt Macy  * ECHILD, and EILSEQ.  These can be controlled through the '-e' option and the
41*eda14cbcSMatt Macy  * default is ENXIO.  For EIO failures, any attempt to read data from the device
42*eda14cbcSMatt Macy  * will return EIO, but a subsequent attempt to reopen the device will succeed.
43*eda14cbcSMatt Macy  * For ENXIO failures, any attempt to read from the device will return EIO, but
44*eda14cbcSMatt Macy  * any attempt to reopen the device will also return ENXIO.  The EILSEQ failures
45*eda14cbcSMatt Macy  * only apply to read operations (-T read) and will flip a bit after the device
46*eda14cbcSMatt Macy  * has read the original data.
47*eda14cbcSMatt Macy  *
48*eda14cbcSMatt Macy  * For label faults, the -L option must be specified. This allows faults
49*eda14cbcSMatt Macy  * to be injected into either the nvlist, uberblock, pad1, or pad2 region
50*eda14cbcSMatt Macy  * of all the labels for the specified device.
51*eda14cbcSMatt Macy  *
52*eda14cbcSMatt Macy  * This form of the command looks like:
53*eda14cbcSMatt Macy  *
54*eda14cbcSMatt Macy  * 	zinject -d device [-e errno] [-L <uber | nvlist | pad1 | pad2>] pool
55*eda14cbcSMatt Macy  *
56*eda14cbcSMatt Macy  *
57*eda14cbcSMatt Macy  * DATA FAULTS
58*eda14cbcSMatt Macy  *
59*eda14cbcSMatt Macy  * We begin with a tuple of the form:
60*eda14cbcSMatt Macy  *
61*eda14cbcSMatt Macy  * 	<type,level,range,object>
62*eda14cbcSMatt Macy  *
63*eda14cbcSMatt Macy  * 	type	A string describing the type of data to target.  Each type
64*eda14cbcSMatt Macy  * 		implicitly describes how to interpret 'object'. Currently,
65*eda14cbcSMatt Macy  * 		the following values are supported:
66*eda14cbcSMatt Macy  *
67*eda14cbcSMatt Macy  * 		data		User data for a file
68*eda14cbcSMatt Macy  * 		dnode		Dnode for a file or directory
69*eda14cbcSMatt Macy  *
70*eda14cbcSMatt Macy  *		The following MOS objects are special.  Instead of injecting
71*eda14cbcSMatt Macy  *		errors on a particular object or blkid, we inject errors across
72*eda14cbcSMatt Macy  *		all objects of the given type.
73*eda14cbcSMatt Macy  *
74*eda14cbcSMatt Macy  * 		mos		Any data in the MOS
75*eda14cbcSMatt Macy  * 		mosdir		object directory
76*eda14cbcSMatt Macy  * 		config		pool configuration
77*eda14cbcSMatt Macy  * 		bpobj		blkptr list
78*eda14cbcSMatt Macy  * 		spacemap	spacemap
79*eda14cbcSMatt Macy  * 		metaslab	metaslab
80*eda14cbcSMatt Macy  * 		errlog		persistent error log
81*eda14cbcSMatt Macy  *
82*eda14cbcSMatt Macy  * 	level	Object level.  Defaults to '0', not applicable to all types.  If
83*eda14cbcSMatt Macy  * 		a range is given, this corresponds to the indirect block
84*eda14cbcSMatt Macy  * 		corresponding to the specific range.
85*eda14cbcSMatt Macy  *
86*eda14cbcSMatt Macy  *	range	A numerical range [start,end) within the object.  Defaults to
87*eda14cbcSMatt Macy  *		the full size of the file.
88*eda14cbcSMatt Macy  *
89*eda14cbcSMatt Macy  * 	object	A string describing the logical location of the object.  For
90*eda14cbcSMatt Macy  * 		files and directories (currently the only supported types),
91*eda14cbcSMatt Macy  * 		this is the path of the object on disk.
92*eda14cbcSMatt Macy  *
93*eda14cbcSMatt Macy  * This is translated, via libzpool, into the following internal representation:
94*eda14cbcSMatt Macy  *
95*eda14cbcSMatt Macy  * 	<type,objset,object,level,range>
96*eda14cbcSMatt Macy  *
97*eda14cbcSMatt Macy  * These types should be self-explanatory.  This tuple is then passed to the
98*eda14cbcSMatt Macy  * kernel via a special ioctl() to initiate fault injection for the given
99*eda14cbcSMatt Macy  * object.  Note that 'type' is not strictly necessary for fault injection, but
100*eda14cbcSMatt Macy  * is used when translating existing faults into a human-readable string.
101*eda14cbcSMatt Macy  *
102*eda14cbcSMatt Macy  *
103*eda14cbcSMatt Macy  * The command itself takes one of the forms:
104*eda14cbcSMatt Macy  *
105*eda14cbcSMatt Macy  * 	zinject
106*eda14cbcSMatt Macy  * 	zinject <-a | -u pool>
107*eda14cbcSMatt Macy  * 	zinject -c <id|all>
108*eda14cbcSMatt Macy  * 	zinject [-q] <-t type> [-f freq] [-u] [-a] [-m] [-e errno] [-l level]
109*eda14cbcSMatt Macy  *	    [-r range] <object>
110*eda14cbcSMatt Macy  * 	zinject [-f freq] [-a] [-m] [-u] -b objset:object:level:start:end pool
111*eda14cbcSMatt Macy  *
112*eda14cbcSMatt Macy  * With no arguments, the command prints all currently registered injection
113*eda14cbcSMatt Macy  * handlers, with their numeric identifiers.
114*eda14cbcSMatt Macy  *
115*eda14cbcSMatt Macy  * The '-c' option will clear the given handler, or all handlers if 'all' is
116*eda14cbcSMatt Macy  * specified.
117*eda14cbcSMatt Macy  *
118*eda14cbcSMatt Macy  * The '-e' option takes a string describing the errno to simulate.  This must
119*eda14cbcSMatt Macy  * be one of 'io', 'checksum', 'decompress', or 'decrypt'.  In most cases this
120*eda14cbcSMatt Macy  * will result in the same behavior, but RAID-Z will produce a different set of
121*eda14cbcSMatt Macy  * ereports for this situation.
122*eda14cbcSMatt Macy  *
123*eda14cbcSMatt Macy  * The '-a', '-u', and '-m' flags toggle internal flush behavior.  If '-a' is
124*eda14cbcSMatt Macy  * specified, then the ARC cache is flushed appropriately.  If '-u' is
125*eda14cbcSMatt Macy  * specified, then the underlying SPA is unloaded.  Either of these flags can be
126*eda14cbcSMatt Macy  * specified independently of any other handlers.  The '-m' flag automatically
127*eda14cbcSMatt Macy  * does an unmount and remount of the underlying dataset to aid in flushing the
128*eda14cbcSMatt Macy  * cache.
129*eda14cbcSMatt Macy  *
130*eda14cbcSMatt Macy  * The '-f' flag controls the frequency of errors injected, expressed as a
131*eda14cbcSMatt Macy  * real number percentage between 0.0001 and 100.  The default is 100.
132*eda14cbcSMatt Macy  *
133*eda14cbcSMatt Macy  * The this form is responsible for actually injecting the handler into the
134*eda14cbcSMatt Macy  * framework.  It takes the arguments described above, translates them to the
135*eda14cbcSMatt Macy  * internal tuple using libzpool, and then issues an ioctl() to register the
136*eda14cbcSMatt Macy  * handler.
137*eda14cbcSMatt Macy  *
138*eda14cbcSMatt Macy  * The final form can target a specific bookmark, regardless of whether a
139*eda14cbcSMatt Macy  * human-readable interface has been designed.  It allows developers to specify
140*eda14cbcSMatt Macy  * a particular block by number.
141*eda14cbcSMatt Macy  */
142*eda14cbcSMatt Macy 
143*eda14cbcSMatt Macy #include <errno.h>
144*eda14cbcSMatt Macy #include <fcntl.h>
145*eda14cbcSMatt Macy #include <stdio.h>
146*eda14cbcSMatt Macy #include <stdlib.h>
147*eda14cbcSMatt Macy #include <strings.h>
148*eda14cbcSMatt Macy #include <unistd.h>
149*eda14cbcSMatt Macy 
150*eda14cbcSMatt Macy #include <sys/fs/zfs.h>
151*eda14cbcSMatt Macy #include <sys/mount.h>
152*eda14cbcSMatt Macy 
153*eda14cbcSMatt Macy #include <libzfs.h>
154*eda14cbcSMatt Macy 
155*eda14cbcSMatt Macy #undef verify	/* both libzfs.h and zfs_context.h want to define this */
156*eda14cbcSMatt Macy 
157*eda14cbcSMatt Macy #include "zinject.h"
158*eda14cbcSMatt Macy 
159*eda14cbcSMatt Macy libzfs_handle_t *g_zfs;
160*eda14cbcSMatt Macy int zfs_fd;
161*eda14cbcSMatt Macy 
162*eda14cbcSMatt Macy static const char *errtable[TYPE_INVAL] = {
163*eda14cbcSMatt Macy 	"data",
164*eda14cbcSMatt Macy 	"dnode",
165*eda14cbcSMatt Macy 	"mos",
166*eda14cbcSMatt Macy 	"mosdir",
167*eda14cbcSMatt Macy 	"metaslab",
168*eda14cbcSMatt Macy 	"config",
169*eda14cbcSMatt Macy 	"bpobj",
170*eda14cbcSMatt Macy 	"spacemap",
171*eda14cbcSMatt Macy 	"errlog",
172*eda14cbcSMatt Macy 	"uber",
173*eda14cbcSMatt Macy 	"nvlist",
174*eda14cbcSMatt Macy 	"pad1",
175*eda14cbcSMatt Macy 	"pad2"
176*eda14cbcSMatt Macy };
177*eda14cbcSMatt Macy 
178*eda14cbcSMatt Macy static err_type_t
179*eda14cbcSMatt Macy name_to_type(const char *arg)
180*eda14cbcSMatt Macy {
181*eda14cbcSMatt Macy 	int i;
182*eda14cbcSMatt Macy 	for (i = 0; i < TYPE_INVAL; i++)
183*eda14cbcSMatt Macy 		if (strcmp(errtable[i], arg) == 0)
184*eda14cbcSMatt Macy 			return (i);
185*eda14cbcSMatt Macy 
186*eda14cbcSMatt Macy 	return (TYPE_INVAL);
187*eda14cbcSMatt Macy }
188*eda14cbcSMatt Macy 
189*eda14cbcSMatt Macy static const char *
190*eda14cbcSMatt Macy type_to_name(uint64_t type)
191*eda14cbcSMatt Macy {
192*eda14cbcSMatt Macy 	switch (type) {
193*eda14cbcSMatt Macy 	case DMU_OT_OBJECT_DIRECTORY:
194*eda14cbcSMatt Macy 		return ("mosdir");
195*eda14cbcSMatt Macy 	case DMU_OT_OBJECT_ARRAY:
196*eda14cbcSMatt Macy 		return ("metaslab");
197*eda14cbcSMatt Macy 	case DMU_OT_PACKED_NVLIST:
198*eda14cbcSMatt Macy 		return ("config");
199*eda14cbcSMatt Macy 	case DMU_OT_BPOBJ:
200*eda14cbcSMatt Macy 		return ("bpobj");
201*eda14cbcSMatt Macy 	case DMU_OT_SPACE_MAP:
202*eda14cbcSMatt Macy 		return ("spacemap");
203*eda14cbcSMatt Macy 	case DMU_OT_ERROR_LOG:
204*eda14cbcSMatt Macy 		return ("errlog");
205*eda14cbcSMatt Macy 	default:
206*eda14cbcSMatt Macy 		return ("-");
207*eda14cbcSMatt Macy 	}
208*eda14cbcSMatt Macy }
209*eda14cbcSMatt Macy 
210*eda14cbcSMatt Macy 
211*eda14cbcSMatt Macy /*
212*eda14cbcSMatt Macy  * Print usage message.
213*eda14cbcSMatt Macy  */
214*eda14cbcSMatt Macy void
215*eda14cbcSMatt Macy usage(void)
216*eda14cbcSMatt Macy {
217*eda14cbcSMatt Macy 	(void) printf(
218*eda14cbcSMatt Macy 	    "usage:\n"
219*eda14cbcSMatt Macy 	    "\n"
220*eda14cbcSMatt Macy 	    "\tzinject\n"
221*eda14cbcSMatt Macy 	    "\n"
222*eda14cbcSMatt Macy 	    "\t\tList all active injection records.\n"
223*eda14cbcSMatt Macy 	    "\n"
224*eda14cbcSMatt Macy 	    "\tzinject -c <id|all>\n"
225*eda14cbcSMatt Macy 	    "\n"
226*eda14cbcSMatt Macy 	    "\t\tClear the particular record (if given a numeric ID), or\n"
227*eda14cbcSMatt Macy 	    "\t\tall records if 'all' is specified.\n"
228*eda14cbcSMatt Macy 	    "\n"
229*eda14cbcSMatt Macy 	    "\tzinject -p <function name> pool\n"
230*eda14cbcSMatt Macy 	    "\t\tInject a panic fault at the specified function. Only \n"
231*eda14cbcSMatt Macy 	    "\t\tfunctions which call spa_vdev_config_exit(), or \n"
232*eda14cbcSMatt Macy 	    "\t\tspa_vdev_exit() will trigger a panic.\n"
233*eda14cbcSMatt Macy 	    "\n"
234*eda14cbcSMatt Macy 	    "\tzinject -d device [-e errno] [-L <nvlist|uber|pad1|pad2>] [-F]\n"
235*eda14cbcSMatt Macy 	    "\t\t[-T <read|write|free|claim|all>] [-f frequency] pool\n\n"
236*eda14cbcSMatt Macy 	    "\t\tInject a fault into a particular device or the device's\n"
237*eda14cbcSMatt Macy 	    "\t\tlabel.  Label injection can either be 'nvlist', 'uber',\n "
238*eda14cbcSMatt Macy 	    "\t\t'pad1', or 'pad2'.\n"
239*eda14cbcSMatt Macy 	    "\t\t'errno' can be 'nxio' (the default), 'io', 'dtl', or\n"
240*eda14cbcSMatt Macy 	    "\t\t'corrupt' (bit flip).\n"
241*eda14cbcSMatt Macy 	    "\t\t'frequency' is a value between 0.0001 and 100.0 that limits\n"
242*eda14cbcSMatt Macy 	    "\t\tdevice error injection to a percentage of the IOs.\n"
243*eda14cbcSMatt Macy 	    "\n"
244*eda14cbcSMatt Macy 	    "\tzinject -d device -A <degrade|fault> -D <delay secs> pool\n"
245*eda14cbcSMatt Macy 	    "\t\tPerform a specific action on a particular device.\n"
246*eda14cbcSMatt Macy 	    "\n"
247*eda14cbcSMatt Macy 	    "\tzinject -d device -D latency:lanes pool\n"
248*eda14cbcSMatt Macy 	    "\n"
249*eda14cbcSMatt Macy 	    "\t\tAdd an artificial delay to IO requests on a particular\n"
250*eda14cbcSMatt Macy 	    "\t\tdevice, such that the requests take a minimum of 'latency'\n"
251*eda14cbcSMatt Macy 	    "\t\tmilliseconds to complete. Each delay has an associated\n"
252*eda14cbcSMatt Macy 	    "\t\tnumber of 'lanes' which defines the number of concurrent\n"
253*eda14cbcSMatt Macy 	    "\t\tIO requests that can be processed.\n"
254*eda14cbcSMatt Macy 	    "\n"
255*eda14cbcSMatt Macy 	    "\t\tFor example, with a single lane delay of 10 ms (-D 10:1),\n"
256*eda14cbcSMatt Macy 	    "\t\tthe device will only be able to service a single IO request\n"
257*eda14cbcSMatt Macy 	    "\t\tat a time with each request taking 10 ms to complete. So,\n"
258*eda14cbcSMatt Macy 	    "\t\tif only a single request is submitted every 10 ms, the\n"
259*eda14cbcSMatt Macy 	    "\t\taverage latency will be 10 ms; but if more than one request\n"
260*eda14cbcSMatt Macy 	    "\t\tis submitted every 10 ms, the average latency will be more\n"
261*eda14cbcSMatt Macy 	    "\t\tthan 10 ms.\n"
262*eda14cbcSMatt Macy 	    "\n"
263*eda14cbcSMatt Macy 	    "\t\tSimilarly, if a delay of 10 ms is specified to have two\n"
264*eda14cbcSMatt Macy 	    "\t\tlanes (-D 10:2), then the device will be able to service\n"
265*eda14cbcSMatt Macy 	    "\t\ttwo requests at a time, each with a minimum latency of\n"
266*eda14cbcSMatt Macy 	    "\t\t10 ms. So, if two requests are submitted every 10 ms, then\n"
267*eda14cbcSMatt Macy 	    "\t\tthe average latency will be 10 ms; but if more than two\n"
268*eda14cbcSMatt Macy 	    "\t\trequests are submitted every 10 ms, the average latency\n"
269*eda14cbcSMatt Macy 	    "\t\twill be more than 10 ms.\n"
270*eda14cbcSMatt Macy 	    "\n"
271*eda14cbcSMatt Macy 	    "\t\tAlso note, these delays are additive. So two invocations\n"
272*eda14cbcSMatt Macy 	    "\t\tof '-D 10:1', is roughly equivalent to a single invocation\n"
273*eda14cbcSMatt Macy 	    "\t\tof '-D 10:2'. This also means, one can specify multiple\n"
274*eda14cbcSMatt Macy 	    "\t\tlanes with differing target latencies. For example, an\n"
275*eda14cbcSMatt Macy 	    "\t\tinvocation of '-D 10:1' followed by '-D 25:2' will\n"
276*eda14cbcSMatt Macy 	    "\t\tcreate 3 lanes on the device; one lane with a latency\n"
277*eda14cbcSMatt Macy 	    "\t\tof 10 ms and two lanes with a 25 ms latency.\n"
278*eda14cbcSMatt Macy 	    "\n"
279*eda14cbcSMatt Macy 	    "\tzinject -I [-s <seconds> | -g <txgs>] pool\n"
280*eda14cbcSMatt Macy 	    "\t\tCause the pool to stop writing blocks yet not\n"
281*eda14cbcSMatt Macy 	    "\t\treport errors for a duration.  Simulates buggy hardware\n"
282*eda14cbcSMatt Macy 	    "\t\tthat fails to honor cache flush requests.\n"
283*eda14cbcSMatt Macy 	    "\t\tDefault duration is 30 seconds.  The machine is panicked\n"
284*eda14cbcSMatt Macy 	    "\t\tat the end of the duration.\n"
285*eda14cbcSMatt Macy 	    "\n"
286*eda14cbcSMatt Macy 	    "\tzinject -b objset:object:level:blkid pool\n"
287*eda14cbcSMatt Macy 	    "\n"
288*eda14cbcSMatt Macy 	    "\t\tInject an error into pool 'pool' with the numeric bookmark\n"
289*eda14cbcSMatt Macy 	    "\t\tspecified by the remaining tuple.  Each number is in\n"
290*eda14cbcSMatt Macy 	    "\t\thexadecimal, and only one block can be specified.\n"
291*eda14cbcSMatt Macy 	    "\n"
292*eda14cbcSMatt Macy 	    "\tzinject [-q] <-t type> [-C dvas] [-e errno] [-l level]\n"
293*eda14cbcSMatt Macy 	    "\t\t[-r range] [-a] [-m] [-u] [-f freq] <object>\n"
294*eda14cbcSMatt Macy 	    "\n"
295*eda14cbcSMatt Macy 	    "\t\tInject an error into the object specified by the '-t' option\n"
296*eda14cbcSMatt Macy 	    "\t\tand the object descriptor.  The 'object' parameter is\n"
297*eda14cbcSMatt Macy 	    "\t\tinterpreted depending on the '-t' option.\n"
298*eda14cbcSMatt Macy 	    "\n"
299*eda14cbcSMatt Macy 	    "\t\t-q\tQuiet mode.  Only print out the handler number added.\n"
300*eda14cbcSMatt Macy 	    "\t\t-e\tInject a specific error.  Must be one of 'io',\n"
301*eda14cbcSMatt Macy 	    "\t\t\t'checksum', 'decompress', or 'decrypt'.  Default is 'io'.\n"
302*eda14cbcSMatt Macy 	    "\t\t-C\tInject the given error only into specific DVAs. The\n"
303*eda14cbcSMatt Macy 	    "\t\t\tDVAs should be specified as a list of 0-indexed DVAs\n"
304*eda14cbcSMatt Macy 	    "\t\t\tseparated by commas (ex. '0,2').\n"
305*eda14cbcSMatt Macy 	    "\t\t-l\tInject error at a particular block level. Default is "
306*eda14cbcSMatt Macy 	    "0.\n"
307*eda14cbcSMatt Macy 	    "\t\t-m\tAutomatically remount underlying filesystem.\n"
308*eda14cbcSMatt Macy 	    "\t\t-r\tInject error over a particular logical range of an\n"
309*eda14cbcSMatt Macy 	    "\t\t\tobject.  Will be translated to the appropriate blkid\n"
310*eda14cbcSMatt Macy 	    "\t\t\trange according to the object's properties.\n"
311*eda14cbcSMatt Macy 	    "\t\t-a\tFlush the ARC cache.  Can be specified without any\n"
312*eda14cbcSMatt Macy 	    "\t\t\tassociated object.\n"
313*eda14cbcSMatt Macy 	    "\t\t-u\tUnload the associated pool.  Can be specified with only\n"
314*eda14cbcSMatt Macy 	    "\t\t\ta pool object.\n"
315*eda14cbcSMatt Macy 	    "\t\t-f\tOnly inject errors a fraction of the time.  Expressed as\n"
316*eda14cbcSMatt Macy 	    "\t\t\ta percentage between 0.0001 and 100.\n"
317*eda14cbcSMatt Macy 	    "\n"
318*eda14cbcSMatt Macy 	    "\t-t data\t\tInject an error into the plain file contents of a\n"
319*eda14cbcSMatt Macy 	    "\t\t\tfile.  The object must be specified as a complete path\n"
320*eda14cbcSMatt Macy 	    "\t\t\tto a file on a ZFS filesystem.\n"
321*eda14cbcSMatt Macy 	    "\n"
322*eda14cbcSMatt Macy 	    "\t-t dnode\tInject an error into the metadnode in the block\n"
323*eda14cbcSMatt Macy 	    "\t\t\tcorresponding to the dnode for a file or directory.  The\n"
324*eda14cbcSMatt Macy 	    "\t\t\t'-r' option is incompatible with this mode.  The object\n"
325*eda14cbcSMatt Macy 	    "\t\t\tis specified as a complete path to a file or directory\n"
326*eda14cbcSMatt Macy 	    "\t\t\ton a ZFS filesystem.\n"
327*eda14cbcSMatt Macy 	    "\n"
328*eda14cbcSMatt Macy 	    "\t-t <mos>\tInject errors into the MOS for objects of the given\n"
329*eda14cbcSMatt Macy 	    "\t\t\ttype.  Valid types are: mos, mosdir, config, bpobj,\n"
330*eda14cbcSMatt Macy 	    "\t\t\tspacemap, metaslab, errlog.  The only valid <object> is\n"
331*eda14cbcSMatt Macy 	    "\t\t\tthe poolname.\n");
332*eda14cbcSMatt Macy }
333*eda14cbcSMatt Macy 
334*eda14cbcSMatt Macy static int
335*eda14cbcSMatt Macy iter_handlers(int (*func)(int, const char *, zinject_record_t *, void *),
336*eda14cbcSMatt Macy     void *data)
337*eda14cbcSMatt Macy {
338*eda14cbcSMatt Macy 	zfs_cmd_t zc = {"\0"};
339*eda14cbcSMatt Macy 	int ret;
340*eda14cbcSMatt Macy 
341*eda14cbcSMatt Macy 	while (zfs_ioctl(g_zfs, ZFS_IOC_INJECT_LIST_NEXT, &zc) == 0)
342*eda14cbcSMatt Macy 		if ((ret = func((int)zc.zc_guid, zc.zc_name,
343*eda14cbcSMatt Macy 		    &zc.zc_inject_record, data)) != 0)
344*eda14cbcSMatt Macy 			return (ret);
345*eda14cbcSMatt Macy 
346*eda14cbcSMatt Macy 	if (errno != ENOENT) {
347*eda14cbcSMatt Macy 		(void) fprintf(stderr, "Unable to list handlers: %s\n",
348*eda14cbcSMatt Macy 		    strerror(errno));
349*eda14cbcSMatt Macy 		return (-1);
350*eda14cbcSMatt Macy 	}
351*eda14cbcSMatt Macy 
352*eda14cbcSMatt Macy 	return (0);
353*eda14cbcSMatt Macy }
354*eda14cbcSMatt Macy 
355*eda14cbcSMatt Macy static int
356*eda14cbcSMatt Macy print_data_handler(int id, const char *pool, zinject_record_t *record,
357*eda14cbcSMatt Macy     void *data)
358*eda14cbcSMatt Macy {
359*eda14cbcSMatt Macy 	int *count = data;
360*eda14cbcSMatt Macy 
361*eda14cbcSMatt Macy 	if (record->zi_guid != 0 || record->zi_func[0] != '\0')
362*eda14cbcSMatt Macy 		return (0);
363*eda14cbcSMatt Macy 
364*eda14cbcSMatt Macy 	if (*count == 0) {
365*eda14cbcSMatt Macy 		(void) printf("%3s  %-15s  %-6s  %-6s  %-8s  %3s  %-4s  "
366*eda14cbcSMatt Macy 		    "%-15s\n", "ID", "POOL", "OBJSET", "OBJECT", "TYPE",
367*eda14cbcSMatt Macy 		    "LVL", "DVAs", "RANGE");
368*eda14cbcSMatt Macy 		(void) printf("---  ---------------  ------  "
369*eda14cbcSMatt Macy 		    "------  --------  ---  ----  ---------------\n");
370*eda14cbcSMatt Macy 	}
371*eda14cbcSMatt Macy 
372*eda14cbcSMatt Macy 	*count += 1;
373*eda14cbcSMatt Macy 
374*eda14cbcSMatt Macy 	(void) printf("%3d  %-15s  %-6llu  %-6llu  %-8s  %-3d  0x%02x  ",
375*eda14cbcSMatt Macy 	    id, pool, (u_longlong_t)record->zi_objset,
376*eda14cbcSMatt Macy 	    (u_longlong_t)record->zi_object, type_to_name(record->zi_type),
377*eda14cbcSMatt Macy 	    record->zi_level, record->zi_dvas);
378*eda14cbcSMatt Macy 
379*eda14cbcSMatt Macy 
380*eda14cbcSMatt Macy 	if (record->zi_start == 0 &&
381*eda14cbcSMatt Macy 	    record->zi_end == -1ULL)
382*eda14cbcSMatt Macy 		(void) printf("all\n");
383*eda14cbcSMatt Macy 	else
384*eda14cbcSMatt Macy 		(void) printf("[%llu, %llu]\n", (u_longlong_t)record->zi_start,
385*eda14cbcSMatt Macy 		    (u_longlong_t)record->zi_end);
386*eda14cbcSMatt Macy 
387*eda14cbcSMatt Macy 	return (0);
388*eda14cbcSMatt Macy }
389*eda14cbcSMatt Macy 
390*eda14cbcSMatt Macy static int
391*eda14cbcSMatt Macy print_device_handler(int id, const char *pool, zinject_record_t *record,
392*eda14cbcSMatt Macy     void *data)
393*eda14cbcSMatt Macy {
394*eda14cbcSMatt Macy 	int *count = data;
395*eda14cbcSMatt Macy 
396*eda14cbcSMatt Macy 	if (record->zi_guid == 0 || record->zi_func[0] != '\0')
397*eda14cbcSMatt Macy 		return (0);
398*eda14cbcSMatt Macy 
399*eda14cbcSMatt Macy 	if (record->zi_cmd == ZINJECT_DELAY_IO)
400*eda14cbcSMatt Macy 		return (0);
401*eda14cbcSMatt Macy 
402*eda14cbcSMatt Macy 	if (*count == 0) {
403*eda14cbcSMatt Macy 		(void) printf("%3s  %-15s  %s\n", "ID", "POOL", "GUID");
404*eda14cbcSMatt Macy 		(void) printf("---  ---------------  ----------------\n");
405*eda14cbcSMatt Macy 	}
406*eda14cbcSMatt Macy 
407*eda14cbcSMatt Macy 	*count += 1;
408*eda14cbcSMatt Macy 
409*eda14cbcSMatt Macy 	(void) printf("%3d  %-15s  %llx\n", id, pool,
410*eda14cbcSMatt Macy 	    (u_longlong_t)record->zi_guid);
411*eda14cbcSMatt Macy 
412*eda14cbcSMatt Macy 	return (0);
413*eda14cbcSMatt Macy }
414*eda14cbcSMatt Macy 
415*eda14cbcSMatt Macy static int
416*eda14cbcSMatt Macy print_delay_handler(int id, const char *pool, zinject_record_t *record,
417*eda14cbcSMatt Macy     void *data)
418*eda14cbcSMatt Macy {
419*eda14cbcSMatt Macy 	int *count = data;
420*eda14cbcSMatt Macy 
421*eda14cbcSMatt Macy 	if (record->zi_guid == 0 || record->zi_func[0] != '\0')
422*eda14cbcSMatt Macy 		return (0);
423*eda14cbcSMatt Macy 
424*eda14cbcSMatt Macy 	if (record->zi_cmd != ZINJECT_DELAY_IO)
425*eda14cbcSMatt Macy 		return (0);
426*eda14cbcSMatt Macy 
427*eda14cbcSMatt Macy 	if (*count == 0) {
428*eda14cbcSMatt Macy 		(void) printf("%3s  %-15s  %-15s  %-15s  %s\n",
429*eda14cbcSMatt Macy 		    "ID", "POOL", "DELAY (ms)", "LANES", "GUID");
430*eda14cbcSMatt Macy 		(void) printf("---  ---------------  ---------------  "
431*eda14cbcSMatt Macy 		    "---------------  ----------------\n");
432*eda14cbcSMatt Macy 	}
433*eda14cbcSMatt Macy 
434*eda14cbcSMatt Macy 	*count += 1;
435*eda14cbcSMatt Macy 
436*eda14cbcSMatt Macy 	(void) printf("%3d  %-15s  %-15llu  %-15llu  %llx\n", id, pool,
437*eda14cbcSMatt Macy 	    (u_longlong_t)NSEC2MSEC(record->zi_timer),
438*eda14cbcSMatt Macy 	    (u_longlong_t)record->zi_nlanes,
439*eda14cbcSMatt Macy 	    (u_longlong_t)record->zi_guid);
440*eda14cbcSMatt Macy 
441*eda14cbcSMatt Macy 	return (0);
442*eda14cbcSMatt Macy }
443*eda14cbcSMatt Macy 
444*eda14cbcSMatt Macy static int
445*eda14cbcSMatt Macy print_panic_handler(int id, const char *pool, zinject_record_t *record,
446*eda14cbcSMatt Macy     void *data)
447*eda14cbcSMatt Macy {
448*eda14cbcSMatt Macy 	int *count = data;
449*eda14cbcSMatt Macy 
450*eda14cbcSMatt Macy 	if (record->zi_func[0] == '\0')
451*eda14cbcSMatt Macy 		return (0);
452*eda14cbcSMatt Macy 
453*eda14cbcSMatt Macy 	if (*count == 0) {
454*eda14cbcSMatt Macy 		(void) printf("%3s  %-15s  %s\n", "ID", "POOL", "FUNCTION");
455*eda14cbcSMatt Macy 		(void) printf("---  ---------------  ----------------\n");
456*eda14cbcSMatt Macy 	}
457*eda14cbcSMatt Macy 
458*eda14cbcSMatt Macy 	*count += 1;
459*eda14cbcSMatt Macy 
460*eda14cbcSMatt Macy 	(void) printf("%3d  %-15s  %s\n", id, pool, record->zi_func);
461*eda14cbcSMatt Macy 
462*eda14cbcSMatt Macy 	return (0);
463*eda14cbcSMatt Macy }
464*eda14cbcSMatt Macy 
465*eda14cbcSMatt Macy /*
466*eda14cbcSMatt Macy  * Print all registered error handlers.  Returns the number of handlers
467*eda14cbcSMatt Macy  * registered.
468*eda14cbcSMatt Macy  */
469*eda14cbcSMatt Macy static int
470*eda14cbcSMatt Macy print_all_handlers(void)
471*eda14cbcSMatt Macy {
472*eda14cbcSMatt Macy 	int count = 0, total = 0;
473*eda14cbcSMatt Macy 
474*eda14cbcSMatt Macy 	(void) iter_handlers(print_device_handler, &count);
475*eda14cbcSMatt Macy 	if (count > 0) {
476*eda14cbcSMatt Macy 		total += count;
477*eda14cbcSMatt Macy 		(void) printf("\n");
478*eda14cbcSMatt Macy 		count = 0;
479*eda14cbcSMatt Macy 	}
480*eda14cbcSMatt Macy 
481*eda14cbcSMatt Macy 	(void) iter_handlers(print_delay_handler, &count);
482*eda14cbcSMatt Macy 	if (count > 0) {
483*eda14cbcSMatt Macy 		total += count;
484*eda14cbcSMatt Macy 		(void) printf("\n");
485*eda14cbcSMatt Macy 		count = 0;
486*eda14cbcSMatt Macy 	}
487*eda14cbcSMatt Macy 
488*eda14cbcSMatt Macy 	(void) iter_handlers(print_data_handler, &count);
489*eda14cbcSMatt Macy 	if (count > 0) {
490*eda14cbcSMatt Macy 		total += count;
491*eda14cbcSMatt Macy 		(void) printf("\n");
492*eda14cbcSMatt Macy 		count = 0;
493*eda14cbcSMatt Macy 	}
494*eda14cbcSMatt Macy 
495*eda14cbcSMatt Macy 	(void) iter_handlers(print_panic_handler, &count);
496*eda14cbcSMatt Macy 
497*eda14cbcSMatt Macy 	return (count + total);
498*eda14cbcSMatt Macy }
499*eda14cbcSMatt Macy 
500*eda14cbcSMatt Macy /* ARGSUSED */
501*eda14cbcSMatt Macy static int
502*eda14cbcSMatt Macy cancel_one_handler(int id, const char *pool, zinject_record_t *record,
503*eda14cbcSMatt Macy     void *data)
504*eda14cbcSMatt Macy {
505*eda14cbcSMatt Macy 	zfs_cmd_t zc = {"\0"};
506*eda14cbcSMatt Macy 
507*eda14cbcSMatt Macy 	zc.zc_guid = (uint64_t)id;
508*eda14cbcSMatt Macy 
509*eda14cbcSMatt Macy 	if (zfs_ioctl(g_zfs, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
510*eda14cbcSMatt Macy 		(void) fprintf(stderr, "failed to remove handler %d: %s\n",
511*eda14cbcSMatt Macy 		    id, strerror(errno));
512*eda14cbcSMatt Macy 		return (1);
513*eda14cbcSMatt Macy 	}
514*eda14cbcSMatt Macy 
515*eda14cbcSMatt Macy 	return (0);
516*eda14cbcSMatt Macy }
517*eda14cbcSMatt Macy 
518*eda14cbcSMatt Macy /*
519*eda14cbcSMatt Macy  * Remove all fault injection handlers.
520*eda14cbcSMatt Macy  */
521*eda14cbcSMatt Macy static int
522*eda14cbcSMatt Macy cancel_all_handlers(void)
523*eda14cbcSMatt Macy {
524*eda14cbcSMatt Macy 	int ret = iter_handlers(cancel_one_handler, NULL);
525*eda14cbcSMatt Macy 
526*eda14cbcSMatt Macy 	if (ret == 0)
527*eda14cbcSMatt Macy 		(void) printf("removed all registered handlers\n");
528*eda14cbcSMatt Macy 
529*eda14cbcSMatt Macy 	return (ret);
530*eda14cbcSMatt Macy }
531*eda14cbcSMatt Macy 
532*eda14cbcSMatt Macy /*
533*eda14cbcSMatt Macy  * Remove a specific fault injection handler.
534*eda14cbcSMatt Macy  */
535*eda14cbcSMatt Macy static int
536*eda14cbcSMatt Macy cancel_handler(int id)
537*eda14cbcSMatt Macy {
538*eda14cbcSMatt Macy 	zfs_cmd_t zc = {"\0"};
539*eda14cbcSMatt Macy 
540*eda14cbcSMatt Macy 	zc.zc_guid = (uint64_t)id;
541*eda14cbcSMatt Macy 
542*eda14cbcSMatt Macy 	if (zfs_ioctl(g_zfs, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
543*eda14cbcSMatt Macy 		(void) fprintf(stderr, "failed to remove handler %d: %s\n",
544*eda14cbcSMatt Macy 		    id, strerror(errno));
545*eda14cbcSMatt Macy 		return (1);
546*eda14cbcSMatt Macy 	}
547*eda14cbcSMatt Macy 
548*eda14cbcSMatt Macy 	(void) printf("removed handler %d\n", id);
549*eda14cbcSMatt Macy 
550*eda14cbcSMatt Macy 	return (0);
551*eda14cbcSMatt Macy }
552*eda14cbcSMatt Macy 
553*eda14cbcSMatt Macy /*
554*eda14cbcSMatt Macy  * Register a new fault injection handler.
555*eda14cbcSMatt Macy  */
556*eda14cbcSMatt Macy static int
557*eda14cbcSMatt Macy register_handler(const char *pool, int flags, zinject_record_t *record,
558*eda14cbcSMatt Macy     int quiet)
559*eda14cbcSMatt Macy {
560*eda14cbcSMatt Macy 	zfs_cmd_t zc = {"\0"};
561*eda14cbcSMatt Macy 
562*eda14cbcSMatt Macy 	(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
563*eda14cbcSMatt Macy 	zc.zc_inject_record = *record;
564*eda14cbcSMatt Macy 	zc.zc_guid = flags;
565*eda14cbcSMatt Macy 
566*eda14cbcSMatt Macy 	if (zfs_ioctl(g_zfs, ZFS_IOC_INJECT_FAULT, &zc) != 0) {
567*eda14cbcSMatt Macy 		(void) fprintf(stderr, "failed to add handler: %s\n",
568*eda14cbcSMatt Macy 		    errno == EDOM ? "block level exceeds max level of object" :
569*eda14cbcSMatt Macy 		    strerror(errno));
570*eda14cbcSMatt Macy 		return (1);
571*eda14cbcSMatt Macy 	}
572*eda14cbcSMatt Macy 
573*eda14cbcSMatt Macy 	if (flags & ZINJECT_NULL)
574*eda14cbcSMatt Macy 		return (0);
575*eda14cbcSMatt Macy 
576*eda14cbcSMatt Macy 	if (quiet) {
577*eda14cbcSMatt Macy 		(void) printf("%llu\n", (u_longlong_t)zc.zc_guid);
578*eda14cbcSMatt Macy 	} else {
579*eda14cbcSMatt Macy 		(void) printf("Added handler %llu with the following "
580*eda14cbcSMatt Macy 		    "properties:\n", (u_longlong_t)zc.zc_guid);
581*eda14cbcSMatt Macy 		(void) printf("  pool: %s\n", pool);
582*eda14cbcSMatt Macy 		if (record->zi_guid) {
583*eda14cbcSMatt Macy 			(void) printf("  vdev: %llx\n",
584*eda14cbcSMatt Macy 			    (u_longlong_t)record->zi_guid);
585*eda14cbcSMatt Macy 		} else if (record->zi_func[0] != '\0') {
586*eda14cbcSMatt Macy 			(void) printf("  panic function: %s\n",
587*eda14cbcSMatt Macy 			    record->zi_func);
588*eda14cbcSMatt Macy 		} else if (record->zi_duration > 0) {
589*eda14cbcSMatt Macy 			(void) printf(" time: %lld seconds\n",
590*eda14cbcSMatt Macy 			    (u_longlong_t)record->zi_duration);
591*eda14cbcSMatt Macy 		} else if (record->zi_duration < 0) {
592*eda14cbcSMatt Macy 			(void) printf(" txgs: %lld \n",
593*eda14cbcSMatt Macy 			    (u_longlong_t)-record->zi_duration);
594*eda14cbcSMatt Macy 		} else {
595*eda14cbcSMatt Macy 			(void) printf("objset: %llu\n",
596*eda14cbcSMatt Macy 			    (u_longlong_t)record->zi_objset);
597*eda14cbcSMatt Macy 			(void) printf("object: %llu\n",
598*eda14cbcSMatt Macy 			    (u_longlong_t)record->zi_object);
599*eda14cbcSMatt Macy 			(void) printf("  type: %llu\n",
600*eda14cbcSMatt Macy 			    (u_longlong_t)record->zi_type);
601*eda14cbcSMatt Macy 			(void) printf(" level: %d\n", record->zi_level);
602*eda14cbcSMatt Macy 			if (record->zi_start == 0 &&
603*eda14cbcSMatt Macy 			    record->zi_end == -1ULL)
604*eda14cbcSMatt Macy 				(void) printf(" range: all\n");
605*eda14cbcSMatt Macy 			else
606*eda14cbcSMatt Macy 				(void) printf(" range: [%llu, %llu)\n",
607*eda14cbcSMatt Macy 				    (u_longlong_t)record->zi_start,
608*eda14cbcSMatt Macy 				    (u_longlong_t)record->zi_end);
609*eda14cbcSMatt Macy 			(void) printf("  dvas: 0x%x\n", record->zi_dvas);
610*eda14cbcSMatt Macy 		}
611*eda14cbcSMatt Macy 	}
612*eda14cbcSMatt Macy 
613*eda14cbcSMatt Macy 	return (0);
614*eda14cbcSMatt Macy }
615*eda14cbcSMatt Macy 
616*eda14cbcSMatt Macy static int
617*eda14cbcSMatt Macy perform_action(const char *pool, zinject_record_t *record, int cmd)
618*eda14cbcSMatt Macy {
619*eda14cbcSMatt Macy 	zfs_cmd_t zc = {"\0"};
620*eda14cbcSMatt Macy 
621*eda14cbcSMatt Macy 	ASSERT(cmd == VDEV_STATE_DEGRADED || cmd == VDEV_STATE_FAULTED);
622*eda14cbcSMatt Macy 	(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
623*eda14cbcSMatt Macy 	zc.zc_guid = record->zi_guid;
624*eda14cbcSMatt Macy 	zc.zc_cookie = cmd;
625*eda14cbcSMatt Macy 
626*eda14cbcSMatt Macy 	if (zfs_ioctl(g_zfs, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
627*eda14cbcSMatt Macy 		return (0);
628*eda14cbcSMatt Macy 
629*eda14cbcSMatt Macy 	return (1);
630*eda14cbcSMatt Macy }
631*eda14cbcSMatt Macy 
632*eda14cbcSMatt Macy static int
633*eda14cbcSMatt Macy parse_delay(char *str, uint64_t *delay, uint64_t *nlanes)
634*eda14cbcSMatt Macy {
635*eda14cbcSMatt Macy 	unsigned long scan_delay;
636*eda14cbcSMatt Macy 	unsigned long scan_nlanes;
637*eda14cbcSMatt Macy 
638*eda14cbcSMatt Macy 	if (sscanf(str, "%lu:%lu", &scan_delay, &scan_nlanes) != 2)
639*eda14cbcSMatt Macy 		return (1);
640*eda14cbcSMatt Macy 
641*eda14cbcSMatt Macy 	/*
642*eda14cbcSMatt Macy 	 * We explicitly disallow a delay of zero here, because we key
643*eda14cbcSMatt Macy 	 * off this value being non-zero in translate_device(), to
644*eda14cbcSMatt Macy 	 * determine if the fault is a ZINJECT_DELAY_IO fault or not.
645*eda14cbcSMatt Macy 	 */
646*eda14cbcSMatt Macy 	if (scan_delay == 0)
647*eda14cbcSMatt Macy 		return (1);
648*eda14cbcSMatt Macy 
649*eda14cbcSMatt Macy 	/*
650*eda14cbcSMatt Macy 	 * The units for the CLI delay parameter is milliseconds, but
651*eda14cbcSMatt Macy 	 * the data passed to the kernel is interpreted as nanoseconds.
652*eda14cbcSMatt Macy 	 * Thus we scale the milliseconds to nanoseconds here, and this
653*eda14cbcSMatt Macy 	 * nanosecond value is used to pass the delay to the kernel.
654*eda14cbcSMatt Macy 	 */
655*eda14cbcSMatt Macy 	*delay = MSEC2NSEC(scan_delay);
656*eda14cbcSMatt Macy 	*nlanes = scan_nlanes;
657*eda14cbcSMatt Macy 
658*eda14cbcSMatt Macy 	return (0);
659*eda14cbcSMatt Macy }
660*eda14cbcSMatt Macy 
661*eda14cbcSMatt Macy static int
662*eda14cbcSMatt Macy parse_frequency(const char *str, uint32_t *percent)
663*eda14cbcSMatt Macy {
664*eda14cbcSMatt Macy 	double val;
665*eda14cbcSMatt Macy 	char *post;
666*eda14cbcSMatt Macy 
667*eda14cbcSMatt Macy 	val = strtod(str, &post);
668*eda14cbcSMatt Macy 	if (post == NULL || *post != '\0')
669*eda14cbcSMatt Macy 		return (EINVAL);
670*eda14cbcSMatt Macy 
671*eda14cbcSMatt Macy 	/* valid range is [0.0001, 100.0] */
672*eda14cbcSMatt Macy 	val /= 100.0f;
673*eda14cbcSMatt Macy 	if (val < 0.000001f || val > 1.0f)
674*eda14cbcSMatt Macy 		return (ERANGE);
675*eda14cbcSMatt Macy 
676*eda14cbcSMatt Macy 	/* convert to an integer for use by kernel */
677*eda14cbcSMatt Macy 	*percent = ((uint32_t)(val * ZI_PERCENTAGE_MAX));
678*eda14cbcSMatt Macy 
679*eda14cbcSMatt Macy 	return (0);
680*eda14cbcSMatt Macy }
681*eda14cbcSMatt Macy 
682*eda14cbcSMatt Macy /*
683*eda14cbcSMatt Macy  * This function converts a string specifier for DVAs into a bit mask.
684*eda14cbcSMatt Macy  * The dva's provided by the user should be 0 indexed and separated by
685*eda14cbcSMatt Macy  * a comma. For example:
686*eda14cbcSMatt Macy  *	"1"	-> 0b0010  (0x2)
687*eda14cbcSMatt Macy  *	"0,1"	-> 0b0011  (0x3)
688*eda14cbcSMatt Macy  *	"0,1,2"	-> 0b0111  (0x7)
689*eda14cbcSMatt Macy  */
690*eda14cbcSMatt Macy static int
691*eda14cbcSMatt Macy parse_dvas(const char *str, uint32_t *dvas_out)
692*eda14cbcSMatt Macy {
693*eda14cbcSMatt Macy 	const char *c = str;
694*eda14cbcSMatt Macy 	uint32_t mask = 0;
695*eda14cbcSMatt Macy 	boolean_t need_delim = B_FALSE;
696*eda14cbcSMatt Macy 
697*eda14cbcSMatt Macy 	/* max string length is 5 ("0,1,2") */
698*eda14cbcSMatt Macy 	if (strlen(str) > 5 || strlen(str) == 0)
699*eda14cbcSMatt Macy 		return (EINVAL);
700*eda14cbcSMatt Macy 
701*eda14cbcSMatt Macy 	while (*c != '\0') {
702*eda14cbcSMatt Macy 		switch (*c) {
703*eda14cbcSMatt Macy 		case '0':
704*eda14cbcSMatt Macy 		case '1':
705*eda14cbcSMatt Macy 		case '2':
706*eda14cbcSMatt Macy 			/* check for pipe between DVAs */
707*eda14cbcSMatt Macy 			if (need_delim)
708*eda14cbcSMatt Macy 				return (EINVAL);
709*eda14cbcSMatt Macy 
710*eda14cbcSMatt Macy 			/* check if this DVA has been set already */
711*eda14cbcSMatt Macy 			if (mask & (1 << ((*c) - '0')))
712*eda14cbcSMatt Macy 				return (EINVAL);
713*eda14cbcSMatt Macy 
714*eda14cbcSMatt Macy 			mask |= (1 << ((*c) - '0'));
715*eda14cbcSMatt Macy 			need_delim = B_TRUE;
716*eda14cbcSMatt Macy 			break;
717*eda14cbcSMatt Macy 		case ',':
718*eda14cbcSMatt Macy 			need_delim = B_FALSE;
719*eda14cbcSMatt Macy 			break;
720*eda14cbcSMatt Macy 		default:
721*eda14cbcSMatt Macy 			/* check for invalid character */
722*eda14cbcSMatt Macy 			return (EINVAL);
723*eda14cbcSMatt Macy 		}
724*eda14cbcSMatt Macy 		c++;
725*eda14cbcSMatt Macy 	}
726*eda14cbcSMatt Macy 
727*eda14cbcSMatt Macy 	/* check for dangling delimiter */
728*eda14cbcSMatt Macy 	if (!need_delim)
729*eda14cbcSMatt Macy 		return (EINVAL);
730*eda14cbcSMatt Macy 
731*eda14cbcSMatt Macy 	*dvas_out = mask;
732*eda14cbcSMatt Macy 	return (0);
733*eda14cbcSMatt Macy }
734*eda14cbcSMatt Macy 
735*eda14cbcSMatt Macy int
736*eda14cbcSMatt Macy main(int argc, char **argv)
737*eda14cbcSMatt Macy {
738*eda14cbcSMatt Macy 	int c;
739*eda14cbcSMatt Macy 	char *range = NULL;
740*eda14cbcSMatt Macy 	char *cancel = NULL;
741*eda14cbcSMatt Macy 	char *end;
742*eda14cbcSMatt Macy 	char *raw = NULL;
743*eda14cbcSMatt Macy 	char *device = NULL;
744*eda14cbcSMatt Macy 	int level = 0;
745*eda14cbcSMatt Macy 	int quiet = 0;
746*eda14cbcSMatt Macy 	int error = 0;
747*eda14cbcSMatt Macy 	int domount = 0;
748*eda14cbcSMatt Macy 	int io_type = ZIO_TYPES;
749*eda14cbcSMatt Macy 	int action = VDEV_STATE_UNKNOWN;
750*eda14cbcSMatt Macy 	err_type_t type = TYPE_INVAL;
751*eda14cbcSMatt Macy 	err_type_t label = TYPE_INVAL;
752*eda14cbcSMatt Macy 	zinject_record_t record = { 0 };
753*eda14cbcSMatt Macy 	char pool[MAXNAMELEN] = "";
754*eda14cbcSMatt Macy 	char dataset[MAXNAMELEN] = "";
755*eda14cbcSMatt Macy 	zfs_handle_t *zhp = NULL;
756*eda14cbcSMatt Macy 	int nowrites = 0;
757*eda14cbcSMatt Macy 	int dur_txg = 0;
758*eda14cbcSMatt Macy 	int dur_secs = 0;
759*eda14cbcSMatt Macy 	int ret;
760*eda14cbcSMatt Macy 	int flags = 0;
761*eda14cbcSMatt Macy 	uint32_t dvas = 0;
762*eda14cbcSMatt Macy 
763*eda14cbcSMatt Macy 	if ((g_zfs = libzfs_init()) == NULL) {
764*eda14cbcSMatt Macy 		(void) fprintf(stderr, "%s\n", libzfs_error_init(errno));
765*eda14cbcSMatt Macy 		return (1);
766*eda14cbcSMatt Macy 	}
767*eda14cbcSMatt Macy 
768*eda14cbcSMatt Macy 	libzfs_print_on_error(g_zfs, B_TRUE);
769*eda14cbcSMatt Macy 
770*eda14cbcSMatt Macy 	if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
771*eda14cbcSMatt Macy 		(void) fprintf(stderr, "failed to open ZFS device\n");
772*eda14cbcSMatt Macy 		libzfs_fini(g_zfs);
773*eda14cbcSMatt Macy 		return (1);
774*eda14cbcSMatt Macy 	}
775*eda14cbcSMatt Macy 
776*eda14cbcSMatt Macy 	if (argc == 1) {
777*eda14cbcSMatt Macy 		/*
778*eda14cbcSMatt Macy 		 * No arguments.  Print the available handlers.  If there are no
779*eda14cbcSMatt Macy 		 * available handlers, direct the user to '-h' for help
780*eda14cbcSMatt Macy 		 * information.
781*eda14cbcSMatt Macy 		 */
782*eda14cbcSMatt Macy 		if (print_all_handlers() == 0) {
783*eda14cbcSMatt Macy 			(void) printf("No handlers registered.\n");
784*eda14cbcSMatt Macy 			(void) printf("Run 'zinject -h' for usage "
785*eda14cbcSMatt Macy 			    "information.\n");
786*eda14cbcSMatt Macy 		}
787*eda14cbcSMatt Macy 		libzfs_fini(g_zfs);
788*eda14cbcSMatt Macy 		return (0);
789*eda14cbcSMatt Macy 	}
790*eda14cbcSMatt Macy 
791*eda14cbcSMatt Macy 	while ((c = getopt(argc, argv,
792*eda14cbcSMatt Macy 	    ":aA:b:C:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:")) != -1) {
793*eda14cbcSMatt Macy 		switch (c) {
794*eda14cbcSMatt Macy 		case 'a':
795*eda14cbcSMatt Macy 			flags |= ZINJECT_FLUSH_ARC;
796*eda14cbcSMatt Macy 			break;
797*eda14cbcSMatt Macy 		case 'A':
798*eda14cbcSMatt Macy 			if (strcasecmp(optarg, "degrade") == 0) {
799*eda14cbcSMatt Macy 				action = VDEV_STATE_DEGRADED;
800*eda14cbcSMatt Macy 			} else if (strcasecmp(optarg, "fault") == 0) {
801*eda14cbcSMatt Macy 				action = VDEV_STATE_FAULTED;
802*eda14cbcSMatt Macy 			} else {
803*eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid action '%s': "
804*eda14cbcSMatt Macy 				    "must be 'degrade' or 'fault'\n", optarg);
805*eda14cbcSMatt Macy 				usage();
806*eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
807*eda14cbcSMatt Macy 				return (1);
808*eda14cbcSMatt Macy 			}
809*eda14cbcSMatt Macy 			break;
810*eda14cbcSMatt Macy 		case 'b':
811*eda14cbcSMatt Macy 			raw = optarg;
812*eda14cbcSMatt Macy 			break;
813*eda14cbcSMatt Macy 		case 'c':
814*eda14cbcSMatt Macy 			cancel = optarg;
815*eda14cbcSMatt Macy 			break;
816*eda14cbcSMatt Macy 		case 'C':
817*eda14cbcSMatt Macy 			ret = parse_dvas(optarg, &dvas);
818*eda14cbcSMatt Macy 			if (ret != 0) {
819*eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid DVA list '%s': "
820*eda14cbcSMatt Macy 				    "DVAs should be 0 indexed and separated by "
821*eda14cbcSMatt Macy 				    "commas.\n", optarg);
822*eda14cbcSMatt Macy 				usage();
823*eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
824*eda14cbcSMatt Macy 				return (1);
825*eda14cbcSMatt Macy 			}
826*eda14cbcSMatt Macy 			break;
827*eda14cbcSMatt Macy 		case 'd':
828*eda14cbcSMatt Macy 			device = optarg;
829*eda14cbcSMatt Macy 			break;
830*eda14cbcSMatt Macy 		case 'D':
831*eda14cbcSMatt Macy 			errno = 0;
832*eda14cbcSMatt Macy 			ret = parse_delay(optarg, &record.zi_timer,
833*eda14cbcSMatt Macy 			    &record.zi_nlanes);
834*eda14cbcSMatt Macy 			if (ret != 0) {
835*eda14cbcSMatt Macy 
836*eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid i/o delay "
837*eda14cbcSMatt Macy 				    "value: '%s'\n", optarg);
838*eda14cbcSMatt Macy 				usage();
839*eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
840*eda14cbcSMatt Macy 				return (1);
841*eda14cbcSMatt Macy 			}
842*eda14cbcSMatt Macy 			break;
843*eda14cbcSMatt Macy 		case 'e':
844*eda14cbcSMatt Macy 			if (strcasecmp(optarg, "io") == 0) {
845*eda14cbcSMatt Macy 				error = EIO;
846*eda14cbcSMatt Macy 			} else if (strcasecmp(optarg, "checksum") == 0) {
847*eda14cbcSMatt Macy 				error = ECKSUM;
848*eda14cbcSMatt Macy 			} else if (strcasecmp(optarg, "decompress") == 0) {
849*eda14cbcSMatt Macy 				error = EINVAL;
850*eda14cbcSMatt Macy 			} else if (strcasecmp(optarg, "decrypt") == 0) {
851*eda14cbcSMatt Macy 				error = EACCES;
852*eda14cbcSMatt Macy 			} else if (strcasecmp(optarg, "nxio") == 0) {
853*eda14cbcSMatt Macy 				error = ENXIO;
854*eda14cbcSMatt Macy 			} else if (strcasecmp(optarg, "dtl") == 0) {
855*eda14cbcSMatt Macy 				error = ECHILD;
856*eda14cbcSMatt Macy 			} else if (strcasecmp(optarg, "corrupt") == 0) {
857*eda14cbcSMatt Macy 				error = EILSEQ;
858*eda14cbcSMatt Macy 			} else {
859*eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid error type "
860*eda14cbcSMatt Macy 				    "'%s': must be 'io', 'checksum' or "
861*eda14cbcSMatt Macy 				    "'nxio'\n", optarg);
862*eda14cbcSMatt Macy 				usage();
863*eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
864*eda14cbcSMatt Macy 				return (1);
865*eda14cbcSMatt Macy 			}
866*eda14cbcSMatt Macy 			break;
867*eda14cbcSMatt Macy 		case 'f':
868*eda14cbcSMatt Macy 			ret = parse_frequency(optarg, &record.zi_freq);
869*eda14cbcSMatt Macy 			if (ret != 0) {
870*eda14cbcSMatt Macy 				(void) fprintf(stderr, "%sfrequency value must "
871*eda14cbcSMatt Macy 				    "be in the range [0.0001, 100.0]\n",
872*eda14cbcSMatt Macy 				    ret == EINVAL ? "invalid value: " :
873*eda14cbcSMatt Macy 				    ret == ERANGE ? "out of range: " : "");
874*eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
875*eda14cbcSMatt Macy 				return (1);
876*eda14cbcSMatt Macy 			}
877*eda14cbcSMatt Macy 			break;
878*eda14cbcSMatt Macy 		case 'F':
879*eda14cbcSMatt Macy 			record.zi_failfast = B_TRUE;
880*eda14cbcSMatt Macy 			break;
881*eda14cbcSMatt Macy 		case 'g':
882*eda14cbcSMatt Macy 			dur_txg = 1;
883*eda14cbcSMatt Macy 			record.zi_duration = (int)strtol(optarg, &end, 10);
884*eda14cbcSMatt Macy 			if (record.zi_duration <= 0 || *end != '\0') {
885*eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid duration '%s': "
886*eda14cbcSMatt Macy 				    "must be a positive integer\n", optarg);
887*eda14cbcSMatt Macy 				usage();
888*eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
889*eda14cbcSMatt Macy 				return (1);
890*eda14cbcSMatt Macy 			}
891*eda14cbcSMatt Macy 			/* store duration of txgs as its negative */
892*eda14cbcSMatt Macy 			record.zi_duration *= -1;
893*eda14cbcSMatt Macy 			break;
894*eda14cbcSMatt Macy 		case 'h':
895*eda14cbcSMatt Macy 			usage();
896*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
897*eda14cbcSMatt Macy 			return (0);
898*eda14cbcSMatt Macy 		case 'I':
899*eda14cbcSMatt Macy 			/* default duration, if one hasn't yet been defined */
900*eda14cbcSMatt Macy 			nowrites = 1;
901*eda14cbcSMatt Macy 			if (dur_secs == 0 && dur_txg == 0)
902*eda14cbcSMatt Macy 				record.zi_duration = 30;
903*eda14cbcSMatt Macy 			break;
904*eda14cbcSMatt Macy 		case 'l':
905*eda14cbcSMatt Macy 			level = (int)strtol(optarg, &end, 10);
906*eda14cbcSMatt Macy 			if (*end != '\0') {
907*eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid level '%s': "
908*eda14cbcSMatt Macy 				    "must be an integer\n", optarg);
909*eda14cbcSMatt Macy 				usage();
910*eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
911*eda14cbcSMatt Macy 				return (1);
912*eda14cbcSMatt Macy 			}
913*eda14cbcSMatt Macy 			break;
914*eda14cbcSMatt Macy 		case 'm':
915*eda14cbcSMatt Macy 			domount = 1;
916*eda14cbcSMatt Macy 			break;
917*eda14cbcSMatt Macy 		case 'p':
918*eda14cbcSMatt Macy 			(void) strlcpy(record.zi_func, optarg,
919*eda14cbcSMatt Macy 			    sizeof (record.zi_func));
920*eda14cbcSMatt Macy 			record.zi_cmd = ZINJECT_PANIC;
921*eda14cbcSMatt Macy 			break;
922*eda14cbcSMatt Macy 		case 'q':
923*eda14cbcSMatt Macy 			quiet = 1;
924*eda14cbcSMatt Macy 			break;
925*eda14cbcSMatt Macy 		case 'r':
926*eda14cbcSMatt Macy 			range = optarg;
927*eda14cbcSMatt Macy 			flags |= ZINJECT_CALC_RANGE;
928*eda14cbcSMatt Macy 			break;
929*eda14cbcSMatt Macy 		case 's':
930*eda14cbcSMatt Macy 			dur_secs = 1;
931*eda14cbcSMatt Macy 			record.zi_duration = (int)strtol(optarg, &end, 10);
932*eda14cbcSMatt Macy 			if (record.zi_duration <= 0 || *end != '\0') {
933*eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid duration '%s': "
934*eda14cbcSMatt Macy 				    "must be a positive integer\n", optarg);
935*eda14cbcSMatt Macy 				usage();
936*eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
937*eda14cbcSMatt Macy 				return (1);
938*eda14cbcSMatt Macy 			}
939*eda14cbcSMatt Macy 			break;
940*eda14cbcSMatt Macy 		case 'T':
941*eda14cbcSMatt Macy 			if (strcasecmp(optarg, "read") == 0) {
942*eda14cbcSMatt Macy 				io_type = ZIO_TYPE_READ;
943*eda14cbcSMatt Macy 			} else if (strcasecmp(optarg, "write") == 0) {
944*eda14cbcSMatt Macy 				io_type = ZIO_TYPE_WRITE;
945*eda14cbcSMatt Macy 			} else if (strcasecmp(optarg, "free") == 0) {
946*eda14cbcSMatt Macy 				io_type = ZIO_TYPE_FREE;
947*eda14cbcSMatt Macy 			} else if (strcasecmp(optarg, "claim") == 0) {
948*eda14cbcSMatt Macy 				io_type = ZIO_TYPE_CLAIM;
949*eda14cbcSMatt Macy 			} else if (strcasecmp(optarg, "all") == 0) {
950*eda14cbcSMatt Macy 				io_type = ZIO_TYPES;
951*eda14cbcSMatt Macy 			} else {
952*eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid I/O type "
953*eda14cbcSMatt Macy 				    "'%s': must be 'read', 'write', 'free', "
954*eda14cbcSMatt Macy 				    "'claim' or 'all'\n", optarg);
955*eda14cbcSMatt Macy 				usage();
956*eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
957*eda14cbcSMatt Macy 				return (1);
958*eda14cbcSMatt Macy 			}
959*eda14cbcSMatt Macy 			break;
960*eda14cbcSMatt Macy 		case 't':
961*eda14cbcSMatt Macy 			if ((type = name_to_type(optarg)) == TYPE_INVAL &&
962*eda14cbcSMatt Macy 			    !MOS_TYPE(type)) {
963*eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid type '%s'\n",
964*eda14cbcSMatt Macy 				    optarg);
965*eda14cbcSMatt Macy 				usage();
966*eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
967*eda14cbcSMatt Macy 				return (1);
968*eda14cbcSMatt Macy 			}
969*eda14cbcSMatt Macy 			break;
970*eda14cbcSMatt Macy 		case 'u':
971*eda14cbcSMatt Macy 			flags |= ZINJECT_UNLOAD_SPA;
972*eda14cbcSMatt Macy 			break;
973*eda14cbcSMatt Macy 		case 'L':
974*eda14cbcSMatt Macy 			if ((label = name_to_type(optarg)) == TYPE_INVAL &&
975*eda14cbcSMatt Macy 			    !LABEL_TYPE(type)) {
976*eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid label type "
977*eda14cbcSMatt Macy 				    "'%s'\n", optarg);
978*eda14cbcSMatt Macy 				usage();
979*eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
980*eda14cbcSMatt Macy 				return (1);
981*eda14cbcSMatt Macy 			}
982*eda14cbcSMatt Macy 			break;
983*eda14cbcSMatt Macy 		case ':':
984*eda14cbcSMatt Macy 			(void) fprintf(stderr, "option -%c requires an "
985*eda14cbcSMatt Macy 			    "operand\n", optopt);
986*eda14cbcSMatt Macy 			usage();
987*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
988*eda14cbcSMatt Macy 			return (1);
989*eda14cbcSMatt Macy 		case '?':
990*eda14cbcSMatt Macy 			(void) fprintf(stderr, "invalid option '%c'\n",
991*eda14cbcSMatt Macy 			    optopt);
992*eda14cbcSMatt Macy 			usage();
993*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
994*eda14cbcSMatt Macy 			return (2);
995*eda14cbcSMatt Macy 		}
996*eda14cbcSMatt Macy 	}
997*eda14cbcSMatt Macy 
998*eda14cbcSMatt Macy 	argc -= optind;
999*eda14cbcSMatt Macy 	argv += optind;
1000*eda14cbcSMatt Macy 
1001*eda14cbcSMatt Macy 	if (record.zi_duration != 0)
1002*eda14cbcSMatt Macy 		record.zi_cmd = ZINJECT_IGNORED_WRITES;
1003*eda14cbcSMatt Macy 
1004*eda14cbcSMatt Macy 	if (cancel != NULL) {
1005*eda14cbcSMatt Macy 		/*
1006*eda14cbcSMatt Macy 		 * '-c' is invalid with any other options.
1007*eda14cbcSMatt Macy 		 */
1008*eda14cbcSMatt Macy 		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
1009*eda14cbcSMatt Macy 		    level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED ||
1010*eda14cbcSMatt Macy 		    record.zi_freq > 0 || dvas != 0) {
1011*eda14cbcSMatt Macy 			(void) fprintf(stderr, "cancel (-c) incompatible with "
1012*eda14cbcSMatt Macy 			    "any other options\n");
1013*eda14cbcSMatt Macy 			usage();
1014*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1015*eda14cbcSMatt Macy 			return (2);
1016*eda14cbcSMatt Macy 		}
1017*eda14cbcSMatt Macy 		if (argc != 0) {
1018*eda14cbcSMatt Macy 			(void) fprintf(stderr, "extraneous argument to '-c'\n");
1019*eda14cbcSMatt Macy 			usage();
1020*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1021*eda14cbcSMatt Macy 			return (2);
1022*eda14cbcSMatt Macy 		}
1023*eda14cbcSMatt Macy 
1024*eda14cbcSMatt Macy 		if (strcmp(cancel, "all") == 0) {
1025*eda14cbcSMatt Macy 			return (cancel_all_handlers());
1026*eda14cbcSMatt Macy 		} else {
1027*eda14cbcSMatt Macy 			int id = (int)strtol(cancel, &end, 10);
1028*eda14cbcSMatt Macy 			if (*end != '\0') {
1029*eda14cbcSMatt Macy 				(void) fprintf(stderr, "invalid handle id '%s':"
1030*eda14cbcSMatt Macy 				    " must be an integer or 'all'\n", cancel);
1031*eda14cbcSMatt Macy 				usage();
1032*eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
1033*eda14cbcSMatt Macy 				return (1);
1034*eda14cbcSMatt Macy 			}
1035*eda14cbcSMatt Macy 			return (cancel_handler(id));
1036*eda14cbcSMatt Macy 		}
1037*eda14cbcSMatt Macy 	}
1038*eda14cbcSMatt Macy 
1039*eda14cbcSMatt Macy 	if (device != NULL) {
1040*eda14cbcSMatt Macy 		/*
1041*eda14cbcSMatt Macy 		 * Device (-d) injection uses a completely different mechanism
1042*eda14cbcSMatt Macy 		 * for doing injection, so handle it separately here.
1043*eda14cbcSMatt Macy 		 */
1044*eda14cbcSMatt Macy 		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
1045*eda14cbcSMatt Macy 		    level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED ||
1046*eda14cbcSMatt Macy 		    dvas != 0) {
1047*eda14cbcSMatt Macy 			(void) fprintf(stderr, "device (-d) incompatible with "
1048*eda14cbcSMatt Macy 			    "data error injection\n");
1049*eda14cbcSMatt Macy 			usage();
1050*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1051*eda14cbcSMatt Macy 			return (2);
1052*eda14cbcSMatt Macy 		}
1053*eda14cbcSMatt Macy 
1054*eda14cbcSMatt Macy 		if (argc != 1) {
1055*eda14cbcSMatt Macy 			(void) fprintf(stderr, "device (-d) injection requires "
1056*eda14cbcSMatt Macy 			    "a single pool name\n");
1057*eda14cbcSMatt Macy 			usage();
1058*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1059*eda14cbcSMatt Macy 			return (2);
1060*eda14cbcSMatt Macy 		}
1061*eda14cbcSMatt Macy 
1062*eda14cbcSMatt Macy 		(void) strlcpy(pool, argv[0], sizeof (pool));
1063*eda14cbcSMatt Macy 		dataset[0] = '\0';
1064*eda14cbcSMatt Macy 
1065*eda14cbcSMatt Macy 		if (error == ECKSUM) {
1066*eda14cbcSMatt Macy 			(void) fprintf(stderr, "device error type must be "
1067*eda14cbcSMatt Macy 			    "'io', 'nxio' or 'corrupt'\n");
1068*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1069*eda14cbcSMatt Macy 			return (1);
1070*eda14cbcSMatt Macy 		}
1071*eda14cbcSMatt Macy 
1072*eda14cbcSMatt Macy 		if (error == EILSEQ &&
1073*eda14cbcSMatt Macy 		    (record.zi_freq == 0 || io_type != ZIO_TYPE_READ)) {
1074*eda14cbcSMatt Macy 			(void) fprintf(stderr, "device corrupt errors require "
1075*eda14cbcSMatt Macy 			    "io type read and a frequency value\n");
1076*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1077*eda14cbcSMatt Macy 			return (1);
1078*eda14cbcSMatt Macy 		}
1079*eda14cbcSMatt Macy 
1080*eda14cbcSMatt Macy 		record.zi_iotype = io_type;
1081*eda14cbcSMatt Macy 		if (translate_device(pool, device, label, &record) != 0) {
1082*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1083*eda14cbcSMatt Macy 			return (1);
1084*eda14cbcSMatt Macy 		}
1085*eda14cbcSMatt Macy 		if (!error)
1086*eda14cbcSMatt Macy 			error = ENXIO;
1087*eda14cbcSMatt Macy 
1088*eda14cbcSMatt Macy 		if (action != VDEV_STATE_UNKNOWN)
1089*eda14cbcSMatt Macy 			return (perform_action(pool, &record, action));
1090*eda14cbcSMatt Macy 
1091*eda14cbcSMatt Macy 	} else if (raw != NULL) {
1092*eda14cbcSMatt Macy 		if (range != NULL || type != TYPE_INVAL || level != 0 ||
1093*eda14cbcSMatt Macy 		    record.zi_cmd != ZINJECT_UNINITIALIZED ||
1094*eda14cbcSMatt Macy 		    record.zi_freq > 0 || dvas != 0) {
1095*eda14cbcSMatt Macy 			(void) fprintf(stderr, "raw (-b) format with "
1096*eda14cbcSMatt Macy 			    "any other options\n");
1097*eda14cbcSMatt Macy 			usage();
1098*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1099*eda14cbcSMatt Macy 			return (2);
1100*eda14cbcSMatt Macy 		}
1101*eda14cbcSMatt Macy 
1102*eda14cbcSMatt Macy 		if (argc != 1) {
1103*eda14cbcSMatt Macy 			(void) fprintf(stderr, "raw (-b) format expects a "
1104*eda14cbcSMatt Macy 			    "single pool name\n");
1105*eda14cbcSMatt Macy 			usage();
1106*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1107*eda14cbcSMatt Macy 			return (2);
1108*eda14cbcSMatt Macy 		}
1109*eda14cbcSMatt Macy 
1110*eda14cbcSMatt Macy 		(void) strlcpy(pool, argv[0], sizeof (pool));
1111*eda14cbcSMatt Macy 		dataset[0] = '\0';
1112*eda14cbcSMatt Macy 
1113*eda14cbcSMatt Macy 		if (error == ENXIO) {
1114*eda14cbcSMatt Macy 			(void) fprintf(stderr, "data error type must be "
1115*eda14cbcSMatt Macy 			    "'checksum' or 'io'\n");
1116*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1117*eda14cbcSMatt Macy 			return (1);
1118*eda14cbcSMatt Macy 		}
1119*eda14cbcSMatt Macy 
1120*eda14cbcSMatt Macy 		record.zi_cmd = ZINJECT_DATA_FAULT;
1121*eda14cbcSMatt Macy 		if (translate_raw(raw, &record) != 0) {
1122*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1123*eda14cbcSMatt Macy 			return (1);
1124*eda14cbcSMatt Macy 		}
1125*eda14cbcSMatt Macy 		if (!error)
1126*eda14cbcSMatt Macy 			error = EIO;
1127*eda14cbcSMatt Macy 	} else if (record.zi_cmd == ZINJECT_PANIC) {
1128*eda14cbcSMatt Macy 		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
1129*eda14cbcSMatt Macy 		    level != 0 || device != NULL || record.zi_freq > 0 ||
1130*eda14cbcSMatt Macy 		    dvas != 0) {
1131*eda14cbcSMatt Macy 			(void) fprintf(stderr, "panic (-p) incompatible with "
1132*eda14cbcSMatt Macy 			    "other options\n");
1133*eda14cbcSMatt Macy 			usage();
1134*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1135*eda14cbcSMatt Macy 			return (2);
1136*eda14cbcSMatt Macy 		}
1137*eda14cbcSMatt Macy 
1138*eda14cbcSMatt Macy 		if (argc < 1 || argc > 2) {
1139*eda14cbcSMatt Macy 			(void) fprintf(stderr, "panic (-p) injection requires "
1140*eda14cbcSMatt Macy 			    "a single pool name and an optional id\n");
1141*eda14cbcSMatt Macy 			usage();
1142*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1143*eda14cbcSMatt Macy 			return (2);
1144*eda14cbcSMatt Macy 		}
1145*eda14cbcSMatt Macy 
1146*eda14cbcSMatt Macy 		(void) strlcpy(pool, argv[0], sizeof (pool));
1147*eda14cbcSMatt Macy 		if (argv[1] != NULL)
1148*eda14cbcSMatt Macy 			record.zi_type = atoi(argv[1]);
1149*eda14cbcSMatt Macy 		dataset[0] = '\0';
1150*eda14cbcSMatt Macy 	} else if (record.zi_cmd == ZINJECT_IGNORED_WRITES) {
1151*eda14cbcSMatt Macy 		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
1152*eda14cbcSMatt Macy 		    level != 0 || record.zi_freq > 0 || dvas != 0) {
1153*eda14cbcSMatt Macy 			(void) fprintf(stderr, "hardware failure (-I) "
1154*eda14cbcSMatt Macy 			    "incompatible with other options\n");
1155*eda14cbcSMatt Macy 			usage();
1156*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1157*eda14cbcSMatt Macy 			return (2);
1158*eda14cbcSMatt Macy 		}
1159*eda14cbcSMatt Macy 
1160*eda14cbcSMatt Macy 		if (nowrites == 0) {
1161*eda14cbcSMatt Macy 			(void) fprintf(stderr, "-s or -g meaningless "
1162*eda14cbcSMatt Macy 			    "without -I (ignore writes)\n");
1163*eda14cbcSMatt Macy 			usage();
1164*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1165*eda14cbcSMatt Macy 			return (2);
1166*eda14cbcSMatt Macy 		} else if (dur_secs && dur_txg) {
1167*eda14cbcSMatt Macy 			(void) fprintf(stderr, "choose a duration either "
1168*eda14cbcSMatt Macy 			    "in seconds (-s) or a number of txgs (-g) "
1169*eda14cbcSMatt Macy 			    "but not both\n");
1170*eda14cbcSMatt Macy 			usage();
1171*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1172*eda14cbcSMatt Macy 			return (2);
1173*eda14cbcSMatt Macy 		} else if (argc != 1) {
1174*eda14cbcSMatt Macy 			(void) fprintf(stderr, "ignore writes (-I) "
1175*eda14cbcSMatt Macy 			    "injection requires a single pool name\n");
1176*eda14cbcSMatt Macy 			usage();
1177*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1178*eda14cbcSMatt Macy 			return (2);
1179*eda14cbcSMatt Macy 		}
1180*eda14cbcSMatt Macy 
1181*eda14cbcSMatt Macy 		(void) strlcpy(pool, argv[0], sizeof (pool));
1182*eda14cbcSMatt Macy 		dataset[0] = '\0';
1183*eda14cbcSMatt Macy 	} else if (type == TYPE_INVAL) {
1184*eda14cbcSMatt Macy 		if (flags == 0) {
1185*eda14cbcSMatt Macy 			(void) fprintf(stderr, "at least one of '-b', '-d', "
1186*eda14cbcSMatt Macy 			    "'-t', '-a', '-p', '-I' or '-u' "
1187*eda14cbcSMatt Macy 			    "must be specified\n");
1188*eda14cbcSMatt Macy 			usage();
1189*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1190*eda14cbcSMatt Macy 			return (2);
1191*eda14cbcSMatt Macy 		}
1192*eda14cbcSMatt Macy 
1193*eda14cbcSMatt Macy 		if (argc == 1 && (flags & ZINJECT_UNLOAD_SPA)) {
1194*eda14cbcSMatt Macy 			(void) strlcpy(pool, argv[0], sizeof (pool));
1195*eda14cbcSMatt Macy 			dataset[0] = '\0';
1196*eda14cbcSMatt Macy 		} else if (argc != 0) {
1197*eda14cbcSMatt Macy 			(void) fprintf(stderr, "extraneous argument for "
1198*eda14cbcSMatt Macy 			    "'-f'\n");
1199*eda14cbcSMatt Macy 			usage();
1200*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1201*eda14cbcSMatt Macy 			return (2);
1202*eda14cbcSMatt Macy 		}
1203*eda14cbcSMatt Macy 
1204*eda14cbcSMatt Macy 		flags |= ZINJECT_NULL;
1205*eda14cbcSMatt Macy 	} else {
1206*eda14cbcSMatt Macy 		if (argc != 1) {
1207*eda14cbcSMatt Macy 			(void) fprintf(stderr, "missing object\n");
1208*eda14cbcSMatt Macy 			usage();
1209*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1210*eda14cbcSMatt Macy 			return (2);
1211*eda14cbcSMatt Macy 		}
1212*eda14cbcSMatt Macy 
1213*eda14cbcSMatt Macy 		if (error == ENXIO || error == EILSEQ) {
1214*eda14cbcSMatt Macy 			(void) fprintf(stderr, "data error type must be "
1215*eda14cbcSMatt Macy 			    "'checksum' or 'io'\n");
1216*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1217*eda14cbcSMatt Macy 			return (1);
1218*eda14cbcSMatt Macy 		}
1219*eda14cbcSMatt Macy 
1220*eda14cbcSMatt Macy 		if (dvas != 0) {
1221*eda14cbcSMatt Macy 			if (error == EACCES || error == EINVAL) {
1222*eda14cbcSMatt Macy 				(void) fprintf(stderr, "the '-C' option may "
1223*eda14cbcSMatt Macy 				    "not be used with logical data errors "
1224*eda14cbcSMatt Macy 				    "'decrypt' and 'decompress'\n");
1225*eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
1226*eda14cbcSMatt Macy 				return (1);
1227*eda14cbcSMatt Macy 			}
1228*eda14cbcSMatt Macy 
1229*eda14cbcSMatt Macy 			record.zi_dvas = dvas;
1230*eda14cbcSMatt Macy 		}
1231*eda14cbcSMatt Macy 
1232*eda14cbcSMatt Macy 		if (error == EACCES) {
1233*eda14cbcSMatt Macy 			if (type != TYPE_DATA) {
1234*eda14cbcSMatt Macy 				(void) fprintf(stderr, "decryption errors "
1235*eda14cbcSMatt Macy 				    "may only be injected for 'data' types\n");
1236*eda14cbcSMatt Macy 				libzfs_fini(g_zfs);
1237*eda14cbcSMatt Macy 				return (1);
1238*eda14cbcSMatt Macy 			}
1239*eda14cbcSMatt Macy 
1240*eda14cbcSMatt Macy 			record.zi_cmd = ZINJECT_DECRYPT_FAULT;
1241*eda14cbcSMatt Macy 			/*
1242*eda14cbcSMatt Macy 			 * Internally, ZFS actually uses ECKSUM for decryption
1243*eda14cbcSMatt Macy 			 * errors since EACCES is used to indicate the key was
1244*eda14cbcSMatt Macy 			 * not found.
1245*eda14cbcSMatt Macy 			 */
1246*eda14cbcSMatt Macy 			error = ECKSUM;
1247*eda14cbcSMatt Macy 		} else {
1248*eda14cbcSMatt Macy 			record.zi_cmd = ZINJECT_DATA_FAULT;
1249*eda14cbcSMatt Macy 		}
1250*eda14cbcSMatt Macy 
1251*eda14cbcSMatt Macy 		if (translate_record(type, argv[0], range, level, &record, pool,
1252*eda14cbcSMatt Macy 		    dataset) != 0) {
1253*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1254*eda14cbcSMatt Macy 			return (1);
1255*eda14cbcSMatt Macy 		}
1256*eda14cbcSMatt Macy 		if (!error)
1257*eda14cbcSMatt Macy 			error = EIO;
1258*eda14cbcSMatt Macy 	}
1259*eda14cbcSMatt Macy 
1260*eda14cbcSMatt Macy 	/*
1261*eda14cbcSMatt Macy 	 * If this is pool-wide metadata, unmount everything.  The ioctl() will
1262*eda14cbcSMatt Macy 	 * unload the pool, so that we trigger spa-wide reopen of metadata next
1263*eda14cbcSMatt Macy 	 * time we access the pool.
1264*eda14cbcSMatt Macy 	 */
1265*eda14cbcSMatt Macy 	if (dataset[0] != '\0' && domount) {
1266*eda14cbcSMatt Macy 		if ((zhp = zfs_open(g_zfs, dataset,
1267*eda14cbcSMatt Macy 		    ZFS_TYPE_DATASET)) == NULL) {
1268*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1269*eda14cbcSMatt Macy 			return (1);
1270*eda14cbcSMatt Macy 		}
1271*eda14cbcSMatt Macy 		if (zfs_unmount(zhp, NULL, 0) != 0) {
1272*eda14cbcSMatt Macy 			libzfs_fini(g_zfs);
1273*eda14cbcSMatt Macy 			return (1);
1274*eda14cbcSMatt Macy 		}
1275*eda14cbcSMatt Macy 	}
1276*eda14cbcSMatt Macy 
1277*eda14cbcSMatt Macy 	record.zi_error = error;
1278*eda14cbcSMatt Macy 
1279*eda14cbcSMatt Macy 	ret = register_handler(pool, flags, &record, quiet);
1280*eda14cbcSMatt Macy 
1281*eda14cbcSMatt Macy 	if (dataset[0] != '\0' && domount)
1282*eda14cbcSMatt Macy 		ret = (zfs_mount(zhp, NULL, 0) != 0);
1283*eda14cbcSMatt Macy 
1284*eda14cbcSMatt Macy 	libzfs_fini(g_zfs);
1285*eda14cbcSMatt Macy 
1286*eda14cbcSMatt Macy 	return (ret);
1287*eda14cbcSMatt Macy }
1288