]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - cddl/contrib/opensolaris/cmd/zinject/zinject.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / cddl / contrib / opensolaris / 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/param.h>
150 #include <sys/mount.h>
151
152 #include <libzfs.h>
153
154 #undef verify   /* both libzfs.h and zfs_context.h want to define this */
155
156 #include "zinject.h"
157
158 libzfs_handle_t *g_zfs;
159 int zfs_fd;
160
161 #ifndef ECKSUM
162 #define ECKSUM  EBADE
163 #endif
164
165 static const char *errtable[TYPE_INVAL] = {
166         "data",
167         "dnode",
168         "mos",
169         "mosdir",
170         "metaslab",
171         "config",
172         "bplist",
173         "spacemap",
174         "errlog",
175         "uber",
176         "nvlist"
177 };
178
179 static err_type_t
180 name_to_type(const char *arg)
181 {
182         int i;
183         for (i = 0; i < TYPE_INVAL; i++)
184                 if (strcmp(errtable[i], arg) == 0)
185                         return (i);
186
187         return (TYPE_INVAL);
188 }
189
190 static const char *
191 type_to_name(uint64_t type)
192 {
193         switch (type) {
194         case DMU_OT_OBJECT_DIRECTORY:
195                 return ("mosdir");
196         case DMU_OT_OBJECT_ARRAY:
197                 return ("metaslab");
198         case DMU_OT_PACKED_NVLIST:
199                 return ("config");
200         case DMU_OT_BPLIST:
201                 return ("bplist");
202         case DMU_OT_SPACE_MAP:
203                 return ("spacemap");
204         case DMU_OT_ERROR_LOG:
205                 return ("errlog");
206         default:
207                 return ("-");
208         }
209 }
210
211
212 /*
213  * Print usage message.
214  */
215 void
216 usage(void)
217 {
218         (void) printf(
219             "usage:\n"
220             "\n"
221             "\tzinject\n"
222             "\n"
223             "\t\tList all active injection records.\n"
224             "\n"
225             "\tzinject -c <id|all>\n"
226             "\n"
227             "\t\tClear the particular record (if given a numeric ID), or\n"
228             "\t\tall records if 'all' is specificed.\n"
229             "\n"
230             "\tzinject -d device [-e errno] [-L <nvlist|uber>] pool\n"
231             "\t\tInject a fault into a particular device or the device's\n"
232             "\t\tlabel.  Label injection can either be 'nvlist' or 'uber'.\n"
233             "\t\t'errno' can either be 'nxio' (the default) or 'io'.\n"
234             "\n"
235             "\tzinject -b objset:object:level:blkid pool\n"
236             "\n"
237             "\t\tInject an error into pool 'pool' with the numeric bookmark\n"
238             "\t\tspecified by the remaining tuple.  Each number is in\n"
239             "\t\thexidecimal, and only one block can be specified.\n"
240             "\n"
241             "\tzinject [-q] <-t type> [-e errno] [-l level] [-r range]\n"
242             "\t    [-a] [-m] [-u] [-f freq] <object>\n"
243             "\n"
244             "\t\tInject an error into the object specified by the '-t' option\n"
245             "\t\tand the object descriptor.  The 'object' parameter is\n"
246             "\t\tinterperted depending on the '-t' option.\n"
247             "\n"
248             "\t\t-q\tQuiet mode.  Only print out the handler number added.\n"
249             "\t\t-e\tInject a specific error.  Must be either 'io' or\n"
250             "\t\t\t'checksum'.  Default is 'io'.\n"
251             "\t\t-l\tInject error at a particular block level. Default is "
252             "0.\n"
253             "\t\t-m\tAutomatically remount underlying filesystem.\n"
254             "\t\t-r\tInject error over a particular logical range of an\n"
255             "\t\t\tobject.  Will be translated to the appropriate blkid\n"
256             "\t\t\trange according to the object's properties.\n"
257             "\t\t-a\tFlush the ARC cache.  Can be specified without any\n"
258             "\t\t\tassociated object.\n"
259             "\t\t-u\tUnload the associated pool.  Can be specified with only\n"
260             "\t\t\ta pool object.\n"
261             "\t\t-f\tOnly inject errors a fraction of the time.  Expressed as\n"
262             "\t\t\ta percentage between 1 and 100.\n"
263             "\n"
264             "\t-t data\t\tInject an error into the plain file contents of a\n"
265             "\t\t\tfile.  The object must be specified as a complete path\n"
266             "\t\t\tto a file on a ZFS filesystem.\n"
267             "\n"
268             "\t-t dnode\tInject an error into the metadnode in the block\n"
269             "\t\t\tcorresponding to the dnode for a file or directory.  The\n"
270             "\t\t\t'-r' option is incompatible with this mode.  The object\n"
271             "\t\t\tis specified as a complete path to a file or directory\n"
272             "\t\t\ton a ZFS filesystem.\n"
273             "\n"
274             "\t-t <mos>\tInject errors into the MOS for objects of the given\n"
275             "\t\t\ttype.  Valid types are: mos, mosdir, config, bplist,\n"
276             "\t\t\tspacemap, metaslab, errlog.  The only valid <object> is\n"
277             "\t\t\tthe poolname.\n");
278 }
279
280 static int
281 iter_handlers(int (*func)(int, const char *, zinject_record_t *, void *),
282     void *data)
283 {
284         zfs_cmd_t zc;
285         int ret;
286
287         zc.zc_guid = 0;
288
289         while (ioctl(zfs_fd, ZFS_IOC_INJECT_LIST_NEXT, &zc) == 0)
290                 if ((ret = func((int)zc.zc_guid, zc.zc_name,
291                     &zc.zc_inject_record, data)) != 0)
292                         return (ret);
293
294         return (0);
295 }
296
297 static int
298 print_data_handler(int id, const char *pool, zinject_record_t *record,
299     void *data)
300 {
301         int *count = data;
302
303         if (record->zi_guid != 0)
304                 return (0);
305
306         if (*count == 0) {
307                 (void) printf("%3s  %-15s  %-6s  %-6s  %-8s  %3s  %-15s\n",
308                     "ID", "POOL", "OBJSET", "OBJECT", "TYPE", "LVL",  "RANGE");
309                 (void) printf("---  ---------------  ------  "
310                     "------  --------  ---  ---------------\n");
311         }
312
313         *count += 1;
314
315         (void) printf("%3d  %-15s  %-6llu  %-6llu  %-8s  %3d  ", id, pool,
316             (u_longlong_t)record->zi_objset, (u_longlong_t)record->zi_object,
317             type_to_name(record->zi_type), record->zi_level);
318
319         if (record->zi_start == 0 &&
320             record->zi_end == -1ULL)
321                 (void) printf("all\n");
322         else
323                 (void) printf("[%llu, %llu]\n", (u_longlong_t)record->zi_start,
324                     (u_longlong_t)record->zi_end);
325
326         return (0);
327 }
328
329 static int
330 print_device_handler(int id, const char *pool, zinject_record_t *record,
331     void *data)
332 {
333         int *count = data;
334
335         if (record->zi_guid == 0)
336                 return (0);
337
338         if (*count == 0) {
339                 (void) printf("%3s  %-15s  %s\n", "ID", "POOL", "GUID");
340                 (void) printf("---  ---------------  ----------------\n");
341         }
342
343         *count += 1;
344
345         (void) printf("%3d  %-15s  %llx\n", id, pool,
346             (u_longlong_t)record->zi_guid);
347
348         return (0);
349 }
350
351 /*
352  * Print all registered error handlers.  Returns the number of handlers
353  * registered.
354  */
355 static int
356 print_all_handlers(void)
357 {
358         int count = 0;
359
360         (void) iter_handlers(print_device_handler, &count);
361         (void) printf("\n");
362         count = 0;
363         (void) iter_handlers(print_data_handler, &count);
364
365         return (count);
366 }
367
368 /* ARGSUSED */
369 static int
370 cancel_one_handler(int id, const char *pool, zinject_record_t *record,
371     void *data)
372 {
373         zfs_cmd_t zc;
374
375         zc.zc_guid = (uint64_t)id;
376
377         if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
378                 (void) fprintf(stderr, "failed to remove handler %d: %s\n",
379                     id, strerror(errno));
380                 return (1);
381         }
382
383         return (0);
384 }
385
386 /*
387  * Remove all fault injection handlers.
388  */
389 static int
390 cancel_all_handlers(void)
391 {
392         int ret = iter_handlers(cancel_one_handler, NULL);
393
394         (void) printf("removed all registered handlers\n");
395
396         return (ret);
397 }
398
399 /*
400  * Remove a specific fault injection handler.
401  */
402 static int
403 cancel_handler(int id)
404 {
405         zfs_cmd_t zc;
406
407         zc.zc_guid = (uint64_t)id;
408
409         if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
410                 (void) fprintf(stderr, "failed to remove handler %d: %s\n",
411                     id, strerror(errno));
412                 return (1);
413         }
414
415         (void) printf("removed handler %d\n", id);
416
417         return (0);
418 }
419
420 /*
421  * Register a new fault injection handler.
422  */
423 static int
424 register_handler(const char *pool, int flags, zinject_record_t *record,
425     int quiet)
426 {
427         zfs_cmd_t zc;
428
429         (void) strcpy(zc.zc_name, pool);
430         zc.zc_inject_record = *record;
431         zc.zc_guid = flags;
432
433         if (ioctl(zfs_fd, ZFS_IOC_INJECT_FAULT, &zc) != 0) {
434                 (void) fprintf(stderr, "failed to add handler: %s\n",
435                     strerror(errno));
436                 return (1);
437         }
438
439         if (flags & ZINJECT_NULL)
440                 return (0);
441
442         if (quiet) {
443                 (void) printf("%llu\n", (u_longlong_t)zc.zc_guid);
444         } else {
445                 (void) printf("Added handler %llu with the following "
446                     "properties:\n", (u_longlong_t)zc.zc_guid);
447                 (void) printf("  pool: %s\n", pool);
448                 if (record->zi_guid) {
449                         (void) printf("  vdev: %llx\n",
450                             (u_longlong_t)record->zi_guid);
451                 } else {
452                         (void) printf("objset: %llu\n",
453                             (u_longlong_t)record->zi_objset);
454                         (void) printf("object: %llu\n",
455                             (u_longlong_t)record->zi_object);
456                         (void) printf("  type: %llu\n",
457                             (u_longlong_t)record->zi_type);
458                         (void) printf(" level: %d\n", record->zi_level);
459                         if (record->zi_start == 0 &&
460                             record->zi_end == -1ULL)
461                                 (void) printf(" range: all\n");
462                         else
463                                 (void) printf(" range: [%llu, %llu)\n",
464                                     (u_longlong_t)record->zi_start,
465                                     (u_longlong_t)record->zi_end);
466                 }
467         }
468
469         return (0);
470 }
471
472 int
473 main(int argc, char **argv)
474 {
475         int c;
476         char *range = NULL;
477         char *cancel = NULL;
478         char *end;
479         char *raw = NULL;
480         char *device = NULL;
481         int level = 0;
482         int quiet = 0;
483         int error = 0;
484         int domount = 0;
485         err_type_t type = TYPE_INVAL;
486         err_type_t label = TYPE_INVAL;
487         zinject_record_t record = { 0 };
488         char pool[MAXNAMELEN];
489         char dataset[MAXNAMELEN];
490         zfs_handle_t *zhp;
491         int ret;
492         int flags = 0;
493
494         if ((g_zfs = libzfs_init()) == NULL) {
495                 (void) fprintf(stderr, "internal error: failed to "
496                     "initialize ZFS library\n");
497                 return (1);
498         }
499
500         libzfs_print_on_error(g_zfs, B_TRUE);
501
502         if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
503                 (void) fprintf(stderr, "failed to open ZFS device\n");
504                 return (1);
505         }
506
507         if (argc == 1) {
508                 /*
509                  * No arguments.  Print the available handlers.  If there are no
510                  * available handlers, direct the user to '-h' for help
511                  * information.
512                  */
513                 if (print_all_handlers() == 0) {
514                         (void) printf("No handlers registered.\n");
515                         (void) printf("Run 'zinject -h' for usage "
516                             "information.\n");
517                 }
518
519                 return (0);
520         }
521
522         while ((c = getopt(argc, argv, ":ab:d:f:qhc:t:l:mr:e:uL:")) != -1) {
523                 switch (c) {
524                 case 'a':
525                         flags |= ZINJECT_FLUSH_ARC;
526                         break;
527                 case 'b':
528                         raw = optarg;
529                         break;
530                 case 'c':
531                         cancel = optarg;
532                         break;
533                 case 'd':
534                         device = optarg;
535                         break;
536                 case 'e':
537                         if (strcasecmp(optarg, "io") == 0) {
538                                 error = EIO;
539                         } else if (strcasecmp(optarg, "checksum") == 0) {
540                                 error = ECKSUM;
541                         } else if (strcasecmp(optarg, "nxio") == 0) {
542                                 error = ENXIO;
543                         } else {
544                                 (void) fprintf(stderr, "invalid error type "
545                                     "'%s': must be 'io', 'checksum' or "
546                                     "'nxio'\n", optarg);
547                                 usage();
548                                 return (1);
549                         }
550                         break;
551                 case 'f':
552                         record.zi_freq = atoi(optarg);
553                         if (record.zi_freq < 1 || record.zi_freq > 100) {
554                                 (void) fprintf(stderr, "frequency range must "
555                                     "be in the range (0, 100]\n");
556                                 return (1);
557                         }
558                         break;
559                 case 'h':
560                         usage();
561                         return (0);
562                 case 'l':
563                         level = (int)strtol(optarg, &end, 10);
564                         if (*end != '\0') {
565                                 (void) fprintf(stderr, "invalid level '%s': "
566                                     "must be an integer\n", optarg);
567                                 usage();
568                                 return (1);
569                         }
570                         break;
571                 case 'm':
572                         domount = 1;
573                         break;
574                 case 'q':
575                         quiet = 1;
576                         break;
577                 case 'r':
578                         range = optarg;
579                         break;
580                 case 't':
581                         if ((type = name_to_type(optarg)) == TYPE_INVAL &&
582                             !MOS_TYPE(type)) {
583                                 (void) fprintf(stderr, "invalid type '%s'\n",
584                                     optarg);
585                                 usage();
586                                 return (1);
587                         }
588                         break;
589                 case 'u':
590                         flags |= ZINJECT_UNLOAD_SPA;
591                         break;
592                 case 'L':
593                         if ((label = name_to_type(optarg)) == TYPE_INVAL &&
594                             !LABEL_TYPE(type)) {
595                                 (void) fprintf(stderr, "invalid label type "
596                                     "'%s'\n", optarg);
597                                 usage();
598                                 return (1);
599                         }
600                         break;
601                 case ':':
602                         (void) fprintf(stderr, "option -%c requires an "
603                             "operand\n", optopt);
604                         usage();
605                         return (1);
606                 case '?':
607                         (void) fprintf(stderr, "invalid option '%c'\n",
608                             optopt);
609                         usage();
610                         return (2);
611                 }
612         }
613
614         argc -= optind;
615         argv += optind;
616
617         if (cancel != NULL) {
618                 /*
619                  * '-c' is invalid with any other options.
620                  */
621                 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
622                     level != 0) {
623                         (void) fprintf(stderr, "cancel (-c) incompatible with "
624                             "any other options\n");
625                         usage();
626                         return (2);
627                 }
628                 if (argc != 0) {
629                         (void) fprintf(stderr, "extraneous argument to '-c'\n");
630                         usage();
631                         return (2);
632                 }
633
634                 if (strcmp(cancel, "all") == 0) {
635                         return (cancel_all_handlers());
636                 } else {
637                         int id = (int)strtol(cancel, &end, 10);
638                         if (*end != '\0') {
639                                 (void) fprintf(stderr, "invalid handle id '%s':"
640                                     " must be an integer or 'all'\n", cancel);
641                                 usage();
642                                 return (1);
643                         }
644                         return (cancel_handler(id));
645                 }
646         }
647
648         if (device != NULL) {
649                 /*
650                  * Device (-d) injection uses a completely different mechanism
651                  * for doing injection, so handle it separately here.
652                  */
653                 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
654                     level != 0) {
655                         (void) fprintf(stderr, "device (-d) incompatible with "
656                             "data error injection\n");
657                         usage();
658                         return (2);
659                 }
660
661                 if (argc != 1) {
662                         (void) fprintf(stderr, "device (-d) injection requires "
663                             "a single pool name\n");
664                         usage();
665                         return (2);
666                 }
667
668                 (void) strcpy(pool, argv[0]);
669                 dataset[0] = '\0';
670
671                 if (error == ECKSUM) {
672                         (void) fprintf(stderr, "device error type must be "
673                             "'io' or 'nxio'\n");
674                         return (1);
675                 }
676
677                 if (translate_device(pool, device, label, &record) != 0)
678                         return (1);
679                 if (!error)
680                         error = ENXIO;
681         } else if (raw != NULL) {
682                 if (range != NULL || type != TYPE_INVAL || level != 0) {
683                         (void) fprintf(stderr, "raw (-b) format with "
684                             "any other options\n");
685                         usage();
686                         return (2);
687                 }
688
689                 if (argc != 1) {
690                         (void) fprintf(stderr, "raw (-b) format expects a "
691                             "single pool name\n");
692                         usage();
693                         return (2);
694                 }
695
696                 (void) strcpy(pool, argv[0]);
697                 dataset[0] = '\0';
698
699                 if (error == ENXIO) {
700                         (void) fprintf(stderr, "data error type must be "
701                             "'checksum' or 'io'\n");
702                         return (1);
703                 }
704
705                 if (translate_raw(raw, &record) != 0)
706                         return (1);
707                 if (!error)
708                         error = EIO;
709         } else if (type == TYPE_INVAL) {
710                 if (flags == 0) {
711                         (void) fprintf(stderr, "at least one of '-b', '-d', "
712                             "'-t', '-a', or '-u' must be specified\n");
713                         usage();
714                         return (2);
715                 }
716
717                 if (argc == 1 && (flags & ZINJECT_UNLOAD_SPA)) {
718                         (void) strcpy(pool, argv[0]);
719                         dataset[0] = '\0';
720                 } else if (argc != 0) {
721                         (void) fprintf(stderr, "extraneous argument for "
722                             "'-f'\n");
723                         usage();
724                         return (2);
725                 }
726
727                 flags |= ZINJECT_NULL;
728         } else {
729                 if (argc != 1) {
730                         (void) fprintf(stderr, "missing object\n");
731                         usage();
732                         return (2);
733                 }
734
735                 if (error == ENXIO) {
736                         (void) fprintf(stderr, "data error type must be "
737                             "'checksum' or 'io'\n");
738                         return (1);
739                 }
740
741                 if (translate_record(type, argv[0], range, level, &record, pool,
742                     dataset) != 0)
743                         return (1);
744                 if (!error)
745                         error = EIO;
746         }
747
748         /*
749          * If this is pool-wide metadata, unmount everything.  The ioctl() will
750          * unload the pool, so that we trigger spa-wide reopen of metadata next
751          * time we access the pool.
752          */
753         if (dataset[0] != '\0' && domount) {
754                 if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL)
755                         return (1);
756
757                 if (zfs_unmount(zhp, NULL, 0) != 0)
758                         return (1);
759         }
760
761         record.zi_error = error;
762
763         ret = register_handler(pool, flags, &record, quiet);
764
765         if (dataset[0] != '\0' && domount)
766                 ret = (zfs_mount(zhp, NULL, 0) != 0);
767
768         libzfs_fini(g_zfs);
769
770         return (ret);
771 }