xref: /NextBSD/cddl/contrib/opensolaris/cmd/zinject/zinject.c (revision 95f7c2f56c7268d6ed9c2a56d357aeeac260363b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright (c) 2012 by Delphix. All rights reserved.
24  */
25 
26 /*
27  * ZFS Fault Injector
28  *
29  * This userland component takes a set of options and uses libzpool to translate
30  * from a user-visible object type and name to an internal representation.
31  * There are two basic types of faults: device faults and data faults.
32  *
33  *
34  * DEVICE FAULTS
35  *
36  * Errors can be injected into a particular vdev using the '-d' option.  This
37  * option takes a path or vdev GUID to uniquely identify the device within a
38  * pool.  There are two types of errors that can be injected, EIO and ENXIO,
39  * that can be controlled through the '-e' option.  The default is ENXIO.  For
40  * EIO failures, any attempt to read data from the device will return EIO, but
41  * subsequent attempt to reopen the device will succeed.  For ENXIO failures,
42  * any attempt to read from the device will return EIO, but any attempt to
43  * reopen the device will also return ENXIO.
44  * For label faults, the -L option must be specified. This allows faults
45  * to be injected into either the nvlist, uberblock, pad1, or pad2 region
46  * of all the labels for the specified device.
47  *
48  * This form of the command looks like:
49  *
50  * 	zinject -d device [-e errno] [-L <uber | nvlist | pad1 | pad2>] pool
51  *
52  *
53  * DATA FAULTS
54  *
55  * We begin with a tuple of the form:
56  *
57  * 	<type,level,range,object>
58  *
59  * 	type	A string describing the type of data to target.  Each type
60  * 		implicitly describes how to interpret 'object'. Currently,
61  * 		the following values are supported:
62  *
63  * 		data		User data for a file
64  * 		dnode		Dnode for a file or directory
65  *
66  *		The following MOS objects are special.  Instead of injecting
67  *		errors on a particular object or blkid, we inject errors across
68  *		all objects of the given type.
69  *
70  * 		mos		Any data in the MOS
71  * 		mosdir		object directory
72  * 		config		pool configuration
73  * 		bpobj		blkptr list
74  * 		spacemap	spacemap
75  * 		metaslab	metaslab
76  * 		errlog		persistent error log
77  *
78  * 	level	Object level.  Defaults to '0', not applicable to all types.  If
79  * 		a range is given, this corresponds to the indirect block
80  * 		corresponding to the specific range.
81  *
82  *	range	A numerical range [start,end) within the object.  Defaults to
83  *		the full size of the file.
84  *
85  * 	object	A string describing the logical location of the object.  For
86  * 		files and directories (currently the only supported types),
87  * 		this is the path of the object on disk.
88  *
89  * This is translated, via libzpool, into the following internal representation:
90  *
91  * 	<type,objset,object,level,range>
92  *
93  * These types should be self-explanatory.  This tuple is then passed to the
94  * kernel via a special ioctl() to initiate fault injection for the given
95  * object.  Note that 'type' is not strictly necessary for fault injection, but
96  * is used when translating existing faults into a human-readable string.
97  *
98  *
99  * The command itself takes one of the forms:
100  *
101  * 	zinject
102  * 	zinject <-a | -u pool>
103  * 	zinject -c <id|all>
104  * 	zinject [-q] <-t type> [-f freq] [-u] [-a] [-m] [-e errno] [-l level]
105  *	    [-r range] <object>
106  * 	zinject [-f freq] [-a] [-m] [-u] -b objset:object:level:start:end pool
107  *
108  * With no arguments, the command prints all currently registered injection
109  * handlers, with their numeric identifiers.
110  *
111  * The '-c' option will clear the given handler, or all handlers if 'all' is
112  * specified.
113  *
114  * The '-e' option takes a string describing the errno to simulate.  This must
115  * be either 'io' or 'checksum'.  In most cases this will result in the same
116  * behavior, but RAID-Z will produce a different set of ereports for this
117  * situation.
118  *
119  * The '-a', '-u', and '-m' flags toggle internal flush behavior.  If '-a' is
120  * specified, then the ARC cache is flushed appropriately.  If '-u' is
121  * specified, then the underlying SPA is unloaded.  Either of these flags can be
122  * specified independently of any other handlers.  The '-m' flag automatically
123  * does an unmount and remount of the underlying dataset to aid in flushing the
124  * cache.
125  *
126  * The '-f' flag controls the frequency of errors injected, expressed as a
127  * integer percentage between 1 and 100.  The default is 100.
128  *
129  * The this form is responsible for actually injecting the handler into the
130  * framework.  It takes the arguments described above, translates them to the
131  * internal tuple using libzpool, and then issues an ioctl() to register the
132  * handler.
133  *
134  * The final form can target a specific bookmark, regardless of whether a
135  * human-readable interface has been designed.  It allows developers to specify
136  * a particular block by number.
137  */
138 
139 #include <errno.h>
140 #include <fcntl.h>
141 #include <stdio.h>
142 #include <stdlib.h>
143 #include <strings.h>
144 #include <unistd.h>
145 
146 #include <sys/fs/zfs.h>
147 #include <sys/param.h>
148 #include <sys/mount.h>
149 
150 #include <libzfs.h>
151 #include <libzfs_compat.h>
152 
153 #undef verify	/* both libzfs.h and zfs_context.h want to define this */
154 
155 #include "zinject.h"
156 
157 libzfs_handle_t *g_zfs;
158 int zfs_fd;
159 
160 #ifndef ECKSUM
161 #define	ECKSUM	EBADE
162 #endif
163 
164 static const char *errtable[TYPE_INVAL] = {
165 	"data",
166 	"dnode",
167 	"mos",
168 	"mosdir",
169 	"metaslab",
170 	"config",
171 	"bpobj",
172 	"spacemap",
173 	"errlog",
174 	"uber",
175 	"nvlist",
176 	"pad1",
177 	"pad2"
178 };
179 
180 static err_type_t
name_to_type(const char * arg)181 name_to_type(const char *arg)
182 {
183 	int i;
184 	for (i = 0; i < TYPE_INVAL; i++)
185 		if (strcmp(errtable[i], arg) == 0)
186 			return (i);
187 
188 	return (TYPE_INVAL);
189 }
190 
191 static const char *
type_to_name(uint64_t type)192 type_to_name(uint64_t type)
193 {
194 	switch (type) {
195 	case DMU_OT_OBJECT_DIRECTORY:
196 		return ("mosdir");
197 	case DMU_OT_OBJECT_ARRAY:
198 		return ("metaslab");
199 	case DMU_OT_PACKED_NVLIST:
200 		return ("config");
201 	case DMU_OT_BPOBJ:
202 		return ("bpobj");
203 	case DMU_OT_SPACE_MAP:
204 		return ("spacemap");
205 	case DMU_OT_ERROR_LOG:
206 		return ("errlog");
207 	default:
208 		return ("-");
209 	}
210 }
211 
212 
213 /*
214  * Print usage message.
215  */
216 void
usage(void)217 usage(void)
218 {
219 	(void) printf(
220 	    "usage:\n"
221 	    "\n"
222 	    "\tzinject\n"
223 	    "\n"
224 	    "\t\tList all active injection records.\n"
225 	    "\n"
226 	    "\tzinject -c <id|all>\n"
227 	    "\n"
228 	    "\t\tClear the particular record (if given a numeric ID), or\n"
229 	    "\t\tall records if 'all' is specificed.\n"
230 	    "\n"
231 	    "\tzinject -p <function name> pool\n"
232 	    "\t\tInject a panic fault at the specified function. Only \n"
233 	    "\t\tfunctions which call spa_vdev_config_exit(), or \n"
234 	    "\t\tspa_vdev_exit() will trigger a panic.\n"
235 	    "\n"
236 	    "\tzinject -d device [-e errno] [-L <nvlist|uber|pad1|pad2>] [-F]\n"
237 	    "\t    [-T <read|write|free|claim|all> pool\n"
238 	    "\t\tInject a fault into a particular device or the device's\n"
239 	    "\t\tlabel.  Label injection can either be 'nvlist', 'uber',\n "
240 	    "\t\t'pad1', or 'pad2'.\n"
241 	    "\t\t'errno' can be 'nxio' (the default), 'io', or 'dtl'.\n"
242 	    "\n"
243 	    "\tzinject -d device -A <degrade|fault> pool\n"
244 	    "\t\tPerform a specific action on a particular device\n"
245 	    "\n"
246 	    "\tzinject -I [-s <seconds> | -g <txgs>] pool\n"
247 	    "\t\tCause the pool to stop writing blocks yet not\n"
248 	    "\t\treport errors for a duration.  Simulates buggy hardware\n"
249 	    "\t\tthat fails to honor cache flush requests.\n"
250 	    "\t\tDefault duration is 30 seconds.  The machine is panicked\n"
251 	    "\t\tat the end of the duration.\n"
252 	    "\n"
253 	    "\tzinject -b objset:object:level:blkid pool\n"
254 	    "\n"
255 	    "\t\tInject an error into pool 'pool' with the numeric bookmark\n"
256 	    "\t\tspecified by the remaining tuple.  Each number is in\n"
257 	    "\t\thexidecimal, and only one block can be specified.\n"
258 	    "\n"
259 	    "\tzinject [-q] <-t type> [-e errno] [-l level] [-r range]\n"
260 	    "\t    [-a] [-m] [-u] [-f freq] <object>\n"
261 	    "\n"
262 	    "\t\tInject an error into the object specified by the '-t' option\n"
263 	    "\t\tand the object descriptor.  The 'object' parameter is\n"
264 	    "\t\tinterperted depending on the '-t' option.\n"
265 	    "\n"
266 	    "\t\t-q\tQuiet mode.  Only print out the handler number added.\n"
267 	    "\t\t-e\tInject a specific error.  Must be either 'io' or\n"
268 	    "\t\t\t'checksum'.  Default is 'io'.\n"
269 	    "\t\t-l\tInject error at a particular block level. Default is "
270 	    "0.\n"
271 	    "\t\t-m\tAutomatically remount underlying filesystem.\n"
272 	    "\t\t-r\tInject error over a particular logical range of an\n"
273 	    "\t\t\tobject.  Will be translated to the appropriate blkid\n"
274 	    "\t\t\trange according to the object's properties.\n"
275 	    "\t\t-a\tFlush the ARC cache.  Can be specified without any\n"
276 	    "\t\t\tassociated object.\n"
277 	    "\t\t-u\tUnload the associated pool.  Can be specified with only\n"
278 	    "\t\t\ta pool object.\n"
279 	    "\t\t-f\tOnly inject errors a fraction of the time.  Expressed as\n"
280 	    "\t\t\ta percentage between 1 and 100.\n"
281 	    "\n"
282 	    "\t-t data\t\tInject an error into the plain file contents of a\n"
283 	    "\t\t\tfile.  The object must be specified as a complete path\n"
284 	    "\t\t\tto a file on a ZFS filesystem.\n"
285 	    "\n"
286 	    "\t-t dnode\tInject an error into the metadnode in the block\n"
287 	    "\t\t\tcorresponding to the dnode for a file or directory.  The\n"
288 	    "\t\t\t'-r' option is incompatible with this mode.  The object\n"
289 	    "\t\t\tis specified as a complete path to a file or directory\n"
290 	    "\t\t\ton a ZFS filesystem.\n"
291 	    "\n"
292 	    "\t-t <mos>\tInject errors into the MOS for objects of the given\n"
293 	    "\t\t\ttype.  Valid types are: mos, mosdir, config, bpobj,\n"
294 	    "\t\t\tspacemap, metaslab, errlog.  The only valid <object> is\n"
295 	    "\t\t\tthe poolname.\n");
296 }
297 
298 static int
iter_handlers(int (* func)(int,const char *,zinject_record_t *,void *),void * data)299 iter_handlers(int (*func)(int, const char *, zinject_record_t *, void *),
300     void *data)
301 {
302 	zfs_cmd_t zc = { 0 };
303 	int ret;
304 
305 	while (ioctl(zfs_fd, ZFS_IOC_INJECT_LIST_NEXT, &zc) == 0)
306 		if ((ret = func((int)zc.zc_guid, zc.zc_name,
307 		    &zc.zc_inject_record, data)) != 0)
308 			return (ret);
309 
310 	if (errno != ENOENT) {
311 		(void) fprintf(stderr, "Unable to list handlers: %s\n",
312 		    strerror(errno));
313 		return (-1);
314 	}
315 
316 	return (0);
317 }
318 
319 static int
print_data_handler(int id,const char * pool,zinject_record_t * record,void * data)320 print_data_handler(int id, const char *pool, zinject_record_t *record,
321     void *data)
322 {
323 	int *count = data;
324 
325 	if (record->zi_guid != 0 || record->zi_func[0] != '\0')
326 		return (0);
327 
328 	if (*count == 0) {
329 		(void) printf("%3s  %-15s  %-6s  %-6s  %-8s  %3s  %-15s\n",
330 		    "ID", "POOL", "OBJSET", "OBJECT", "TYPE", "LVL",  "RANGE");
331 		(void) printf("---  ---------------  ------  "
332 		    "------  --------  ---  ---------------\n");
333 	}
334 
335 	*count += 1;
336 
337 	(void) printf("%3d  %-15s  %-6llu  %-6llu  %-8s  %3d  ", id, pool,
338 	    (u_longlong_t)record->zi_objset, (u_longlong_t)record->zi_object,
339 	    type_to_name(record->zi_type), record->zi_level);
340 
341 	if (record->zi_start == 0 &&
342 	    record->zi_end == -1ULL)
343 		(void) printf("all\n");
344 	else
345 		(void) printf("[%llu, %llu]\n", (u_longlong_t)record->zi_start,
346 		    (u_longlong_t)record->zi_end);
347 
348 	return (0);
349 }
350 
351 static int
print_device_handler(int id,const char * pool,zinject_record_t * record,void * data)352 print_device_handler(int id, const char *pool, zinject_record_t *record,
353     void *data)
354 {
355 	int *count = data;
356 
357 	if (record->zi_guid == 0 || record->zi_func[0] != '\0')
358 		return (0);
359 
360 	if (*count == 0) {
361 		(void) printf("%3s  %-15s  %s\n", "ID", "POOL", "GUID");
362 		(void) printf("---  ---------------  ----------------\n");
363 	}
364 
365 	*count += 1;
366 
367 	(void) printf("%3d  %-15s  %llx\n", id, pool,
368 	    (u_longlong_t)record->zi_guid);
369 
370 	return (0);
371 }
372 
373 static int
print_panic_handler(int id,const char * pool,zinject_record_t * record,void * data)374 print_panic_handler(int id, const char *pool, zinject_record_t *record,
375     void *data)
376 {
377 	int *count = data;
378 
379 	if (record->zi_func[0] == '\0')
380 		return (0);
381 
382 	if (*count == 0) {
383 		(void) printf("%3s  %-15s  %s\n", "ID", "POOL", "FUNCTION");
384 		(void) printf("---  ---------------  ----------------\n");
385 	}
386 
387 	*count += 1;
388 
389 	(void) printf("%3d  %-15s  %s\n", id, pool, record->zi_func);
390 
391 	return (0);
392 }
393 
394 /*
395  * Print all registered error handlers.  Returns the number of handlers
396  * registered.
397  */
398 static int
print_all_handlers(void)399 print_all_handlers(void)
400 {
401 	int count = 0, total = 0;
402 
403 	(void) iter_handlers(print_device_handler, &count);
404 	if (count > 0) {
405 		total += count;
406 		(void) printf("\n");
407 		count = 0;
408 	}
409 
410 	(void) iter_handlers(print_data_handler, &count);
411 	if (count > 0) {
412 		total += count;
413 		(void) printf("\n");
414 		count = 0;
415 	}
416 
417 	(void) iter_handlers(print_panic_handler, &count);
418 
419 	return (count + total);
420 }
421 
422 /* ARGSUSED */
423 static int
cancel_one_handler(int id,const char * pool,zinject_record_t * record,void * data)424 cancel_one_handler(int id, const char *pool, zinject_record_t *record,
425     void *data)
426 {
427 	zfs_cmd_t zc = { 0 };
428 
429 	zc.zc_guid = (uint64_t)id;
430 
431 	if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
432 		(void) fprintf(stderr, "failed to remove handler %d: %s\n",
433 		    id, strerror(errno));
434 		return (1);
435 	}
436 
437 	return (0);
438 }
439 
440 /*
441  * Remove all fault injection handlers.
442  */
443 static int
cancel_all_handlers(void)444 cancel_all_handlers(void)
445 {
446 	int ret = iter_handlers(cancel_one_handler, NULL);
447 
448 	if (ret == 0)
449 		(void) printf("removed all registered handlers\n");
450 
451 	return (ret);
452 }
453 
454 /*
455  * Remove a specific fault injection handler.
456  */
457 static int
cancel_handler(int id)458 cancel_handler(int id)
459 {
460 	zfs_cmd_t zc = { 0 };
461 
462 	zc.zc_guid = (uint64_t)id;
463 
464 	if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
465 		(void) fprintf(stderr, "failed to remove handler %d: %s\n",
466 		    id, strerror(errno));
467 		return (1);
468 	}
469 
470 	(void) printf("removed handler %d\n", id);
471 
472 	return (0);
473 }
474 
475 /*
476  * Register a new fault injection handler.
477  */
478 static int
register_handler(const char * pool,int flags,zinject_record_t * record,int quiet)479 register_handler(const char *pool, int flags, zinject_record_t *record,
480     int quiet)
481 {
482 	zfs_cmd_t zc = { 0 };
483 
484 	(void) strcpy(zc.zc_name, pool);
485 	zc.zc_inject_record = *record;
486 	zc.zc_guid = flags;
487 
488 	if (ioctl(zfs_fd, ZFS_IOC_INJECT_FAULT, &zc) != 0) {
489 		(void) fprintf(stderr, "failed to add handler: %s\n",
490 		    strerror(errno));
491 		return (1);
492 	}
493 
494 	if (flags & ZINJECT_NULL)
495 		return (0);
496 
497 	if (quiet) {
498 		(void) printf("%llu\n", (u_longlong_t)zc.zc_guid);
499 	} else {
500 		(void) printf("Added handler %llu with the following "
501 		    "properties:\n", (u_longlong_t)zc.zc_guid);
502 		(void) printf("  pool: %s\n", pool);
503 		if (record->zi_guid) {
504 			(void) printf("  vdev: %llx\n",
505 			    (u_longlong_t)record->zi_guid);
506 		} else if (record->zi_func[0] != '\0') {
507 			(void) printf("  panic function: %s\n",
508 			    record->zi_func);
509 		} else if (record->zi_duration > 0) {
510 			(void) printf(" time: %lld seconds\n",
511 			    (u_longlong_t)record->zi_duration);
512 		} else if (record->zi_duration < 0) {
513 			(void) printf(" txgs: %lld \n",
514 			    (u_longlong_t)-record->zi_duration);
515 		} else {
516 			(void) printf("objset: %llu\n",
517 			    (u_longlong_t)record->zi_objset);
518 			(void) printf("object: %llu\n",
519 			    (u_longlong_t)record->zi_object);
520 			(void) printf("  type: %llu\n",
521 			    (u_longlong_t)record->zi_type);
522 			(void) printf(" level: %d\n", record->zi_level);
523 			if (record->zi_start == 0 &&
524 			    record->zi_end == -1ULL)
525 				(void) printf(" range: all\n");
526 			else
527 				(void) printf(" range: [%llu, %llu)\n",
528 				    (u_longlong_t)record->zi_start,
529 				    (u_longlong_t)record->zi_end);
530 		}
531 	}
532 
533 	return (0);
534 }
535 
536 int
perform_action(const char * pool,zinject_record_t * record,int cmd)537 perform_action(const char *pool, zinject_record_t *record, int cmd)
538 {
539 	zfs_cmd_t zc = { 0 };
540 
541 	ASSERT(cmd == VDEV_STATE_DEGRADED || cmd == VDEV_STATE_FAULTED);
542 	(void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
543 	zc.zc_guid = record->zi_guid;
544 	zc.zc_cookie = cmd;
545 
546 	if (ioctl(zfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
547 		return (0);
548 
549 	return (1);
550 }
551 
552 int
main(int argc,char ** argv)553 main(int argc, char **argv)
554 {
555 	int c;
556 	char *range = NULL;
557 	char *cancel = NULL;
558 	char *end;
559 	char *raw = NULL;
560 	char *device = NULL;
561 	int level = 0;
562 	int quiet = 0;
563 	int error = 0;
564 	int domount = 0;
565 	int io_type = ZIO_TYPES;
566 	int action = VDEV_STATE_UNKNOWN;
567 	err_type_t type = TYPE_INVAL;
568 	err_type_t label = TYPE_INVAL;
569 	zinject_record_t record = { 0 };
570 	char pool[MAXNAMELEN];
571 	char dataset[MAXNAMELEN];
572 	zfs_handle_t *zhp;
573 	int nowrites = 0;
574 	int dur_txg = 0;
575 	int dur_secs = 0;
576 	int ret;
577 	int flags = 0;
578 
579 	if ((g_zfs = libzfs_init()) == NULL) {
580 		(void) fprintf(stderr, "internal error: failed to "
581 		    "initialize ZFS library\n");
582 		return (1);
583 	}
584 
585 	libzfs_print_on_error(g_zfs, B_TRUE);
586 
587 	if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
588 		(void) fprintf(stderr, "failed to open ZFS device\n");
589 		return (1);
590 	}
591 
592 	if (argc == 1) {
593 		/*
594 		 * No arguments.  Print the available handlers.  If there are no
595 		 * available handlers, direct the user to '-h' for help
596 		 * information.
597 		 */
598 		if (print_all_handlers() == 0) {
599 			(void) printf("No handlers registered.\n");
600 			(void) printf("Run 'zinject -h' for usage "
601 			    "information.\n");
602 		}
603 
604 		return (0);
605 	}
606 
607 	while ((c = getopt(argc, argv,
608 	    ":aA:b:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:")) != -1) {
609 		switch (c) {
610 		case 'a':
611 			flags |= ZINJECT_FLUSH_ARC;
612 			break;
613 		case 'A':
614 			if (strcasecmp(optarg, "degrade") == 0) {
615 				action = VDEV_STATE_DEGRADED;
616 			} else if (strcasecmp(optarg, "fault") == 0) {
617 				action = VDEV_STATE_FAULTED;
618 			} else {
619 				(void) fprintf(stderr, "invalid action '%s': "
620 				    "must be 'degrade' or 'fault'\n", optarg);
621 				usage();
622 				return (1);
623 			}
624 			break;
625 		case 'b':
626 			raw = optarg;
627 			break;
628 		case 'c':
629 			cancel = optarg;
630 			break;
631 		case 'd':
632 			device = optarg;
633 			break;
634 		case 'D':
635 			record.zi_timer = strtoull(optarg, &end, 10);
636 			if (errno != 0 || *end != '\0') {
637 				(void) fprintf(stderr, "invalid i/o delay "
638 				    "value: '%s'\n", optarg);
639 				usage();
640 				return (1);
641 			}
642 			break;
643 		case 'e':
644 			if (strcasecmp(optarg, "io") == 0) {
645 				error = EIO;
646 			} else if (strcasecmp(optarg, "checksum") == 0) {
647 				error = ECKSUM;
648 			} else if (strcasecmp(optarg, "nxio") == 0) {
649 				error = ENXIO;
650 			} else if (strcasecmp(optarg, "dtl") == 0) {
651 				error = ECHILD;
652 			} else {
653 				(void) fprintf(stderr, "invalid error type "
654 				    "'%s': must be 'io', 'checksum' or "
655 				    "'nxio'\n", optarg);
656 				usage();
657 				return (1);
658 			}
659 			break;
660 		case 'f':
661 			record.zi_freq = atoi(optarg);
662 			if (record.zi_freq < 1 || record.zi_freq > 100) {
663 				(void) fprintf(stderr, "frequency range must "
664 				    "be in the range (0, 100]\n");
665 				return (1);
666 			}
667 			break;
668 		case 'F':
669 			record.zi_failfast = B_TRUE;
670 			break;
671 		case 'g':
672 			dur_txg = 1;
673 			record.zi_duration = (int)strtol(optarg, &end, 10);
674 			if (record.zi_duration <= 0 || *end != '\0') {
675 				(void) fprintf(stderr, "invalid duration '%s': "
676 				    "must be a positive integer\n", optarg);
677 				usage();
678 				return (1);
679 			}
680 			/* store duration of txgs as its negative */
681 			record.zi_duration *= -1;
682 			break;
683 		case 'h':
684 			usage();
685 			return (0);
686 		case 'I':
687 			/* default duration, if one hasn't yet been defined */
688 			nowrites = 1;
689 			if (dur_secs == 0 && dur_txg == 0)
690 				record.zi_duration = 30;
691 			break;
692 		case 'l':
693 			level = (int)strtol(optarg, &end, 10);
694 			if (*end != '\0') {
695 				(void) fprintf(stderr, "invalid level '%s': "
696 				    "must be an integer\n", optarg);
697 				usage();
698 				return (1);
699 			}
700 			break;
701 		case 'm':
702 			domount = 1;
703 			break;
704 		case 'p':
705 			(void) strlcpy(record.zi_func, optarg,
706 			    sizeof (record.zi_func));
707 			record.zi_cmd = ZINJECT_PANIC;
708 			break;
709 		case 'q':
710 			quiet = 1;
711 			break;
712 		case 'r':
713 			range = optarg;
714 			break;
715 		case 's':
716 			dur_secs = 1;
717 			record.zi_duration = (int)strtol(optarg, &end, 10);
718 			if (record.zi_duration <= 0 || *end != '\0') {
719 				(void) fprintf(stderr, "invalid duration '%s': "
720 				    "must be a positive integer\n", optarg);
721 				usage();
722 				return (1);
723 			}
724 			break;
725 		case 'T':
726 			if (strcasecmp(optarg, "read") == 0) {
727 				io_type = ZIO_TYPE_READ;
728 			} else if (strcasecmp(optarg, "write") == 0) {
729 				io_type = ZIO_TYPE_WRITE;
730 			} else if (strcasecmp(optarg, "free") == 0) {
731 				io_type = ZIO_TYPE_FREE;
732 			} else if (strcasecmp(optarg, "claim") == 0) {
733 				io_type = ZIO_TYPE_CLAIM;
734 			} else if (strcasecmp(optarg, "all") == 0) {
735 				io_type = ZIO_TYPES;
736 			} else {
737 				(void) fprintf(stderr, "invalid I/O type "
738 				    "'%s': must be 'read', 'write', 'free', "
739 				    "'claim' or 'all'\n", optarg);
740 				usage();
741 				return (1);
742 			}
743 			break;
744 		case 't':
745 			if ((type = name_to_type(optarg)) == TYPE_INVAL &&
746 			    !MOS_TYPE(type)) {
747 				(void) fprintf(stderr, "invalid type '%s'\n",
748 				    optarg);
749 				usage();
750 				return (1);
751 			}
752 			break;
753 		case 'u':
754 			flags |= ZINJECT_UNLOAD_SPA;
755 			break;
756 		case 'L':
757 			if ((label = name_to_type(optarg)) == TYPE_INVAL &&
758 			    !LABEL_TYPE(type)) {
759 				(void) fprintf(stderr, "invalid label type "
760 				    "'%s'\n", optarg);
761 				usage();
762 				return (1);
763 			}
764 			break;
765 		case ':':
766 			(void) fprintf(stderr, "option -%c requires an "
767 			    "operand\n", optopt);
768 			usage();
769 			return (1);
770 		case '?':
771 			(void) fprintf(stderr, "invalid option '%c'\n",
772 			    optopt);
773 			usage();
774 			return (2);
775 		}
776 	}
777 
778 	argc -= optind;
779 	argv += optind;
780 
781 	if (record.zi_duration != 0)
782 		record.zi_cmd = ZINJECT_IGNORED_WRITES;
783 
784 	if (cancel != NULL) {
785 		/*
786 		 * '-c' is invalid with any other options.
787 		 */
788 		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
789 		    level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
790 			(void) fprintf(stderr, "cancel (-c) incompatible with "
791 			    "any other options\n");
792 			usage();
793 			return (2);
794 		}
795 		if (argc != 0) {
796 			(void) fprintf(stderr, "extraneous argument to '-c'\n");
797 			usage();
798 			return (2);
799 		}
800 
801 		if (strcmp(cancel, "all") == 0) {
802 			return (cancel_all_handlers());
803 		} else {
804 			int id = (int)strtol(cancel, &end, 10);
805 			if (*end != '\0') {
806 				(void) fprintf(stderr, "invalid handle id '%s':"
807 				    " must be an integer or 'all'\n", cancel);
808 				usage();
809 				return (1);
810 			}
811 			return (cancel_handler(id));
812 		}
813 	}
814 
815 	if (device != NULL) {
816 		/*
817 		 * Device (-d) injection uses a completely different mechanism
818 		 * for doing injection, so handle it separately here.
819 		 */
820 		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
821 		    level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
822 			(void) fprintf(stderr, "device (-d) incompatible with "
823 			    "data error injection\n");
824 			usage();
825 			return (2);
826 		}
827 
828 		if (argc != 1) {
829 			(void) fprintf(stderr, "device (-d) injection requires "
830 			    "a single pool name\n");
831 			usage();
832 			return (2);
833 		}
834 
835 		(void) strcpy(pool, argv[0]);
836 		dataset[0] = '\0';
837 
838 		if (error == ECKSUM) {
839 			(void) fprintf(stderr, "device error type must be "
840 			    "'io' or 'nxio'\n");
841 			return (1);
842 		}
843 
844 		record.zi_iotype = io_type;
845 		if (translate_device(pool, device, label, &record) != 0)
846 			return (1);
847 		if (!error)
848 			error = ENXIO;
849 
850 		if (action != VDEV_STATE_UNKNOWN)
851 			return (perform_action(pool, &record, action));
852 
853 	} else if (raw != NULL) {
854 		if (range != NULL || type != TYPE_INVAL || level != 0 ||
855 		    record.zi_cmd != ZINJECT_UNINITIALIZED) {
856 			(void) fprintf(stderr, "raw (-b) format with "
857 			    "any other options\n");
858 			usage();
859 			return (2);
860 		}
861 
862 		if (argc != 1) {
863 			(void) fprintf(stderr, "raw (-b) format expects a "
864 			    "single pool name\n");
865 			usage();
866 			return (2);
867 		}
868 
869 		(void) strcpy(pool, argv[0]);
870 		dataset[0] = '\0';
871 
872 		if (error == ENXIO) {
873 			(void) fprintf(stderr, "data error type must be "
874 			    "'checksum' or 'io'\n");
875 			return (1);
876 		}
877 
878 		record.zi_cmd = ZINJECT_DATA_FAULT;
879 		if (translate_raw(raw, &record) != 0)
880 			return (1);
881 		if (!error)
882 			error = EIO;
883 	} else if (record.zi_cmd == ZINJECT_PANIC) {
884 		if (raw != NULL || range != NULL || type != TYPE_INVAL ||
885 		    level != 0 || device != NULL) {
886 			(void) fprintf(stderr, "panic (-p) incompatible with "
887 			    "other options\n");
888 			usage();
889 			return (2);
890 		}
891 
892 		if (argc < 1 || argc > 2) {
893 			(void) fprintf(stderr, "panic (-p) injection requires "
894 			    "a single pool name and an optional id\n");
895 			usage();
896 			return (2);
897 		}
898 
899 		(void) strcpy(pool, argv[0]);
900 		if (argv[1] != NULL)
901 			record.zi_type = atoi(argv[1]);
902 		dataset[0] = '\0';
903 	} else if (record.zi_cmd == ZINJECT_IGNORED_WRITES) {
904 		if (nowrites == 0) {
905 			(void) fprintf(stderr, "-s or -g meaningless "
906 			    "without -I (ignore writes)\n");
907 			usage();
908 			return (2);
909 		} else if (dur_secs && dur_txg) {
910 			(void) fprintf(stderr, "choose a duration either "
911 			    "in seconds (-s) or a number of txgs (-g) "
912 			    "but not both\n");
913 			usage();
914 			return (2);
915 		} else if (argc != 1) {
916 			(void) fprintf(stderr, "ignore writes (-I) "
917 			    "injection requires a single pool name\n");
918 			usage();
919 			return (2);
920 		}
921 
922 		(void) strcpy(pool, argv[0]);
923 		dataset[0] = '\0';
924 	} else if (type == TYPE_INVAL) {
925 		if (flags == 0) {
926 			(void) fprintf(stderr, "at least one of '-b', '-d', "
927 			    "'-t', '-a', '-p', '-I' or '-u' "
928 			    "must be specified\n");
929 			usage();
930 			return (2);
931 		}
932 
933 		if (argc == 1 && (flags & ZINJECT_UNLOAD_SPA)) {
934 			(void) strcpy(pool, argv[0]);
935 			dataset[0] = '\0';
936 		} else if (argc != 0) {
937 			(void) fprintf(stderr, "extraneous argument for "
938 			    "'-f'\n");
939 			usage();
940 			return (2);
941 		}
942 
943 		flags |= ZINJECT_NULL;
944 	} else {
945 		if (argc != 1) {
946 			(void) fprintf(stderr, "missing object\n");
947 			usage();
948 			return (2);
949 		}
950 
951 		if (error == ENXIO) {
952 			(void) fprintf(stderr, "data error type must be "
953 			    "'checksum' or 'io'\n");
954 			return (1);
955 		}
956 
957 		record.zi_cmd = ZINJECT_DATA_FAULT;
958 		if (translate_record(type, argv[0], range, level, &record, pool,
959 		    dataset) != 0)
960 			return (1);
961 		if (!error)
962 			error = EIO;
963 	}
964 
965 	/*
966 	 * If this is pool-wide metadata, unmount everything.  The ioctl() will
967 	 * unload the pool, so that we trigger spa-wide reopen of metadata next
968 	 * time we access the pool.
969 	 */
970 	if (dataset[0] != '\0' && domount) {
971 		if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL)
972 			return (1);
973 
974 		if (zfs_unmount(zhp, NULL, 0) != 0)
975 			return (1);
976 	}
977 
978 	record.zi_error = error;
979 
980 	ret = register_handler(pool, flags, &record, quiet);
981 
982 	if (dataset[0] != '\0' && domount)
983 		ret = (zfs_mount(zhp, NULL, 0) != 0);
984 
985 	libzfs_fini(g_zfs);
986 
987 	return (ret);
988 }
989