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