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