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