]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/sys/fail.h
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / sys / fail.h
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/types.h>
36
37 #include <sys/linker_set.h>
38 #include <sys/param.h>
39 #include <sys/queue.h>
40 #include <sys/sysctl.h>
41
42
43 /**
44  * Failpoint types.
45  * Don't change these without changing fail_type_strings in fail.c.
46  * @ingroup failpoint_private
47  */
48 enum fail_point_t {
49         FAIL_POINT_OFF,         /**< don't fail */
50         FAIL_POINT_PANIC,       /**< panic */
51         FAIL_POINT_RETURN,      /**< return an errorcode */
52         FAIL_POINT_BREAK,       /**< break into the debugger */
53         FAIL_POINT_PRINT,       /**< print a message */
54         FAIL_POINT_SLEEP,       /**< sleep for some msecs */
55         FAIL_POINT_INVALID,     /**< placeholder */
56 };
57
58 /**
59  * Failpoint return codes, used internally.
60  * @ingroup failpoint_private
61  */
62 enum fail_point_return_code {
63         FAIL_POINT_RC_CONTINUE = 0,     /**< Continue with normal execution */
64         FAIL_POINT_RC_RETURN,           /**< FP evaluated to 'return' */
65         FAIL_POINT_RC_QUEUED,           /**< sleep_fn will be called */
66 };
67
68 TAILQ_HEAD(fail_point_entries, fail_point_entry);
69 /**
70  * Internal failpoint structure, tracking all the current details of the
71  * failpoint.  This structure is the core component shared between the
72  * failure-injection code and the user-interface.
73  * @ingroup failpoint_private
74  */
75 struct fail_point {
76         const char *fp_name;            /**< name of fail point */
77         const char *fp_location;        /**< file:line of fail point */
78         struct fail_point_entries fp_entries;   /**< list of entries */
79         int fp_flags;
80         void (*fp_sleep_fn)(void *);    /**< Function to call at end of
81                                          * sleep for sleep failpoints */
82         void *fp_sleep_arg;             /**< Arg for sleep_fn */
83 };
84
85 #define FAIL_POINT_DYNAMIC_NAME 0x01    /**< Must free name on destroy */
86
87 /**
88  * Internal structure tracking a single term of a complete failpoint.
89  * @ingroup failpoint_private
90  */
91 struct fail_point_entry {
92         enum fail_point_t fe_type;      /**< type of entry */
93         int             fe_arg;         /**< argument to type (e.g. return value) */
94         int             fe_prob;        /**< likelihood of firing in millionths */
95         int             fe_count;       /**< number of times to fire, 0 means always */
96
97         TAILQ_ENTRY(fail_point_entry) fe_entries; /**< next entry in fail point */
98 };
99
100 /* Private failpoint eval function -- use fail_point_eval() instead. */
101 enum fail_point_return_code fail_point_eval_nontrivial(struct fail_point *,
102         int *ret);
103
104 /**
105  * @addtogroup failpoint
106  * @{
107  */
108 /*
109  * Initialize a fail-point.  The name is formed in printf-like fashion
110  * from "fmt" and the subsequent arguments.
111  * Pair with fail_point_destroy().
112  */
113 void fail_point_init(struct fail_point *, const char *fmt, ...)
114     __printflike(2, 3);
115
116 /**
117  * Set the sleep function for a fail point
118  * If sleep_fn is specified, then FAIL_POINT_SLEEP will result in a
119  * (*fp->sleep_fn)(fp->sleep_arg) call by the timer thread.  Otherwise,
120  * if sleep_fn is NULL (default), then FAIL_POINT_SLEEP will result in the
121  * fail_point_eval() call sleeping.
122  */
123 static __inline void
124 fail_point_sleep_set_func(struct fail_point *fp, void (*sleep_fn)(void *))
125 {
126         fp->fp_sleep_fn = sleep_fn;
127 }
128
129 /**
130  * Set the argument for the sleep function for a fail point
131  */
132 static __inline void
133 fail_point_sleep_set_arg(struct fail_point *fp, void *sleep_arg)
134 {
135         fp->fp_sleep_arg = sleep_arg;
136 }
137
138 /**
139  * Free the resources used by a fail-point.  Pair with fail_point_init().
140  */
141 void fail_point_destroy(struct fail_point *);
142
143 /**
144  * Evaluate a failpoint.
145  */
146 static __inline enum fail_point_return_code
147 fail_point_eval(struct fail_point *fp, int *ret)
148 {
149         if (TAILQ_EMPTY(&fp->fp_entries)) {
150                 return (FAIL_POINT_RC_CONTINUE);
151         }
152         return (fail_point_eval_nontrivial(fp, ret));
153 }
154
155 /* Declare a fail_point and its sysctl in a function. */
156 #define _FAIL_POINT_NAME(name) _fail_point_##name
157 #define _STRINGIFY_HELPER(x) #x
158 #define _STRINGIFY(x) _STRINGIFY_HELPER(x)
159 #define _FAIL_POINT_LOCATION() __FILE__ ":" _STRINGIFY(__LINE__)
160
161 /**
162  * Instantiate a failpoint which returns "value" from the function when triggered.
163  * @param parent  The parent sysctl under which to locate the sysctl
164  * @param name    The name of the failpoint in the sysctl tree (and printouts)
165  * @return        Instantly returns the return("value") specified in the
166  *                failpoint, if triggered.
167  */
168 #define KFAIL_POINT_RETURN(parent, name) \
169         KFAIL_POINT_CODE(parent, name, return RETURN_VALUE)
170
171 /**
172  * Instantiate a failpoint which returns (void) from the function when triggered.
173  * @param parent  The parent sysctl under which to locate the sysctl
174  * @param name    The name of the failpoint in the sysctl tree (and printouts)
175  * @return        Instantly returns void, if triggered in the failpoint.
176  */
177 #define KFAIL_POINT_RETURN_VOID(parent, name) \
178         KFAIL_POINT_CODE(parent, name, return)
179
180 /**
181  * Instantiate a failpoint which sets an error when triggered.
182  * @param parent     The parent sysctl under which to locate the sysctl
183  * @param name       The name of the failpoint in the sysctl tree (and printouts)
184  * @param error_var  A variable to set to the failpoint's specified
185  *                   return-value when triggered
186  */
187 #define KFAIL_POINT_ERROR(parent, name, error_var) \
188         KFAIL_POINT_CODE(parent, name, (error_var) = RETURN_VALUE)
189
190 /**
191  * Instantiate a failpoint which sets an error and then goes to a
192  * specified label in the function when triggered.
193  * @param parent     The parent sysctl under which to locate the sysctl
194  * @param name       The name of the failpoint in the sysctl tree (and printouts)
195  * @param error_var  A variable to set to the failpoint's specified
196  *                   return-value when triggered
197  * @param label      The location to goto when triggered.
198  */
199 #define KFAIL_POINT_GOTO(parent, name, error_var, label) \
200         KFAIL_POINT_CODE(parent, name, (error_var) = RETURN_VALUE; goto label)
201
202 /**
203  * Instantiate a failpoint which runs arbitrary code when triggered.
204  * @param parent     The parent sysctl under which to locate the sysctl
205  * @param name       The name of the failpoint in the sysctl tree (and printouts)
206  * @param code       The arbitrary code to run when triggered.  Can reference
207  *                   "RETURN_VALUE" if desired to extract the specified user
208  *                   return-value when triggered
209  */
210 #define KFAIL_POINT_CODE(parent, name, code)                            \
211         KFAIL_POINT_START(parent, name) {                               \
212                 code;                                                   \
213         } FAIL_POINT_END
214
215 /**
216  * @}
217  * (end group failpoint)
218  */
219
220 /**
221  * Internal macro to implement above #defines -- should not be used directly.
222  * @ingroup failpoint_private
223  */
224 #define KFAIL_POINT_START(parent, name)                                 \
225         do {                                                            \
226                 int RETURN_VALUE;                                       \
227                 static struct fail_point _FAIL_POINT_NAME(name) = {     \
228                         #name,                                          \
229                         _FAIL_POINT_LOCATION(),                         \
230                         TAILQ_HEAD_INITIALIZER(                         \
231                                 _FAIL_POINT_NAME(name).fp_entries),     \
232                         0,                                              \
233                         NULL, NULL,                                     \
234                 };                                                      \
235                 SYSCTL_OID(parent, OID_AUTO, name,                      \
236                         CTLTYPE_STRING | CTLFLAG_RW,                    \
237                         &_FAIL_POINT_NAME(name), 0, fail_point_sysctl,  \
238                         "A", "");                                       \
239                                                                         \
240                 if (__predict_false(                                    \
241                     fail_point_eval(&_FAIL_POINT_NAME(name),            \
242                     &RETURN_VALUE))) {
243
244 /**
245  * Internal macro to implement above #defines -- should not be used directly.
246  * @ingroup failpoint_private
247  */
248 #define FAIL_POINT_END                                                  \
249                 }                                                       \
250         } while (0)
251
252 #ifdef _KERNEL
253 int fail_point_sysctl(SYSCTL_HANDLER_ARGS);
254
255 /* The fail point sysctl tree. */
256 SYSCTL_DECL(_debug_fail_point);
257 #endif
258 #define DEBUG_FP _debug_fail_point
259
260 #endif /* _SYS_FAIL_H_ */