1ea8dc4b6Seschrock /*
2ea8dc4b6Seschrock * CDDL HEADER START
3ea8dc4b6Seschrock *
4ea8dc4b6Seschrock * The contents of this file are subject to the terms of the
5ea8dc4b6Seschrock * Common Development and Distribution License (the "License").
6ea8dc4b6Seschrock * You may not use this file except in compliance with the License.
7ea8dc4b6Seschrock *
8ea8dc4b6Seschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9ea8dc4b6Seschrock * or http://www.opensolaris.org/os/licensing.
10ea8dc4b6Seschrock * See the License for the specific language governing permissions
11ea8dc4b6Seschrock * and limitations under the License.
12ea8dc4b6Seschrock *
13ea8dc4b6Seschrock * When distributing Covered Code, include this CDDL HEADER in each
14ea8dc4b6Seschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15ea8dc4b6Seschrock * If applicable, add the following below this CDDL HEADER, with the
16ea8dc4b6Seschrock * fields enclosed by brackets "[]" replaced with your own identifying
17ea8dc4b6Seschrock * information: Portions Copyright [yyyy] [name of copyright owner]
18ea8dc4b6Seschrock *
19ea8dc4b6Seschrock * CDDL HEADER END
20ea8dc4b6Seschrock */
21ea8dc4b6Seschrock /*
2298d1cbfeSGeorge Wilson * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
2305d95d03SMatthew Ahrens * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
24ea8dc4b6Seschrock */
25ea8dc4b6Seschrock
26ea8dc4b6Seschrock /*
27ea8dc4b6Seschrock * ZFS fault injection
28ea8dc4b6Seschrock *
29ea8dc4b6Seschrock * To handle fault injection, we keep track of a series of zinject_record_t
30ea8dc4b6Seschrock * structures which describe which logical block(s) should be injected with a
31ea8dc4b6Seschrock * fault. These are kept in a global list. Each record corresponds to a given
32ea8dc4b6Seschrock * spa_t and maintains a special hold on the spa_t so that it cannot be deleted
33ea8dc4b6Seschrock * or exported while the injection record exists.
34ea8dc4b6Seschrock *
35ea8dc4b6Seschrock * Device level injection is done using the 'zi_guid' field. If this is set, it
36ea8dc4b6Seschrock * means that the error is destined for a particular device, not a piece of
37ea8dc4b6Seschrock * data.
38ea8dc4b6Seschrock *
39ea8dc4b6Seschrock * This is a rather poor data structure and algorithm, but we don't expect more
40ea8dc4b6Seschrock * than a few faults at any one time, so it should be sufficient for our needs.
41ea8dc4b6Seschrock */
42ea8dc4b6Seschrock
43ea8dc4b6Seschrock #include <sys/arc.h>
44ea8dc4b6Seschrock #include <sys/zio_impl.h>
45ea8dc4b6Seschrock #include <sys/zfs_ioctl.h>
46ea8dc4b6Seschrock #include <sys/vdev_impl.h>
47b24ab676SJeff Bonwick #include <sys/dmu_objset.h>
4821bf64a7Sgw25295 #include <sys/fs/zfs.h>
49ea8dc4b6Seschrock
50ea8dc4b6Seschrock uint32_t zio_injection_enabled;
51ea8dc4b6Seschrock
52ea8dc4b6Seschrock typedef struct inject_handler {
53ea8dc4b6Seschrock int zi_id;
54ea8dc4b6Seschrock spa_t *zi_spa;
55ea8dc4b6Seschrock zinject_record_t zi_record;
56ea8dc4b6Seschrock list_node_t zi_link;
57ea8dc4b6Seschrock } inject_handler_t;
58ea8dc4b6Seschrock
59ea8dc4b6Seschrock static list_t inject_handlers;
60ea8dc4b6Seschrock static krwlock_t inject_lock;
61ea8dc4b6Seschrock static int inject_next_id = 1;
62ea8dc4b6Seschrock
63ea8dc4b6Seschrock /*
64ea8dc4b6Seschrock * Returns true if the given record matches the I/O in progress.
65ea8dc4b6Seschrock */
66ea8dc4b6Seschrock static boolean_t
zio_match_handler(zbookmark_phys_t * zb,uint64_t type,zinject_record_t * record,int error)6705d95d03SMatthew Ahrens zio_match_handler(zbookmark_phys_t *zb, uint64_t type,
68ea8dc4b6Seschrock zinject_record_t *record, int error)
69ea8dc4b6Seschrock {
70ea8dc4b6Seschrock /*
71ea8dc4b6Seschrock * Check for a match against the MOS, which is based on type
72ea8dc4b6Seschrock */
73b24ab676SJeff Bonwick if (zb->zb_objset == DMU_META_OBJSET &&
74b24ab676SJeff Bonwick record->zi_objset == DMU_META_OBJSET &&
75b24ab676SJeff Bonwick record->zi_object == DMU_META_DNODE_OBJECT) {
76ea8dc4b6Seschrock if (record->zi_type == DMU_OT_NONE ||
77ea8dc4b6Seschrock type == record->zi_type)
78ea8dc4b6Seschrock return (record->zi_freq == 0 ||
79ea8dc4b6Seschrock spa_get_random(100) < record->zi_freq);
80ea8dc4b6Seschrock else
81ea8dc4b6Seschrock return (B_FALSE);
82ea8dc4b6Seschrock }
83ea8dc4b6Seschrock
84ea8dc4b6Seschrock /*
85ea8dc4b6Seschrock * Check for an exact match.
86ea8dc4b6Seschrock */
87ea8dc4b6Seschrock if (zb->zb_objset == record->zi_objset &&
88ea8dc4b6Seschrock zb->zb_object == record->zi_object &&
89ea8dc4b6Seschrock zb->zb_level == record->zi_level &&
90ea8dc4b6Seschrock zb->zb_blkid >= record->zi_start &&
91ea8dc4b6Seschrock zb->zb_blkid <= record->zi_end &&
92ea8dc4b6Seschrock error == record->zi_error)
93ea8dc4b6Seschrock return (record->zi_freq == 0 ||
94ea8dc4b6Seschrock spa_get_random(100) < record->zi_freq);
95ea8dc4b6Seschrock
96ea8dc4b6Seschrock return (B_FALSE);
97ea8dc4b6Seschrock }
98ea8dc4b6Seschrock
99ea8dc4b6Seschrock /*
10088ecc943SGeorge Wilson * Panic the system when a config change happens in the function
10188ecc943SGeorge Wilson * specified by tag.
10288ecc943SGeorge Wilson */
10388ecc943SGeorge Wilson void
zio_handle_panic_injection(spa_t * spa,char * tag,uint64_t type)1041195e687SMark J Musante zio_handle_panic_injection(spa_t *spa, char *tag, uint64_t type)
10588ecc943SGeorge Wilson {
10688ecc943SGeorge Wilson inject_handler_t *handler;
10788ecc943SGeorge Wilson
10888ecc943SGeorge Wilson rw_enter(&inject_lock, RW_READER);
10988ecc943SGeorge Wilson
11088ecc943SGeorge Wilson for (handler = list_head(&inject_handlers); handler != NULL;
11188ecc943SGeorge Wilson handler = list_next(&inject_handlers, handler)) {
11288ecc943SGeorge Wilson
11388ecc943SGeorge Wilson if (spa != handler->zi_spa)
11488ecc943SGeorge Wilson continue;
11588ecc943SGeorge Wilson
1161195e687SMark J Musante if (handler->zi_record.zi_type == type &&
1171195e687SMark J Musante strcmp(tag, handler->zi_record.zi_func) == 0)
11888ecc943SGeorge Wilson panic("Panic requested in function %s\n", tag);
11988ecc943SGeorge Wilson }
12088ecc943SGeorge Wilson
12188ecc943SGeorge Wilson rw_exit(&inject_lock);
12288ecc943SGeorge Wilson }
12388ecc943SGeorge Wilson
12488ecc943SGeorge Wilson /*
125ea8dc4b6Seschrock * Determine if the I/O in question should return failure. Returns the errno
126ea8dc4b6Seschrock * to be returned to the caller.
127ea8dc4b6Seschrock */
128ea8dc4b6Seschrock int
zio_handle_fault_injection(zio_t * zio,int error)129ea8dc4b6Seschrock zio_handle_fault_injection(zio_t *zio, int error)
130ea8dc4b6Seschrock {
131ea8dc4b6Seschrock int ret = 0;
132ea8dc4b6Seschrock inject_handler_t *handler;
133ea8dc4b6Seschrock
134ea8dc4b6Seschrock /*
135ea8dc4b6Seschrock * Ignore I/O not associated with any logical data.
136ea8dc4b6Seschrock */
137ea8dc4b6Seschrock if (zio->io_logical == NULL)
138ea8dc4b6Seschrock return (0);
139ea8dc4b6Seschrock
140ea8dc4b6Seschrock /*
141ea8dc4b6Seschrock * Currently, we only support fault injection on reads.
142ea8dc4b6Seschrock */
143ea8dc4b6Seschrock if (zio->io_type != ZIO_TYPE_READ)
144ea8dc4b6Seschrock return (0);
145ea8dc4b6Seschrock
146ea8dc4b6Seschrock rw_enter(&inject_lock, RW_READER);
147ea8dc4b6Seschrock
148ea8dc4b6Seschrock for (handler = list_head(&inject_handlers); handler != NULL;
149ea8dc4b6Seschrock handler = list_next(&inject_handlers, handler)) {
150ea8dc4b6Seschrock
151283b8460SGeorge.Wilson if (zio->io_spa != handler->zi_spa ||
152283b8460SGeorge.Wilson handler->zi_record.zi_cmd != ZINJECT_DATA_FAULT)
153ea8dc4b6Seschrock continue;
154ea8dc4b6Seschrock
155ea8dc4b6Seschrock /* If this handler matches, return EIO */
156ea8dc4b6Seschrock if (zio_match_handler(&zio->io_logical->io_bookmark,
157ea8dc4b6Seschrock zio->io_bp ? BP_GET_TYPE(zio->io_bp) : DMU_OT_NONE,
158ea8dc4b6Seschrock &handler->zi_record, error)) {
159ea8dc4b6Seschrock ret = error;
160ea8dc4b6Seschrock break;
161ea8dc4b6Seschrock }
162ea8dc4b6Seschrock }
163ea8dc4b6Seschrock
164ea8dc4b6Seschrock rw_exit(&inject_lock);
165ea8dc4b6Seschrock
166ea8dc4b6Seschrock return (ret);
167ea8dc4b6Seschrock }
168ea8dc4b6Seschrock
16921bf64a7Sgw25295 /*
17021bf64a7Sgw25295 * Determine if the zio is part of a label update and has an injection
17121bf64a7Sgw25295 * handler associated with that portion of the label. Currently, we
17221bf64a7Sgw25295 * allow error injection in either the nvlist or the uberblock region of
17321bf64a7Sgw25295 * of the vdev label.
17421bf64a7Sgw25295 */
17521bf64a7Sgw25295 int
zio_handle_label_injection(zio_t * zio,int error)17621bf64a7Sgw25295 zio_handle_label_injection(zio_t *zio, int error)
17721bf64a7Sgw25295 {
17821bf64a7Sgw25295 inject_handler_t *handler;
17921bf64a7Sgw25295 vdev_t *vd = zio->io_vd;
18021bf64a7Sgw25295 uint64_t offset = zio->io_offset;
18121bf64a7Sgw25295 int label;
18221bf64a7Sgw25295 int ret = 0;
18321bf64a7Sgw25295
1848f18d1faSGeorge Wilson if (offset >= VDEV_LABEL_START_SIZE &&
18521bf64a7Sgw25295 offset < vd->vdev_psize - VDEV_LABEL_END_SIZE)
18621bf64a7Sgw25295 return (0);
18721bf64a7Sgw25295
18821bf64a7Sgw25295 rw_enter(&inject_lock, RW_READER);
18921bf64a7Sgw25295
19021bf64a7Sgw25295 for (handler = list_head(&inject_handlers); handler != NULL;
19121bf64a7Sgw25295 handler = list_next(&inject_handlers, handler)) {
19221bf64a7Sgw25295 uint64_t start = handler->zi_record.zi_start;
19321bf64a7Sgw25295 uint64_t end = handler->zi_record.zi_end;
19421bf64a7Sgw25295
195283b8460SGeorge.Wilson if (handler->zi_record.zi_cmd != ZINJECT_LABEL_FAULT)
19621bf64a7Sgw25295 continue;
19721bf64a7Sgw25295
19821bf64a7Sgw25295 /*
19921bf64a7Sgw25295 * The injection region is the relative offsets within a
20021bf64a7Sgw25295 * vdev label. We must determine the label which is being
20121bf64a7Sgw25295 * updated and adjust our region accordingly.
20221bf64a7Sgw25295 */
20321bf64a7Sgw25295 label = vdev_label_number(vd->vdev_psize, offset);
20421bf64a7Sgw25295 start = vdev_label_offset(vd->vdev_psize, label, start);
20521bf64a7Sgw25295 end = vdev_label_offset(vd->vdev_psize, label, end);
20621bf64a7Sgw25295
20721bf64a7Sgw25295 if (zio->io_vd->vdev_guid == handler->zi_record.zi_guid &&
20821bf64a7Sgw25295 (offset >= start && offset <= end)) {
20921bf64a7Sgw25295 ret = error;
21021bf64a7Sgw25295 break;
21121bf64a7Sgw25295 }
21221bf64a7Sgw25295 }
21321bf64a7Sgw25295 rw_exit(&inject_lock);
21421bf64a7Sgw25295 return (ret);
21521bf64a7Sgw25295 }
21621bf64a7Sgw25295
21721bf64a7Sgw25295
218ea8dc4b6Seschrock int
zio_handle_device_injection(vdev_t * vd,zio_t * zio,int error)2198956713aSEric Schrock zio_handle_device_injection(vdev_t *vd, zio_t *zio, int error)
220ea8dc4b6Seschrock {
221ea8dc4b6Seschrock inject_handler_t *handler;
222ea8dc4b6Seschrock int ret = 0;
223ea8dc4b6Seschrock
2248f18d1faSGeorge Wilson /*
2258f18d1faSGeorge Wilson * We skip over faults in the labels unless it's during
2268f18d1faSGeorge Wilson * device open (i.e. zio == NULL).
2278f18d1faSGeorge Wilson */
2288f18d1faSGeorge Wilson if (zio != NULL) {
2298f18d1faSGeorge Wilson uint64_t offset = zio->io_offset;
2308f18d1faSGeorge Wilson
2318f18d1faSGeorge Wilson if (offset < VDEV_LABEL_START_SIZE ||
2328f18d1faSGeorge Wilson offset >= vd->vdev_psize - VDEV_LABEL_END_SIZE)
2338f18d1faSGeorge Wilson return (0);
2348f18d1faSGeorge Wilson }
2358f18d1faSGeorge Wilson
236ea8dc4b6Seschrock rw_enter(&inject_lock, RW_READER);
237ea8dc4b6Seschrock
238ea8dc4b6Seschrock for (handler = list_head(&inject_handlers); handler != NULL;
239ea8dc4b6Seschrock handler = list_next(&inject_handlers, handler)) {
240ea8dc4b6Seschrock
241283b8460SGeorge.Wilson if (handler->zi_record.zi_cmd != ZINJECT_DEVICE_FAULT)
24221bf64a7Sgw25295 continue;
24321bf64a7Sgw25295
244ea8dc4b6Seschrock if (vd->vdev_guid == handler->zi_record.zi_guid) {
2458956713aSEric Schrock if (handler->zi_record.zi_failfast &&
2468956713aSEric Schrock (zio == NULL || (zio->io_flags &
2478956713aSEric Schrock (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD)))) {
2488956713aSEric Schrock continue;
2498956713aSEric Schrock }
2508956713aSEric Schrock
2518f18d1faSGeorge Wilson /* Handle type specific I/O failures */
2528f18d1faSGeorge Wilson if (zio != NULL &&
2538f18d1faSGeorge Wilson handler->zi_record.zi_iotype != ZIO_TYPES &&
2548f18d1faSGeorge Wilson handler->zi_record.zi_iotype != zio->io_type)
2558f18d1faSGeorge Wilson continue;
2568f18d1faSGeorge Wilson
257ea8dc4b6Seschrock if (handler->zi_record.zi_error == error) {
258ea8dc4b6Seschrock /*
259ea8dc4b6Seschrock * For a failed open, pretend like the device
260ea8dc4b6Seschrock * has gone away.
261ea8dc4b6Seschrock */
262ea8dc4b6Seschrock if (error == ENXIO)
263ea8dc4b6Seschrock vd->vdev_stat.vs_aux =
264ea8dc4b6Seschrock VDEV_AUX_OPEN_FAILED;
26598d1cbfeSGeorge Wilson
26698d1cbfeSGeorge Wilson /*
26798d1cbfeSGeorge Wilson * Treat these errors as if they had been
26898d1cbfeSGeorge Wilson * retried so that all the appropriate stats
26998d1cbfeSGeorge Wilson * and FMA events are generated.
27098d1cbfeSGeorge Wilson */
27198d1cbfeSGeorge Wilson if (!handler->zi_record.zi_failfast &&
27298d1cbfeSGeorge Wilson zio != NULL)
27398d1cbfeSGeorge Wilson zio->io_flags |= ZIO_FLAG_IO_RETRY;
27498d1cbfeSGeorge Wilson
275ea8dc4b6Seschrock ret = error;
276ea8dc4b6Seschrock break;
277ea8dc4b6Seschrock }
278ea8dc4b6Seschrock if (handler->zi_record.zi_error == ENXIO) {
279be6fd75aSMatthew Ahrens ret = SET_ERROR(EIO);
280ea8dc4b6Seschrock break;
281ea8dc4b6Seschrock }
282ea8dc4b6Seschrock }
283ea8dc4b6Seschrock }
284ea8dc4b6Seschrock
285ea8dc4b6Seschrock rw_exit(&inject_lock);
286ea8dc4b6Seschrock
287ea8dc4b6Seschrock return (ret);
288ea8dc4b6Seschrock }
289ea8dc4b6Seschrock
290ea8dc4b6Seschrock /*
291468c413aSTim Haley * Simulate hardware that ignores cache flushes. For requested number
292468c413aSTim Haley * of seconds nix the actual writing to disk.
293468c413aSTim Haley */
294468c413aSTim Haley void
zio_handle_ignored_writes(zio_t * zio)295468c413aSTim Haley zio_handle_ignored_writes(zio_t *zio)
296468c413aSTim Haley {
297468c413aSTim Haley inject_handler_t *handler;
298468c413aSTim Haley
299468c413aSTim Haley rw_enter(&inject_lock, RW_READER);
300468c413aSTim Haley
301468c413aSTim Haley for (handler = list_head(&inject_handlers); handler != NULL;
302468c413aSTim Haley handler = list_next(&inject_handlers, handler)) {
303468c413aSTim Haley
304468c413aSTim Haley /* Ignore errors not destined for this pool */
305283b8460SGeorge.Wilson if (zio->io_spa != handler->zi_spa ||
306283b8460SGeorge.Wilson handler->zi_record.zi_cmd != ZINJECT_IGNORED_WRITES)
307468c413aSTim Haley continue;
308468c413aSTim Haley
309468c413aSTim Haley /*
310468c413aSTim Haley * Positive duration implies # of seconds, negative
311468c413aSTim Haley * a number of txgs
312468c413aSTim Haley */
313468c413aSTim Haley if (handler->zi_record.zi_timer == 0) {
314468c413aSTim Haley if (handler->zi_record.zi_duration > 0)
315d3d50737SRafael Vanoni handler->zi_record.zi_timer = ddi_get_lbolt64();
316468c413aSTim Haley else
317468c413aSTim Haley handler->zi_record.zi_timer = zio->io_txg;
318468c413aSTim Haley }
319a33cae98STim Haley
320a33cae98STim Haley /* Have a "problem" writing 60% of the time */
321a33cae98STim Haley if (spa_get_random(100) < 60)
322468c413aSTim Haley zio->io_pipeline &= ~ZIO_VDEV_IO_STAGES;
323468c413aSTim Haley break;
324468c413aSTim Haley }
325468c413aSTim Haley
326468c413aSTim Haley rw_exit(&inject_lock);
327468c413aSTim Haley }
328468c413aSTim Haley
329468c413aSTim Haley void
spa_handle_ignored_writes(spa_t * spa)330468c413aSTim Haley spa_handle_ignored_writes(spa_t *spa)
331468c413aSTim Haley {
332468c413aSTim Haley inject_handler_t *handler;
333468c413aSTim Haley
334468c413aSTim Haley if (zio_injection_enabled == 0)
335468c413aSTim Haley return;
336468c413aSTim Haley
337468c413aSTim Haley rw_enter(&inject_lock, RW_READER);
338468c413aSTim Haley
339468c413aSTim Haley for (handler = list_head(&inject_handlers); handler != NULL;
340468c413aSTim Haley handler = list_next(&inject_handlers, handler)) {
341468c413aSTim Haley
342283b8460SGeorge.Wilson if (spa != handler->zi_spa ||
343283b8460SGeorge.Wilson handler->zi_record.zi_cmd != ZINJECT_IGNORED_WRITES)
344468c413aSTim Haley continue;
345468c413aSTim Haley
346468c413aSTim Haley if (handler->zi_record.zi_duration > 0) {
347468c413aSTim Haley VERIFY(handler->zi_record.zi_timer == 0 ||
348468c413aSTim Haley handler->zi_record.zi_timer +
349d3d50737SRafael Vanoni handler->zi_record.zi_duration * hz >
350d3d50737SRafael Vanoni ddi_get_lbolt64());
351468c413aSTim Haley } else {
352468c413aSTim Haley /* duration is negative so the subtraction here adds */
353468c413aSTim Haley VERIFY(handler->zi_record.zi_timer == 0 ||
354468c413aSTim Haley handler->zi_record.zi_timer -
355468c413aSTim Haley handler->zi_record.zi_duration >=
356b24ab676SJeff Bonwick spa_syncing_txg(spa));
357468c413aSTim Haley }
358468c413aSTim Haley }
359468c413aSTim Haley
360468c413aSTim Haley rw_exit(&inject_lock);
361468c413aSTim Haley }
362468c413aSTim Haley
363283b8460SGeorge.Wilson uint64_t
zio_handle_io_delay(zio_t * zio)364283b8460SGeorge.Wilson zio_handle_io_delay(zio_t *zio)
365283b8460SGeorge.Wilson {
366283b8460SGeorge.Wilson vdev_t *vd = zio->io_vd;
367283b8460SGeorge.Wilson inject_handler_t *handler;
368283b8460SGeorge.Wilson uint64_t seconds = 0;
369283b8460SGeorge.Wilson
370283b8460SGeorge.Wilson if (zio_injection_enabled == 0)
371283b8460SGeorge.Wilson return (0);
372283b8460SGeorge.Wilson
373283b8460SGeorge.Wilson rw_enter(&inject_lock, RW_READER);
374283b8460SGeorge.Wilson
375283b8460SGeorge.Wilson for (handler = list_head(&inject_handlers); handler != NULL;
376283b8460SGeorge.Wilson handler = list_next(&inject_handlers, handler)) {
377283b8460SGeorge.Wilson
378283b8460SGeorge.Wilson if (handler->zi_record.zi_cmd != ZINJECT_DELAY_IO)
379283b8460SGeorge.Wilson continue;
380283b8460SGeorge.Wilson
381283b8460SGeorge.Wilson if (vd->vdev_guid == handler->zi_record.zi_guid) {
382283b8460SGeorge.Wilson seconds = handler->zi_record.zi_timer;
383283b8460SGeorge.Wilson break;
384283b8460SGeorge.Wilson }
385283b8460SGeorge.Wilson
386283b8460SGeorge.Wilson }
387283b8460SGeorge.Wilson rw_exit(&inject_lock);
388283b8460SGeorge.Wilson return (seconds);
389283b8460SGeorge.Wilson }
390283b8460SGeorge.Wilson
391468c413aSTim Haley /*
392ea8dc4b6Seschrock * Create a new handler for the given record. We add it to the list, adding
393ea8dc4b6Seschrock * a reference to the spa_t in the process. We increment zio_injection_enabled,
394ea8dc4b6Seschrock * which is the switch to trigger all fault injection.
395ea8dc4b6Seschrock */
396ea8dc4b6Seschrock int
zio_inject_fault(char * name,int flags,int * id,zinject_record_t * record)397ea8dc4b6Seschrock zio_inject_fault(char *name, int flags, int *id, zinject_record_t *record)
398ea8dc4b6Seschrock {
399ea8dc4b6Seschrock inject_handler_t *handler;
400ea8dc4b6Seschrock int error;
401ea8dc4b6Seschrock spa_t *spa;
402ea8dc4b6Seschrock
403ea8dc4b6Seschrock /*
404ea8dc4b6Seschrock * If this is pool-wide metadata, make sure we unload the corresponding
405ea8dc4b6Seschrock * spa_t, so that the next attempt to load it will trigger the fault.
406ea8dc4b6Seschrock * We call spa_reset() to unload the pool appropriately.
407ea8dc4b6Seschrock */
408ea8dc4b6Seschrock if (flags & ZINJECT_UNLOAD_SPA)
409ea8dc4b6Seschrock if ((error = spa_reset(name)) != 0)
410ea8dc4b6Seschrock return (error);
411ea8dc4b6Seschrock
412ea8dc4b6Seschrock if (!(flags & ZINJECT_NULL)) {
413ea8dc4b6Seschrock /*
414ea8dc4b6Seschrock * spa_inject_ref() will add an injection reference, which will
415ea8dc4b6Seschrock * prevent the pool from being removed from the namespace while
416ea8dc4b6Seschrock * still allowing it to be unloaded.
417ea8dc4b6Seschrock */
418ea8dc4b6Seschrock if ((spa = spa_inject_addref(name)) == NULL)
419be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT));
420ea8dc4b6Seschrock
421ea8dc4b6Seschrock handler = kmem_alloc(sizeof (inject_handler_t), KM_SLEEP);
422ea8dc4b6Seschrock
423ea8dc4b6Seschrock rw_enter(&inject_lock, RW_WRITER);
424ea8dc4b6Seschrock
425ea8dc4b6Seschrock *id = handler->zi_id = inject_next_id++;
426ea8dc4b6Seschrock handler->zi_spa = spa;
427ea8dc4b6Seschrock handler->zi_record = *record;
428ea8dc4b6Seschrock list_insert_tail(&inject_handlers, handler);
4290d6bb4c6SJosef 'Jeff' Sipek atomic_inc_32(&zio_injection_enabled);
430ea8dc4b6Seschrock
431ea8dc4b6Seschrock rw_exit(&inject_lock);
432ea8dc4b6Seschrock }
433ea8dc4b6Seschrock
434ea8dc4b6Seschrock /*
435ea8dc4b6Seschrock * Flush the ARC, so that any attempts to read this data will end up
436ea8dc4b6Seschrock * going to the ZIO layer. Note that this is a little overkill, but
437ea8dc4b6Seschrock * we don't have the necessary ARC interfaces to do anything else, and
438ea8dc4b6Seschrock * fault injection isn't a performance critical path.
439ea8dc4b6Seschrock */
440ea8dc4b6Seschrock if (flags & ZINJECT_FLUSH_ARC)
441*b959b0b3SPrakash Surya /*
442*b959b0b3SPrakash Surya * We must use FALSE to ensure arc_flush returns, since
443*b959b0b3SPrakash Surya * we're not preventing concurrent ARC insertions.
444*b959b0b3SPrakash Surya */
445*b959b0b3SPrakash Surya arc_flush(NULL, FALSE);
446ea8dc4b6Seschrock
447ea8dc4b6Seschrock return (0);
448ea8dc4b6Seschrock }
449ea8dc4b6Seschrock
450ea8dc4b6Seschrock /*
451ea8dc4b6Seschrock * Returns the next record with an ID greater than that supplied to the
452ea8dc4b6Seschrock * function. Used to iterate over all handlers in the system.
453ea8dc4b6Seschrock */
454ea8dc4b6Seschrock int
zio_inject_list_next(int * id,char * name,size_t buflen,zinject_record_t * record)455ea8dc4b6Seschrock zio_inject_list_next(int *id, char *name, size_t buflen,
456ea8dc4b6Seschrock zinject_record_t *record)
457ea8dc4b6Seschrock {
458ea8dc4b6Seschrock inject_handler_t *handler;
459ea8dc4b6Seschrock int ret;
460ea8dc4b6Seschrock
461ea8dc4b6Seschrock mutex_enter(&spa_namespace_lock);
462ea8dc4b6Seschrock rw_enter(&inject_lock, RW_READER);
463ea8dc4b6Seschrock
464ea8dc4b6Seschrock for (handler = list_head(&inject_handlers); handler != NULL;
465ea8dc4b6Seschrock handler = list_next(&inject_handlers, handler))
466ea8dc4b6Seschrock if (handler->zi_id > *id)
467ea8dc4b6Seschrock break;
468ea8dc4b6Seschrock
469ea8dc4b6Seschrock if (handler) {
470ea8dc4b6Seschrock *record = handler->zi_record;
471ea8dc4b6Seschrock *id = handler->zi_id;
472ea8dc4b6Seschrock (void) strncpy(name, spa_name(handler->zi_spa), buflen);
473ea8dc4b6Seschrock ret = 0;
474ea8dc4b6Seschrock } else {
475be6fd75aSMatthew Ahrens ret = SET_ERROR(ENOENT);
476ea8dc4b6Seschrock }
477ea8dc4b6Seschrock
478ea8dc4b6Seschrock rw_exit(&inject_lock);
479ea8dc4b6Seschrock mutex_exit(&spa_namespace_lock);
480ea8dc4b6Seschrock
481ea8dc4b6Seschrock return (ret);
482ea8dc4b6Seschrock }
483ea8dc4b6Seschrock
484ea8dc4b6Seschrock /*
485ea8dc4b6Seschrock * Clear the fault handler with the given identifier, or return ENOENT if none
486ea8dc4b6Seschrock * exists.
487ea8dc4b6Seschrock */
488ea8dc4b6Seschrock int
zio_clear_fault(int id)489ea8dc4b6Seschrock zio_clear_fault(int id)
490ea8dc4b6Seschrock {
491ea8dc4b6Seschrock inject_handler_t *handler;
492ea8dc4b6Seschrock
493ea8dc4b6Seschrock rw_enter(&inject_lock, RW_WRITER);
494ea8dc4b6Seschrock
495ea8dc4b6Seschrock for (handler = list_head(&inject_handlers); handler != NULL;
496ea8dc4b6Seschrock handler = list_next(&inject_handlers, handler))
497ea8dc4b6Seschrock if (handler->zi_id == id)
498ea8dc4b6Seschrock break;
499ea8dc4b6Seschrock
500ea8dc4b6Seschrock if (handler == NULL) {
501679b018dSMark J Musante rw_exit(&inject_lock);
502be6fd75aSMatthew Ahrens return (SET_ERROR(ENOENT));
503679b018dSMark J Musante }
504679b018dSMark J Musante
505ea8dc4b6Seschrock list_remove(&inject_handlers, handler);
506679b018dSMark J Musante rw_exit(&inject_lock);
507679b018dSMark J Musante
508ea8dc4b6Seschrock spa_inject_delref(handler->zi_spa);
509ea8dc4b6Seschrock kmem_free(handler, sizeof (inject_handler_t));
5100d6bb4c6SJosef 'Jeff' Sipek atomic_dec_32(&zio_injection_enabled);
511ea8dc4b6Seschrock
512679b018dSMark J Musante return (0);
513ea8dc4b6Seschrock }
514ea8dc4b6Seschrock
515ea8dc4b6Seschrock void
zio_inject_init(void)516ea8dc4b6Seschrock zio_inject_init(void)
517ea8dc4b6Seschrock {
5189b3f6b42SEric Kustarz rw_init(&inject_lock, NULL, RW_DEFAULT, NULL);
519ea8dc4b6Seschrock list_create(&inject_handlers, sizeof (inject_handler_t),
520ea8dc4b6Seschrock offsetof(inject_handler_t, zi_link));
521ea8dc4b6Seschrock }
522ea8dc4b6Seschrock
523ea8dc4b6Seschrock void
zio_inject_fini(void)524ea8dc4b6Seschrock zio_inject_fini(void)
525ea8dc4b6Seschrock {
526ea8dc4b6Seschrock list_destroy(&inject_handlers);
5279b3f6b42SEric Kustarz rw_destroy(&inject_lock);
528ea8dc4b6Seschrock }
529