]> git.proxmox.com Git - mirror_zfs.git/blame - cmd/zinject/zinject.c
Provide links to info about ZFS Buildbot options
[mirror_zfs.git] / cmd / zinject / zinject.c
CommitLineData
34dc7c2f
BB
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/*
428870ff 22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
26ef0cc7 23 * Copyright (c) 2012, 2015 by Delphix. All rights reserved.
34dc7c2f
BB
24 */
25
34dc7c2f
BB
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,
b128c09f 39 * that can be controlled through the '-e' option. The default is ENXIO. For
34dc7c2f
BB
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.
b128c09f 44 * For label faults, the -L option must be specified. This allows faults
428870ff
BB
45 * to be injected into either the nvlist, uberblock, pad1, or pad2 region
46 * of all the labels for the specified device.
34dc7c2f
BB
47 *
48 * This form of the command looks like:
49 *
428870ff 50 * zinject -d device [-e errno] [-L <uber | nvlist | pad1 | pad2>] pool
34dc7c2f
BB
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
428870ff 73 * bpobj blkptr list
34dc7c2f
BB
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/mount.h>
148
149#include <libzfs.h>
150
151#undef verify /* both libzfs.h and zfs_context.h want to define this */
152
153#include "zinject.h"
154
155libzfs_handle_t *g_zfs;
156int zfs_fd;
157
158#define ECKSUM EBADE
159
160static const char *errtable[TYPE_INVAL] = {
161 "data",
162 "dnode",
163 "mos",
164 "mosdir",
165 "metaslab",
166 "config",
428870ff 167 "bpobj",
34dc7c2f 168 "spacemap",
b128c09f
BB
169 "errlog",
170 "uber",
428870ff
BB
171 "nvlist",
172 "pad1",
173 "pad2"
34dc7c2f
BB
174};
175
176static err_type_t
177name_to_type(const char *arg)
178{
179 int i;
180 for (i = 0; i < TYPE_INVAL; i++)
181 if (strcmp(errtable[i], arg) == 0)
182 return (i);
183
184 return (TYPE_INVAL);
185}
186
187static const char *
188type_to_name(uint64_t type)
189{
190 switch (type) {
191 case DMU_OT_OBJECT_DIRECTORY:
192 return ("mosdir");
193 case DMU_OT_OBJECT_ARRAY:
194 return ("metaslab");
195 case DMU_OT_PACKED_NVLIST:
196 return ("config");
428870ff
BB
197 case DMU_OT_BPOBJ:
198 return ("bpobj");
34dc7c2f
BB
199 case DMU_OT_SPACE_MAP:
200 return ("spacemap");
201 case DMU_OT_ERROR_LOG:
202 return ("errlog");
203 default:
204 return ("-");
205 }
206}
207
208
209/*
210 * Print usage message.
211 */
212void
213usage(void)
214{
215 (void) printf(
216 "usage:\n"
217 "\n"
218 "\tzinject\n"
219 "\n"
220 "\t\tList all active injection records.\n"
221 "\n"
222 "\tzinject -c <id|all>\n"
223 "\n"
224 "\t\tClear the particular record (if given a numeric ID), or\n"
2627e752 225 "\t\tall records if 'all' is specified.\n"
34dc7c2f 226 "\n"
428870ff
BB
227 "\tzinject -p <function name> pool\n"
228 "\t\tInject a panic fault at the specified function. Only \n"
229 "\t\tfunctions which call spa_vdev_config_exit(), or \n"
230 "\t\tspa_vdev_exit() will trigger a panic.\n"
231 "\n"
232 "\tzinject -d device [-e errno] [-L <nvlist|uber|pad1|pad2>] [-F]\n"
233 "\t [-T <read|write|free|claim|all> pool\n"
b128c09f 234 "\t\tInject a fault into a particular device or the device's\n"
428870ff
BB
235 "\t\tlabel. Label injection can either be 'nvlist', 'uber',\n "
236 "\t\t'pad1', or 'pad2'.\n"
572e2857 237 "\t\t'errno' can be 'nxio' (the default), 'io', or 'dtl'.\n"
34dc7c2f 238 "\n"
cc92e9d0
GW
239 "\tzinject -d device -A <degrade|fault> -D <delay secs> pool\n"
240 "\t\tPerform a specific action on a particular device.\n"
428870ff 241 "\n"
26ef0cc7
TH
242 "\tzinject -d device -D latency:lanes pool\n"
243 "\n"
244 "\t\tAdd an artificial delay to IO requests on a particular\n"
245 "\t\tdevice, such that the requests take a minimum of 'latency'\n"
246 "\t\tmilliseconds to complete. Each delay has an associated\n"
247 "\t\tnumber of 'lanes' which defines the number of concurrent\n"
248 "\t\tIO requests that can be processed.\n"
249 "\n"
250 "\t\tFor example, with a single lane delay of 10 ms (-D 10:1),\n"
251 "\t\tthe device will only be able to service a single IO request\n"
252 "\t\tat a time with each request taking 10 ms to complete. So,\n"
253 "\t\tif only a single request is submitted every 10 ms, the\n"
254 "\t\taverage latency will be 10 ms; but if more than one request\n"
255 "\t\tis submitted every 10 ms, the average latency will be more\n"
256 "\t\tthan 10 ms.\n"
257 "\n"
258 "\t\tSimilarly, if a delay of 10 ms is specified to have two\n"
259 "\t\tlanes (-D 10:2), then the device will be able to service\n"
260 "\t\ttwo requests at a time, each with a minimum latency of\n"
261 "\t\t10 ms. So, if two requests are submitted every 10 ms, then\n"
262 "\t\tthe average latency will be 10 ms; but if more than two\n"
263 "\t\trequests are submitted every 10 ms, the average latency\n"
264 "\t\twill be more than 10 ms.\n"
265 "\n"
266 "\t\tAlso note, these delays are additive. So two invocations\n"
267 "\t\tof '-D 10:1', is roughly equivalent to a single invocation\n"
268 "\t\tof '-D 10:2'. This also means, one can specify multiple\n"
269 "\t\tlanes with differing target latencies. For example, an\n"
270 "\t\tinvocation of '-D 10:1' followed by '-D 25:2' will\n"
271 "\t\tcreate 3 lanes on the device; one lane with a latency\n"
272 "\t\tof 10 ms and two lanes with a 25 ms latency.\n"
273 "\n"
428870ff
BB
274 "\tzinject -I [-s <seconds> | -g <txgs>] pool\n"
275 "\t\tCause the pool to stop writing blocks yet not\n"
276 "\t\treport errors for a duration. Simulates buggy hardware\n"
277 "\t\tthat fails to honor cache flush requests.\n"
278 "\t\tDefault duration is 30 seconds. The machine is panicked\n"
279 "\t\tat the end of the duration.\n"
280 "\n"
34dc7c2f
BB
281 "\tzinject -b objset:object:level:blkid pool\n"
282 "\n"
283 "\t\tInject an error into pool 'pool' with the numeric bookmark\n"
284 "\t\tspecified by the remaining tuple. Each number is in\n"
4e33ba4c 285 "\t\thexadecimal, and only one block can be specified.\n"
34dc7c2f
BB
286 "\n"
287 "\tzinject [-q] <-t type> [-e errno] [-l level] [-r range]\n"
288 "\t [-a] [-m] [-u] [-f freq] <object>\n"
289 "\n"
290 "\t\tInject an error into the object specified by the '-t' option\n"
291 "\t\tand the object descriptor. The 'object' parameter is\n"
2627e752 292 "\t\tinterpreted depending on the '-t' option.\n"
34dc7c2f
BB
293 "\n"
294 "\t\t-q\tQuiet mode. Only print out the handler number added.\n"
295 "\t\t-e\tInject a specific error. Must be either 'io' or\n"
296 "\t\t\t'checksum'. Default is 'io'.\n"
297 "\t\t-l\tInject error at a particular block level. Default is "
298 "0.\n"
299 "\t\t-m\tAutomatically remount underlying filesystem.\n"
300 "\t\t-r\tInject error over a particular logical range of an\n"
301 "\t\t\tobject. Will be translated to the appropriate blkid\n"
302 "\t\t\trange according to the object's properties.\n"
303 "\t\t-a\tFlush the ARC cache. Can be specified without any\n"
304 "\t\t\tassociated object.\n"
305 "\t\t-u\tUnload the associated pool. Can be specified with only\n"
306 "\t\t\ta pool object.\n"
307 "\t\t-f\tOnly inject errors a fraction of the time. Expressed as\n"
308 "\t\t\ta percentage between 1 and 100.\n"
309 "\n"
310 "\t-t data\t\tInject an error into the plain file contents of a\n"
311 "\t\t\tfile. The object must be specified as a complete path\n"
312 "\t\t\tto a file on a ZFS filesystem.\n"
313 "\n"
314 "\t-t dnode\tInject an error into the metadnode in the block\n"
315 "\t\t\tcorresponding to the dnode for a file or directory. The\n"
316 "\t\t\t'-r' option is incompatible with this mode. The object\n"
317 "\t\t\tis specified as a complete path to a file or directory\n"
318 "\t\t\ton a ZFS filesystem.\n"
319 "\n"
320 "\t-t <mos>\tInject errors into the MOS for objects of the given\n"
428870ff 321 "\t\t\ttype. Valid types are: mos, mosdir, config, bpobj,\n"
34dc7c2f
BB
322 "\t\t\tspacemap, metaslab, errlog. The only valid <object> is\n"
323 "\t\t\tthe poolname.\n");
324}
325
326static int
327iter_handlers(int (*func)(int, const char *, zinject_record_t *, void *),
328 void *data)
329{
d3773fda 330 zfs_cmd_t zc = {"\0"};
34dc7c2f
BB
331 int ret;
332
34dc7c2f
BB
333 while (ioctl(zfs_fd, ZFS_IOC_INJECT_LIST_NEXT, &zc) == 0)
334 if ((ret = func((int)zc.zc_guid, zc.zc_name,
335 &zc.zc_inject_record, data)) != 0)
336 return (ret);
337
428870ff
BB
338 if (errno != ENOENT) {
339 (void) fprintf(stderr, "Unable to list handlers: %s\n",
340 strerror(errno));
341 return (-1);
342 }
343
34dc7c2f
BB
344 return (0);
345}
346
347static int
348print_data_handler(int id, const char *pool, zinject_record_t *record,
349 void *data)
350{
351 int *count = data;
352
428870ff 353 if (record->zi_guid != 0 || record->zi_func[0] != '\0')
34dc7c2f
BB
354 return (0);
355
356 if (*count == 0) {
357 (void) printf("%3s %-15s %-6s %-6s %-8s %3s %-15s\n",
358 "ID", "POOL", "OBJSET", "OBJECT", "TYPE", "LVL", "RANGE");
359 (void) printf("--- --------------- ------ "
360 "------ -------- --- ---------------\n");
361 }
362
363 *count += 1;
364
365 (void) printf("%3d %-15s %-6llu %-6llu %-8s %3d ", id, pool,
366 (u_longlong_t)record->zi_objset, (u_longlong_t)record->zi_object,
367 type_to_name(record->zi_type), record->zi_level);
368
369 if (record->zi_start == 0 &&
370 record->zi_end == -1ULL)
371 (void) printf("all\n");
372 else
373 (void) printf("[%llu, %llu]\n", (u_longlong_t)record->zi_start,
374 (u_longlong_t)record->zi_end);
375
376 return (0);
377}
378
379static int
380print_device_handler(int id, const char *pool, zinject_record_t *record,
381 void *data)
382{
383 int *count = data;
384
428870ff 385 if (record->zi_guid == 0 || record->zi_func[0] != '\0')
34dc7c2f
BB
386 return (0);
387
26ef0cc7
TH
388 if (record->zi_cmd == ZINJECT_DELAY_IO)
389 return (0);
390
34dc7c2f
BB
391 if (*count == 0) {
392 (void) printf("%3s %-15s %s\n", "ID", "POOL", "GUID");
393 (void) printf("--- --------------- ----------------\n");
394 }
395
396 *count += 1;
397
398 (void) printf("%3d %-15s %llx\n", id, pool,
399 (u_longlong_t)record->zi_guid);
400
401 return (0);
402}
403
26ef0cc7
TH
404static int
405print_delay_handler(int id, const char *pool, zinject_record_t *record,
406 void *data)
407{
408 int *count = data;
409
410 if (record->zi_guid == 0 || record->zi_func[0] != '\0')
411 return (0);
412
413 if (record->zi_cmd != ZINJECT_DELAY_IO)
414 return (0);
415
416 if (*count == 0) {
417 (void) printf("%3s %-15s %-15s %-15s %s\n",
418 "ID", "POOL", "DELAY (ms)", "LANES", "GUID");
419 (void) printf("--- --------------- --------------- "
420 "--------------- ----------------\n");
421 }
422
423 *count += 1;
424
425 (void) printf("%3d %-15s %-15llu %-15llu %llx\n", id, pool,
426 (u_longlong_t)NSEC2MSEC(record->zi_timer),
427 (u_longlong_t)record->zi_nlanes,
428 (u_longlong_t)record->zi_guid);
429
430 return (0);
431}
432
428870ff
BB
433static int
434print_panic_handler(int id, const char *pool, zinject_record_t *record,
435 void *data)
436{
437 int *count = data;
438
439 if (record->zi_func[0] == '\0')
440 return (0);
441
442 if (*count == 0) {
443 (void) printf("%3s %-15s %s\n", "ID", "POOL", "FUNCTION");
444 (void) printf("--- --------------- ----------------\n");
445 }
446
447 *count += 1;
448
449 (void) printf("%3d %-15s %s\n", id, pool, record->zi_func);
450
451 return (0);
452}
453
34dc7c2f
BB
454/*
455 * Print all registered error handlers. Returns the number of handlers
456 * registered.
457 */
458static int
459print_all_handlers(void)
460{
572e2857 461 int count = 0, total = 0;
34dc7c2f
BB
462
463 (void) iter_handlers(print_device_handler, &count);
572e2857
BB
464 if (count > 0) {
465 total += count;
466 (void) printf("\n");
467 count = 0;
468 }
469
26ef0cc7
TH
470 (void) iter_handlers(print_delay_handler, &count);
471 if (count > 0) {
472 total += count;
473 (void) printf("\n");
474 count = 0;
475 }
476
34dc7c2f 477 (void) iter_handlers(print_data_handler, &count);
572e2857
BB
478 if (count > 0) {
479 total += count;
480 (void) printf("\n");
481 count = 0;
482 }
483
428870ff 484 (void) iter_handlers(print_panic_handler, &count);
34dc7c2f 485
572e2857 486 return (count + total);
34dc7c2f
BB
487}
488
489/* ARGSUSED */
490static int
491cancel_one_handler(int id, const char *pool, zinject_record_t *record,
492 void *data)
493{
d3773fda 494 zfs_cmd_t zc = {"\0"};
34dc7c2f
BB
495
496 zc.zc_guid = (uint64_t)id;
497
498 if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
499 (void) fprintf(stderr, "failed to remove handler %d: %s\n",
500 id, strerror(errno));
501 return (1);
502 }
503
504 return (0);
505}
506
507/*
508 * Remove all fault injection handlers.
509 */
510static int
511cancel_all_handlers(void)
512{
513 int ret = iter_handlers(cancel_one_handler, NULL);
514
428870ff
BB
515 if (ret == 0)
516 (void) printf("removed all registered handlers\n");
34dc7c2f
BB
517
518 return (ret);
519}
520
521/*
522 * Remove a specific fault injection handler.
523 */
524static int
525cancel_handler(int id)
526{
d3773fda 527 zfs_cmd_t zc = {"\0"};
34dc7c2f
BB
528
529 zc.zc_guid = (uint64_t)id;
530
531 if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
532 (void) fprintf(stderr, "failed to remove handler %d: %s\n",
533 id, strerror(errno));
534 return (1);
535 }
536
537 (void) printf("removed handler %d\n", id);
538
539 return (0);
540}
541
542/*
543 * Register a new fault injection handler.
544 */
545static int
546register_handler(const char *pool, int flags, zinject_record_t *record,
547 int quiet)
548{
d3773fda 549 zfs_cmd_t zc = {"\0"};
34dc7c2f 550
0b78aeae 551 (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
34dc7c2f
BB
552 zc.zc_inject_record = *record;
553 zc.zc_guid = flags;
554
555 if (ioctl(zfs_fd, ZFS_IOC_INJECT_FAULT, &zc) != 0) {
556 (void) fprintf(stderr, "failed to add handler: %s\n",
557 strerror(errno));
558 return (1);
559 }
560
561 if (flags & ZINJECT_NULL)
562 return (0);
563
564 if (quiet) {
565 (void) printf("%llu\n", (u_longlong_t)zc.zc_guid);
566 } else {
567 (void) printf("Added handler %llu with the following "
568 "properties:\n", (u_longlong_t)zc.zc_guid);
569 (void) printf(" pool: %s\n", pool);
570 if (record->zi_guid) {
571 (void) printf(" vdev: %llx\n",
572 (u_longlong_t)record->zi_guid);
428870ff
BB
573 } else if (record->zi_func[0] != '\0') {
574 (void) printf(" panic function: %s\n",
575 record->zi_func);
576 } else if (record->zi_duration > 0) {
577 (void) printf(" time: %lld seconds\n",
578 (u_longlong_t)record->zi_duration);
579 } else if (record->zi_duration < 0) {
580 (void) printf(" txgs: %lld \n",
581 (u_longlong_t)-record->zi_duration);
34dc7c2f
BB
582 } else {
583 (void) printf("objset: %llu\n",
584 (u_longlong_t)record->zi_objset);
585 (void) printf("object: %llu\n",
586 (u_longlong_t)record->zi_object);
587 (void) printf(" type: %llu\n",
588 (u_longlong_t)record->zi_type);
589 (void) printf(" level: %d\n", record->zi_level);
590 if (record->zi_start == 0 &&
591 record->zi_end == -1ULL)
592 (void) printf(" range: all\n");
593 else
594 (void) printf(" range: [%llu, %llu)\n",
595 (u_longlong_t)record->zi_start,
596 (u_longlong_t)record->zi_end);
597 }
598 }
599
600 return (0);
601}
602
428870ff
BB
603int
604perform_action(const char *pool, zinject_record_t *record, int cmd)
605{
d3773fda 606 zfs_cmd_t zc = {"\0"};
428870ff
BB
607
608 ASSERT(cmd == VDEV_STATE_DEGRADED || cmd == VDEV_STATE_FAULTED);
609 (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
610 zc.zc_guid = record->zi_guid;
611 zc.zc_cookie = cmd;
612
613 if (ioctl(zfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
614 return (0);
615
616 return (1);
617}
618
26ef0cc7
TH
619static int
620parse_delay(char *str, uint64_t *delay, uint64_t *nlanes)
621{
622 unsigned long scan_delay;
623 unsigned long scan_nlanes;
624
625 if (sscanf(str, "%lu:%lu", &scan_delay, &scan_nlanes) != 2)
626 return (1);
627
628 /*
629 * We explicitly disallow a delay of zero here, because we key
630 * off this value being non-zero in translate_device(), to
631 * determine if the fault is a ZINJECT_DELAY_IO fault or not.
632 */
633 if (scan_delay == 0)
634 return (1);
635
636 /*
637 * The units for the CLI delay parameter is milliseconds, but
638 * the data passed to the kernel is interpreted as nanoseconds.
639 * Thus we scale the milliseconds to nanoseconds here, and this
640 * nanosecond value is used to pass the delay to the kernel.
641 */
642 *delay = MSEC2NSEC(scan_delay);
643 *nlanes = scan_nlanes;
644
645 return (0);
646}
647
34dc7c2f
BB
648int
649main(int argc, char **argv)
650{
651 int c;
652 char *range = NULL;
653 char *cancel = NULL;
654 char *end;
655 char *raw = NULL;
656 char *device = NULL;
657 int level = 0;
658 int quiet = 0;
659 int error = 0;
660 int domount = 0;
428870ff
BB
661 int io_type = ZIO_TYPES;
662 int action = VDEV_STATE_UNKNOWN;
34dc7c2f 663 err_type_t type = TYPE_INVAL;
b128c09f 664 err_type_t label = TYPE_INVAL;
34dc7c2f 665 zinject_record_t record = { 0 };
a64f903b
GN
666 char pool[MAXNAMELEN] = "";
667 char dataset[MAXNAMELEN] = "";
149e873a 668 zfs_handle_t *zhp = NULL;
428870ff
BB
669 int nowrites = 0;
670 int dur_txg = 0;
671 int dur_secs = 0;
34dc7c2f
BB
672 int ret;
673 int flags = 0;
674
65037d9b
BB
675 if ((g_zfs = libzfs_init()) == NULL) {
676 (void) fprintf(stderr, "%s", libzfs_error_init(errno));
937210a5 677 return (1);
65037d9b 678 }
937210a5
BB
679
680 libzfs_print_on_error(g_zfs, B_TRUE);
681
682 if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
683 (void) fprintf(stderr, "failed to open ZFS device\n");
5df39c1e 684 libzfs_fini(g_zfs);
937210a5
BB
685 return (1);
686 }
687
34dc7c2f
BB
688 if (argc == 1) {
689 /*
690 * No arguments. Print the available handlers. If there are no
691 * available handlers, direct the user to '-h' for help
692 * information.
693 */
694 if (print_all_handlers() == 0) {
695 (void) printf("No handlers registered.\n");
696 (void) printf("Run 'zinject -h' for usage "
697 "information.\n");
698 }
5df39c1e 699 libzfs_fini(g_zfs);
34dc7c2f
BB
700 return (0);
701 }
702
428870ff 703 while ((c = getopt(argc, argv,
cc92e9d0 704 ":aA:b:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:")) != -1) {
34dc7c2f
BB
705 switch (c) {
706 case 'a':
707 flags |= ZINJECT_FLUSH_ARC;
708 break;
428870ff
BB
709 case 'A':
710 if (strcasecmp(optarg, "degrade") == 0) {
711 action = VDEV_STATE_DEGRADED;
712 } else if (strcasecmp(optarg, "fault") == 0) {
713 action = VDEV_STATE_FAULTED;
714 } else {
715 (void) fprintf(stderr, "invalid action '%s': "
716 "must be 'degrade' or 'fault'\n", optarg);
717 usage();
5df39c1e 718 libzfs_fini(g_zfs);
428870ff
BB
719 return (1);
720 }
721 break;
34dc7c2f
BB
722 case 'b':
723 raw = optarg;
724 break;
725 case 'c':
726 cancel = optarg;
727 break;
728 case 'd':
729 device = optarg;
730 break;
cc92e9d0
GW
731 case 'D':
732 errno = 0;
26ef0cc7
TH
733 ret = parse_delay(optarg, &record.zi_timer,
734 &record.zi_nlanes);
735 if (ret != 0) {
736
cc92e9d0
GW
737 (void) fprintf(stderr, "invalid i/o delay "
738 "value: '%s'\n", optarg);
739 usage();
5df39c1e 740 libzfs_fini(g_zfs);
cc92e9d0
GW
741 return (1);
742 }
743 break;
34dc7c2f
BB
744 case 'e':
745 if (strcasecmp(optarg, "io") == 0) {
746 error = EIO;
747 } else if (strcasecmp(optarg, "checksum") == 0) {
748 error = ECKSUM;
749 } else if (strcasecmp(optarg, "nxio") == 0) {
750 error = ENXIO;
572e2857
BB
751 } else if (strcasecmp(optarg, "dtl") == 0) {
752 error = ECHILD;
34dc7c2f
BB
753 } else {
754 (void) fprintf(stderr, "invalid error type "
755 "'%s': must be 'io', 'checksum' or "
756 "'nxio'\n", optarg);
757 usage();
5df39c1e 758 libzfs_fini(g_zfs);
34dc7c2f
BB
759 return (1);
760 }
761 break;
762 case 'f':
763 record.zi_freq = atoi(optarg);
764 if (record.zi_freq < 1 || record.zi_freq > 100) {
765 (void) fprintf(stderr, "frequency range must "
766 "be in the range (0, 100]\n");
5df39c1e 767 libzfs_fini(g_zfs);
34dc7c2f
BB
768 return (1);
769 }
770 break;
9babb374
BB
771 case 'F':
772 record.zi_failfast = B_TRUE;
773 break;
428870ff
BB
774 case 'g':
775 dur_txg = 1;
776 record.zi_duration = (int)strtol(optarg, &end, 10);
777 if (record.zi_duration <= 0 || *end != '\0') {
778 (void) fprintf(stderr, "invalid duration '%s': "
779 "must be a positive integer\n", optarg);
780 usage();
5df39c1e 781 libzfs_fini(g_zfs);
428870ff
BB
782 return (1);
783 }
784 /* store duration of txgs as its negative */
785 record.zi_duration *= -1;
786 break;
34dc7c2f
BB
787 case 'h':
788 usage();
5df39c1e 789 libzfs_fini(g_zfs);
34dc7c2f 790 return (0);
428870ff
BB
791 case 'I':
792 /* default duration, if one hasn't yet been defined */
793 nowrites = 1;
794 if (dur_secs == 0 && dur_txg == 0)
795 record.zi_duration = 30;
796 break;
34dc7c2f
BB
797 case 'l':
798 level = (int)strtol(optarg, &end, 10);
799 if (*end != '\0') {
800 (void) fprintf(stderr, "invalid level '%s': "
801 "must be an integer\n", optarg);
802 usage();
5df39c1e 803 libzfs_fini(g_zfs);
34dc7c2f
BB
804 return (1);
805 }
806 break;
807 case 'm':
808 domount = 1;
809 break;
428870ff
BB
810 case 'p':
811 (void) strlcpy(record.zi_func, optarg,
812 sizeof (record.zi_func));
cc92e9d0 813 record.zi_cmd = ZINJECT_PANIC;
428870ff 814 break;
34dc7c2f
BB
815 case 'q':
816 quiet = 1;
817 break;
818 case 'r':
819 range = optarg;
820 break;
428870ff
BB
821 case 's':
822 dur_secs = 1;
823 record.zi_duration = (int)strtol(optarg, &end, 10);
824 if (record.zi_duration <= 0 || *end != '\0') {
825 (void) fprintf(stderr, "invalid duration '%s': "
826 "must be a positive integer\n", optarg);
827 usage();
5df39c1e 828 libzfs_fini(g_zfs);
428870ff
BB
829 return (1);
830 }
831 break;
832 case 'T':
833 if (strcasecmp(optarg, "read") == 0) {
834 io_type = ZIO_TYPE_READ;
835 } else if (strcasecmp(optarg, "write") == 0) {
836 io_type = ZIO_TYPE_WRITE;
837 } else if (strcasecmp(optarg, "free") == 0) {
838 io_type = ZIO_TYPE_FREE;
839 } else if (strcasecmp(optarg, "claim") == 0) {
840 io_type = ZIO_TYPE_CLAIM;
841 } else if (strcasecmp(optarg, "all") == 0) {
842 io_type = ZIO_TYPES;
843 } else {
844 (void) fprintf(stderr, "invalid I/O type "
845 "'%s': must be 'read', 'write', 'free', "
846 "'claim' or 'all'\n", optarg);
847 usage();
5df39c1e 848 libzfs_fini(g_zfs);
428870ff
BB
849 return (1);
850 }
851 break;
34dc7c2f 852 case 't':
b128c09f
BB
853 if ((type = name_to_type(optarg)) == TYPE_INVAL &&
854 !MOS_TYPE(type)) {
34dc7c2f
BB
855 (void) fprintf(stderr, "invalid type '%s'\n",
856 optarg);
857 usage();
5df39c1e 858 libzfs_fini(g_zfs);
34dc7c2f
BB
859 return (1);
860 }
861 break;
862 case 'u':
863 flags |= ZINJECT_UNLOAD_SPA;
864 break;
b128c09f
BB
865 case 'L':
866 if ((label = name_to_type(optarg)) == TYPE_INVAL &&
867 !LABEL_TYPE(type)) {
868 (void) fprintf(stderr, "invalid label type "
869 "'%s'\n", optarg);
870 usage();
5df39c1e 871 libzfs_fini(g_zfs);
b128c09f
BB
872 return (1);
873 }
874 break;
34dc7c2f
BB
875 case ':':
876 (void) fprintf(stderr, "option -%c requires an "
877 "operand\n", optopt);
878 usage();
5df39c1e 879 libzfs_fini(g_zfs);
34dc7c2f
BB
880 return (1);
881 case '?':
882 (void) fprintf(stderr, "invalid option '%c'\n",
883 optopt);
884 usage();
5df39c1e 885 libzfs_fini(g_zfs);
34dc7c2f
BB
886 return (2);
887 }
888 }
889
890 argc -= optind;
891 argv += optind;
892
cc92e9d0
GW
893 if (record.zi_duration != 0)
894 record.zi_cmd = ZINJECT_IGNORED_WRITES;
895
34dc7c2f
BB
896 if (cancel != NULL) {
897 /*
898 * '-c' is invalid with any other options.
899 */
900 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
cc92e9d0 901 level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
34dc7c2f
BB
902 (void) fprintf(stderr, "cancel (-c) incompatible with "
903 "any other options\n");
904 usage();
5df39c1e 905 libzfs_fini(g_zfs);
34dc7c2f
BB
906 return (2);
907 }
908 if (argc != 0) {
909 (void) fprintf(stderr, "extraneous argument to '-c'\n");
910 usage();
5df39c1e 911 libzfs_fini(g_zfs);
34dc7c2f
BB
912 return (2);
913 }
914
915 if (strcmp(cancel, "all") == 0) {
916 return (cancel_all_handlers());
917 } else {
918 int id = (int)strtol(cancel, &end, 10);
919 if (*end != '\0') {
920 (void) fprintf(stderr, "invalid handle id '%s':"
921 " must be an integer or 'all'\n", cancel);
922 usage();
5df39c1e 923 libzfs_fini(g_zfs);
34dc7c2f
BB
924 return (1);
925 }
926 return (cancel_handler(id));
927 }
928 }
929
930 if (device != NULL) {
931 /*
932 * Device (-d) injection uses a completely different mechanism
933 * for doing injection, so handle it separately here.
934 */
935 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
cc92e9d0 936 level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) {
34dc7c2f
BB
937 (void) fprintf(stderr, "device (-d) incompatible with "
938 "data error injection\n");
939 usage();
5df39c1e 940 libzfs_fini(g_zfs);
34dc7c2f
BB
941 return (2);
942 }
943
944 if (argc != 1) {
945 (void) fprintf(stderr, "device (-d) injection requires "
946 "a single pool name\n");
947 usage();
5df39c1e 948 libzfs_fini(g_zfs);
34dc7c2f
BB
949 return (2);
950 }
951
5df39c1e 952 (void) strlcpy(pool, argv[0], sizeof (pool));
34dc7c2f
BB
953 dataset[0] = '\0';
954
955 if (error == ECKSUM) {
956 (void) fprintf(stderr, "device error type must be "
957 "'io' or 'nxio'\n");
5df39c1e 958 libzfs_fini(g_zfs);
34dc7c2f
BB
959 return (1);
960 }
961
428870ff 962 record.zi_iotype = io_type;
5df39c1e 963 if (translate_device(pool, device, label, &record) != 0) {
964 libzfs_fini(g_zfs);
34dc7c2f 965 return (1);
5df39c1e 966 }
34dc7c2f
BB
967 if (!error)
968 error = ENXIO;
428870ff
BB
969
970 if (action != VDEV_STATE_UNKNOWN)
971 return (perform_action(pool, &record, action));
972
34dc7c2f 973 } else if (raw != NULL) {
428870ff 974 if (range != NULL || type != TYPE_INVAL || level != 0 ||
cc92e9d0 975 record.zi_cmd != ZINJECT_UNINITIALIZED) {
34dc7c2f
BB
976 (void) fprintf(stderr, "raw (-b) format with "
977 "any other options\n");
978 usage();
5df39c1e 979 libzfs_fini(g_zfs);
34dc7c2f
BB
980 return (2);
981 }
982
983 if (argc != 1) {
984 (void) fprintf(stderr, "raw (-b) format expects a "
985 "single pool name\n");
986 usage();
5df39c1e 987 libzfs_fini(g_zfs);
34dc7c2f
BB
988 return (2);
989 }
990
5df39c1e 991 (void) strlcpy(pool, argv[0], sizeof (pool));
34dc7c2f
BB
992 dataset[0] = '\0';
993
994 if (error == ENXIO) {
995 (void) fprintf(stderr, "data error type must be "
996 "'checksum' or 'io'\n");
5df39c1e 997 libzfs_fini(g_zfs);
34dc7c2f
BB
998 return (1);
999 }
1000
cc92e9d0 1001 record.zi_cmd = ZINJECT_DATA_FAULT;
5df39c1e 1002 if (translate_raw(raw, &record) != 0) {
1003 libzfs_fini(g_zfs);
34dc7c2f 1004 return (1);
5df39c1e 1005 }
34dc7c2f
BB
1006 if (!error)
1007 error = EIO;
cc92e9d0 1008 } else if (record.zi_cmd == ZINJECT_PANIC) {
428870ff 1009 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
cc92e9d0 1010 level != 0 || device != NULL) {
428870ff
BB
1011 (void) fprintf(stderr, "panic (-p) incompatible with "
1012 "other options\n");
1013 usage();
5df39c1e 1014 libzfs_fini(g_zfs);
428870ff
BB
1015 return (2);
1016 }
1017
1018 if (argc < 1 || argc > 2) {
1019 (void) fprintf(stderr, "panic (-p) injection requires "
1020 "a single pool name and an optional id\n");
1021 usage();
5df39c1e 1022 libzfs_fini(g_zfs);
428870ff
BB
1023 return (2);
1024 }
1025
5df39c1e 1026 (void) strlcpy(pool, argv[0], sizeof (pool));
428870ff
BB
1027 if (argv[1] != NULL)
1028 record.zi_type = atoi(argv[1]);
1029 dataset[0] = '\0';
cc92e9d0 1030 } else if (record.zi_cmd == ZINJECT_IGNORED_WRITES) {
428870ff
BB
1031 if (nowrites == 0) {
1032 (void) fprintf(stderr, "-s or -g meaningless "
1033 "without -I (ignore writes)\n");
1034 usage();
5df39c1e 1035 libzfs_fini(g_zfs);
428870ff
BB
1036 return (2);
1037 } else if (dur_secs && dur_txg) {
1038 (void) fprintf(stderr, "choose a duration either "
1039 "in seconds (-s) or a number of txgs (-g) "
1040 "but not both\n");
1041 usage();
5df39c1e 1042 libzfs_fini(g_zfs);
428870ff
BB
1043 return (2);
1044 } else if (argc != 1) {
1045 (void) fprintf(stderr, "ignore writes (-I) "
1046 "injection requires a single pool name\n");
1047 usage();
5df39c1e 1048 libzfs_fini(g_zfs);
428870ff
BB
1049 return (2);
1050 }
1051
5df39c1e 1052 (void) strlcpy(pool, argv[0], sizeof (pool));
428870ff 1053 dataset[0] = '\0';
34dc7c2f
BB
1054 } else if (type == TYPE_INVAL) {
1055 if (flags == 0) {
1056 (void) fprintf(stderr, "at least one of '-b', '-d', "
428870ff
BB
1057 "'-t', '-a', '-p', '-I' or '-u' "
1058 "must be specified\n");
34dc7c2f 1059 usage();
5df39c1e 1060 libzfs_fini(g_zfs);
34dc7c2f
BB
1061 return (2);
1062 }
1063
1064 if (argc == 1 && (flags & ZINJECT_UNLOAD_SPA)) {
5df39c1e 1065 (void) strlcpy(pool, argv[0], sizeof (pool));
34dc7c2f
BB
1066 dataset[0] = '\0';
1067 } else if (argc != 0) {
1068 (void) fprintf(stderr, "extraneous argument for "
1069 "'-f'\n");
1070 usage();
5df39c1e 1071 libzfs_fini(g_zfs);
34dc7c2f
BB
1072 return (2);
1073 }
1074
1075 flags |= ZINJECT_NULL;
1076 } else {
1077 if (argc != 1) {
1078 (void) fprintf(stderr, "missing object\n");
1079 usage();
5df39c1e 1080 libzfs_fini(g_zfs);
34dc7c2f
BB
1081 return (2);
1082 }
1083
1084 if (error == ENXIO) {
1085 (void) fprintf(stderr, "data error type must be "
1086 "'checksum' or 'io'\n");
5df39c1e 1087 libzfs_fini(g_zfs);
34dc7c2f
BB
1088 return (1);
1089 }
1090
cc92e9d0 1091 record.zi_cmd = ZINJECT_DATA_FAULT;
34dc7c2f 1092 if (translate_record(type, argv[0], range, level, &record, pool,
5df39c1e 1093 dataset) != 0) {
02730c33 1094 libzfs_fini(g_zfs);
34dc7c2f 1095 return (1);
5df39c1e 1096 }
34dc7c2f
BB
1097 if (!error)
1098 error = EIO;
1099 }
1100
1101 /*
1102 * If this is pool-wide metadata, unmount everything. The ioctl() will
1103 * unload the pool, so that we trigger spa-wide reopen of metadata next
1104 * time we access the pool.
1105 */
1106 if (dataset[0] != '\0' && domount) {
5df39c1e 1107 if ((zhp = zfs_open(g_zfs, dataset,
02730c33 1108 ZFS_TYPE_DATASET)) == NULL) {
5df39c1e 1109 libzfs_fini(g_zfs);
34dc7c2f 1110 return (1);
5df39c1e 1111 }
1112 if (zfs_unmount(zhp, NULL, 0) != 0) {
1113 libzfs_fini(g_zfs);
34dc7c2f 1114 return (1);
5df39c1e 1115 }
34dc7c2f
BB
1116 }
1117
1118 record.zi_error = error;
1119
1120 ret = register_handler(pool, flags, &record, quiet);
1121
1122 if (dataset[0] != '\0' && domount)
1123 ret = (zfs_mount(zhp, NULL, 0) != 0);
1124
1125 libzfs_fini(g_zfs);
1126
1127 return (ret);
1128}