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