]> git.proxmox.com Git - mirror_zfs-debian.git/blob - cmd/zinject/zinject.c
02dc18b9c841fbf136d54bdbd3d3c538f237a446
[mirror_zfs-debian.git] / cmd / zinject / zinject.c
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 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 /*
29 * ZFS Fault Injector
30 *
31 * This userland component takes a set of options and uses libzpool to translate
32 * from a user-visible object type and name to an internal representation.
33 * There are two basic types of faults: device faults and data faults.
34 *
35 *
36 * DEVICE FAULTS
37 *
38 * Errors can be injected into a particular vdev using the '-d' option. This
39 * option takes a path or vdev GUID to uniquely identify the device within a
40 * pool. There are two types of errors that can be injected, EIO and ENXIO,
41 * that can be controlled through the '-e' option. The default is ENXIO. For
42 * EIO failures, any attempt to read data from the device will return EIO, but
43 * subsequent attempt to reopen the device will succeed. For ENXIO failures,
44 * any attempt to read from the device will return EIO, but any attempt to
45 * reopen the device will also return ENXIO.
46 * For label faults, the -L option must be specified. This allows faults
47 * to be injected into either the nvlist or uberblock region of all the labels
48 * for the specified device.
49 *
50 * This form of the command looks like:
51 *
52 * zinject -d device [-e errno] [-L <uber | nvlist>] pool
53 *
54 *
55 * DATA FAULTS
56 *
57 * We begin with a tuple of the form:
58 *
59 * <type,level,range,object>
60 *
61 * type A string describing the type of data to target. Each type
62 * implicitly describes how to interpret 'object'. Currently,
63 * the following values are supported:
64 *
65 * data User data for a file
66 * dnode Dnode for a file or directory
67 *
68 * The following MOS objects are special. Instead of injecting
69 * errors on a particular object or blkid, we inject errors across
70 * all objects of the given type.
71 *
72 * mos Any data in the MOS
73 * mosdir object directory
74 * config pool configuration
75 * bplist blkptr list
76 * spacemap spacemap
77 * metaslab metaslab
78 * errlog persistent error log
79 *
80 * level Object level. Defaults to '0', not applicable to all types. If
81 * a range is given, this corresponds to the indirect block
82 * corresponding to the specific range.
83 *
84 * range A numerical range [start,end) within the object. Defaults to
85 * the full size of the file.
86 *
87 * object A string describing the logical location of the object. For
88 * files and directories (currently the only supported types),
89 * this is the path of the object on disk.
90 *
91 * This is translated, via libzpool, into the following internal representation:
92 *
93 * <type,objset,object,level,range>
94 *
95 * These types should be self-explanatory. This tuple is then passed to the
96 * kernel via a special ioctl() to initiate fault injection for the given
97 * object. Note that 'type' is not strictly necessary for fault injection, but
98 * is used when translating existing faults into a human-readable string.
99 *
100 *
101 * The command itself takes one of the forms:
102 *
103 * zinject
104 * zinject <-a | -u pool>
105 * zinject -c <id|all>
106 * zinject [-q] <-t type> [-f freq] [-u] [-a] [-m] [-e errno] [-l level]
107 * [-r range] <object>
108 * zinject [-f freq] [-a] [-m] [-u] -b objset:object:level:start:end pool
109 *
110 * With no arguments, the command prints all currently registered injection
111 * handlers, with their numeric identifiers.
112 *
113 * The '-c' option will clear the given handler, or all handlers if 'all' is
114 * specified.
115 *
116 * The '-e' option takes a string describing the errno to simulate. This must
117 * be either 'io' or 'checksum'. In most cases this will result in the same
118 * behavior, but RAID-Z will produce a different set of ereports for this
119 * situation.
120 *
121 * The '-a', '-u', and '-m' flags toggle internal flush behavior. If '-a' is
122 * specified, then the ARC cache is flushed appropriately. If '-u' is
123 * specified, then the underlying SPA is unloaded. Either of these flags can be
124 * specified independently of any other handlers. The '-m' flag automatically
125 * does an unmount and remount of the underlying dataset to aid in flushing the
126 * cache.
127 *
128 * The '-f' flag controls the frequency of errors injected, expressed as a
129 * integer percentage between 1 and 100. The default is 100.
130 *
131 * The this form is responsible for actually injecting the handler into the
132 * framework. It takes the arguments described above, translates them to the
133 * internal tuple using libzpool, and then issues an ioctl() to register the
134 * handler.
135 *
136 * The final form can target a specific bookmark, regardless of whether a
137 * human-readable interface has been designed. It allows developers to specify
138 * a particular block by number.
139 */
140
141 #include <errno.h>
142 #include <fcntl.h>
143 #include <stdio.h>
144 #include <stdlib.h>
145 #include <strings.h>
146 #include <unistd.h>
147
148 #include <sys/fs/zfs.h>
149 #include <sys/mount.h>
150
151 #include <libzfs.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 #define ECKSUM EBADE
161
162 static const char *errtable[TYPE_INVAL] = {
163 "data",
164 "dnode",
165 "mos",
166 "mosdir",
167 "metaslab",
168 "config",
169 "bplist",
170 "spacemap",
171 "errlog",
172 "uber",
173 "nvlist"
174 };
175
176 static err_type_t
177 name_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
187 static const char *
188 type_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");
197 case DMU_OT_BPLIST:
198 return ("bplist");
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 */
212 void
213 usage(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"
225 "\t\tall records if 'all' is specificed.\n"
226 "\n"
227 "\tzinject -d device [-e errno] [-L <nvlist|uber>] pool\n"
228 "\t\tInject a fault into a particular device or the device's\n"
229 "\t\tlabel. Label injection can either be 'nvlist' or 'uber'.\n"
230 "\t\t'errno' can either be 'nxio' (the default) or 'io'.\n"
231 "\n"
232 "\tzinject -b objset:object:level:blkid pool\n"
233 "\n"
234 "\t\tInject an error into pool 'pool' with the numeric bookmark\n"
235 "\t\tspecified by the remaining tuple. Each number is in\n"
236 "\t\thexidecimal, and only one block can be specified.\n"
237 "\n"
238 "\tzinject [-q] <-t type> [-e errno] [-l level] [-r range]\n"
239 "\t [-a] [-m] [-u] [-f freq] <object>\n"
240 "\n"
241 "\t\tInject an error into the object specified by the '-t' option\n"
242 "\t\tand the object descriptor. The 'object' parameter is\n"
243 "\t\tinterperted depending on the '-t' option.\n"
244 "\n"
245 "\t\t-q\tQuiet mode. Only print out the handler number added.\n"
246 "\t\t-e\tInject a specific error. Must be either 'io' or\n"
247 "\t\t\t'checksum'. Default is 'io'.\n"
248 "\t\t-l\tInject error at a particular block level. Default is "
249 "0.\n"
250 "\t\t-m\tAutomatically remount underlying filesystem.\n"
251 "\t\t-r\tInject error over a particular logical range of an\n"
252 "\t\t\tobject. Will be translated to the appropriate blkid\n"
253 "\t\t\trange according to the object's properties.\n"
254 "\t\t-a\tFlush the ARC cache. Can be specified without any\n"
255 "\t\t\tassociated object.\n"
256 "\t\t-u\tUnload the associated pool. Can be specified with only\n"
257 "\t\t\ta pool object.\n"
258 "\t\t-f\tOnly inject errors a fraction of the time. Expressed as\n"
259 "\t\t\ta percentage between 1 and 100.\n"
260 "\n"
261 "\t-t data\t\tInject an error into the plain file contents of a\n"
262 "\t\t\tfile. The object must be specified as a complete path\n"
263 "\t\t\tto a file on a ZFS filesystem.\n"
264 "\n"
265 "\t-t dnode\tInject an error into the metadnode in the block\n"
266 "\t\t\tcorresponding to the dnode for a file or directory. The\n"
267 "\t\t\t'-r' option is incompatible with this mode. The object\n"
268 "\t\t\tis specified as a complete path to a file or directory\n"
269 "\t\t\ton a ZFS filesystem.\n"
270 "\n"
271 "\t-t <mos>\tInject errors into the MOS for objects of the given\n"
272 "\t\t\ttype. Valid types are: mos, mosdir, config, bplist,\n"
273 "\t\t\tspacemap, metaslab, errlog. The only valid <object> is\n"
274 "\t\t\tthe poolname.\n");
275 }
276
277 static int
278 iter_handlers(int (*func)(int, const char *, zinject_record_t *, void *),
279 void *data)
280 {
281 zfs_cmd_t zc;
282 int ret;
283
284 zc.zc_guid = 0;
285
286 while (ioctl(zfs_fd, ZFS_IOC_INJECT_LIST_NEXT, &zc) == 0)
287 if ((ret = func((int)zc.zc_guid, zc.zc_name,
288 &zc.zc_inject_record, data)) != 0)
289 return (ret);
290
291 return (0);
292 }
293
294 static int
295 print_data_handler(int id, const char *pool, zinject_record_t *record,
296 void *data)
297 {
298 int *count = data;
299
300 if (record->zi_guid != 0)
301 return (0);
302
303 if (*count == 0) {
304 (void) printf("%3s %-15s %-6s %-6s %-8s %3s %-15s\n",
305 "ID", "POOL", "OBJSET", "OBJECT", "TYPE", "LVL", "RANGE");
306 (void) printf("--- --------------- ------ "
307 "------ -------- --- ---------------\n");
308 }
309
310 *count += 1;
311
312 (void) printf("%3d %-15s %-6llu %-6llu %-8s %3d ", id, pool,
313 (u_longlong_t)record->zi_objset, (u_longlong_t)record->zi_object,
314 type_to_name(record->zi_type), record->zi_level);
315
316 if (record->zi_start == 0 &&
317 record->zi_end == -1ULL)
318 (void) printf("all\n");
319 else
320 (void) printf("[%llu, %llu]\n", (u_longlong_t)record->zi_start,
321 (u_longlong_t)record->zi_end);
322
323 return (0);
324 }
325
326 static int
327 print_device_handler(int id, const char *pool, zinject_record_t *record,
328 void *data)
329 {
330 int *count = data;
331
332 if (record->zi_guid == 0)
333 return (0);
334
335 if (*count == 0) {
336 (void) printf("%3s %-15s %s\n", "ID", "POOL", "GUID");
337 (void) printf("--- --------------- ----------------\n");
338 }
339
340 *count += 1;
341
342 (void) printf("%3d %-15s %llx\n", id, pool,
343 (u_longlong_t)record->zi_guid);
344
345 return (0);
346 }
347
348 /*
349 * Print all registered error handlers. Returns the number of handlers
350 * registered.
351 */
352 static int
353 print_all_handlers(void)
354 {
355 int count = 0;
356
357 (void) iter_handlers(print_device_handler, &count);
358 (void) printf("\n");
359 count = 0;
360 (void) iter_handlers(print_data_handler, &count);
361
362 return (count);
363 }
364
365 /* ARGSUSED */
366 static int
367 cancel_one_handler(int id, const char *pool, zinject_record_t *record,
368 void *data)
369 {
370 zfs_cmd_t zc;
371
372 zc.zc_guid = (uint64_t)id;
373
374 if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
375 (void) fprintf(stderr, "failed to remove handler %d: %s\n",
376 id, strerror(errno));
377 return (1);
378 }
379
380 return (0);
381 }
382
383 /*
384 * Remove all fault injection handlers.
385 */
386 static int
387 cancel_all_handlers(void)
388 {
389 int ret = iter_handlers(cancel_one_handler, NULL);
390
391 (void) printf("removed all registered handlers\n");
392
393 return (ret);
394 }
395
396 /*
397 * Remove a specific fault injection handler.
398 */
399 static int
400 cancel_handler(int id)
401 {
402 zfs_cmd_t zc;
403
404 zc.zc_guid = (uint64_t)id;
405
406 if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
407 (void) fprintf(stderr, "failed to remove handler %d: %s\n",
408 id, strerror(errno));
409 return (1);
410 }
411
412 (void) printf("removed handler %d\n", id);
413
414 return (0);
415 }
416
417 /*
418 * Register a new fault injection handler.
419 */
420 static int
421 register_handler(const char *pool, int flags, zinject_record_t *record,
422 int quiet)
423 {
424 zfs_cmd_t zc;
425
426 (void) strcpy(zc.zc_name, pool);
427 zc.zc_inject_record = *record;
428 zc.zc_guid = flags;
429
430 if (ioctl(zfs_fd, ZFS_IOC_INJECT_FAULT, &zc) != 0) {
431 (void) fprintf(stderr, "failed to add handler: %s\n",
432 strerror(errno));
433 return (1);
434 }
435
436 if (flags & ZINJECT_NULL)
437 return (0);
438
439 if (quiet) {
440 (void) printf("%llu\n", (u_longlong_t)zc.zc_guid);
441 } else {
442 (void) printf("Added handler %llu with the following "
443 "properties:\n", (u_longlong_t)zc.zc_guid);
444 (void) printf(" pool: %s\n", pool);
445 if (record->zi_guid) {
446 (void) printf(" vdev: %llx\n",
447 (u_longlong_t)record->zi_guid);
448 } else {
449 (void) printf("objset: %llu\n",
450 (u_longlong_t)record->zi_objset);
451 (void) printf("object: %llu\n",
452 (u_longlong_t)record->zi_object);
453 (void) printf(" type: %llu\n",
454 (u_longlong_t)record->zi_type);
455 (void) printf(" level: %d\n", record->zi_level);
456 if (record->zi_start == 0 &&
457 record->zi_end == -1ULL)
458 (void) printf(" range: all\n");
459 else
460 (void) printf(" range: [%llu, %llu)\n",
461 (u_longlong_t)record->zi_start,
462 (u_longlong_t)record->zi_end);
463 }
464 }
465
466 return (0);
467 }
468
469 int
470 main(int argc, char **argv)
471 {
472 int c;
473 char *range = NULL;
474 char *cancel = NULL;
475 char *end;
476 char *raw = NULL;
477 char *device = NULL;
478 int level = 0;
479 int quiet = 0;
480 int error = 0;
481 int domount = 0;
482 err_type_t type = TYPE_INVAL;
483 err_type_t label = TYPE_INVAL;
484 zinject_record_t record = { 0 };
485 char pool[MAXNAMELEN];
486 char dataset[MAXNAMELEN];
487 zfs_handle_t *zhp;
488 int ret;
489 int flags = 0;
490
491 if ((g_zfs = libzfs_init()) == NULL) {
492 (void) fprintf(stderr, "internal error: failed to "
493 "initialize ZFS library\n");
494 return (1);
495 }
496
497 libzfs_print_on_error(g_zfs, B_TRUE);
498
499 if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
500 (void) fprintf(stderr, "failed to open ZFS device\n");
501 return (1);
502 }
503
504 if (argc == 1) {
505 /*
506 * No arguments. Print the available handlers. If there are no
507 * available handlers, direct the user to '-h' for help
508 * information.
509 */
510 if (print_all_handlers() == 0) {
511 (void) printf("No handlers registered.\n");
512 (void) printf("Run 'zinject -h' for usage "
513 "information.\n");
514 }
515
516 return (0);
517 }
518
519 while ((c = getopt(argc, argv, ":ab:d:f:qhc:t:l:mr:e:uL:")) != -1) {
520 switch (c) {
521 case 'a':
522 flags |= ZINJECT_FLUSH_ARC;
523 break;
524 case 'b':
525 raw = optarg;
526 break;
527 case 'c':
528 cancel = optarg;
529 break;
530 case 'd':
531 device = optarg;
532 break;
533 case 'e':
534 if (strcasecmp(optarg, "io") == 0) {
535 error = EIO;
536 } else if (strcasecmp(optarg, "checksum") == 0) {
537 error = ECKSUM;
538 } else if (strcasecmp(optarg, "nxio") == 0) {
539 error = ENXIO;
540 } else {
541 (void) fprintf(stderr, "invalid error type "
542 "'%s': must be 'io', 'checksum' or "
543 "'nxio'\n", optarg);
544 usage();
545 return (1);
546 }
547 break;
548 case 'f':
549 record.zi_freq = atoi(optarg);
550 if (record.zi_freq < 1 || record.zi_freq > 100) {
551 (void) fprintf(stderr, "frequency range must "
552 "be in the range (0, 100]\n");
553 return (1);
554 }
555 break;
556 case 'h':
557 usage();
558 return (0);
559 case 'l':
560 level = (int)strtol(optarg, &end, 10);
561 if (*end != '\0') {
562 (void) fprintf(stderr, "invalid level '%s': "
563 "must be an integer\n", optarg);
564 usage();
565 return (1);
566 }
567 break;
568 case 'm':
569 domount = 1;
570 break;
571 case 'q':
572 quiet = 1;
573 break;
574 case 'r':
575 range = optarg;
576 break;
577 case 't':
578 if ((type = name_to_type(optarg)) == TYPE_INVAL &&
579 !MOS_TYPE(type)) {
580 (void) fprintf(stderr, "invalid type '%s'\n",
581 optarg);
582 usage();
583 return (1);
584 }
585 break;
586 case 'u':
587 flags |= ZINJECT_UNLOAD_SPA;
588 break;
589 case 'L':
590 if ((label = name_to_type(optarg)) == TYPE_INVAL &&
591 !LABEL_TYPE(type)) {
592 (void) fprintf(stderr, "invalid label type "
593 "'%s'\n", optarg);
594 usage();
595 return (1);
596 }
597 break;
598 case ':':
599 (void) fprintf(stderr, "option -%c requires an "
600 "operand\n", optopt);
601 usage();
602 return (1);
603 case '?':
604 (void) fprintf(stderr, "invalid option '%c'\n",
605 optopt);
606 usage();
607 return (2);
608 }
609 }
610
611 argc -= optind;
612 argv += optind;
613
614 if (cancel != NULL) {
615 /*
616 * '-c' is invalid with any other options.
617 */
618 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
619 level != 0) {
620 (void) fprintf(stderr, "cancel (-c) incompatible with "
621 "any other options\n");
622 usage();
623 return (2);
624 }
625 if (argc != 0) {
626 (void) fprintf(stderr, "extraneous argument to '-c'\n");
627 usage();
628 return (2);
629 }
630
631 if (strcmp(cancel, "all") == 0) {
632 return (cancel_all_handlers());
633 } else {
634 int id = (int)strtol(cancel, &end, 10);
635 if (*end != '\0') {
636 (void) fprintf(stderr, "invalid handle id '%s':"
637 " must be an integer or 'all'\n", cancel);
638 usage();
639 return (1);
640 }
641 return (cancel_handler(id));
642 }
643 }
644
645 if (device != NULL) {
646 /*
647 * Device (-d) injection uses a completely different mechanism
648 * for doing injection, so handle it separately here.
649 */
650 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
651 level != 0) {
652 (void) fprintf(stderr, "device (-d) incompatible with "
653 "data error injection\n");
654 usage();
655 return (2);
656 }
657
658 if (argc != 1) {
659 (void) fprintf(stderr, "device (-d) injection requires "
660 "a single pool name\n");
661 usage();
662 return (2);
663 }
664
665 (void) strcpy(pool, argv[0]);
666 dataset[0] = '\0';
667
668 if (error == ECKSUM) {
669 (void) fprintf(stderr, "device error type must be "
670 "'io' or 'nxio'\n");
671 return (1);
672 }
673
674 if (translate_device(pool, device, label, &record) != 0)
675 return (1);
676 if (!error)
677 error = ENXIO;
678 } else if (raw != NULL) {
679 if (range != NULL || type != TYPE_INVAL || level != 0) {
680 (void) fprintf(stderr, "raw (-b) format with "
681 "any other options\n");
682 usage();
683 return (2);
684 }
685
686 if (argc != 1) {
687 (void) fprintf(stderr, "raw (-b) format expects a "
688 "single pool name\n");
689 usage();
690 return (2);
691 }
692
693 (void) strcpy(pool, argv[0]);
694 dataset[0] = '\0';
695
696 if (error == ENXIO) {
697 (void) fprintf(stderr, "data error type must be "
698 "'checksum' or 'io'\n");
699 return (1);
700 }
701
702 if (translate_raw(raw, &record) != 0)
703 return (1);
704 if (!error)
705 error = EIO;
706 } else if (type == TYPE_INVAL) {
707 if (flags == 0) {
708 (void) fprintf(stderr, "at least one of '-b', '-d', "
709 "'-t', '-a', or '-u' must be specified\n");
710 usage();
711 return (2);
712 }
713
714 if (argc == 1 && (flags & ZINJECT_UNLOAD_SPA)) {
715 (void) strcpy(pool, argv[0]);
716 dataset[0] = '\0';
717 } else if (argc != 0) {
718 (void) fprintf(stderr, "extraneous argument for "
719 "'-f'\n");
720 usage();
721 return (2);
722 }
723
724 flags |= ZINJECT_NULL;
725 } else {
726 if (argc != 1) {
727 (void) fprintf(stderr, "missing object\n");
728 usage();
729 return (2);
730 }
731
732 if (error == ENXIO) {
733 (void) fprintf(stderr, "data error type must be "
734 "'checksum' or 'io'\n");
735 return (1);
736 }
737
738 if (translate_record(type, argv[0], range, level, &record, pool,
739 dataset) != 0)
740 return (1);
741 if (!error)
742 error = EIO;
743 }
744
745 /*
746 * If this is pool-wide metadata, unmount everything. The ioctl() will
747 * unload the pool, so that we trigger spa-wide reopen of metadata next
748 * time we access the pool.
749 */
750 if (dataset[0] != '\0' && domount) {
751 if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL)
752 return (1);
753
754 if (zfs_unmount(zhp, NULL, 0) != 0)
755 return (1);
756 }
757
758 record.zi_error = error;
759
760 ret = register_handler(pool, flags, &record, quiet);
761
762 if (dataset[0] != '\0' && domount)
763 ret = (zfs_mount(zhp, NULL, 0) != 0);
764
765 libzfs_fini(g_zfs);
766
767 return (ret);
768 }