1185029Spjd/* 2185029Spjd * CDDL HEADER START 3185029Spjd * 4185029Spjd * The contents of this file are subject to the terms of the 5185029Spjd * Common Development and Distribution License (the "License"). 6185029Spjd * You may not use this file except in compliance with the License. 7185029Spjd * 8185029Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9185029Spjd * or http://www.opensolaris.org/os/licensing. 10185029Spjd * See the License for the specific language governing permissions 11185029Spjd * and limitations under the License. 12185029Spjd * 13185029Spjd * When distributing Covered Code, include this CDDL HEADER in each 14185029Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15185029Spjd * If applicable, add the following below this CDDL HEADER, with the 16185029Spjd * fields enclosed by brackets "[]" replaced with your own identifying 17185029Spjd * information: Portions Copyright [yyyy] [name of copyright owner] 18185029Spjd * 19185029Spjd * CDDL HEADER END 20185029Spjd */ 21185029Spjd/* 22219089Spjd * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23297108Smav * Copyright (c) 2012, 2015 by Delphix. All rights reserved. 24185029Spjd */ 25185029Spjd 26185029Spjd/* 27185029Spjd * ZFS Fault Injector 28185029Spjd * 29185029Spjd * This userland component takes a set of options and uses libzpool to translate 30185029Spjd * from a user-visible object type and name to an internal representation. 31185029Spjd * There are two basic types of faults: device faults and data faults. 32185029Spjd * 33185029Spjd * 34185029Spjd * DEVICE FAULTS 35185029Spjd * 36185029Spjd * Errors can be injected into a particular vdev using the '-d' option. This 37185029Spjd * option takes a path or vdev GUID to uniquely identify the device within a 38185029Spjd * pool. There are two types of errors that can be injected, EIO and ENXIO, 39185029Spjd * that can be controlled through the '-e' option. The default is ENXIO. For 40185029Spjd * EIO failures, any attempt to read data from the device will return EIO, but 41185029Spjd * subsequent attempt to reopen the device will succeed. For ENXIO failures, 42185029Spjd * any attempt to read from the device will return EIO, but any attempt to 43185029Spjd * reopen the device will also return ENXIO. 44185029Spjd * For label faults, the -L option must be specified. This allows faults 45219089Spjd * to be injected into either the nvlist, uberblock, pad1, or pad2 region 46219089Spjd * of all the labels for the specified device. 47185029Spjd * 48185029Spjd * This form of the command looks like: 49185029Spjd * 50219089Spjd * zinject -d device [-e errno] [-L <uber | nvlist | pad1 | pad2>] pool 51185029Spjd * 52185029Spjd * 53185029Spjd * DATA FAULTS 54185029Spjd * 55185029Spjd * We begin with a tuple of the form: 56185029Spjd * 57185029Spjd * <type,level,range,object> 58185029Spjd * 59185029Spjd * type A string describing the type of data to target. Each type 60185029Spjd * implicitly describes how to interpret 'object'. Currently, 61185029Spjd * the following values are supported: 62185029Spjd * 63185029Spjd * data User data for a file 64185029Spjd * dnode Dnode for a file or directory 65185029Spjd * 66185029Spjd * The following MOS objects are special. Instead of injecting 67185029Spjd * errors on a particular object or blkid, we inject errors across 68185029Spjd * all objects of the given type. 69185029Spjd * 70185029Spjd * mos Any data in the MOS 71185029Spjd * mosdir object directory 72185029Spjd * config pool configuration 73219089Spjd * bpobj blkptr list 74185029Spjd * spacemap spacemap 75185029Spjd * metaslab metaslab 76185029Spjd * errlog persistent error log 77185029Spjd * 78185029Spjd * level Object level. Defaults to '0', not applicable to all types. If 79185029Spjd * a range is given, this corresponds to the indirect block 80185029Spjd * corresponding to the specific range. 81185029Spjd * 82185029Spjd * range A numerical range [start,end) within the object. Defaults to 83185029Spjd * the full size of the file. 84185029Spjd * 85185029Spjd * object A string describing the logical location of the object. For 86185029Spjd * files and directories (currently the only supported types), 87185029Spjd * this is the path of the object on disk. 88185029Spjd * 89185029Spjd * This is translated, via libzpool, into the following internal representation: 90185029Spjd * 91185029Spjd * <type,objset,object,level,range> 92185029Spjd * 93185029Spjd * These types should be self-explanatory. This tuple is then passed to the 94185029Spjd * kernel via a special ioctl() to initiate fault injection for the given 95185029Spjd * object. Note that 'type' is not strictly necessary for fault injection, but 96185029Spjd * is used when translating existing faults into a human-readable string. 97185029Spjd * 98185029Spjd * 99185029Spjd * The command itself takes one of the forms: 100185029Spjd * 101185029Spjd * zinject 102185029Spjd * zinject <-a | -u pool> 103185029Spjd * zinject -c <id|all> 104185029Spjd * zinject [-q] <-t type> [-f freq] [-u] [-a] [-m] [-e errno] [-l level] 105185029Spjd * [-r range] <object> 106185029Spjd * zinject [-f freq] [-a] [-m] [-u] -b objset:object:level:start:end pool 107185029Spjd * 108185029Spjd * With no arguments, the command prints all currently registered injection 109185029Spjd * handlers, with their numeric identifiers. 110185029Spjd * 111185029Spjd * The '-c' option will clear the given handler, or all handlers if 'all' is 112185029Spjd * specified. 113185029Spjd * 114185029Spjd * The '-e' option takes a string describing the errno to simulate. This must 115185029Spjd * be either 'io' or 'checksum'. In most cases this will result in the same 116185029Spjd * behavior, but RAID-Z will produce a different set of ereports for this 117185029Spjd * situation. 118185029Spjd * 119185029Spjd * The '-a', '-u', and '-m' flags toggle internal flush behavior. If '-a' is 120185029Spjd * specified, then the ARC cache is flushed appropriately. If '-u' is 121185029Spjd * specified, then the underlying SPA is unloaded. Either of these flags can be 122185029Spjd * specified independently of any other handlers. The '-m' flag automatically 123185029Spjd * does an unmount and remount of the underlying dataset to aid in flushing the 124185029Spjd * cache. 125185029Spjd * 126185029Spjd * The '-f' flag controls the frequency of errors injected, expressed as a 127185029Spjd * integer percentage between 1 and 100. The default is 100. 128185029Spjd * 129185029Spjd * The this form is responsible for actually injecting the handler into the 130185029Spjd * framework. It takes the arguments described above, translates them to the 131185029Spjd * internal tuple using libzpool, and then issues an ioctl() to register the 132185029Spjd * handler. 133185029Spjd * 134185029Spjd * The final form can target a specific bookmark, regardless of whether a 135185029Spjd * human-readable interface has been designed. It allows developers to specify 136185029Spjd * a particular block by number. 137185029Spjd */ 138185029Spjd 139185029Spjd#include <errno.h> 140185029Spjd#include <fcntl.h> 141185029Spjd#include <stdio.h> 142185029Spjd#include <stdlib.h> 143185029Spjd#include <strings.h> 144185029Spjd#include <unistd.h> 145185029Spjd 146185029Spjd#include <sys/fs/zfs.h> 147186568Srwatson#include <sys/param.h> 148185029Spjd#include <sys/mount.h> 149185029Spjd 150185029Spjd#include <libzfs.h> 151262101Savg#include <libzfs_compat.h> 152185029Spjd 153185029Spjd#undef verify /* both libzfs.h and zfs_context.h want to define this */ 154185029Spjd 155185029Spjd#include "zinject.h" 156185029Spjd 157185029Spjdlibzfs_handle_t *g_zfs; 158185029Spjdint zfs_fd; 159185029Spjd 160185029Spjd#ifndef ECKSUM 161185029Spjd#define ECKSUM EBADE 162185029Spjd#endif 163185029Spjd 164185029Spjdstatic const char *errtable[TYPE_INVAL] = { 165185029Spjd "data", 166185029Spjd "dnode", 167185029Spjd "mos", 168185029Spjd "mosdir", 169185029Spjd "metaslab", 170185029Spjd "config", 171219089Spjd "bpobj", 172185029Spjd "spacemap", 173185029Spjd "errlog", 174185029Spjd "uber", 175219089Spjd "nvlist", 176219089Spjd "pad1", 177219089Spjd "pad2" 178185029Spjd}; 179185029Spjd 180185029Spjdstatic err_type_t 181185029Spjdname_to_type(const char *arg) 182185029Spjd{ 183185029Spjd int i; 184185029Spjd for (i = 0; i < TYPE_INVAL; i++) 185185029Spjd if (strcmp(errtable[i], arg) == 0) 186185029Spjd return (i); 187185029Spjd 188185029Spjd return (TYPE_INVAL); 189185029Spjd} 190185029Spjd 191185029Spjdstatic const char * 192185029Spjdtype_to_name(uint64_t type) 193185029Spjd{ 194185029Spjd switch (type) { 195185029Spjd case DMU_OT_OBJECT_DIRECTORY: 196185029Spjd return ("mosdir"); 197185029Spjd case DMU_OT_OBJECT_ARRAY: 198185029Spjd return ("metaslab"); 199185029Spjd case DMU_OT_PACKED_NVLIST: 200185029Spjd return ("config"); 201219089Spjd case DMU_OT_BPOBJ: 202219089Spjd return ("bpobj"); 203185029Spjd case DMU_OT_SPACE_MAP: 204185029Spjd return ("spacemap"); 205185029Spjd case DMU_OT_ERROR_LOG: 206185029Spjd return ("errlog"); 207185029Spjd default: 208185029Spjd return ("-"); 209185029Spjd } 210185029Spjd} 211185029Spjd 212185029Spjd 213185029Spjd/* 214185029Spjd * Print usage message. 215185029Spjd */ 216185029Spjdvoid 217185029Spjdusage(void) 218185029Spjd{ 219185029Spjd (void) printf( 220185029Spjd "usage:\n" 221185029Spjd "\n" 222185029Spjd "\tzinject\n" 223185029Spjd "\n" 224185029Spjd "\t\tList all active injection records.\n" 225185029Spjd "\n" 226185029Spjd "\tzinject -c <id|all>\n" 227185029Spjd "\n" 228185029Spjd "\t\tClear the particular record (if given a numeric ID), or\n" 229185029Spjd "\t\tall records if 'all' is specificed.\n" 230185029Spjd "\n" 231219089Spjd "\tzinject -p <function name> pool\n" 232297108Smav "\n" 233219089Spjd "\t\tInject a panic fault at the specified function. Only \n" 234219089Spjd "\t\tfunctions which call spa_vdev_config_exit(), or \n" 235219089Spjd "\t\tspa_vdev_exit() will trigger a panic.\n" 236219089Spjd "\n" 237219089Spjd "\tzinject -d device [-e errno] [-L <nvlist|uber|pad1|pad2>] [-F]\n" 238219089Spjd "\t [-T <read|write|free|claim|all> pool\n" 239297108Smav "\n" 240185029Spjd "\t\tInject a fault into a particular device or the device's\n" 241219089Spjd "\t\tlabel. Label injection can either be 'nvlist', 'uber',\n " 242219089Spjd "\t\t'pad1', or 'pad2'.\n" 243219089Spjd "\t\t'errno' can be 'nxio' (the default), 'io', or 'dtl'.\n" 244185029Spjd "\n" 245219089Spjd "\tzinject -d device -A <degrade|fault> pool\n" 246297108Smav "\n" 247219089Spjd "\t\tPerform a specific action on a particular device\n" 248219089Spjd "\n" 249297108Smav "\tzinject -d device -D latency:lanes pool\n" 250297108Smav "\n" 251297108Smav "\t\tAdd an artificial delay to IO requests on a particular\n" 252297108Smav "\t\tdevice, such that the requests take a minimum of 'latency'\n" 253297108Smav "\t\tmilliseconds to complete. Each delay has an associated\n" 254297108Smav "\t\tnumber of 'lanes' which defines the number of concurrent\n" 255297108Smav "\t\tIO requests that can be processed.\n" 256297108Smav "\n" 257297108Smav "\t\tFor example, with a single lane delay of 10 ms (-D 10:1),\n" 258297108Smav "\t\tthe device will only be able to service a single IO request\n" 259297108Smav "\t\tat a time with each request taking 10 ms to complete. So,\n" 260297108Smav "\t\tif only a single request is submitted every 10 ms, the\n" 261297108Smav "\t\taverage latency will be 10 ms; but if more than one request\n" 262297108Smav "\t\tis submitted every 10 ms, the average latency will be more\n" 263297108Smav "\t\tthan 10 ms.\n" 264297108Smav "\n" 265297108Smav "\t\tSimilarly, if a delay of 10 ms is specified to have two\n" 266297108Smav "\t\tlanes (-D 10:2), then the device will be able to service\n" 267297108Smav "\t\ttwo requests at a time, each with a minimum latency of\n" 268297108Smav "\t\t10 ms. So, if two requests are submitted every 10 ms, then\n" 269297108Smav "\t\tthe average latency will be 10 ms; but if more than two\n" 270297108Smav "\t\trequests are submitted every 10 ms, the average latency\n" 271297108Smav "\t\twill be more than 10 ms.\n" 272297108Smav "\n" 273297108Smav "\t\tAlso note, these delays are additive. So two invocations\n" 274297108Smav "\t\tof '-D 10:1', is roughly equivalent to a single invocation\n" 275297108Smav "\t\tof '-D 10:2'. This also means, one can specify multiple\n" 276297108Smav "\t\tlanes with differing target latencies. For example, an\n" 277297108Smav "\t\tinvocation of '-D 10:1' followed by '-D 25:2' will\n" 278297108Smav "\t\tcreate 3 lanes on the device; one lane with a latency\n" 279297108Smav "\t\tof 10 ms and two lanes with a 25 ms latency.\n" 280297108Smav "\n" 281219089Spjd "\tzinject -I [-s <seconds> | -g <txgs>] pool\n" 282297108Smav "\n" 283219089Spjd "\t\tCause the pool to stop writing blocks yet not\n" 284219089Spjd "\t\treport errors for a duration. Simulates buggy hardware\n" 285219089Spjd "\t\tthat fails to honor cache flush requests.\n" 286219089Spjd "\t\tDefault duration is 30 seconds. The machine is panicked\n" 287219089Spjd "\t\tat the end of the duration.\n" 288219089Spjd "\n" 289185029Spjd "\tzinject -b objset:object:level:blkid pool\n" 290185029Spjd "\n" 291185029Spjd "\t\tInject an error into pool 'pool' with the numeric bookmark\n" 292185029Spjd "\t\tspecified by the remaining tuple. Each number is in\n" 293185029Spjd "\t\thexidecimal, and only one block can be specified.\n" 294185029Spjd "\n" 295185029Spjd "\tzinject [-q] <-t type> [-e errno] [-l level] [-r range]\n" 296185029Spjd "\t [-a] [-m] [-u] [-f freq] <object>\n" 297185029Spjd "\n" 298185029Spjd "\t\tInject an error into the object specified by the '-t' option\n" 299185029Spjd "\t\tand the object descriptor. The 'object' parameter is\n" 300185029Spjd "\t\tinterperted depending on the '-t' option.\n" 301185029Spjd "\n" 302185029Spjd "\t\t-q\tQuiet mode. Only print out the handler number added.\n" 303185029Spjd "\t\t-e\tInject a specific error. Must be either 'io' or\n" 304185029Spjd "\t\t\t'checksum'. Default is 'io'.\n" 305185029Spjd "\t\t-l\tInject error at a particular block level. Default is " 306185029Spjd "0.\n" 307185029Spjd "\t\t-m\tAutomatically remount underlying filesystem.\n" 308185029Spjd "\t\t-r\tInject error over a particular logical range of an\n" 309185029Spjd "\t\t\tobject. Will be translated to the appropriate blkid\n" 310185029Spjd "\t\t\trange according to the object's properties.\n" 311185029Spjd "\t\t-a\tFlush the ARC cache. Can be specified without any\n" 312185029Spjd "\t\t\tassociated object.\n" 313185029Spjd "\t\t-u\tUnload the associated pool. Can be specified with only\n" 314185029Spjd "\t\t\ta pool object.\n" 315185029Spjd "\t\t-f\tOnly inject errors a fraction of the time. Expressed as\n" 316185029Spjd "\t\t\ta percentage between 1 and 100.\n" 317185029Spjd "\n" 318185029Spjd "\t-t data\t\tInject an error into the plain file contents of a\n" 319185029Spjd "\t\t\tfile. The object must be specified as a complete path\n" 320185029Spjd "\t\t\tto a file on a ZFS filesystem.\n" 321185029Spjd "\n" 322185029Spjd "\t-t dnode\tInject an error into the metadnode in the block\n" 323185029Spjd "\t\t\tcorresponding to the dnode for a file or directory. The\n" 324185029Spjd "\t\t\t'-r' option is incompatible with this mode. The object\n" 325185029Spjd "\t\t\tis specified as a complete path to a file or directory\n" 326185029Spjd "\t\t\ton a ZFS filesystem.\n" 327185029Spjd "\n" 328185029Spjd "\t-t <mos>\tInject errors into the MOS for objects of the given\n" 329219089Spjd "\t\t\ttype. Valid types are: mos, mosdir, config, bpobj,\n" 330185029Spjd "\t\t\tspacemap, metaslab, errlog. The only valid <object> is\n" 331185029Spjd "\t\t\tthe poolname.\n"); 332185029Spjd} 333185029Spjd 334185029Spjdstatic int 335185029Spjditer_handlers(int (*func)(int, const char *, zinject_record_t *, void *), 336185029Spjd void *data) 337185029Spjd{ 338239774Smm zfs_cmd_t zc = { 0 }; 339185029Spjd int ret; 340185029Spjd 341185029Spjd while (ioctl(zfs_fd, ZFS_IOC_INJECT_LIST_NEXT, &zc) == 0) 342185029Spjd if ((ret = func((int)zc.zc_guid, zc.zc_name, 343185029Spjd &zc.zc_inject_record, data)) != 0) 344185029Spjd return (ret); 345185029Spjd 346219089Spjd if (errno != ENOENT) { 347219089Spjd (void) fprintf(stderr, "Unable to list handlers: %s\n", 348219089Spjd strerror(errno)); 349219089Spjd return (-1); 350219089Spjd } 351219089Spjd 352185029Spjd return (0); 353185029Spjd} 354185029Spjd 355185029Spjdstatic int 356185029Spjdprint_data_handler(int id, const char *pool, zinject_record_t *record, 357185029Spjd void *data) 358185029Spjd{ 359185029Spjd int *count = data; 360185029Spjd 361219089Spjd if (record->zi_guid != 0 || record->zi_func[0] != '\0') 362185029Spjd return (0); 363185029Spjd 364185029Spjd if (*count == 0) { 365185029Spjd (void) printf("%3s %-15s %-6s %-6s %-8s %3s %-15s\n", 366185029Spjd "ID", "POOL", "OBJSET", "OBJECT", "TYPE", "LVL", "RANGE"); 367185029Spjd (void) printf("--- --------------- ------ " 368185029Spjd "------ -------- --- ---------------\n"); 369185029Spjd } 370185029Spjd 371185029Spjd *count += 1; 372185029Spjd 373185029Spjd (void) printf("%3d %-15s %-6llu %-6llu %-8s %3d ", id, pool, 374185029Spjd (u_longlong_t)record->zi_objset, (u_longlong_t)record->zi_object, 375185029Spjd type_to_name(record->zi_type), record->zi_level); 376185029Spjd 377185029Spjd if (record->zi_start == 0 && 378185029Spjd record->zi_end == -1ULL) 379185029Spjd (void) printf("all\n"); 380185029Spjd else 381185029Spjd (void) printf("[%llu, %llu]\n", (u_longlong_t)record->zi_start, 382185029Spjd (u_longlong_t)record->zi_end); 383185029Spjd 384185029Spjd return (0); 385185029Spjd} 386185029Spjd 387185029Spjdstatic int 388185029Spjdprint_device_handler(int id, const char *pool, zinject_record_t *record, 389185029Spjd void *data) 390185029Spjd{ 391185029Spjd int *count = data; 392185029Spjd 393219089Spjd if (record->zi_guid == 0 || record->zi_func[0] != '\0') 394185029Spjd return (0); 395185029Spjd 396297108Smav if (record->zi_cmd == ZINJECT_DELAY_IO) 397297108Smav return (0); 398297108Smav 399185029Spjd if (*count == 0) { 400185029Spjd (void) printf("%3s %-15s %s\n", "ID", "POOL", "GUID"); 401185029Spjd (void) printf("--- --------------- ----------------\n"); 402185029Spjd } 403185029Spjd 404185029Spjd *count += 1; 405185029Spjd 406185029Spjd (void) printf("%3d %-15s %llx\n", id, pool, 407185029Spjd (u_longlong_t)record->zi_guid); 408185029Spjd 409185029Spjd return (0); 410185029Spjd} 411185029Spjd 412219089Spjdstatic int 413297108Smavprint_delay_handler(int id, const char *pool, zinject_record_t *record, 414297108Smav void *data) 415297108Smav{ 416297108Smav int *count = data; 417297108Smav 418297108Smav if (record->zi_guid == 0 || record->zi_func[0] != '\0') 419297108Smav return (0); 420297108Smav 421297108Smav if (record->zi_cmd != ZINJECT_DELAY_IO) 422297108Smav return (0); 423297108Smav 424297108Smav if (*count == 0) { 425297108Smav (void) printf("%3s %-15s %-15s %-15s %s\n", 426297108Smav "ID", "POOL", "DELAY (ms)", "LANES", "GUID"); 427297108Smav (void) printf("--- --------------- --------------- " 428297108Smav "--------------- ----------------\n"); 429297108Smav } 430297108Smav 431297108Smav *count += 1; 432297108Smav 433297108Smav (void) printf("%3d %-15s %-15llu %-15llu %llx\n", id, pool, 434297108Smav (u_longlong_t)NSEC2MSEC(record->zi_timer), 435297108Smav (u_longlong_t)record->zi_nlanes, 436297108Smav (u_longlong_t)record->zi_guid); 437297108Smav 438297108Smav return (0); 439297108Smav} 440297108Smav 441297108Smavstatic int 442219089Spjdprint_panic_handler(int id, const char *pool, zinject_record_t *record, 443219089Spjd void *data) 444219089Spjd{ 445219089Spjd int *count = data; 446219089Spjd 447219089Spjd if (record->zi_func[0] == '\0') 448219089Spjd return (0); 449219089Spjd 450219089Spjd if (*count == 0) { 451219089Spjd (void) printf("%3s %-15s %s\n", "ID", "POOL", "FUNCTION"); 452219089Spjd (void) printf("--- --------------- ----------------\n"); 453219089Spjd } 454219089Spjd 455219089Spjd *count += 1; 456219089Spjd 457219089Spjd (void) printf("%3d %-15s %s\n", id, pool, record->zi_func); 458219089Spjd 459219089Spjd return (0); 460219089Spjd} 461219089Spjd 462185029Spjd/* 463185029Spjd * Print all registered error handlers. Returns the number of handlers 464185029Spjd * registered. 465185029Spjd */ 466185029Spjdstatic int 467185029Spjdprint_all_handlers(void) 468185029Spjd{ 469219089Spjd int count = 0, total = 0; 470185029Spjd 471185029Spjd (void) iter_handlers(print_device_handler, &count); 472219089Spjd if (count > 0) { 473219089Spjd total += count; 474219089Spjd (void) printf("\n"); 475219089Spjd count = 0; 476219089Spjd } 477219089Spjd 478297108Smav (void) iter_handlers(print_delay_handler, &count); 479297108Smav if (count > 0) { 480297108Smav total += count; 481297108Smav (void) printf("\n"); 482297108Smav count = 0; 483297108Smav } 484297108Smav 485185029Spjd (void) iter_handlers(print_data_handler, &count); 486219089Spjd if (count > 0) { 487219089Spjd total += count; 488219089Spjd (void) printf("\n"); 489219089Spjd count = 0; 490219089Spjd } 491185029Spjd 492219089Spjd (void) iter_handlers(print_panic_handler, &count); 493219089Spjd 494219089Spjd return (count + total); 495185029Spjd} 496185029Spjd 497185029Spjd/* ARGSUSED */ 498185029Spjdstatic int 499185029Spjdcancel_one_handler(int id, const char *pool, zinject_record_t *record, 500185029Spjd void *data) 501185029Spjd{ 502239774Smm zfs_cmd_t zc = { 0 }; 503185029Spjd 504185029Spjd zc.zc_guid = (uint64_t)id; 505185029Spjd 506185029Spjd if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) { 507185029Spjd (void) fprintf(stderr, "failed to remove handler %d: %s\n", 508185029Spjd id, strerror(errno)); 509185029Spjd return (1); 510185029Spjd } 511185029Spjd 512185029Spjd return (0); 513185029Spjd} 514185029Spjd 515185029Spjd/* 516185029Spjd * Remove all fault injection handlers. 517185029Spjd */ 518185029Spjdstatic int 519185029Spjdcancel_all_handlers(void) 520185029Spjd{ 521185029Spjd int ret = iter_handlers(cancel_one_handler, NULL); 522185029Spjd 523219089Spjd if (ret == 0) 524219089Spjd (void) printf("removed all registered handlers\n"); 525185029Spjd 526185029Spjd return (ret); 527185029Spjd} 528185029Spjd 529185029Spjd/* 530185029Spjd * Remove a specific fault injection handler. 531185029Spjd */ 532185029Spjdstatic int 533185029Spjdcancel_handler(int id) 534185029Spjd{ 535239774Smm zfs_cmd_t zc = { 0 }; 536185029Spjd 537185029Spjd zc.zc_guid = (uint64_t)id; 538185029Spjd 539185029Spjd if (ioctl(zfs_fd, ZFS_IOC_CLEAR_FAULT, &zc) != 0) { 540185029Spjd (void) fprintf(stderr, "failed to remove handler %d: %s\n", 541185029Spjd id, strerror(errno)); 542185029Spjd return (1); 543185029Spjd } 544185029Spjd 545185029Spjd (void) printf("removed handler %d\n", id); 546185029Spjd 547185029Spjd return (0); 548185029Spjd} 549185029Spjd 550185029Spjd/* 551185029Spjd * Register a new fault injection handler. 552185029Spjd */ 553185029Spjdstatic int 554185029Spjdregister_handler(const char *pool, int flags, zinject_record_t *record, 555185029Spjd int quiet) 556185029Spjd{ 557239774Smm zfs_cmd_t zc = { 0 }; 558185029Spjd 559185029Spjd (void) strcpy(zc.zc_name, pool); 560185029Spjd zc.zc_inject_record = *record; 561185029Spjd zc.zc_guid = flags; 562185029Spjd 563185029Spjd if (ioctl(zfs_fd, ZFS_IOC_INJECT_FAULT, &zc) != 0) { 564185029Spjd (void) fprintf(stderr, "failed to add handler: %s\n", 565185029Spjd strerror(errno)); 566185029Spjd return (1); 567185029Spjd } 568185029Spjd 569185029Spjd if (flags & ZINJECT_NULL) 570185029Spjd return (0); 571185029Spjd 572185029Spjd if (quiet) { 573185029Spjd (void) printf("%llu\n", (u_longlong_t)zc.zc_guid); 574185029Spjd } else { 575185029Spjd (void) printf("Added handler %llu with the following " 576185029Spjd "properties:\n", (u_longlong_t)zc.zc_guid); 577185029Spjd (void) printf(" pool: %s\n", pool); 578185029Spjd if (record->zi_guid) { 579185029Spjd (void) printf(" vdev: %llx\n", 580185029Spjd (u_longlong_t)record->zi_guid); 581219089Spjd } else if (record->zi_func[0] != '\0') { 582219089Spjd (void) printf(" panic function: %s\n", 583219089Spjd record->zi_func); 584219089Spjd } else if (record->zi_duration > 0) { 585219089Spjd (void) printf(" time: %lld seconds\n", 586219089Spjd (u_longlong_t)record->zi_duration); 587219089Spjd } else if (record->zi_duration < 0) { 588219089Spjd (void) printf(" txgs: %lld \n", 589219089Spjd (u_longlong_t)-record->zi_duration); 590185029Spjd } else { 591185029Spjd (void) printf("objset: %llu\n", 592185029Spjd (u_longlong_t)record->zi_objset); 593185029Spjd (void) printf("object: %llu\n", 594185029Spjd (u_longlong_t)record->zi_object); 595185029Spjd (void) printf(" type: %llu\n", 596185029Spjd (u_longlong_t)record->zi_type); 597185029Spjd (void) printf(" level: %d\n", record->zi_level); 598185029Spjd if (record->zi_start == 0 && 599185029Spjd record->zi_end == -1ULL) 600185029Spjd (void) printf(" range: all\n"); 601185029Spjd else 602185029Spjd (void) printf(" range: [%llu, %llu)\n", 603185029Spjd (u_longlong_t)record->zi_start, 604185029Spjd (u_longlong_t)record->zi_end); 605185029Spjd } 606185029Spjd } 607185029Spjd 608185029Spjd return (0); 609185029Spjd} 610185029Spjd 611185029Spjdint 612219089Spjdperform_action(const char *pool, zinject_record_t *record, int cmd) 613219089Spjd{ 614239774Smm zfs_cmd_t zc = { 0 }; 615219089Spjd 616219089Spjd ASSERT(cmd == VDEV_STATE_DEGRADED || cmd == VDEV_STATE_FAULTED); 617219089Spjd (void) strlcpy(zc.zc_name, pool, sizeof (zc.zc_name)); 618219089Spjd zc.zc_guid = record->zi_guid; 619219089Spjd zc.zc_cookie = cmd; 620219089Spjd 621219089Spjd if (ioctl(zfs_fd, ZFS_IOC_VDEV_SET_STATE, &zc) == 0) 622219089Spjd return (0); 623219089Spjd 624219089Spjd return (1); 625219089Spjd} 626219089Spjd 627297108Smavstatic int 628297108Smavparse_delay(char *str, uint64_t *delay, uint64_t *nlanes) 629297108Smav{ 630297108Smav unsigned long scan_delay; 631297108Smav unsigned long scan_nlanes; 632297108Smav 633297108Smav if (sscanf(str, "%lu:%lu", &scan_delay, &scan_nlanes) != 2) 634297108Smav return (1); 635297108Smav 636297108Smav /* 637297108Smav * We explicitly disallow a delay of zero here, because we key 638297108Smav * off this value being non-zero in translate_device(), to 639297108Smav * determine if the fault is a ZINJECT_DELAY_IO fault or not. 640297108Smav */ 641297108Smav if (scan_delay == 0) 642297108Smav return (1); 643297108Smav 644297108Smav /* 645297108Smav * The units for the CLI delay parameter is milliseconds, but 646297108Smav * the data passed to the kernel is interpreted as nanoseconds. 647297108Smav * Thus we scale the milliseconds to nanoseconds here, and this 648297108Smav * nanosecond value is used to pass the delay to the kernel. 649297108Smav */ 650297108Smav *delay = MSEC2NSEC(scan_delay); 651297108Smav *nlanes = scan_nlanes; 652297108Smav 653297108Smav return (0); 654297108Smav} 655297108Smav 656219089Spjdint 657185029Spjdmain(int argc, char **argv) 658185029Spjd{ 659185029Spjd int c; 660185029Spjd char *range = NULL; 661185029Spjd char *cancel = NULL; 662185029Spjd char *end; 663185029Spjd char *raw = NULL; 664185029Spjd char *device = NULL; 665185029Spjd int level = 0; 666185029Spjd int quiet = 0; 667185029Spjd int error = 0; 668185029Spjd int domount = 0; 669219089Spjd int io_type = ZIO_TYPES; 670219089Spjd int action = VDEV_STATE_UNKNOWN; 671185029Spjd err_type_t type = TYPE_INVAL; 672185029Spjd err_type_t label = TYPE_INVAL; 673185029Spjd zinject_record_t record = { 0 }; 674185029Spjd char pool[MAXNAMELEN]; 675185029Spjd char dataset[MAXNAMELEN]; 676185029Spjd zfs_handle_t *zhp; 677219089Spjd int nowrites = 0; 678219089Spjd int dur_txg = 0; 679219089Spjd int dur_secs = 0; 680185029Spjd int ret; 681185029Spjd int flags = 0; 682185029Spjd 683185029Spjd if ((g_zfs = libzfs_init()) == NULL) { 684185029Spjd (void) fprintf(stderr, "internal error: failed to " 685185029Spjd "initialize ZFS library\n"); 686185029Spjd return (1); 687185029Spjd } 688185029Spjd 689185029Spjd libzfs_print_on_error(g_zfs, B_TRUE); 690185029Spjd 691185029Spjd if ((zfs_fd = open(ZFS_DEV, O_RDWR)) < 0) { 692185029Spjd (void) fprintf(stderr, "failed to open ZFS device\n"); 693185029Spjd return (1); 694185029Spjd } 695185029Spjd 696185029Spjd if (argc == 1) { 697185029Spjd /* 698185029Spjd * No arguments. Print the available handlers. If there are no 699185029Spjd * available handlers, direct the user to '-h' for help 700185029Spjd * information. 701185029Spjd */ 702185029Spjd if (print_all_handlers() == 0) { 703185029Spjd (void) printf("No handlers registered.\n"); 704185029Spjd (void) printf("Run 'zinject -h' for usage " 705185029Spjd "information.\n"); 706185029Spjd } 707185029Spjd 708185029Spjd return (0); 709185029Spjd } 710185029Spjd 711219089Spjd while ((c = getopt(argc, argv, 712247265Smm ":aA:b:d:D:f:Fg:qhIc:t:T:l:mr:s:e:uL:p:")) != -1) { 713185029Spjd switch (c) { 714185029Spjd case 'a': 715185029Spjd flags |= ZINJECT_FLUSH_ARC; 716185029Spjd break; 717219089Spjd case 'A': 718219089Spjd if (strcasecmp(optarg, "degrade") == 0) { 719219089Spjd action = VDEV_STATE_DEGRADED; 720219089Spjd } else if (strcasecmp(optarg, "fault") == 0) { 721219089Spjd action = VDEV_STATE_FAULTED; 722219089Spjd } else { 723219089Spjd (void) fprintf(stderr, "invalid action '%s': " 724219089Spjd "must be 'degrade' or 'fault'\n", optarg); 725219089Spjd usage(); 726219089Spjd return (1); 727219089Spjd } 728219089Spjd break; 729185029Spjd case 'b': 730185029Spjd raw = optarg; 731185029Spjd break; 732185029Spjd case 'c': 733185029Spjd cancel = optarg; 734185029Spjd break; 735185029Spjd case 'd': 736185029Spjd device = optarg; 737185029Spjd break; 738247265Smm case 'D': 739297108Smav ret = parse_delay(optarg, &record.zi_timer, 740297108Smav &record.zi_nlanes); 741297108Smav if (ret != 0) { 742247265Smm (void) fprintf(stderr, "invalid i/o delay " 743247265Smm "value: '%s'\n", optarg); 744247265Smm usage(); 745247265Smm return (1); 746247265Smm } 747247265Smm break; 748185029Spjd case 'e': 749185029Spjd if (strcasecmp(optarg, "io") == 0) { 750185029Spjd error = EIO; 751185029Spjd } else if (strcasecmp(optarg, "checksum") == 0) { 752185029Spjd error = ECKSUM; 753185029Spjd } else if (strcasecmp(optarg, "nxio") == 0) { 754185029Spjd error = ENXIO; 755219089Spjd } else if (strcasecmp(optarg, "dtl") == 0) { 756219089Spjd error = ECHILD; 757185029Spjd } else { 758185029Spjd (void) fprintf(stderr, "invalid error type " 759185029Spjd "'%s': must be 'io', 'checksum' or " 760185029Spjd "'nxio'\n", optarg); 761185029Spjd usage(); 762185029Spjd return (1); 763185029Spjd } 764185029Spjd break; 765185029Spjd case 'f': 766185029Spjd record.zi_freq = atoi(optarg); 767185029Spjd if (record.zi_freq < 1 || record.zi_freq > 100) { 768185029Spjd (void) fprintf(stderr, "frequency range must " 769185029Spjd "be in the range (0, 100]\n"); 770185029Spjd return (1); 771185029Spjd } 772185029Spjd break; 773213198Smm case 'F': 774213198Smm record.zi_failfast = B_TRUE; 775213198Smm break; 776219089Spjd case 'g': 777219089Spjd dur_txg = 1; 778219089Spjd record.zi_duration = (int)strtol(optarg, &end, 10); 779219089Spjd if (record.zi_duration <= 0 || *end != '\0') { 780219089Spjd (void) fprintf(stderr, "invalid duration '%s': " 781219089Spjd "must be a positive integer\n", optarg); 782219089Spjd usage(); 783219089Spjd return (1); 784219089Spjd } 785219089Spjd /* store duration of txgs as its negative */ 786219089Spjd record.zi_duration *= -1; 787219089Spjd break; 788185029Spjd case 'h': 789185029Spjd usage(); 790185029Spjd return (0); 791219089Spjd case 'I': 792219089Spjd /* default duration, if one hasn't yet been defined */ 793219089Spjd nowrites = 1; 794219089Spjd if (dur_secs == 0 && dur_txg == 0) 795219089Spjd record.zi_duration = 30; 796219089Spjd break; 797185029Spjd case 'l': 798185029Spjd level = (int)strtol(optarg, &end, 10); 799185029Spjd if (*end != '\0') { 800185029Spjd (void) fprintf(stderr, "invalid level '%s': " 801185029Spjd "must be an integer\n", optarg); 802185029Spjd usage(); 803185029Spjd return (1); 804185029Spjd } 805185029Spjd break; 806185029Spjd case 'm': 807185029Spjd domount = 1; 808185029Spjd break; 809219089Spjd case 'p': 810219089Spjd (void) strlcpy(record.zi_func, optarg, 811219089Spjd sizeof (record.zi_func)); 812247265Smm record.zi_cmd = ZINJECT_PANIC; 813219089Spjd break; 814185029Spjd case 'q': 815185029Spjd quiet = 1; 816185029Spjd break; 817185029Spjd case 'r': 818185029Spjd range = optarg; 819185029Spjd break; 820219089Spjd case 's': 821219089Spjd dur_secs = 1; 822219089Spjd record.zi_duration = (int)strtol(optarg, &end, 10); 823219089Spjd if (record.zi_duration <= 0 || *end != '\0') { 824219089Spjd (void) fprintf(stderr, "invalid duration '%s': " 825219089Spjd "must be a positive integer\n", optarg); 826219089Spjd usage(); 827219089Spjd return (1); 828219089Spjd } 829219089Spjd break; 830219089Spjd case 'T': 831219089Spjd if (strcasecmp(optarg, "read") == 0) { 832219089Spjd io_type = ZIO_TYPE_READ; 833219089Spjd } else if (strcasecmp(optarg, "write") == 0) { 834219089Spjd io_type = ZIO_TYPE_WRITE; 835219089Spjd } else if (strcasecmp(optarg, "free") == 0) { 836219089Spjd io_type = ZIO_TYPE_FREE; 837219089Spjd } else if (strcasecmp(optarg, "claim") == 0) { 838219089Spjd io_type = ZIO_TYPE_CLAIM; 839219089Spjd } else if (strcasecmp(optarg, "all") == 0) { 840219089Spjd io_type = ZIO_TYPES; 841219089Spjd } else { 842219089Spjd (void) fprintf(stderr, "invalid I/O type " 843219089Spjd "'%s': must be 'read', 'write', 'free', " 844219089Spjd "'claim' or 'all'\n", optarg); 845219089Spjd usage(); 846219089Spjd return (1); 847219089Spjd } 848219089Spjd break; 849185029Spjd case 't': 850185029Spjd if ((type = name_to_type(optarg)) == TYPE_INVAL && 851185029Spjd !MOS_TYPE(type)) { 852185029Spjd (void) fprintf(stderr, "invalid type '%s'\n", 853185029Spjd optarg); 854185029Spjd usage(); 855185029Spjd return (1); 856185029Spjd } 857185029Spjd break; 858185029Spjd case 'u': 859185029Spjd flags |= ZINJECT_UNLOAD_SPA; 860185029Spjd break; 861185029Spjd case 'L': 862185029Spjd if ((label = name_to_type(optarg)) == TYPE_INVAL && 863185029Spjd !LABEL_TYPE(type)) { 864185029Spjd (void) fprintf(stderr, "invalid label type " 865185029Spjd "'%s'\n", optarg); 866185029Spjd usage(); 867185029Spjd return (1); 868185029Spjd } 869185029Spjd break; 870185029Spjd case ':': 871185029Spjd (void) fprintf(stderr, "option -%c requires an " 872185029Spjd "operand\n", optopt); 873185029Spjd usage(); 874185029Spjd return (1); 875185029Spjd case '?': 876185029Spjd (void) fprintf(stderr, "invalid option '%c'\n", 877185029Spjd optopt); 878185029Spjd usage(); 879185029Spjd return (2); 880185029Spjd } 881185029Spjd } 882185029Spjd 883185029Spjd argc -= optind; 884185029Spjd argv += optind; 885185029Spjd 886247265Smm if (record.zi_duration != 0) 887247265Smm record.zi_cmd = ZINJECT_IGNORED_WRITES; 888247265Smm 889185029Spjd if (cancel != NULL) { 890185029Spjd /* 891185029Spjd * '-c' is invalid with any other options. 892185029Spjd */ 893185029Spjd if (raw != NULL || range != NULL || type != TYPE_INVAL || 894247265Smm level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) { 895185029Spjd (void) fprintf(stderr, "cancel (-c) incompatible with " 896185029Spjd "any other options\n"); 897185029Spjd usage(); 898185029Spjd return (2); 899185029Spjd } 900185029Spjd if (argc != 0) { 901185029Spjd (void) fprintf(stderr, "extraneous argument to '-c'\n"); 902185029Spjd usage(); 903185029Spjd return (2); 904185029Spjd } 905185029Spjd 906185029Spjd if (strcmp(cancel, "all") == 0) { 907185029Spjd return (cancel_all_handlers()); 908185029Spjd } else { 909185029Spjd int id = (int)strtol(cancel, &end, 10); 910185029Spjd if (*end != '\0') { 911185029Spjd (void) fprintf(stderr, "invalid handle id '%s':" 912185029Spjd " must be an integer or 'all'\n", cancel); 913185029Spjd usage(); 914185029Spjd return (1); 915185029Spjd } 916185029Spjd return (cancel_handler(id)); 917185029Spjd } 918185029Spjd } 919185029Spjd 920185029Spjd if (device != NULL) { 921185029Spjd /* 922185029Spjd * Device (-d) injection uses a completely different mechanism 923185029Spjd * for doing injection, so handle it separately here. 924185029Spjd */ 925185029Spjd if (raw != NULL || range != NULL || type != TYPE_INVAL || 926247265Smm level != 0 || record.zi_cmd != ZINJECT_UNINITIALIZED) { 927185029Spjd (void) fprintf(stderr, "device (-d) incompatible with " 928185029Spjd "data error injection\n"); 929185029Spjd usage(); 930185029Spjd return (2); 931185029Spjd } 932185029Spjd 933185029Spjd if (argc != 1) { 934185029Spjd (void) fprintf(stderr, "device (-d) injection requires " 935185029Spjd "a single pool name\n"); 936185029Spjd usage(); 937185029Spjd return (2); 938185029Spjd } 939185029Spjd 940185029Spjd (void) strcpy(pool, argv[0]); 941185029Spjd dataset[0] = '\0'; 942185029Spjd 943185029Spjd if (error == ECKSUM) { 944185029Spjd (void) fprintf(stderr, "device error type must be " 945185029Spjd "'io' or 'nxio'\n"); 946185029Spjd return (1); 947185029Spjd } 948185029Spjd 949219089Spjd record.zi_iotype = io_type; 950185029Spjd if (translate_device(pool, device, label, &record) != 0) 951185029Spjd return (1); 952185029Spjd if (!error) 953185029Spjd error = ENXIO; 954219089Spjd 955219089Spjd if (action != VDEV_STATE_UNKNOWN) 956219089Spjd return (perform_action(pool, &record, action)); 957219089Spjd 958185029Spjd } else if (raw != NULL) { 959219089Spjd if (range != NULL || type != TYPE_INVAL || level != 0 || 960247265Smm record.zi_cmd != ZINJECT_UNINITIALIZED) { 961185029Spjd (void) fprintf(stderr, "raw (-b) format with " 962185029Spjd "any other options\n"); 963185029Spjd usage(); 964185029Spjd return (2); 965185029Spjd } 966185029Spjd 967185029Spjd if (argc != 1) { 968185029Spjd (void) fprintf(stderr, "raw (-b) format expects a " 969185029Spjd "single pool name\n"); 970185029Spjd usage(); 971185029Spjd return (2); 972185029Spjd } 973185029Spjd 974185029Spjd (void) strcpy(pool, argv[0]); 975185029Spjd dataset[0] = '\0'; 976185029Spjd 977185029Spjd if (error == ENXIO) { 978185029Spjd (void) fprintf(stderr, "data error type must be " 979185029Spjd "'checksum' or 'io'\n"); 980185029Spjd return (1); 981185029Spjd } 982185029Spjd 983247265Smm record.zi_cmd = ZINJECT_DATA_FAULT; 984185029Spjd if (translate_raw(raw, &record) != 0) 985185029Spjd return (1); 986185029Spjd if (!error) 987185029Spjd error = EIO; 988247265Smm } else if (record.zi_cmd == ZINJECT_PANIC) { 989219089Spjd if (raw != NULL || range != NULL || type != TYPE_INVAL || 990247265Smm level != 0 || device != NULL) { 991219089Spjd (void) fprintf(stderr, "panic (-p) incompatible with " 992219089Spjd "other options\n"); 993219089Spjd usage(); 994219089Spjd return (2); 995219089Spjd } 996219089Spjd 997219089Spjd if (argc < 1 || argc > 2) { 998219089Spjd (void) fprintf(stderr, "panic (-p) injection requires " 999219089Spjd "a single pool name and an optional id\n"); 1000219089Spjd usage(); 1001219089Spjd return (2); 1002219089Spjd } 1003219089Spjd 1004219089Spjd (void) strcpy(pool, argv[0]); 1005219089Spjd if (argv[1] != NULL) 1006219089Spjd record.zi_type = atoi(argv[1]); 1007219089Spjd dataset[0] = '\0'; 1008247265Smm } else if (record.zi_cmd == ZINJECT_IGNORED_WRITES) { 1009219089Spjd if (nowrites == 0) { 1010219089Spjd (void) fprintf(stderr, "-s or -g meaningless " 1011219089Spjd "without -I (ignore writes)\n"); 1012219089Spjd usage(); 1013219089Spjd return (2); 1014219089Spjd } else if (dur_secs && dur_txg) { 1015219089Spjd (void) fprintf(stderr, "choose a duration either " 1016219089Spjd "in seconds (-s) or a number of txgs (-g) " 1017219089Spjd "but not both\n"); 1018219089Spjd usage(); 1019219089Spjd return (2); 1020219089Spjd } else if (argc != 1) { 1021219089Spjd (void) fprintf(stderr, "ignore writes (-I) " 1022219089Spjd "injection requires a single pool name\n"); 1023219089Spjd usage(); 1024219089Spjd return (2); 1025219089Spjd } 1026219089Spjd 1027219089Spjd (void) strcpy(pool, argv[0]); 1028219089Spjd dataset[0] = '\0'; 1029185029Spjd } else if (type == TYPE_INVAL) { 1030185029Spjd if (flags == 0) { 1031185029Spjd (void) fprintf(stderr, "at least one of '-b', '-d', " 1032219089Spjd "'-t', '-a', '-p', '-I' or '-u' " 1033219089Spjd "must be specified\n"); 1034185029Spjd usage(); 1035185029Spjd return (2); 1036185029Spjd } 1037185029Spjd 1038185029Spjd if (argc == 1 && (flags & ZINJECT_UNLOAD_SPA)) { 1039185029Spjd (void) strcpy(pool, argv[0]); 1040185029Spjd dataset[0] = '\0'; 1041185029Spjd } else if (argc != 0) { 1042185029Spjd (void) fprintf(stderr, "extraneous argument for " 1043185029Spjd "'-f'\n"); 1044185029Spjd usage(); 1045185029Spjd return (2); 1046185029Spjd } 1047185029Spjd 1048185029Spjd flags |= ZINJECT_NULL; 1049185029Spjd } else { 1050185029Spjd if (argc != 1) { 1051185029Spjd (void) fprintf(stderr, "missing object\n"); 1052185029Spjd usage(); 1053185029Spjd return (2); 1054185029Spjd } 1055185029Spjd 1056185029Spjd if (error == ENXIO) { 1057185029Spjd (void) fprintf(stderr, "data error type must be " 1058185029Spjd "'checksum' or 'io'\n"); 1059185029Spjd return (1); 1060185029Spjd } 1061185029Spjd 1062247265Smm record.zi_cmd = ZINJECT_DATA_FAULT; 1063185029Spjd if (translate_record(type, argv[0], range, level, &record, pool, 1064185029Spjd dataset) != 0) 1065185029Spjd return (1); 1066185029Spjd if (!error) 1067185029Spjd error = EIO; 1068185029Spjd } 1069185029Spjd 1070185029Spjd /* 1071185029Spjd * If this is pool-wide metadata, unmount everything. The ioctl() will 1072185029Spjd * unload the pool, so that we trigger spa-wide reopen of metadata next 1073185029Spjd * time we access the pool. 1074185029Spjd */ 1075185029Spjd if (dataset[0] != '\0' && domount) { 1076185029Spjd if ((zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET)) == NULL) 1077185029Spjd return (1); 1078185029Spjd 1079185029Spjd if (zfs_unmount(zhp, NULL, 0) != 0) 1080185029Spjd return (1); 1081185029Spjd } 1082185029Spjd 1083185029Spjd record.zi_error = error; 1084185029Spjd 1085185029Spjd ret = register_handler(pool, flags, &record, quiet); 1086185029Spjd 1087185029Spjd if (dataset[0] != '\0' && domount) 1088185029Spjd ret = (zfs_mount(zhp, NULL, 0) != 0); 1089185029Spjd 1090185029Spjd libzfs_fini(g_zfs); 1091185029Spjd 1092185029Spjd return (ret); 1093185029Spjd} 1094