xref: /freebsd/sys/sys/fail.h (revision aa0a1e58)
1 /*-
2  * Copyright (c) 2009 Isilon Inc http://www.isilon.com/
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27 /**
28  * @file
29  *
30  * Main header for failpoint facility.
31  */
32 #ifndef _SYS_FAIL_H_
33 #define _SYS_FAIL_H_
34 
35 #include <sys/param.h>
36 #include <sys/cdefs.h>
37 #include <sys/linker_set.h>
38 #include <sys/queue.h>
39 #include <sys/sysctl.h>
40 
41 /**
42  * Failpoint return codes, used internally.
43  * @ingroup failpoint_private
44  */
45 enum fail_point_return_code {
46 	FAIL_POINT_RC_CONTINUE = 0,	/**< Continue with normal execution */
47 	FAIL_POINT_RC_RETURN,		/**< FP evaluated to 'return' */
48 	FAIL_POINT_RC_QUEUED,		/**< sleep_fn will be called */
49 };
50 
51 struct fail_point_entry;
52 TAILQ_HEAD(fail_point_entries, fail_point_entry);
53 /**
54  * Internal failpoint structure, tracking all the current details of the
55  * failpoint.  This structure is the core component shared between the
56  * failure-injection code and the user-interface.
57  * @ingroup failpoint_private
58  */
59 struct fail_point {
60 	const char *fp_name;		/**< name of fail point */
61 	const char *fp_location;	/**< file:line of fail point */
62 	struct fail_point_entries fp_entries;	/**< list of entries */
63 	int fp_flags;
64 	void (*fp_sleep_fn)(void *);	/**< Function to call at end of
65 					 * sleep for sleep failpoints */
66 	void *fp_sleep_arg;		/**< Arg for sleep_fn */
67 };
68 
69 #define	FAIL_POINT_DYNAMIC_NAME	0x01	/**< Must free name on destroy */
70 
71 __BEGIN_DECLS
72 
73 /* Private failpoint eval function -- use fail_point_eval() instead. */
74 enum fail_point_return_code fail_point_eval_nontrivial(struct fail_point *,
75 	int *ret);
76 
77 /**
78  * @addtogroup failpoint
79  * @{
80  */
81 /*
82  * Initialize a fail-point.  The name is formed in printf-like fashion
83  * from "fmt" and the subsequent arguments.
84  * Pair with fail_point_destroy().
85  */
86 void fail_point_init(struct fail_point *, const char *fmt, ...)
87     __printflike(2, 3);
88 
89 /**
90  * Set the sleep function for a fail point
91  * If sleep_fn is specified, then FAIL_POINT_SLEEP will result in a
92  * (*fp->sleep_fn)(fp->sleep_arg) call by the timer thread.  Otherwise,
93  * if sleep_fn is NULL (default), then FAIL_POINT_SLEEP will result in the
94  * fail_point_eval() call sleeping.
95  */
96 static __inline void
97 fail_point_sleep_set_func(struct fail_point *fp, void (*sleep_fn)(void *))
98 {
99 	fp->fp_sleep_fn = sleep_fn;
100 }
101 
102 /**
103  * Set the argument for the sleep function for a fail point
104  */
105 static __inline void
106 fail_point_sleep_set_arg(struct fail_point *fp, void *sleep_arg)
107 {
108 	fp->fp_sleep_arg = sleep_arg;
109 }
110 
111 /**
112  * Free the resources used by a fail-point.  Pair with fail_point_init().
113  */
114 void fail_point_destroy(struct fail_point *);
115 
116 /**
117  * Evaluate a failpoint.
118  */
119 static __inline enum fail_point_return_code
120 fail_point_eval(struct fail_point *fp, int *ret)
121 {
122 	if (TAILQ_EMPTY(&fp->fp_entries)) {
123 		return (FAIL_POINT_RC_CONTINUE);
124 	}
125 	return (fail_point_eval_nontrivial(fp, ret));
126 }
127 
128 __END_DECLS
129 
130 /* Declare a fail_point and its sysctl in a function. */
131 #define	_FAIL_POINT_NAME(name)	_fail_point_##name
132 #define	_FAIL_POINT_LOCATION()	"(" __FILE__ ":" __XSTRING(__LINE__) ")"
133 
134 /**
135  * Instantiate a failpoint which returns "value" from the function when triggered.
136  * @param parent  The parent sysctl under which to locate the sysctl
137  * @param name    The name of the failpoint in the sysctl tree (and printouts)
138  * @return        Instantly returns the return("value") specified in the
139  *                failpoint, if triggered.
140  */
141 #define KFAIL_POINT_RETURN(parent, name) \
142 	KFAIL_POINT_CODE(parent, name, return RETURN_VALUE)
143 
144 /**
145  * Instantiate a failpoint which returns (void) from the function when triggered.
146  * @param parent  The parent sysctl under which to locate the sysctl
147  * @param name    The name of the failpoint in the sysctl tree (and printouts)
148  * @return        Instantly returns void, if triggered in the failpoint.
149  */
150 #define KFAIL_POINT_RETURN_VOID(parent, name) \
151 	KFAIL_POINT_CODE(parent, name, return)
152 
153 /**
154  * Instantiate a failpoint which sets an error when triggered.
155  * @param parent     The parent sysctl under which to locate the sysctl
156  * @param name       The name of the failpoint in the sysctl tree (and printouts)
157  * @param error_var  A variable to set to the failpoint's specified
158  *                   return-value when triggered
159  */
160 #define KFAIL_POINT_ERROR(parent, name, error_var) \
161 	KFAIL_POINT_CODE(parent, name, (error_var) = RETURN_VALUE)
162 
163 /**
164  * Instantiate a failpoint which sets an error and then goes to a
165  * specified label in the function when triggered.
166  * @param parent     The parent sysctl under which to locate the sysctl
167  * @param name       The name of the failpoint in the sysctl tree (and printouts)
168  * @param error_var  A variable to set to the failpoint's specified
169  *                   return-value when triggered
170  * @param label      The location to goto when triggered.
171  */
172 #define KFAIL_POINT_GOTO(parent, name, error_var, label) \
173 	KFAIL_POINT_CODE(parent, name, (error_var) = RETURN_VALUE; goto label)
174 
175 /**
176  * Instantiate a failpoint which runs arbitrary code when triggered.
177  * @param parent     The parent sysctl under which to locate the sysctl
178  * @param name       The name of the failpoint in the sysctl tree
179  *		     (and printouts)
180  * @param code       The arbitrary code to run when triggered.  Can reference
181  *                   "RETURN_VALUE" if desired to extract the specified
182  *                   user return-value when triggered.  Note that this is
183  *                   implemented with a do-while loop so be careful of
184  *                   break and continue statements.
185  */
186 #define KFAIL_POINT_CODE(parent, name, code)				\
187 do {									\
188 	int RETURN_VALUE;						\
189 	static struct fail_point _FAIL_POINT_NAME(name) = {		\
190 		#name,							\
191 		_FAIL_POINT_LOCATION(),					\
192 		TAILQ_HEAD_INITIALIZER(_FAIL_POINT_NAME(name).fp_entries), \
193 		0,							\
194 		NULL, NULL,						\
195 	};								\
196 	SYSCTL_OID(parent, OID_AUTO, name,				\
197 	    CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,		\
198 	    &_FAIL_POINT_NAME(name), 0, fail_point_sysctl,		\
199 	    "A", "");							\
200 									\
201 	if (__predict_false(						\
202 	    fail_point_eval(&_FAIL_POINT_NAME(name), &RETURN_VALUE))) {	\
203 									\
204 		code;							\
205 									\
206 	}								\
207 } while (0)
208 
209 
210 /**
211  * @}
212  * (end group failpoint)
213  */
214 
215 #ifdef _KERNEL
216 int fail_point_sysctl(SYSCTL_HANDLER_ARGS);
217 
218 /* The fail point sysctl tree. */
219 SYSCTL_DECL(_debug_fail_point);
220 #define	DEBUG_FP	_debug_fail_point
221 #endif
222 
223 #endif /* _SYS_FAIL_H_ */
224