The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/openzfs/cmd/zinject/zinject.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 https://opensource.org/licenses/CDDL-1.0.
   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, 2015 by Delphix. All rights reserved.
   24  * Copyright (c) 2017, Intel Corporation.
   25  */
   26 
   27 /*
   28  * ZFS Fault Injector
   29  *
   30  * This userland component takes a set of options and uses libzpool to translate
   31  * from a user-visible object type and name to an internal representation.
   32  * There are two basic types of faults: device faults and data faults.
   33  *
   34  *
   35  * DEVICE FAULTS
   36  *
   37  * Errors can be injected into a particular vdev using the '-d' option.  This
   38  * option takes a path or vdev GUID to uniquely identify the device within a
   39  * pool.  There are four types of errors that can be injected, IO, ENXIO,
   40  * ECHILD, and EILSEQ.  These can be controlled through the '-e' option and the
   41  * default is ENXIO.  For EIO failures, any attempt to read data from the device
   42  * will return EIO, but a subsequent attempt to reopen the device will succeed.
   43  * For ENXIO failures, any attempt to read from the device will return EIO, but
   44  * any attempt to reopen the device will also return ENXIO.  The EILSEQ failures
   45  * only apply to read operations (-T read) and will flip a bit after the device
   46  * has read the original data.
   47  *
   48  * For label faults, the -L option must be specified. This allows faults
   49  * to be injected into either the nvlist, uberblock, pad1, or pad2 region
   50  * of all the labels for the specified device.
   51  *
   52  * This form of the command looks like:
   53  *
   54  *      zinject -d device [-e errno] [-L <uber | nvlist | pad1 | pad2>] pool
   55  *
   56  *
   57  * DATA FAULTS
   58  *
   59  * We begin with a tuple of the form:
   60  *
   61  *      <type,level,range,object>
   62  *
   63  *      type    A string describing the type of data to target.  Each type
   64  *              implicitly describes how to interpret 'object'. Currently,
   65  *              the following values are supported:
   66  *
   67  *              data            User data for a file
   68  *              dnode           Dnode for a file or directory
   69  *
   70  *              The following MOS objects are special.  Instead of injecting
   71  *              errors on a particular object or blkid, we inject errors across
   72  *              all objects of the given type.
   73  *
   74  *              mos             Any data in the MOS
   75  *              mosdir          object directory
   76  *              config          pool configuration
   77  *              bpobj           blkptr list
   78  *              spacemap        spacemap
   79  *              metaslab        metaslab
   80  *              errlog          persistent error log
   81  *
   82  *      level   Object level.  Defaults to '', not applicable to all types.  If
   83  *              a range is given, this corresponds to the indirect block
   84  *              corresponding to the specific range.
   85  *
   86  *      range   A numerical range [start,end) within the object.  Defaults to
   87  *              the full size of the file.
   88  *
   89  *      object  A string describing the logical location of the object.  For
   90  *              files and directories (currently the only supported types),
   91  *              this is the path of the object on disk.
   92  *
   93  * This is translated, via libzpool, into the following internal representation:
   94  *
   95  *      <type,objset,object,level,range>
   96  *
   97  * These types should be self-explanatory.  This tuple is then passed to the
   98  * kernel via a special ioctl() to initiate fault injection for the given
   99  * object.  Note that 'type' is not strictly necessary for fault injection, but
  100  * is used when translating existing faults into a human-readable string.
  101  *
  102  *
  103  * The command itself takes one of the forms:
  104  *
  105  *      zinject
  106  *      zinject <-a | -u pool>
  107  *      zinject -c <id|all>
  108  *      zinject [-q] <-t type> [-f freq] [-u] [-a] [-m] [-e errno] [-l level]
  109  *          [-r range] <object>
  110  *      zinject [-f freq] [-a] [-m] [-u] -b objset:object:level:start:end pool
  111  *
  112  * With no arguments, the command prints all currently registered injection
  113  * handlers, with their numeric identifiers.
  114  *
  115  * The '-c' option will clear the given handler, or all handlers if 'all' is
  116  * specified.
  117  *
  118  * The '-e' option takes a string describing the errno to simulate.  This must
  119  * be one of 'io', 'checksum', 'decompress', or 'decrypt'.  In most cases this
  120  * will result in the same behavior, but RAID-Z will produce a different set of
  121  * ereports for this situation.
  122  *
  123  * The '-a', '-u', and '-m' flags toggle internal flush behavior.  If '-a' is
  124  * specified, then the ARC cache is flushed appropriately.  If '-u' is
  125  * specified, then the underlying SPA is unloaded.  Either of these flags can be
  126  * specified independently of any other handlers.  The '-m' flag automatically
  127  * does an unmount and remount of the underlying dataset to aid in flushing the
  128  * cache.
  129  *
  130  * The '-f' flag controls the frequency of errors injected, expressed as a
  131  * real number percentage between 0.0001 and 100.  The default is 100.
  132  *
  133  * The this form is responsible for actually injecting the handler into the
  134  * framework.  It takes the arguments described above, translates them to the
  135  * internal tuple using libzpool, and then issues an ioctl() to register the
  136  * handler.
  137  *
  138  * The final form can target a specific bookmark, regardless of whether a
  139  * human-readable interface has been designed.  It allows developers to specify
  140  * a particular block by number.
  141  */
  142 
  143 #include <errno.h>
  144 #include <fcntl.h>
  145 #include <stdio.h>
  146 #include <stdlib.h>
  147 #include <string.h>
  148 #include <strings.h>
  149 #include <unistd.h>
  150 
  151 #include <sys/fs/zfs.h>
  152 #include <sys/mount.h>
  153 
  154 #include <libzfs.h>
  155 
  156 #undef verify   /* both libzfs.h and zfs_context.h want to define this */
  157 
  158 #include "zinject.h"
  159 
  160 libzfs_handle_t *g_zfs;
  161 int zfs_fd;
  162 
  163 static const char *const errtable[TYPE_INVAL] = {
  164         "data",
  165         "dnode",
  166         "mos",
  167         "mosdir",
  168         "metaslab",
  169         "config",
  170         "bpobj",
  171         "spacemap",
  172         "errlog",
  173         "uber",
  174         "nvlist",
  175         "pad1",
  176         "pad2"
  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_BPOBJ:
  201                 return ("bpobj");
  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 specified.\n"
  229             "\n"
  230             "\tzinject -p <function name> pool\n"
  231             "\t\tInject a panic fault at the specified function. Only \n"
  232             "\t\tfunctions which call spa_vdev_config_exit(), or \n"
  233             "\t\tspa_vdev_exit() will trigger a panic.\n"
  234             "\n"
  235             "\tzinject -d device [-e errno] [-L <nvlist|uber|pad1|pad2>] [-F]\n"
  236             "\t\t[-T <read|write|free|claim|all>] [-f frequency] pool\n\n"
  237             "\t\tInject a fault into a particular device or the device's\n"
  238             "\t\tlabel.  Label injection can either be 'nvlist', 'uber',\n "
  239             "\t\t'pad1', or 'pad2'.\n"
  240             "\t\t'errno' can be 'nxio' (the default), 'io', 'dtl', or\n"
  241             "\t\t'corrupt' (bit flip).\n"
  242             "\t\t'frequency' is a value between 0.0001 and 100.0 that limits\n"
  243             "\t\tdevice error injection to a percentage of the IOs.\n"
  244             "\n"
  245             "\tzinject -d device -A <degrade|fault> -D <delay secs> pool\n"
  246             "\t\tPerform a specific action on a particular device.\n"
  247             "\n"
  248             "\tzinject -d device -D latency:lanes pool\n"
  249             "\n"
  250             "\t\tAdd an artificial delay to IO requests on a particular\n"
  251             "\t\tdevice, such that the requests take a minimum of 'latency'\n"
  252             "\t\tmilliseconds to complete. Each delay has an associated\n"
  253             "\t\tnumber of 'lanes' which defines the number of concurrent\n"
  254             "\t\tIO requests that can be processed.\n"
  255             "\n"
  256             "\t\tFor example, with a single lane delay of 10 ms (-D 10:1),\n"
  257             "\t\tthe device will only be able to service a single IO request\n"
  258             "\t\tat a time with each request taking 10 ms to complete. So,\n"
  259             "\t\tif only a single request is submitted every 10 ms, the\n"
  260             "\t\taverage latency will be 10 ms; but if more than one request\n"
  261             "\t\tis submitted every 10 ms, the average latency will be more\n"
  262             "\t\tthan 10 ms.\n"
  263             "\n"
  264             "\t\tSimilarly, if a delay of 10 ms is specified to have two\n"
  265             "\t\tlanes (-D 10:2), then the device will be able to service\n"
  266             "\t\ttwo requests at a time, each with a minimum latency of\n"
  267             "\t\t10 ms. So, if two requests are submitted every 10 ms, then\n"
  268             "\t\tthe average latency will be 10 ms; but if more than two\n"
  269             "\t\trequests are submitted every 10 ms, the average latency\n"
  270             "\t\twill be more than 10 ms.\n"
  271             "\n"
  272             "\t\tAlso note, these delays are additive. So two invocations\n"
  273             "\t\tof '-D 10:1', is roughly equivalent to a single invocation\n"
  274             "\t\tof '-D 10:2'. This also means, one can specify multiple\n"
  275             "\t\tlanes with differing target latencies. For example, an\n"
  276             "\t\tinvocation of '-D 10:1' followed by '-D 25:2' will\n"
  277             "\t\tcreate 3 lanes on the device; one lane with a latency\n"
  278             "\t\tof 10 ms and two lanes with a 25 ms latency.\n"
  279             "\n"
  280             "\tzinject -I [-s <seconds> | -g <txgs>] pool\n"
  281             "\t\tCause the pool to stop writing blocks yet not\n"
  282             "\t\treport errors for a duration.  Simulates buggy hardware\n"
  283             "\t\tthat fails to honor cache flush requests.\n"
  284             "\t\tDefault duration is 30 seconds.  The machine is panicked\n"
  285             "\t\tat the end of the duration.\n"
  286             "\n"
  287             "\tzinject -b objset:object:level:blkid pool\n"
  288             "\n"
  289             "\t\tInject an error into pool 'pool' with the numeric bookmark\n"
  290             "\t\tspecified by the remaining tuple.  Each number is in\n"
  291             "\t\thexadecimal, and only one block can be specified.\n"
  292             "\n"
  293             "\tzinject [-q] <-t type> [-C dvas] [-e errno] [-l level]\n"
  294             "\t\t[-r range] [-a] [-m] [-u] [-f freq] <object>\n"
  295             "\n"
  296             "\t\tInject an error into the object specified by the '-t' option\n"
  297             "\t\tand the object descriptor.  The 'object' parameter is\n"
  298             "\t\tinterpreted depending on the '-t' option.\n"
  299             "\n"
  300             "\t\t-q\tQuiet mode.  Only print out the handler number added.\n"
  301             "\t\t-e\tInject a specific error.  Must be one of 'io',\n"
  302             "\t\t\t'checksum', 'decompress', or 'decrypt'.  Default is 'io'.\n"
  303             "\t\t-C\tInject the given error only into specific DVAs. The\n"
  304             "\t\t\tDVAs should be specified as a list of 0-indexed DVAs\n"
  305             "\t\t\tseparated by commas (ex. '0,2').\n"
  306             "\t\t-l\tInject error at a particular block level. Default is "
  307             "0.\n"
  308             "\t\t-m\tAutomatically remount underlying filesystem.\n"
  309             "\t\t-r\tInject error over a particular logical range of an\n"
  310             "\t\t\tobject.  Will be translated to the appropriate blkid\n"
  311             "\t\t\trange according to the object's properties.\n"
  312             "\t\t-a\tFlush the ARC cache.  Can be specified without any\n"
  313             "\t\t\tassociated object.\n"
  314             "\t\t-u\tUnload the associated pool.  Can be specified with only\n"
  315             "\t\t\ta pool object.\n"
  316             "\t\t-f\tOnly inject errors a fraction of the time.  Expressed as\n"
  317             "\t\t\ta percentage between 0.0001 and 100.\n"
  318             "\n"
  319             "\t-t data\t\tInject an error into the plain file contents of a\n"
  320             "\t\t\tfile.  The object must be specified as a complete path\n"
  321             "\t\t\tto a file on a ZFS filesystem.\n"
  322             "\n"
  323             "\t-t dnode\tInject an error into the metadnode in the block\n"
  324             "\t\t\tcorresponding to the dnode for a file or directory.  The\n"
  325             "\t\t\t'-r' option is incompatible with this mode.  The object\n"
  326             "\t\t\tis specified as a complete path to a file or directory\n"
  327             "\t\t\ton a ZFS filesystem.\n"
  328             "\n"
  329             "\t-t <mos>\tInject errors into the MOS for objects of the given\n"
  330             "\t\t\ttype.  Valid types are: mos, mosdir, config, bpobj,\n"
  331             "\t\t\tspacemap, metaslab, errlog.  The only valid <object> is\n"
  332             "\t\t\tthe poolname.\n");
  333 }
  334 
  335 static int
  336 iter_handlers(int (*func)(int, const char *, zinject_record_t *, void *),
  337     void *data)
  338 {
  339         zfs_cmd_t zc = {"\0"};
  340         int ret;
  341 
  342         while (zfs_ioctl(g_zfs, ZFS_IOC_INJECT_LIST_NEXT, &zc) == 0)
  343                 if ((ret = func((int)zc.zc_guid, zc.zc_name,
  344                     &zc.zc_inject_record, data)) != 0)
  345                         return (ret);
  346 
  347         if (errno != ENOENT) {
  348                 (void) fprintf(stderr, "Unable to list handlers: %s\n",
  349                     strerror(errno));
  350                 return (-1);
  351         }
  352 
  353         return (0);
  354 }
  355 
  356 static int
  357 print_data_handler(int id, const char *pool, zinject_record_t *record,
  358     void *data)
  359 {
  360         int *count = data;
  361 
  362         if (record->zi_guid != 0 || record->zi_func[0] != '\0')
  363                 return (0);
  364 
  365         if (*count == 0) {
  366                 (void) printf("%3s  %-15s  %-6s  %-6s  %-8s  %3s  %-4s  "
  367                     "%-15s\n", "ID", "POOL", "OBJSET", "OBJECT", "TYPE",
  368                     "LVL", "DVAs", "RANGE");
  369                 (void) printf("---  ---------------  ------  "
  370                     "------  --------  ---  ----  ---------------\n");
  371         }
  372 
  373         *count += 1;
  374 
  375         (void) printf("%3d  %-15s  %-6llu  %-6llu  %-8s  %-3d  0x%02x  ",
  376             id, pool, (u_longlong_t)record->zi_objset,
  377             (u_longlong_t)record->zi_object, type_to_name(record->zi_type),
  378             record->zi_level, record->zi_dvas);
  379 
  380 
  381         if (record->zi_start == 0 &&
  382             record->zi_end == -1ULL)
  383                 (void) printf("all\n");
  384         else
  385                 (void) printf("[%llu, %llu]\n", (u_longlong_t)record->zi_start,
  386                     (u_longlong_t)record->zi_end);
  387 
  388         return (0);
  389 }
  390 
  391 static int
  392 print_device_handler(int id, const char *pool, zinject_record_t *record,
  393     void *data)
  394 {
  395         int *count = data;
  396 
  397         if (record->zi_guid == 0 || record->zi_func[0] != '\0')
  398                 return (0);
  399 
  400         if (record->zi_cmd == ZINJECT_DELAY_IO)
  401                 return (0);
  402 
  403         if (*count == 0) {
  404                 (void) printf("%3s  %-15s  %s\n", "ID", "POOL", "GUID");
  405                 (void) printf("---  ---------------  ----------------\n");
  406         }
  407 
  408         *count += 1;
  409 
  410         (void) printf("%3d  %-15s  %llx\n", id, pool,
  411             (u_longlong_t)record->zi_guid);
  412 
  413         return (0);
  414 }
  415 
  416 static int
  417 print_delay_handler(int id, const char *pool, zinject_record_t *record,
  418     void *data)
  419 {
  420         int *count = data;
  421 
  422         if (record->zi_guid == 0 || record->zi_func[0] != '\0')
  423                 return (0);
  424 
  425         if (record->zi_cmd != ZINJECT_DELAY_IO)
  426                 return (0);
  427 
  428         if (*count == 0) {
  429                 (void) printf("%3s  %-15s  %-15s  %-15s  %s\n",
  430                     "ID", "POOL", "DELAY (ms)", "LANES", "GUID");
  431                 (void) printf("---  ---------------  ---------------  "
  432                     "---------------  ----------------\n");
  433         }
  434 
  435         *count += 1;
  436 
  437         (void) printf("%3d  %-15s  %-15llu  %-15llu  %llx\n", id, pool,
  438             (u_longlong_t)NSEC2MSEC(record->zi_timer),
  439             (u_longlong_t)record->zi_nlanes,
  440             (u_longlong_t)record->zi_guid);
  441 
  442         return (0);
  443 }
  444 
  445 static int
  446 print_panic_handler(int id, const char *pool, zinject_record_t *record,
  447     void *data)
  448 {
  449         int *count = data;
  450 
  451         if (record->zi_func[0] == '\0')
  452                 return (0);
  453 
  454         if (*count == 0) {
  455                 (void) printf("%3s  %-15s  %s\n", "ID", "POOL", "FUNCTION");
  456                 (void) printf("---  ---------------  ----------------\n");
  457         }
  458 
  459         *count += 1;
  460 
  461         (void) printf("%3d  %-15s  %s\n", id, pool, record->zi_func);
  462 
  463         return (0);
  464 }
  465 
  466 /*
  467  * Print all registered error handlers.  Returns the number of handlers
  468  * registered.
  469  */
  470 static int
  471 print_all_handlers(void)
  472 {
  473         int count = 0, total = 0;
  474 
  475         (void) iter_handlers(print_device_handler, &count);
  476         if (count > 0) {
  477                 total += count;
  478                 (void) printf("\n");
  479                 count = 0;
  480         }
  481 
  482         (void) iter_handlers(print_delay_handler, &count);
  483         if (count > 0) {
  484                 total += count;
  485                 (void) printf("\n");
  486                 count = 0;
  487         }
  488 
  489         (void) iter_handlers(print_data_handler, &count);
  490         if (count > 0) {
  491                 total += count;
  492                 (void) printf("\n");
  493                 count = 0;
  494         }
  495 
  496         (void) iter_handlers(print_panic_handler, &count);
  497 
  498         return (count + total);
  499 }
  500 
  501 static int
  502 cancel_one_handler(int id, const char *pool, zinject_record_t *record,
  503     void *data)
  504 {
  505         (void) pool, (void) record, (void) data;
  506         zfs_cmd_t zc = {"\0"};
  507 
  508         zc.zc_guid = (uint64_t)id;
  509 
  510         if (zfs_ioctl(g_zfs, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
  511                 (void) fprintf(stderr, "failed to remove handler %d: %s\n",
  512                     id, strerror(errno));
  513                 return (1);
  514         }
  515 
  516         return (0);
  517 }
  518 
  519 /*
  520  * Remove all fault injection handlers.
  521  */
  522 static int
  523 cancel_all_handlers(void)
  524 {
  525         int ret = iter_handlers(cancel_one_handler, NULL);
  526 
  527         if (ret == 0)
  528                 (void) printf("removed all registered handlers\n");
  529 
  530         return (ret);
  531 }
  532 
  533 /*
  534  * Remove a specific fault injection handler.
  535  */
  536 static int
  537 cancel_handler(int id)
  538 {
  539         zfs_cmd_t zc = {"\0"};
  540 
  541         zc.zc_guid = (uint64_t)id;
  542 
  543         if (zfs_ioctl(g_zfs, ZFS_IOC_CLEAR_FAULT, &zc) != 0) {
  544                 (void) fprintf(stderr, "failed to remove handler %d: %s\n",
  545                     id, strerror(errno));
  546                 return (1);
  547         }
  548 
  549         (void) printf("removed handler %d\n", id);
  550 
  551         return (0);
  552 }
  553 
  554 /*
  555  * Register a new fault injection handler.
  556  */
  557 static int
  558 register_handler(const char *pool, int flags, zinject_record_t *record,
  559     int quiet)
  560 {
  561         zfs_cmd_t zc = {"\0"};
  562 
  563         (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
  564         zc.zc_inject_record = *record;
  565         zc.zc_guid = flags;
  566 
  567         if (zfs_ioctl(g_zfs, ZFS_IOC_INJECT_FAULT, &zc) != 0) {
  568                 (void) fprintf(stderr, "failed to add handler: %s\n",
  569                     errno == EDOM ? "block level exceeds max level of object" :
  570                     strerror(errno));
  571                 return (1);
  572         }
  573 
  574         if (flags & ZINJECT_NULL)
  575                 return (0);
  576 
  577         if (quiet) {
  578                 (void) printf("%llu\n", (u_longlong_t)zc.zc_guid);
  579         } else {
  580                 (void) printf("Added handler %llu with the following "
  581                     "properties:\n", (u_longlong_t)zc.zc_guid);
  582                 (void) printf("  pool: %s\n", pool);
  583                 if (record->zi_guid) {
  584                         (void) printf("  vdev: %llx\n",
  585                             (u_longlong_t)record->zi_guid);
  586                 } else if (record->zi_func[0] != '\0') {
  587                         (void) printf("  panic function: %s\n",
  588                             record->zi_func);
  589                 } else if (record->zi_duration > 0) {
  590                         (void) printf(" time: %lld seconds\n",
  591                             (u_longlong_t)record->zi_duration);
  592                 } else if (record->zi_duration < 0) {
  593                         (void) printf(" txgs: %lld \n",
  594                             (u_longlong_t)-record->zi_duration);
  595                 } else {
  596                         (void) printf("objset: %llu\n",
  597                             (u_longlong_t)record->zi_objset);
  598                         (void) printf("object: %llu\n",
  599                             (u_longlong_t)record->zi_object);
  600                         (void) printf("  type: %llu\n",
  601                             (u_longlong_t)record->zi_type);
  602                         (void) printf(" level: %d\n", record->zi_level);
  603                         if (record->zi_start == 0 &&
  604                             record->zi_end == -1ULL)
  605                                 (void) printf(" range: all\n");
  606                         else
  607                                 (void) printf(" range: [%llu, %llu)\n",
  608                                     (u_longlong_t)record->zi_start,
  609                                     (u_longlong_t)record->zi_end);
  610                         (void) printf("  dvas: 0x%x\n", record->zi_dvas);
  611                 }
  612         }
  613 
  614         return (0);
  615 }
  616 
  617 static int
  618 perform_action(const char *pool, zinject_record_t *record, int cmd)
  619 {
  620         zfs_cmd_t zc = {"\0"};
  621 
  622         ASSERT(cmd == VDEV_STATE_DEGRADED || cmd == VDEV_STATE_FAULTED);
  623         (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name));
  624         zc.zc_guid = record->zi_guid;
  625         zc.zc_cookie = cmd;
  626 
  627         if (zfs_ioctl(g_zfs, ZFS_IOC_VDEV_SET_STATE, &zc) == 0)
  628                 return (0);
  629 
  630         return (1);
  631 }
  632 
  633 static int
  634 parse_delay(char *str, uint64_t *delay, uint64_t *nlanes)
  635 {
  636         unsigned long scan_delay;
  637         unsigned long scan_nlanes;
  638 
  639         if (sscanf(str, "%lu:%lu", &scan_delay, &scan_nlanes) != 2)
  640                 return (1);
  641 
  642         /*
  643          * We explicitly disallow a delay of zero here, because we key
  644          * off this value being non-zero in translate_device(), to
  645          * determine if the fault is a ZINJECT_DELAY_IO fault or not.
  646          */
  647         if (scan_delay == 0)
  648                 return (1);
  649 
  650         /*
  651          * The units for the CLI delay parameter is milliseconds, but
  652          * the data passed to the kernel is interpreted as nanoseconds.
  653          * Thus we scale the milliseconds to nanoseconds here, and this
  654          * nanosecond value is used to pass the delay to the kernel.
  655          */
  656         *delay = MSEC2NSEC(scan_delay);
  657         *nlanes = scan_nlanes;
  658 
  659         return (0);
  660 }
  661 
  662 static int
  663 parse_frequency(const char *str, uint32_t *percent)
  664 {
  665         double val;
  666         char *post;
  667 
  668         val = strtod(str, &post);
  669         if (post == NULL || *post != '\0')
  670                 return (EINVAL);
  671 
  672         /* valid range is [0.0001, 100.0] */
  673         val /= 100.0f;
  674         if (val < 0.000001f || val > 1.0f)
  675                 return (ERANGE);
  676 
  677         /* convert to an integer for use by kernel */
  678         *percent = ((uint32_t)(val * ZI_PERCENTAGE_MAX));
  679 
  680         return (0);
  681 }
  682 
  683 /*
  684  * This function converts a string specifier for DVAs into a bit mask.
  685  * The dva's provided by the user should be 0 indexed and separated by
  686  * a comma. For example:
  687  *      "1"     -> 0b0010  (0x2)
  688  *      "0,1"   -> 0b0011  (0x3)
  689  *      "0,1,2" -> 0b0111  (0x7)
  690  */
  691 static int
  692 parse_dvas(const char *str, uint32_t *dvas_out)
  693 {
  694         const char *c = str;
  695         uint32_t mask = 0;
  696         boolean_t need_delim = B_FALSE;
  697 
  698         /* max string length is 5 ("0,1,2") */
  699         if (strlen(str) > 5 || strlen(str) == 0)
  700                 return (EINVAL);
  701 
  702         while (*c != '\0') {
  703                 switch (*c) {
  704                 case '':
  705                 case '1':
  706                 case '2':
  707                         /* check for pipe between DVAs */
  708                         if (need_delim)
  709                                 return (EINVAL);
  710 
  711                         /* check if this DVA has been set already */
  712                         if (mask & (1 << ((*c) - '')))
  713                                 return (EINVAL);
  714 
  715                         mask |= (1 << ((*c) - ''));
  716                         need_delim = B_TRUE;
  717                         break;
  718                 case ',':
  719                         need_delim = B_FALSE;
  720                         break;
  721                 default:
  722                         /* check for invalid character */
  723                         return (EINVAL);
  724                 }
  725                 c++;
  726         }
  727 
  728         /* check for dangling delimiter */
  729         if (!need_delim)
  730                 return (EINVAL);
  731 
  732         *dvas_out = mask;
  733         return (0);
  734 }
  735 
  736 int
  737 main(int argc, char **argv)
  738 {
  739         int c;
  740         char *range = NULL;
  741         char *cancel = NULL;
  742         char *end;
  743         char *raw = NULL;
  744         char *device = NULL;
  745         int level = 0;
  746         int quiet = 0;
  747         int error = 0;
  748         int domount = 0;
  749         int io_type = ZIO_TYPES;
  750         int action = VDEV_STATE_UNKNOWN;
  751         err_type_t type = TYPE_INVAL;
  752         err_type_t label = TYPE_INVAL;
  753         zinject_record_t record = { 0 };
  754         char pool[MAXNAMELEN] = "";
  755         char dataset[MAXNAMELEN] = "";
  756         zfs_handle_t *zhp = NULL;
  757         int nowrites = 0;
  758         int dur_txg = 0;
  759         int dur_secs = 0;
  760         int ret;
  761         int flags = 0;
  762         uint32_t dvas = 0;
  763 
  764         if ((g_zfs = libzfs_init()) == NULL) {
  765                 (void) fprintf(stderr, "%s\n", libzfs_error_init(errno));
  766                 return (1);
  767         }
  768 
  769         libzfs_print_on_error(g_zfs, B_TRUE);
  770 
  771         if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0) {
  772                 (void) fprintf(stderr, "failed to open ZFS device\n");
  773                 libzfs_fini(g_zfs);
  774                 return (1);
  775         }
  776 
  777         if (argc == 1) {
  778                 /*
  779                  * No arguments.  Print the available handlers.  If there are no
  780                  * available handlers, direct the user to '-h' for help
  781                  * information.
  782                  */
  783                 if (print_all_handlers() == 0) {
  784                         (void) printf("No handlers registered.\n");
  785                         (void) printf("Run 'zinject -h' for usage "
  786                             "information.\n");
  787                 }
  788                 libzfs_fini(g_zfs);
  789                 return (0);
  790         }
  791 
  792         while ((c = getopt(argc, argv,
  793             ":aA:b:C:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:")) != -1) {
  794                 switch (c) {
  795                 case 'a':
  796                         flags |= ZINJECT_FLUSH_ARC;
  797                         break;
  798                 case 'A':
  799                         if (strcasecmp(optarg, "degrade") == 0) {
  800                                 action = VDEV_STATE_DEGRADED;
  801                         } else if (strcasecmp(optarg, "fault") == 0) {
  802                                 action = VDEV_STATE_FAULTED;
  803                         } else {
  804                                 (void) fprintf(stderr, "invalid action '%s': "
  805                                     "must be 'degrade' or 'fault'\n", optarg);
  806                                 usage();
  807                                 libzfs_fini(g_zfs);
  808                                 return (1);
  809                         }
  810                         break;
  811                 case 'b':
  812                         raw = optarg;
  813                         break;
  814                 case 'c':
  815                         cancel = optarg;
  816                         break;
  817                 case 'C':
  818                         ret = parse_dvas(optarg, &dvas);
  819                         if (ret != 0) {
  820                                 (void) fprintf(stderr, "invalid DVA list '%s': "
  821                                     "DVAs should be 0 indexed and separated by "
  822                                     "commas.\n", optarg);
  823                                 usage();
  824                                 libzfs_fini(g_zfs);
  825                                 return (1);
  826                         }
  827                         break;
  828                 case 'd':
  829                         device = optarg;
  830                         break;
  831                 case 'D':
  832                         errno = 0;
  833                         ret = parse_delay(optarg, &record.zi_timer,
  834                             &record.zi_nlanes);
  835                         if (ret != 0) {
  836 
  837                                 (void) fprintf(stderr, "invalid i/o delay "
  838                                     "value: '%s'\n", optarg);
  839                                 usage();
  840                                 libzfs_fini(g_zfs);
  841                                 return (1);
  842                         }
  843                         break;
  844                 case 'e':
  845                         if (strcasecmp(optarg, "io") == 0) {
  846                                 error = EIO;
  847                         } else if (strcasecmp(optarg, "checksum") == 0) {
  848                                 error = ECKSUM;
  849                         } else if (strcasecmp(optarg, "decompress") == 0) {
  850                                 error = EINVAL;
  851                         } else if (strcasecmp(optarg, "decrypt") == 0) {
  852                                 error = EACCES;
  853                         } else if (strcasecmp(optarg, "nxio") == 0) {
  854                                 error = ENXIO;
  855                         } else if (strcasecmp(optarg, "dtl") == 0) {
  856                                 error = ECHILD;
  857                         } else if (strcasecmp(optarg, "corrupt") == 0) {
  858                                 error = EILSEQ;
  859                         } else {
  860                                 (void) fprintf(stderr, "invalid error type "
  861                                     "'%s': must be 'io', 'checksum' or "
  862                                     "'nxio'\n", optarg);
  863                                 usage();
  864                                 libzfs_fini(g_zfs);
  865                                 return (1);
  866                         }
  867                         break;
  868                 case 'f':
  869                         ret = parse_frequency(optarg, &record.zi_freq);
  870                         if (ret != 0) {
  871                                 (void) fprintf(stderr, "%sfrequency value must "
  872                                     "be in the range [0.0001, 100.0]\n",
  873                                     ret == EINVAL ? "invalid value: " :
  874                                     ret == ERANGE ? "out of range: " : "");
  875                                 libzfs_fini(g_zfs);
  876                                 return (1);
  877                         }
  878                         break;
  879                 case 'F':
  880                         record.zi_failfast = B_TRUE;
  881                         break;
  882                 case 'g':
  883                         dur_txg = 1;
  884                         record.zi_duration = (int)strtol(optarg, &end, 10);
  885                         if (record.zi_duration <= 0 || *end != '\0') {
  886                                 (void) fprintf(stderr, "invalid duration '%s': "
  887                                     "must be a positive integer\n", optarg);
  888                                 usage();
  889                                 libzfs_fini(g_zfs);
  890                                 return (1);
  891                         }
  892                         /* store duration of txgs as its negative */
  893                         record.zi_duration *= -1;
  894                         break;
  895                 case 'h':
  896                         usage();
  897                         libzfs_fini(g_zfs);
  898                         return (0);
  899                 case 'I':
  900                         /* default duration, if one hasn't yet been defined */
  901                         nowrites = 1;
  902                         if (dur_secs == 0 && dur_txg == 0)
  903                                 record.zi_duration = 30;
  904                         break;
  905                 case 'l':
  906                         level = (int)strtol(optarg, &end, 10);
  907                         if (*end != '\0') {
  908                                 (void) fprintf(stderr, "invalid level '%s': "
  909                                     "must be an integer\n", optarg);
  910                                 usage();
  911                                 libzfs_fini(g_zfs);
  912                                 return (1);
  913                         }
  914                         break;
  915                 case 'm':
  916                         domount = 1;
  917                         break;
  918                 case 'p':
  919                         (void) strlcpy(record.zi_func, optarg,
  920                             sizeof (record.zi_func));
  921                         record.zi_cmd = ZINJECT_PANIC;
  922                         break;
  923                 case 'q':
  924                         quiet = 1;
  925                         break;
  926                 case 'r':
  927                         range = optarg;
  928                         flags |= ZINJECT_CALC_RANGE;
  929                         break;
  930                 case 's':
  931                         dur_secs = 1;
  932                         record.zi_duration = (int)strtol(optarg, &end, 10);
  933                         if (record.zi_duration <= 0 || *end != '\0') {
  934                                 (void) fprintf(stderr, "invalid duration '%s': "
  935                                     "must be a positive integer\n", optarg);
  936                                 usage();
  937                                 libzfs_fini(g_zfs);
  938                                 return (1);
  939                         }
  940                         break;
  941                 case 'T':
  942                         if (strcasecmp(optarg, "read") == 0) {
  943                                 io_type = ZIO_TYPE_READ;
  944                         } else if (strcasecmp(optarg, "write") == 0) {
  945                                 io_type = ZIO_TYPE_WRITE;
  946                         } else if (strcasecmp(optarg, "free") == 0) {
  947                                 io_type = ZIO_TYPE_FREE;
  948                         } else if (strcasecmp(optarg, "claim") == 0) {
  949                                 io_type = ZIO_TYPE_CLAIM;
  950                         } else if (strcasecmp(optarg, "all") == 0) {
  951                                 io_type = ZIO_TYPES;
  952                         } else {
  953                                 (void) fprintf(stderr, "invalid I/O type "
  954                                     "'%s': must be 'read', 'write', 'free', "
  955                                     "'claim' or 'all'\n", optarg);
  956                                 usage();
  957                                 libzfs_fini(g_zfs);
  958                                 return (1);
  959                         }
  960                         break;
  961                 case 't':
  962                         if ((type = name_to_type(optarg)) == TYPE_INVAL &&
  963                             !MOS_TYPE(type)) {
  964                                 (void) fprintf(stderr, "invalid type '%s'\n",
  965                                     optarg);
  966                                 usage();
  967                                 libzfs_fini(g_zfs);
  968                                 return (1);
  969                         }
  970                         break;
  971                 case 'u':
  972                         flags |= ZINJECT_UNLOAD_SPA;
  973                         break;
  974                 case 'L':
  975                         if ((label = name_to_type(optarg)) == TYPE_INVAL &&
  976                             !LABEL_TYPE(type)) {
  977                                 (void) fprintf(stderr, "invalid label type "
  978                                     "'%s'\n", optarg);
  979                                 usage();
  980                                 libzfs_fini(g_zfs);
  981                                 return (1);
  982                         }
  983                         break;
  984                 case ':':
  985                         (void) fprintf(stderr, "option -%c requires an "
  986                             "operand\n", optopt);
  987                         usage();
  988                         libzfs_fini(g_zfs);
  989                         return (1);
  990                 case '?':
  991                         (void) fprintf(stderr, "invalid option '%c'\n",
  992                             optopt);
  993                         usage();
  994                         libzfs_fini(g_zfs);
  995                         return (2);
  996                 }
  997         }
  998 
  999         argc -= optind;
 1000         argv += optind;
 1001 
 1002         if (record.zi_duration != 0)
 1003                 record.zi_cmd = ZINJECT_IGNORED_WRITES;
 1004 
 1005         if (cancel != NULL) {
 1006                 /*
 1007                  * '-c' is invalid with any other options.
 1008                  */
 1009                 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
 1010                     level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED ||
 1011                     record.zi_freq > 0 || dvas != 0) {
 1012                         (void) fprintf(stderr, "cancel (-c) incompatible with "
 1013                             "any other options\n");
 1014                         usage();
 1015                         libzfs_fini(g_zfs);
 1016                         return (2);
 1017                 }
 1018                 if (argc != 0) {
 1019                         (void) fprintf(stderr, "extraneous argument to '-c'\n");
 1020                         usage();
 1021                         libzfs_fini(g_zfs);
 1022                         return (2);
 1023                 }
 1024 
 1025                 if (strcmp(cancel, "all") == 0) {
 1026                         return (cancel_all_handlers());
 1027                 } else {
 1028                         int id = (int)strtol(cancel, &end, 10);
 1029                         if (*end != '\0') {
 1030                                 (void) fprintf(stderr, "invalid handle id '%s':"
 1031                                     " must be an integer or 'all'\n", cancel);
 1032                                 usage();
 1033                                 libzfs_fini(g_zfs);
 1034                                 return (1);
 1035                         }
 1036                         return (cancel_handler(id));
 1037                 }
 1038         }
 1039 
 1040         if (device != NULL) {
 1041                 /*
 1042                  * Device (-d) injection uses a completely different mechanism
 1043                  * for doing injection, so handle it separately here.
 1044                  */
 1045                 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
 1046                     level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED ||
 1047                     dvas != 0) {
 1048                         (void) fprintf(stderr, "device (-d) incompatible with "
 1049                             "data error injection\n");
 1050                         usage();
 1051                         libzfs_fini(g_zfs);
 1052                         return (2);
 1053                 }
 1054 
 1055                 if (argc != 1) {
 1056                         (void) fprintf(stderr, "device (-d) injection requires "
 1057                             "a single pool name\n");
 1058                         usage();
 1059                         libzfs_fini(g_zfs);
 1060                         return (2);
 1061                 }
 1062 
 1063                 (void) strlcpy(pool, argv[0], sizeof (pool));
 1064                 dataset[0] = '\0';
 1065 
 1066                 if (error == ECKSUM) {
 1067                         (void) fprintf(stderr, "device error type must be "
 1068                             "'io', 'nxio' or 'corrupt'\n");
 1069                         libzfs_fini(g_zfs);
 1070                         return (1);
 1071                 }
 1072 
 1073                 if (error == EILSEQ &&
 1074                     (record.zi_freq == 0 || io_type != ZIO_TYPE_READ)) {
 1075                         (void) fprintf(stderr, "device corrupt errors require "
 1076                             "io type read and a frequency value\n");
 1077                         libzfs_fini(g_zfs);
 1078                         return (1);
 1079                 }
 1080 
 1081                 record.zi_iotype = io_type;
 1082                 if (translate_device(pool, device, label, &record) != 0) {
 1083                         libzfs_fini(g_zfs);
 1084                         return (1);
 1085                 }
 1086                 if (!error)
 1087                         error = ENXIO;
 1088 
 1089                 if (action != VDEV_STATE_UNKNOWN)
 1090                         return (perform_action(pool, &record, action));
 1091 
 1092         } else if (raw != NULL) {
 1093                 if (range != NULL || type != TYPE_INVAL || level != 0 ||
 1094                     record.zi_cmd != ZINJECT_UNINITIALIZED ||
 1095                     record.zi_freq > 0 || dvas != 0) {
 1096                         (void) fprintf(stderr, "raw (-b) format with "
 1097                             "any other options\n");
 1098                         usage();
 1099                         libzfs_fini(g_zfs);
 1100                         return (2);
 1101                 }
 1102 
 1103                 if (argc != 1) {
 1104                         (void) fprintf(stderr, "raw (-b) format expects a "
 1105                             "single pool name\n");
 1106                         usage();
 1107                         libzfs_fini(g_zfs);
 1108                         return (2);
 1109                 }
 1110 
 1111                 (void) strlcpy(pool, argv[0], sizeof (pool));
 1112                 dataset[0] = '\0';
 1113 
 1114                 if (error == ENXIO) {
 1115                         (void) fprintf(stderr, "data error type must be "
 1116                             "'checksum' or 'io'\n");
 1117                         libzfs_fini(g_zfs);
 1118                         return (1);
 1119                 }
 1120 
 1121                 record.zi_cmd = ZINJECT_DATA_FAULT;
 1122                 if (translate_raw(raw, &record) != 0) {
 1123                         libzfs_fini(g_zfs);
 1124                         return (1);
 1125                 }
 1126                 if (!error)
 1127                         error = EIO;
 1128         } else if (record.zi_cmd == ZINJECT_PANIC) {
 1129                 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
 1130                     level != 0 || device != NULL || record.zi_freq > 0 ||
 1131                     dvas != 0) {
 1132                         (void) fprintf(stderr, "panic (-p) incompatible with "
 1133                             "other options\n");
 1134                         usage();
 1135                         libzfs_fini(g_zfs);
 1136                         return (2);
 1137                 }
 1138 
 1139                 if (argc < 1 || argc > 2) {
 1140                         (void) fprintf(stderr, "panic (-p) injection requires "
 1141                             "a single pool name and an optional id\n");
 1142                         usage();
 1143                         libzfs_fini(g_zfs);
 1144                         return (2);
 1145                 }
 1146 
 1147                 (void) strlcpy(pool, argv[0], sizeof (pool));
 1148                 if (argv[1] != NULL)
 1149                         record.zi_type = atoi(argv[1]);
 1150                 dataset[0] = '\0';
 1151         } else if (record.zi_cmd == ZINJECT_IGNORED_WRITES) {
 1152                 if (raw != NULL || range != NULL || type != TYPE_INVAL ||
 1153                     level != 0 || record.zi_freq > 0 || dvas != 0) {
 1154                         (void) fprintf(stderr, "hardware failure (-I) "
 1155                             "incompatible with other options\n");
 1156                         usage();
 1157                         libzfs_fini(g_zfs);
 1158                         return (2);
 1159                 }
 1160 
 1161                 if (nowrites == 0) {
 1162                         (void) fprintf(stderr, "-s or -g meaningless "
 1163                             "without -I (ignore writes)\n");
 1164                         usage();
 1165                         libzfs_fini(g_zfs);
 1166                         return (2);
 1167                 } else if (dur_secs && dur_txg) {
 1168                         (void) fprintf(stderr, "choose a duration either "
 1169                             "in seconds (-s) or a number of txgs (-g) "
 1170                             "but not both\n");
 1171                         usage();
 1172                         libzfs_fini(g_zfs);
 1173                         return (2);
 1174                 } else if (argc != 1) {
 1175                         (void) fprintf(stderr, "ignore writes (-I) "
 1176                             "injection requires a single pool name\n");
 1177                         usage();
 1178                         libzfs_fini(g_zfs);
 1179                         return (2);
 1180                 }
 1181 
 1182                 (void) strlcpy(pool, argv[0], sizeof (pool));
 1183                 dataset[0] = '\0';
 1184         } else if (type == TYPE_INVAL) {
 1185                 if (flags == 0) {
 1186                         (void) fprintf(stderr, "at least one of '-b', '-d', "
 1187                             "'-t', '-a', '-p', '-I' or '-u' "
 1188                             "must be specified\n");
 1189                         usage();
 1190                         libzfs_fini(g_zfs);
 1191                         return (2);
 1192                 }
 1193 
 1194                 if (argc == 1 && (flags & ZINJECT_UNLOAD_SPA)) {
 1195                         (void) strlcpy(pool, argv[0], sizeof (pool));
 1196                         dataset[0] = '\0';
 1197                 } else if (argc != 0) {
 1198                         (void) fprintf(stderr, "extraneous argument for "
 1199                             "'-f'\n");
 1200                         usage();
 1201                         libzfs_fini(g_zfs);
 1202                         return (2);
 1203                 }
 1204 
 1205                 flags |= ZINJECT_NULL;
 1206         } else {
 1207                 if (argc != 1) {
 1208                         (void) fprintf(stderr, "missing object\n");
 1209                         usage();
 1210                         libzfs_fini(g_zfs);
 1211                         return (2);
 1212                 }
 1213 
 1214                 if (error == ENXIO || error == EILSEQ) {
 1215                         (void) fprintf(stderr, "data error type must be "
 1216                             "'checksum' or 'io'\n");
 1217                         libzfs_fini(g_zfs);
 1218                         return (1);
 1219                 }
 1220 
 1221                 if (dvas != 0) {
 1222                         if (error == EACCES || error == EINVAL) {
 1223                                 (void) fprintf(stderr, "the '-C' option may "
 1224                                     "not be used with logical data errors "
 1225                                     "'decrypt' and 'decompress'\n");
 1226                                 libzfs_fini(g_zfs);
 1227                                 return (1);
 1228                         }
 1229 
 1230                         record.zi_dvas = dvas;
 1231                 }
 1232 
 1233                 if (error == EACCES) {
 1234                         if (type != TYPE_DATA) {
 1235                                 (void) fprintf(stderr, "decryption errors "
 1236                                     "may only be injected for 'data' types\n");
 1237                                 libzfs_fini(g_zfs);
 1238                                 return (1);
 1239                         }
 1240 
 1241                         record.zi_cmd = ZINJECT_DECRYPT_FAULT;
 1242                         /*
 1243                          * Internally, ZFS actually uses ECKSUM for decryption
 1244                          * errors since EACCES is used to indicate the key was
 1245                          * not found.
 1246                          */
 1247                         error = ECKSUM;
 1248                 } else {
 1249                         record.zi_cmd = ZINJECT_DATA_FAULT;
 1250                 }
 1251 
 1252                 if (translate_record(type, argv[0], range, level, &record, pool,
 1253                     dataset) != 0) {
 1254                         libzfs_fini(g_zfs);
 1255                         return (1);
 1256                 }
 1257                 if (!error)
 1258                         error = EIO;
 1259         }
 1260 
 1261         /*
 1262          * If this is pool-wide metadata, unmount everything.  The ioctl() will
 1263          * unload the pool, so that we trigger spa-wide reopen of metadata next
 1264          * time we access the pool.
 1265          */
 1266         if (dataset[0] != '\0' && domount) {
 1267                 if ((zhp = zfs_open(g_zfs, dataset,
 1268                     ZFS_TYPE_DATASET)) == NULL) {
 1269                         libzfs_fini(g_zfs);
 1270                         return (1);
 1271                 }
 1272                 if (zfs_unmount(zhp, NULL, 0) != 0) {
 1273                         libzfs_fini(g_zfs);
 1274                         return (1);
 1275                 }
 1276         }
 1277 
 1278         record.zi_error = error;
 1279 
 1280         ret = register_handler(pool, flags, &record, quiet);
 1281 
 1282         if (dataset[0] != '\0' && domount)
 1283                 ret = (zfs_mount(zhp, NULL, 0) != 0);
 1284 
 1285         libzfs_fini(g_zfs);
 1286 
 1287         return (ret);
 1288 }

Cache object: d5b6e98ec1b3a0d38d2397702f855992


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.