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