]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/sys/fail.h
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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/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_ */