xref: /onnv-gate/usr/src/uts/common/fs/zfs/zio_inject.c (revision 10921:8aac17999e4d)
11544Seschrock /*
21544Seschrock  * CDDL HEADER START
31544Seschrock  *
41544Seschrock  * The contents of this file are subject to the terms of the
51544Seschrock  * Common Development and Distribution License (the "License").
61544Seschrock  * You may not use this file except in compliance with the License.
71544Seschrock  *
81544Seschrock  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91544Seschrock  * or http://www.opensolaris.org/os/licensing.
101544Seschrock  * See the License for the specific language governing permissions
111544Seschrock  * and limitations under the License.
121544Seschrock  *
131544Seschrock  * When distributing Covered Code, include this CDDL HEADER in each
141544Seschrock  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151544Seschrock  * If applicable, add the following below this CDDL HEADER, with the
161544Seschrock  * fields enclosed by brackets "[]" replaced with your own identifying
171544Seschrock  * information: Portions Copyright [yyyy] [name of copyright owner]
181544Seschrock  *
191544Seschrock  * CDDL HEADER END
201544Seschrock  */
211544Seschrock /*
229725SEric.Schrock@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
231544Seschrock  * Use is subject to license terms.
241544Seschrock  */
251544Seschrock 
261544Seschrock /*
271544Seschrock  * ZFS fault injection
281544Seschrock  *
291544Seschrock  * To handle fault injection, we keep track of a series of zinject_record_t
301544Seschrock  * structures which describe which logical block(s) should be injected with a
311544Seschrock  * fault.  These are kept in a global list.  Each record corresponds to a given
321544Seschrock  * spa_t and maintains a special hold on the spa_t so that it cannot be deleted
331544Seschrock  * or exported while the injection record exists.
341544Seschrock  *
351544Seschrock  * Device level injection is done using the 'zi_guid' field.  If this is set, it
361544Seschrock  * means that the error is destined for a particular device, not a piece of
371544Seschrock  * data.
381544Seschrock  *
391544Seschrock  * This is a rather poor data structure and algorithm, but we don't expect more
401544Seschrock  * than a few faults at any one time, so it should be sufficient for our needs.
411544Seschrock  */
421544Seschrock 
431544Seschrock #include <sys/arc.h>
441544Seschrock #include <sys/zio_impl.h>
451544Seschrock #include <sys/zfs_ioctl.h>
461544Seschrock #include <sys/spa_impl.h>
471544Seschrock #include <sys/vdev_impl.h>
486615Sgw25295 #include <sys/fs/zfs.h>
491544Seschrock 
501544Seschrock uint32_t zio_injection_enabled;
511544Seschrock 
521544Seschrock typedef struct inject_handler {
531544Seschrock 	int			zi_id;
541544Seschrock 	spa_t			*zi_spa;
551544Seschrock 	zinject_record_t	zi_record;
561544Seschrock 	list_node_t		zi_link;
571544Seschrock } inject_handler_t;
581544Seschrock 
591544Seschrock static list_t inject_handlers;
601544Seschrock static krwlock_t inject_lock;
611544Seschrock static int inject_next_id = 1;
621544Seschrock 
631544Seschrock /*
641544Seschrock  * Returns true if the given record matches the I/O in progress.
651544Seschrock  */
661544Seschrock static boolean_t
671544Seschrock zio_match_handler(zbookmark_t *zb, uint64_t type,
681544Seschrock     zinject_record_t *record, int error)
691544Seschrock {
701544Seschrock 	/*
711544Seschrock 	 * Check for a match against the MOS, which is based on type
721544Seschrock 	 */
731544Seschrock 	if (zb->zb_objset == 0 && record->zi_objset == 0 &&
741544Seschrock 	    record->zi_object == 0) {
751544Seschrock 		if (record->zi_type == DMU_OT_NONE ||
761544Seschrock 		    type == record->zi_type)
771544Seschrock 			return (record->zi_freq == 0 ||
781544Seschrock 			    spa_get_random(100) < record->zi_freq);
791544Seschrock 		else
801544Seschrock 			return (B_FALSE);
811544Seschrock 	}
821544Seschrock 
831544Seschrock 	/*
841544Seschrock 	 * Check for an exact match.
851544Seschrock 	 */
861544Seschrock 	if (zb->zb_objset == record->zi_objset &&
871544Seschrock 	    zb->zb_object == record->zi_object &&
881544Seschrock 	    zb->zb_level == record->zi_level &&
891544Seschrock 	    zb->zb_blkid >= record->zi_start &&
901544Seschrock 	    zb->zb_blkid <= record->zi_end &&
911544Seschrock 	    error == record->zi_error)
921544Seschrock 		return (record->zi_freq == 0 ||
931544Seschrock 		    spa_get_random(100) < record->zi_freq);
941544Seschrock 
951544Seschrock 	return (B_FALSE);
961544Seschrock }
971544Seschrock 
981544Seschrock /*
9910594SGeorge.Wilson@Sun.COM  * Panic the system when a config change happens in the function
10010594SGeorge.Wilson@Sun.COM  * specified by tag.
10110594SGeorge.Wilson@Sun.COM  */
10210594SGeorge.Wilson@Sun.COM void
10310594SGeorge.Wilson@Sun.COM zio_handle_panic_injection(spa_t *spa, char *tag)
10410594SGeorge.Wilson@Sun.COM {
10510594SGeorge.Wilson@Sun.COM 	inject_handler_t *handler;
10610594SGeorge.Wilson@Sun.COM 
10710594SGeorge.Wilson@Sun.COM 	rw_enter(&inject_lock, RW_READER);
10810594SGeorge.Wilson@Sun.COM 
10910594SGeorge.Wilson@Sun.COM 	for (handler = list_head(&inject_handlers); handler != NULL;
11010594SGeorge.Wilson@Sun.COM 	    handler = list_next(&inject_handlers, handler)) {
11110594SGeorge.Wilson@Sun.COM 
11210594SGeorge.Wilson@Sun.COM 		if (spa != handler->zi_spa)
11310594SGeorge.Wilson@Sun.COM 			continue;
11410594SGeorge.Wilson@Sun.COM 
11510594SGeorge.Wilson@Sun.COM 		if (strcmp(tag, handler->zi_record.zi_func) == 0)
11610594SGeorge.Wilson@Sun.COM 			panic("Panic requested in function %s\n", tag);
11710594SGeorge.Wilson@Sun.COM 	}
11810594SGeorge.Wilson@Sun.COM 
11910594SGeorge.Wilson@Sun.COM 	rw_exit(&inject_lock);
12010594SGeorge.Wilson@Sun.COM }
12110594SGeorge.Wilson@Sun.COM 
12210594SGeorge.Wilson@Sun.COM /*
1231544Seschrock  * Determine if the I/O in question should return failure.  Returns the errno
1241544Seschrock  * to be returned to the caller.
1251544Seschrock  */
1261544Seschrock int
1271544Seschrock zio_handle_fault_injection(zio_t *zio, int error)
1281544Seschrock {
1291544Seschrock 	int ret = 0;
1301544Seschrock 	inject_handler_t *handler;
1311544Seschrock 
1321544Seschrock 	/*
1331544Seschrock 	 * Ignore I/O not associated with any logical data.
1341544Seschrock 	 */
1351544Seschrock 	if (zio->io_logical == NULL)
1361544Seschrock 		return (0);
1371544Seschrock 
1381544Seschrock 	/*
1391544Seschrock 	 * Currently, we only support fault injection on reads.
1401544Seschrock 	 */
1411544Seschrock 	if (zio->io_type != ZIO_TYPE_READ)
1421544Seschrock 		return (0);
1431544Seschrock 
1441544Seschrock 	rw_enter(&inject_lock, RW_READER);
1451544Seschrock 
1461544Seschrock 	for (handler = list_head(&inject_handlers); handler != NULL;
1471544Seschrock 	    handler = list_next(&inject_handlers, handler)) {
1481544Seschrock 
1491544Seschrock 		/* Ignore errors not destined for this pool */
1501544Seschrock 		if (zio->io_spa != handler->zi_spa)
1511544Seschrock 			continue;
1521544Seschrock 
15310594SGeorge.Wilson@Sun.COM 		/* Ignore device errors and panic injection */
15410594SGeorge.Wilson@Sun.COM 		if (handler->zi_record.zi_guid != 0 ||
155*10921STim.Haley@Sun.COM 		    handler->zi_record.zi_func[0] != '\0' ||
156*10921STim.Haley@Sun.COM 		    handler->zi_record.zi_duration != 0)
1571544Seschrock 			continue;
1581544Seschrock 
1591544Seschrock 		/* If this handler matches, return EIO */
1601544Seschrock 		if (zio_match_handler(&zio->io_logical->io_bookmark,
1611544Seschrock 		    zio->io_bp ? BP_GET_TYPE(zio->io_bp) : DMU_OT_NONE,
1621544Seschrock 		    &handler->zi_record, error)) {
1631544Seschrock 			ret = error;
1641544Seschrock 			break;
1651544Seschrock 		}
1661544Seschrock 	}
1671544Seschrock 
1681544Seschrock 	rw_exit(&inject_lock);
1691544Seschrock 
1701544Seschrock 	return (ret);
1711544Seschrock }
1721544Seschrock 
1736615Sgw25295 /*
1746615Sgw25295  * Determine if the zio is part of a label update and has an injection
1756615Sgw25295  * handler associated with that portion of the label. Currently, we
1766615Sgw25295  * allow error injection in either the nvlist or the uberblock region of
1776615Sgw25295  * of the vdev label.
1786615Sgw25295  */
1796615Sgw25295 int
1806615Sgw25295 zio_handle_label_injection(zio_t *zio, int error)
1816615Sgw25295 {
1826615Sgw25295 	inject_handler_t *handler;
1836615Sgw25295 	vdev_t *vd = zio->io_vd;
1846615Sgw25295 	uint64_t offset = zio->io_offset;
1856615Sgw25295 	int label;
1866615Sgw25295 	int ret = 0;
1876615Sgw25295 
18810685SGeorge.Wilson@Sun.COM 	if (offset >= VDEV_LABEL_START_SIZE &&
1896615Sgw25295 	    offset < vd->vdev_psize - VDEV_LABEL_END_SIZE)
1906615Sgw25295 		return (0);
1916615Sgw25295 
1926615Sgw25295 	rw_enter(&inject_lock, RW_READER);
1936615Sgw25295 
1946615Sgw25295 	for (handler = list_head(&inject_handlers); handler != NULL;
1956615Sgw25295 	    handler = list_next(&inject_handlers, handler)) {
1966615Sgw25295 		uint64_t start = handler->zi_record.zi_start;
1976615Sgw25295 		uint64_t end = handler->zi_record.zi_end;
1986615Sgw25295 
19910594SGeorge.Wilson@Sun.COM 		/* Ignore device only faults or panic injection */
20010594SGeorge.Wilson@Sun.COM 		if (handler->zi_record.zi_start == 0 ||
201*10921STim.Haley@Sun.COM 		    handler->zi_record.zi_func[0] != '\0' ||
202*10921STim.Haley@Sun.COM 		    handler->zi_record.zi_duration != 0)
2036615Sgw25295 			continue;
2046615Sgw25295 
2056615Sgw25295 		/*
2066615Sgw25295 		 * The injection region is the relative offsets within a
2076615Sgw25295 		 * vdev label. We must determine the label which is being
2086615Sgw25295 		 * updated and adjust our region accordingly.
2096615Sgw25295 		 */
2106615Sgw25295 		label = vdev_label_number(vd->vdev_psize, offset);
2116615Sgw25295 		start = vdev_label_offset(vd->vdev_psize, label, start);
2126615Sgw25295 		end = vdev_label_offset(vd->vdev_psize, label, end);
2136615Sgw25295 
2146615Sgw25295 		if (zio->io_vd->vdev_guid == handler->zi_record.zi_guid &&
2156615Sgw25295 		    (offset >= start && offset <= end)) {
2166615Sgw25295 			ret = error;
2176615Sgw25295 			break;
2186615Sgw25295 		}
2196615Sgw25295 	}
2206615Sgw25295 	rw_exit(&inject_lock);
2216615Sgw25295 	return (ret);
2226615Sgw25295 }
2236615Sgw25295 
2246615Sgw25295 
2251544Seschrock int
2269725SEric.Schrock@Sun.COM zio_handle_device_injection(vdev_t *vd, zio_t *zio, int error)
2271544Seschrock {
2281544Seschrock 	inject_handler_t *handler;
2291544Seschrock 	int ret = 0;
2301544Seschrock 
23110685SGeorge.Wilson@Sun.COM 	/*
23210685SGeorge.Wilson@Sun.COM 	 * We skip over faults in the labels unless it's during
23310685SGeorge.Wilson@Sun.COM 	 * device open (i.e. zio == NULL).
23410685SGeorge.Wilson@Sun.COM 	 */
23510685SGeorge.Wilson@Sun.COM 	if (zio != NULL) {
23610685SGeorge.Wilson@Sun.COM 		uint64_t offset = zio->io_offset;
23710685SGeorge.Wilson@Sun.COM 
23810685SGeorge.Wilson@Sun.COM 		if (offset < VDEV_LABEL_START_SIZE ||
23910685SGeorge.Wilson@Sun.COM 		    offset >= vd->vdev_psize - VDEV_LABEL_END_SIZE)
24010685SGeorge.Wilson@Sun.COM 		return (0);
24110685SGeorge.Wilson@Sun.COM 	}
24210685SGeorge.Wilson@Sun.COM 
2431544Seschrock 	rw_enter(&inject_lock, RW_READER);
2441544Seschrock 
2451544Seschrock 	for (handler = list_head(&inject_handlers); handler != NULL;
2461544Seschrock 	    handler = list_next(&inject_handlers, handler)) {
2471544Seschrock 
248*10921STim.Haley@Sun.COM 		/*
249*10921STim.Haley@Sun.COM 		 * Ignore label specific faults, panic injection
250*10921STim.Haley@Sun.COM 		 * or fake writes
251*10921STim.Haley@Sun.COM 		 */
25210594SGeorge.Wilson@Sun.COM 		if (handler->zi_record.zi_start != 0 ||
253*10921STim.Haley@Sun.COM 		    handler->zi_record.zi_func[0] != '\0' ||
254*10921STim.Haley@Sun.COM 		    handler->zi_record.zi_duration != 0)
2556615Sgw25295 			continue;
2566615Sgw25295 
2571544Seschrock 		if (vd->vdev_guid == handler->zi_record.zi_guid) {
2589725SEric.Schrock@Sun.COM 			if (handler->zi_record.zi_failfast &&
2599725SEric.Schrock@Sun.COM 			    (zio == NULL || (zio->io_flags &
2609725SEric.Schrock@Sun.COM 			    (ZIO_FLAG_IO_RETRY | ZIO_FLAG_TRYHARD)))) {
2619725SEric.Schrock@Sun.COM 				continue;
2629725SEric.Schrock@Sun.COM 			}
2639725SEric.Schrock@Sun.COM 
26410685SGeorge.Wilson@Sun.COM 			/* Handle type specific I/O failures */
26510685SGeorge.Wilson@Sun.COM 			if (zio != NULL &&
26610685SGeorge.Wilson@Sun.COM 			    handler->zi_record.zi_iotype != ZIO_TYPES &&
26710685SGeorge.Wilson@Sun.COM 			    handler->zi_record.zi_iotype != zio->io_type)
26810685SGeorge.Wilson@Sun.COM 				continue;
26910685SGeorge.Wilson@Sun.COM 
2701544Seschrock 			if (handler->zi_record.zi_error == error) {
2711544Seschrock 				/*
2721544Seschrock 				 * For a failed open, pretend like the device
2731544Seschrock 				 * has gone away.
2741544Seschrock 				 */
2751544Seschrock 				if (error == ENXIO)
2761544Seschrock 					vd->vdev_stat.vs_aux =
2771544Seschrock 					    VDEV_AUX_OPEN_FAILED;
2781544Seschrock 				ret = error;
2791544Seschrock 				break;
2801544Seschrock 			}
2811544Seschrock 			if (handler->zi_record.zi_error == ENXIO) {
2821544Seschrock 				ret = EIO;
2831544Seschrock 				break;
2841544Seschrock 			}
2851544Seschrock 		}
2861544Seschrock 	}
2871544Seschrock 
2881544Seschrock 	rw_exit(&inject_lock);
2891544Seschrock 
2901544Seschrock 	return (ret);
2911544Seschrock }
2921544Seschrock 
2931544Seschrock /*
294*10921STim.Haley@Sun.COM  * Simulate hardware that ignores cache flushes.  For requested number
295*10921STim.Haley@Sun.COM  * of seconds nix the actual writing to disk.
296*10921STim.Haley@Sun.COM  */
297*10921STim.Haley@Sun.COM void
298*10921STim.Haley@Sun.COM zio_handle_ignored_writes(zio_t *zio)
299*10921STim.Haley@Sun.COM {
300*10921STim.Haley@Sun.COM 	inject_handler_t *handler;
301*10921STim.Haley@Sun.COM 
302*10921STim.Haley@Sun.COM 	rw_enter(&inject_lock, RW_READER);
303*10921STim.Haley@Sun.COM 
304*10921STim.Haley@Sun.COM 	for (handler = list_head(&inject_handlers); handler != NULL;
305*10921STim.Haley@Sun.COM 	    handler = list_next(&inject_handlers, handler)) {
306*10921STim.Haley@Sun.COM 
307*10921STim.Haley@Sun.COM 		/* Ignore errors not destined for this pool */
308*10921STim.Haley@Sun.COM 		if (zio->io_spa != handler->zi_spa)
309*10921STim.Haley@Sun.COM 			continue;
310*10921STim.Haley@Sun.COM 
311*10921STim.Haley@Sun.COM 		if (handler->zi_record.zi_duration == 0)
312*10921STim.Haley@Sun.COM 			continue;
313*10921STim.Haley@Sun.COM 
314*10921STim.Haley@Sun.COM 		/*
315*10921STim.Haley@Sun.COM 		 * Positive duration implies # of seconds, negative
316*10921STim.Haley@Sun.COM 		 * a number of txgs
317*10921STim.Haley@Sun.COM 		 */
318*10921STim.Haley@Sun.COM 		if (handler->zi_record.zi_timer == 0) {
319*10921STim.Haley@Sun.COM 			if (handler->zi_record.zi_duration > 0)
320*10921STim.Haley@Sun.COM 				handler->zi_record.zi_timer = lbolt64;
321*10921STim.Haley@Sun.COM 			else
322*10921STim.Haley@Sun.COM 				handler->zi_record.zi_timer = zio->io_txg;
323*10921STim.Haley@Sun.COM 		}
324*10921STim.Haley@Sun.COM 		zio->io_pipeline &= ~ZIO_VDEV_IO_STAGES;
325*10921STim.Haley@Sun.COM 		break;
326*10921STim.Haley@Sun.COM 	}
327*10921STim.Haley@Sun.COM 
328*10921STim.Haley@Sun.COM 	rw_exit(&inject_lock);
329*10921STim.Haley@Sun.COM }
330*10921STim.Haley@Sun.COM 
331*10921STim.Haley@Sun.COM void
332*10921STim.Haley@Sun.COM spa_handle_ignored_writes(spa_t *spa)
333*10921STim.Haley@Sun.COM {
334*10921STim.Haley@Sun.COM 	inject_handler_t *handler;
335*10921STim.Haley@Sun.COM 
336*10921STim.Haley@Sun.COM 	if (zio_injection_enabled == 0)
337*10921STim.Haley@Sun.COM 		return;
338*10921STim.Haley@Sun.COM 
339*10921STim.Haley@Sun.COM 	rw_enter(&inject_lock, RW_READER);
340*10921STim.Haley@Sun.COM 
341*10921STim.Haley@Sun.COM 	for (handler = list_head(&inject_handlers); handler != NULL;
342*10921STim.Haley@Sun.COM 	    handler = list_next(&inject_handlers, handler)) {
343*10921STim.Haley@Sun.COM 
344*10921STim.Haley@Sun.COM 		/* Ignore errors not destined for this pool */
345*10921STim.Haley@Sun.COM 		if (spa != handler->zi_spa)
346*10921STim.Haley@Sun.COM 			continue;
347*10921STim.Haley@Sun.COM 
348*10921STim.Haley@Sun.COM 		if (handler->zi_record.zi_duration == 0)
349*10921STim.Haley@Sun.COM 			continue;
350*10921STim.Haley@Sun.COM 
351*10921STim.Haley@Sun.COM 		if (handler->zi_record.zi_duration > 0) {
352*10921STim.Haley@Sun.COM 			VERIFY(handler->zi_record.zi_timer == 0 ||
353*10921STim.Haley@Sun.COM 			    handler->zi_record.zi_timer +
354*10921STim.Haley@Sun.COM 			    handler->zi_record.zi_duration * hz > lbolt64);
355*10921STim.Haley@Sun.COM 		} else {
356*10921STim.Haley@Sun.COM 			/* duration is negative so the subtraction here adds */
357*10921STim.Haley@Sun.COM 			VERIFY(handler->zi_record.zi_timer == 0 ||
358*10921STim.Haley@Sun.COM 			    handler->zi_record.zi_timer -
359*10921STim.Haley@Sun.COM 			    handler->zi_record.zi_duration >=
360*10921STim.Haley@Sun.COM 			    spa->spa_syncing_txg);
361*10921STim.Haley@Sun.COM 		}
362*10921STim.Haley@Sun.COM 	}
363*10921STim.Haley@Sun.COM 
364*10921STim.Haley@Sun.COM 	rw_exit(&inject_lock);
365*10921STim.Haley@Sun.COM }
366*10921STim.Haley@Sun.COM 
367*10921STim.Haley@Sun.COM /*
3681544Seschrock  * Create a new handler for the given record.  We add it to the list, adding
3691544Seschrock  * a reference to the spa_t in the process.  We increment zio_injection_enabled,
3701544Seschrock  * which is the switch to trigger all fault injection.
3711544Seschrock  */
3721544Seschrock int
3731544Seschrock zio_inject_fault(char *name, int flags, int *id, zinject_record_t *record)
3741544Seschrock {
3751544Seschrock 	inject_handler_t *handler;
3761544Seschrock 	int error;
3771544Seschrock 	spa_t *spa;
3781544Seschrock 
3791544Seschrock 	/*
3801544Seschrock 	 * If this is pool-wide metadata, make sure we unload the corresponding
3811544Seschrock 	 * spa_t, so that the next attempt to load it will trigger the fault.
3821544Seschrock 	 * We call spa_reset() to unload the pool appropriately.
3831544Seschrock 	 */
3841544Seschrock 	if (flags & ZINJECT_UNLOAD_SPA)
3851544Seschrock 		if ((error = spa_reset(name)) != 0)
3861544Seschrock 			return (error);
3871544Seschrock 
3881544Seschrock 	if (!(flags & ZINJECT_NULL)) {
3891544Seschrock 		/*
3901544Seschrock 		 * spa_inject_ref() will add an injection reference, which will
3911544Seschrock 		 * prevent the pool from being removed from the namespace while
3921544Seschrock 		 * still allowing it to be unloaded.
3931544Seschrock 		 */
3941544Seschrock 		if ((spa = spa_inject_addref(name)) == NULL)
3951544Seschrock 			return (ENOENT);
3961544Seschrock 
3971544Seschrock 		handler = kmem_alloc(sizeof (inject_handler_t), KM_SLEEP);
3981544Seschrock 
3991544Seschrock 		rw_enter(&inject_lock, RW_WRITER);
4001544Seschrock 
4011544Seschrock 		*id = handler->zi_id = inject_next_id++;
4021544Seschrock 		handler->zi_spa = spa;
4031544Seschrock 		handler->zi_record = *record;
4041544Seschrock 		list_insert_tail(&inject_handlers, handler);
4051544Seschrock 		atomic_add_32(&zio_injection_enabled, 1);
4061544Seschrock 
4071544Seschrock 		rw_exit(&inject_lock);
4081544Seschrock 	}
4091544Seschrock 
4101544Seschrock 	/*
4111544Seschrock 	 * Flush the ARC, so that any attempts to read this data will end up
4121544Seschrock 	 * going to the ZIO layer.  Note that this is a little overkill, but
4131544Seschrock 	 * we don't have the necessary ARC interfaces to do anything else, and
4141544Seschrock 	 * fault injection isn't a performance critical path.
4151544Seschrock 	 */
4161544Seschrock 	if (flags & ZINJECT_FLUSH_ARC)
4175642Smaybee 		arc_flush(NULL);
4181544Seschrock 
4191544Seschrock 	return (0);
4201544Seschrock }
4211544Seschrock 
4221544Seschrock /*
4231544Seschrock  * Returns the next record with an ID greater than that supplied to the
4241544Seschrock  * function.  Used to iterate over all handlers in the system.
4251544Seschrock  */
4261544Seschrock int
4271544Seschrock zio_inject_list_next(int *id, char *name, size_t buflen,
4281544Seschrock     zinject_record_t *record)
4291544Seschrock {
4301544Seschrock 	inject_handler_t *handler;
4311544Seschrock 	int ret;
4321544Seschrock 
4331544Seschrock 	mutex_enter(&spa_namespace_lock);
4341544Seschrock 	rw_enter(&inject_lock, RW_READER);
4351544Seschrock 
4361544Seschrock 	for (handler = list_head(&inject_handlers); handler != NULL;
4371544Seschrock 	    handler = list_next(&inject_handlers, handler))
4381544Seschrock 		if (handler->zi_id > *id)
4391544Seschrock 			break;
4401544Seschrock 
4411544Seschrock 	if (handler) {
4421544Seschrock 		*record = handler->zi_record;
4431544Seschrock 		*id = handler->zi_id;
4441544Seschrock 		(void) strncpy(name, spa_name(handler->zi_spa), buflen);
4451544Seschrock 		ret = 0;
4461544Seschrock 	} else {
4471544Seschrock 		ret = ENOENT;
4481544Seschrock 	}
4491544Seschrock 
4501544Seschrock 	rw_exit(&inject_lock);
4511544Seschrock 	mutex_exit(&spa_namespace_lock);
4521544Seschrock 
4531544Seschrock 	return (ret);
4541544Seschrock }
4551544Seschrock 
4561544Seschrock /*
4571544Seschrock  * Clear the fault handler with the given identifier, or return ENOENT if none
4581544Seschrock  * exists.
4591544Seschrock  */
4601544Seschrock int
4611544Seschrock zio_clear_fault(int id)
4621544Seschrock {
4631544Seschrock 	inject_handler_t *handler;
4641544Seschrock 	int ret;
4651544Seschrock 
4661544Seschrock 	rw_enter(&inject_lock, RW_WRITER);
4671544Seschrock 
4681544Seschrock 	for (handler = list_head(&inject_handlers); handler != NULL;
4691544Seschrock 	    handler = list_next(&inject_handlers, handler))
4701544Seschrock 		if (handler->zi_id == id)
4711544Seschrock 			break;
4721544Seschrock 
4731544Seschrock 	if (handler == NULL) {
4741544Seschrock 		ret = ENOENT;
4751544Seschrock 	} else {
4761544Seschrock 		list_remove(&inject_handlers, handler);
4771544Seschrock 		spa_inject_delref(handler->zi_spa);
4781544Seschrock 		kmem_free(handler, sizeof (inject_handler_t));
4791544Seschrock 		atomic_add_32(&zio_injection_enabled, -1);
4801544Seschrock 		ret = 0;
4811544Seschrock 	}
4821544Seschrock 
4831544Seschrock 	rw_exit(&inject_lock);
4841544Seschrock 
4851544Seschrock 	return (ret);
4861544Seschrock }
4871544Seschrock 
4881544Seschrock void
4891544Seschrock zio_inject_init(void)
4901544Seschrock {
4917313SEric.Kustarz@Sun.COM 	rw_init(&inject_lock, NULL, RW_DEFAULT, NULL);
4921544Seschrock 	list_create(&inject_handlers, sizeof (inject_handler_t),
4931544Seschrock 	    offsetof(inject_handler_t, zi_link));
4941544Seschrock }
4951544Seschrock 
4961544Seschrock void
4971544Seschrock zio_inject_fini(void)
4981544Seschrock {
4991544Seschrock 	list_destroy(&inject_handlers);
5007313SEric.Kustarz@Sun.COM 	rw_destroy(&inject_lock);
5011544Seschrock }
502