xref: /freebsd/sys/kern/kern_fail.c (revision 70e20d4e1a6b23cb7bd8b869d1ff782c590f0fa8)
1cfeb7489SZachary Loafman /*-
2cfeb7489SZachary Loafman  * Copyright (c) 2009 Isilon Inc http://www.isilon.com/
3cfeb7489SZachary Loafman  *
4cfeb7489SZachary Loafman  * Redistribution and use in source and binary forms, with or without
5cfeb7489SZachary Loafman  * modification, are permitted provided that the following conditions
6cfeb7489SZachary Loafman  * are met:
7cfeb7489SZachary Loafman  * 1. Redistributions of source code must retain the above copyright
8cfeb7489SZachary Loafman  *    notice, this list of conditions and the following disclaimer.
9cfeb7489SZachary Loafman  * 2. Redistributions in binary form must reproduce the above copyright
10cfeb7489SZachary Loafman  *    notice, this list of conditions and the following disclaimer in the
11cfeb7489SZachary Loafman  *    documentation and/or other materials provided with the distribution.
12cfeb7489SZachary Loafman  *
13cfeb7489SZachary Loafman  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14cfeb7489SZachary Loafman  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15cfeb7489SZachary Loafman  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16cfeb7489SZachary Loafman  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17cfeb7489SZachary Loafman  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18cfeb7489SZachary Loafman  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19cfeb7489SZachary Loafman  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20cfeb7489SZachary Loafman  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21cfeb7489SZachary Loafman  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22cfeb7489SZachary Loafman  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23cfeb7489SZachary Loafman  * SUCH DAMAGE.
24cfeb7489SZachary Loafman  */
25cfeb7489SZachary Loafman /**
26cfeb7489SZachary Loafman  * @file
27cfeb7489SZachary Loafman  *
28cfeb7489SZachary Loafman  * fail(9) Facility.
29cfeb7489SZachary Loafman  *
30cfeb7489SZachary Loafman  * @ingroup failpoint_private
31cfeb7489SZachary Loafman  */
32cfeb7489SZachary Loafman /**
33cfeb7489SZachary Loafman  * @defgroup failpoint fail(9) Facility
34cfeb7489SZachary Loafman  *
35cfeb7489SZachary Loafman  * Failpoints allow for injecting fake errors into running code on the fly,
36cfeb7489SZachary Loafman  * without modifying code or recompiling with flags.  Failpoints are always
37cfeb7489SZachary Loafman  * present, and are very efficient when disabled.  Failpoints are described
38cfeb7489SZachary Loafman  * in man fail(9).
39cfeb7489SZachary Loafman  */
40cfeb7489SZachary Loafman /**
41cfeb7489SZachary Loafman  * @defgroup failpoint_private Private fail(9) Implementation functions
42cfeb7489SZachary Loafman  *
43cfeb7489SZachary Loafman  * Private implementations for the actual failpoint code.
44cfeb7489SZachary Loafman  *
45cfeb7489SZachary Loafman  * @ingroup failpoint
46cfeb7489SZachary Loafman  */
47cfeb7489SZachary Loafman /**
48cfeb7489SZachary Loafman  * @addtogroup failpoint_private
49cfeb7489SZachary Loafman  * @{
50cfeb7489SZachary Loafman  */
51cfeb7489SZachary Loafman 
52cfeb7489SZachary Loafman #include <sys/cdefs.h>
53cfeb7489SZachary Loafman __FBSDID("$FreeBSD$");
54cfeb7489SZachary Loafman 
550894a9bcSMatthew D Fleming #include <sys/ctype.h>
56cfeb7489SZachary Loafman #include <sys/errno.h>
57cfeb7489SZachary Loafman #include <sys/fail.h>
58cfeb7489SZachary Loafman #include <sys/kernel.h>
59cfeb7489SZachary Loafman #include <sys/libkern.h>
60*70e20d4eSConrad Meyer #include <sys/limits.h>
61cfeb7489SZachary Loafman #include <sys/lock.h>
62cfeb7489SZachary Loafman #include <sys/malloc.h>
63cfeb7489SZachary Loafman #include <sys/mutex.h>
64b5bd50aeSMatthew D Fleming #include <sys/proc.h>
65cfeb7489SZachary Loafman #include <sys/sbuf.h>
66*70e20d4eSConrad Meyer #include <sys/sleepqueue.h>
67*70e20d4eSConrad Meyer #include <sys/sx.h>
68*70e20d4eSConrad Meyer #include <sys/sysctl.h>
69*70e20d4eSConrad Meyer #include <sys/types.h>
70cfeb7489SZachary Loafman 
71*70e20d4eSConrad Meyer #include <machine/atomic.h>
72cfeb7489SZachary Loafman #include <machine/stdarg.h>
73cfeb7489SZachary Loafman 
74cfeb7489SZachary Loafman #ifdef ILOG_DEFINE_FOR_FILE
75cfeb7489SZachary Loafman ILOG_DEFINE_FOR_FILE(L_ISI_FAIL_POINT, L_ILOG, fail_point);
76cfeb7489SZachary Loafman #endif
77cfeb7489SZachary Loafman 
78d745c852SEd Schouten static MALLOC_DEFINE(M_FAIL_POINT, "Fail Points", "fail points system");
79cfeb7489SZachary Loafman #define fp_free(ptr) free(ptr, M_FAIL_POINT)
80cfeb7489SZachary Loafman #define fp_malloc(size, flags) malloc((size), M_FAIL_POINT, (flags))
81*70e20d4eSConrad Meyer #define fs_free(ptr) fp_free(ptr)
82*70e20d4eSConrad Meyer #define fs_malloc() fp_malloc(sizeof(struct fail_point_setting), \
83*70e20d4eSConrad Meyer         M_WAITOK | M_ZERO)
84cfeb7489SZachary Loafman 
85*70e20d4eSConrad Meyer  /**
86*70e20d4eSConrad Meyer   * These define the wchans that are used for sleeping, pausing respectively.
87*70e20d4eSConrad Meyer   * They are chosen arbitrarily but need to be distinct to the failpoint and
88*70e20d4eSConrad Meyer   * the sleep/pause distinction.
89*70e20d4eSConrad Meyer   */
90*70e20d4eSConrad Meyer #define FP_SLEEP_CHANNEL(fp) (void*)(fp)
91*70e20d4eSConrad Meyer #define FP_PAUSE_CHANNEL(fp) __DEVOLATILE(void*, &fp->fp_setting)
92*70e20d4eSConrad Meyer 
93*70e20d4eSConrad Meyer /**
94*70e20d4eSConrad Meyer  * Don't allow more than this many entries in a fail point set by sysctl.
95*70e20d4eSConrad Meyer  * The 99.99...% case is to have 1 entry.  I can't imagine having this many
96*70e20d4eSConrad Meyer  * entries, so it should not limit us.  Saves on re-mallocs while holding
97*70e20d4eSConrad Meyer  * a non-sleepable lock.
98*70e20d4eSConrad Meyer  */
99*70e20d4eSConrad Meyer #define FP_MAX_ENTRY_COUNT 20
100*70e20d4eSConrad Meyer 
101*70e20d4eSConrad Meyer /* Used to drain sbufs to the sysctl output */
102*70e20d4eSConrad Meyer int fail_sysctl_drain_func(void *, const char *, int);
103*70e20d4eSConrad Meyer 
104*70e20d4eSConrad Meyer /* Head of tailq of struct fail_point_entry */
105*70e20d4eSConrad Meyer TAILQ_HEAD(fail_point_entry_queue, fail_point_entry);
106*70e20d4eSConrad Meyer 
107*70e20d4eSConrad Meyer /**
108*70e20d4eSConrad Meyer  * fp entries garbage list; outstanding entries are cleaned up in the
109*70e20d4eSConrad Meyer  * garbage collector
110*70e20d4eSConrad Meyer  */
111*70e20d4eSConrad Meyer STAILQ_HEAD(fail_point_setting_garbage, fail_point_setting);
112*70e20d4eSConrad Meyer static struct fail_point_setting_garbage fp_setting_garbage =
113*70e20d4eSConrad Meyer         STAILQ_HEAD_INITIALIZER(fp_setting_garbage);
114*70e20d4eSConrad Meyer static struct mtx mtx_garbage_list;
115*70e20d4eSConrad Meyer MTX_SYSINIT(mtx_garbage_list, &mtx_garbage_list, "fail point garbage mtx",
116*70e20d4eSConrad Meyer         MTX_SPIN);
117*70e20d4eSConrad Meyer 
118*70e20d4eSConrad Meyer static struct sx sx_fp_set;
119*70e20d4eSConrad Meyer SX_SYSINIT(sx_fp_set, &sx_fp_set, "fail point set sx");
120cfeb7489SZachary Loafman 
121d26b7945SMatthew D Fleming /**
122d26b7945SMatthew D Fleming  * Failpoint types.
123d26b7945SMatthew D Fleming  * Don't change these without changing fail_type_strings in fail.c.
124d26b7945SMatthew D Fleming  * @ingroup failpoint_private
125d26b7945SMatthew D Fleming  */
126d26b7945SMatthew D Fleming enum fail_point_t {
127d26b7945SMatthew D Fleming 	FAIL_POINT_OFF,		/**< don't fail */
128d26b7945SMatthew D Fleming 	FAIL_POINT_PANIC,	/**< panic */
129d26b7945SMatthew D Fleming 	FAIL_POINT_RETURN,	/**< return an errorcode */
130d26b7945SMatthew D Fleming 	FAIL_POINT_BREAK,	/**< break into the debugger */
131d26b7945SMatthew D Fleming 	FAIL_POINT_PRINT,	/**< print a message */
132d26b7945SMatthew D Fleming 	FAIL_POINT_SLEEP,	/**< sleep for some msecs */
133*70e20d4eSConrad Meyer 	FAIL_POINT_PAUSE,	/**< sleep until failpoint is set to off */
134*70e20d4eSConrad Meyer 	FAIL_POINT_YIELD,	/**< yield the cpu */
135*70e20d4eSConrad Meyer 	FAIL_POINT_DELAY,	/**< busy wait the cpu */
136*70e20d4eSConrad Meyer 	FAIL_POINT_NUMTYPES,
137*70e20d4eSConrad Meyer 	FAIL_POINT_INVALID = -1
138d26b7945SMatthew D Fleming };
139d26b7945SMatthew D Fleming 
1400894a9bcSMatthew D Fleming static struct {
1410894a9bcSMatthew D Fleming 	const char *name;
1420894a9bcSMatthew D Fleming 	int	nmlen;
1430894a9bcSMatthew D Fleming } fail_type_strings[] = {
1440894a9bcSMatthew D Fleming #define	FP_TYPE_NM_LEN(s)	{ s, sizeof(s) - 1 }
1450894a9bcSMatthew D Fleming 	[FAIL_POINT_OFF] =	FP_TYPE_NM_LEN("off"),
1460894a9bcSMatthew D Fleming 	[FAIL_POINT_PANIC] =	FP_TYPE_NM_LEN("panic"),
1470894a9bcSMatthew D Fleming 	[FAIL_POINT_RETURN] =	FP_TYPE_NM_LEN("return"),
1480894a9bcSMatthew D Fleming 	[FAIL_POINT_BREAK] =	FP_TYPE_NM_LEN("break"),
1490894a9bcSMatthew D Fleming 	[FAIL_POINT_PRINT] =	FP_TYPE_NM_LEN("print"),
1500894a9bcSMatthew D Fleming 	[FAIL_POINT_SLEEP] =	FP_TYPE_NM_LEN("sleep"),
151*70e20d4eSConrad Meyer 	[FAIL_POINT_PAUSE] =	FP_TYPE_NM_LEN("pause"),
152*70e20d4eSConrad Meyer 	[FAIL_POINT_YIELD] =	FP_TYPE_NM_LEN("yield"),
153*70e20d4eSConrad Meyer 	[FAIL_POINT_DELAY] =	FP_TYPE_NM_LEN("delay"),
154d26b7945SMatthew D Fleming };
155d26b7945SMatthew D Fleming 
156*70e20d4eSConrad Meyer #define FE_COUNT_UNTRACKED (INT_MIN)
157*70e20d4eSConrad Meyer 
158d26b7945SMatthew D Fleming /**
159d26b7945SMatthew D Fleming  * Internal structure tracking a single term of a complete failpoint.
160d26b7945SMatthew D Fleming  * @ingroup failpoint_private
161d26b7945SMatthew D Fleming  */
162d26b7945SMatthew D Fleming struct fail_point_entry {
163*70e20d4eSConrad Meyer 	volatile bool	fe_stale;
164d26b7945SMatthew D Fleming 	enum fail_point_t	fe_type;	/**< type of entry */
165d26b7945SMatthew D Fleming 	int		fe_arg;		/**< argument to type (e.g. return value) */
166d26b7945SMatthew D Fleming 	int		fe_prob;	/**< likelihood of firing in millionths */
167*70e20d4eSConrad Meyer 	int		fe_count;	/**< number of times to fire, -1 means infinite */
168b5bd50aeSMatthew D Fleming 	pid_t		fe_pid;		/**< only fail for this process */
169*70e20d4eSConrad Meyer 	struct fail_point	*fe_parent;	/**< backpointer to fp */
170*70e20d4eSConrad Meyer 	TAILQ_ENTRY(fail_point_entry)	fe_entries; /**< next entry ptr */
171d26b7945SMatthew D Fleming };
172d26b7945SMatthew D Fleming 
173*70e20d4eSConrad Meyer struct fail_point_setting {
174*70e20d4eSConrad Meyer 	STAILQ_ENTRY(fail_point_setting) fs_garbage_link;
175*70e20d4eSConrad Meyer 	struct fail_point_entry_queue fp_entry_queue;
176*70e20d4eSConrad Meyer 	struct fail_point * fs_parent;
177*70e20d4eSConrad Meyer 	struct mtx feq_mtx; /* Gives fail_point_pause something to do.  */
178*70e20d4eSConrad Meyer };
179cfeb7489SZachary Loafman 
180cfeb7489SZachary Loafman /**
181cfeb7489SZachary Loafman  * Defines stating the equivalent of probablilty one (100%)
182cfeb7489SZachary Loafman  */
183cfeb7489SZachary Loafman enum {
184cfeb7489SZachary Loafman 	PROB_MAX = 1000000,	/* probability between zero and this number */
185*70e20d4eSConrad Meyer 	PROB_DIGITS = 6		/* number of zero's in above number */
186cfeb7489SZachary Loafman };
187cfeb7489SZachary Loafman 
188*70e20d4eSConrad Meyer /* Get a ref on an fp's fp_setting */
189*70e20d4eSConrad Meyer static inline struct fail_point_setting *fail_point_setting_get_ref(
190*70e20d4eSConrad Meyer         struct fail_point *fp);
191*70e20d4eSConrad Meyer /* Release a ref on an fp_setting */
192*70e20d4eSConrad Meyer static inline void fail_point_setting_release_ref(struct fail_point *fp);
193*70e20d4eSConrad Meyer /* Allocate and initialize a struct fail_point_setting */
194*70e20d4eSConrad Meyer static struct fail_point_setting *fail_point_setting_new(struct
195*70e20d4eSConrad Meyer         fail_point *);
196*70e20d4eSConrad Meyer /* Free a struct fail_point_setting */
197*70e20d4eSConrad Meyer static void fail_point_setting_destroy(struct fail_point_setting *fp_setting);
198*70e20d4eSConrad Meyer /* Allocate and initialize a struct fail_point_entry */
199*70e20d4eSConrad Meyer static struct fail_point_entry *fail_point_entry_new(struct
200*70e20d4eSConrad Meyer         fail_point_setting *);
201*70e20d4eSConrad Meyer /* Free a struct fail_point_entry */
202*70e20d4eSConrad Meyer static void fail_point_entry_destroy(struct fail_point_entry *fp_entry);
203*70e20d4eSConrad Meyer /* Append fp setting to garbage list */
204*70e20d4eSConrad Meyer static inline void fail_point_setting_garbage_append(
205*70e20d4eSConrad Meyer         struct fail_point_setting *fp_setting);
206*70e20d4eSConrad Meyer /* Swap fp's setting with fp_setting_new */
207*70e20d4eSConrad Meyer static inline struct fail_point_setting *
208*70e20d4eSConrad Meyer         fail_point_swap_settings(struct fail_point *fp,
209*70e20d4eSConrad Meyer         struct fail_point_setting *fp_setting_new);
210*70e20d4eSConrad Meyer /* Free up any zero-ref setting in the garbage queue */
211*70e20d4eSConrad Meyer static void fail_point_garbage_collect(void);
212*70e20d4eSConrad Meyer /* If this fail point's setting are empty, then swap it out to NULL. */
213*70e20d4eSConrad Meyer static inline void fail_point_eval_swap_out(struct fail_point *fp,
214*70e20d4eSConrad Meyer         struct fail_point_setting *fp_setting);
215*70e20d4eSConrad Meyer 
216*70e20d4eSConrad Meyer bool
217*70e20d4eSConrad Meyer fail_point_is_off(struct fail_point *fp)
218*70e20d4eSConrad Meyer {
219*70e20d4eSConrad Meyer 	bool return_val;
220*70e20d4eSConrad Meyer 	struct fail_point_setting *fp_setting;
221*70e20d4eSConrad Meyer 	struct fail_point_entry *ent;
222*70e20d4eSConrad Meyer 
223*70e20d4eSConrad Meyer 	return_val = true;
224*70e20d4eSConrad Meyer 
225*70e20d4eSConrad Meyer 	fp_setting = fail_point_setting_get_ref(fp);
226*70e20d4eSConrad Meyer 	if (fp_setting != NULL) {
227*70e20d4eSConrad Meyer 		TAILQ_FOREACH(ent, &fp_setting->fp_entry_queue,
228*70e20d4eSConrad Meyer 		    fe_entries) {
229*70e20d4eSConrad Meyer 			if (!ent->fe_stale) {
230*70e20d4eSConrad Meyer 				return_val = false;
231*70e20d4eSConrad Meyer 				break;
232*70e20d4eSConrad Meyer 			}
233*70e20d4eSConrad Meyer 		}
234*70e20d4eSConrad Meyer 	}
235*70e20d4eSConrad Meyer 	fail_point_setting_release_ref(fp);
236*70e20d4eSConrad Meyer 
237*70e20d4eSConrad Meyer 	return (return_val);
238*70e20d4eSConrad Meyer }
239*70e20d4eSConrad Meyer 
240*70e20d4eSConrad Meyer /* Allocate and initialize a struct fail_point_setting */
241*70e20d4eSConrad Meyer static struct fail_point_setting *
242*70e20d4eSConrad Meyer fail_point_setting_new(struct fail_point *fp)
243*70e20d4eSConrad Meyer {
244*70e20d4eSConrad Meyer 	struct fail_point_setting *fs_new;
245*70e20d4eSConrad Meyer 
246*70e20d4eSConrad Meyer 	fs_new = fs_malloc();
247*70e20d4eSConrad Meyer 	fs_new->fs_parent = fp;
248*70e20d4eSConrad Meyer 	TAILQ_INIT(&fs_new->fp_entry_queue);
249*70e20d4eSConrad Meyer 	mtx_init(&fs_new->feq_mtx, "fail point entries", NULL, MTX_SPIN);
250*70e20d4eSConrad Meyer 
251*70e20d4eSConrad Meyer 	fail_point_setting_garbage_append(fs_new);
252*70e20d4eSConrad Meyer 
253*70e20d4eSConrad Meyer 	return (fs_new);
254*70e20d4eSConrad Meyer }
255*70e20d4eSConrad Meyer 
256*70e20d4eSConrad Meyer /* Free a struct fail_point_setting */
257*70e20d4eSConrad Meyer static void
258*70e20d4eSConrad Meyer fail_point_setting_destroy(struct fail_point_setting *fp_setting)
259*70e20d4eSConrad Meyer {
260*70e20d4eSConrad Meyer 	struct fail_point_entry *ent;
261*70e20d4eSConrad Meyer 
262*70e20d4eSConrad Meyer 	while (!TAILQ_EMPTY(&fp_setting->fp_entry_queue)) {
263*70e20d4eSConrad Meyer 		ent = TAILQ_FIRST(&fp_setting->fp_entry_queue);
264*70e20d4eSConrad Meyer 		TAILQ_REMOVE(&fp_setting->fp_entry_queue, ent, fe_entries);
265*70e20d4eSConrad Meyer 		fail_point_entry_destroy(ent);
266*70e20d4eSConrad Meyer 	}
267*70e20d4eSConrad Meyer 
268*70e20d4eSConrad Meyer 	fs_free(fp_setting);
269*70e20d4eSConrad Meyer }
270*70e20d4eSConrad Meyer 
271*70e20d4eSConrad Meyer /* Allocate and initialize a struct fail_point_entry */
272*70e20d4eSConrad Meyer static struct fail_point_entry *
273*70e20d4eSConrad Meyer fail_point_entry_new(struct fail_point_setting *fp_setting)
274*70e20d4eSConrad Meyer {
275*70e20d4eSConrad Meyer 	struct fail_point_entry *fp_entry;
276*70e20d4eSConrad Meyer 
277*70e20d4eSConrad Meyer 	fp_entry = fp_malloc(sizeof(struct fail_point_entry),
278*70e20d4eSConrad Meyer 	        M_WAITOK | M_ZERO);
279*70e20d4eSConrad Meyer 	fp_entry->fe_parent = fp_setting->fs_parent;
280*70e20d4eSConrad Meyer 	fp_entry->fe_prob = PROB_MAX;
281*70e20d4eSConrad Meyer 	fp_entry->fe_pid = NO_PID;
282*70e20d4eSConrad Meyer 	fp_entry->fe_count = FE_COUNT_UNTRACKED;
283*70e20d4eSConrad Meyer 	TAILQ_INSERT_TAIL(&fp_setting->fp_entry_queue, fp_entry,
284*70e20d4eSConrad Meyer 	        fe_entries);
285*70e20d4eSConrad Meyer 
286*70e20d4eSConrad Meyer 	return (fp_entry);
287*70e20d4eSConrad Meyer }
288*70e20d4eSConrad Meyer 
289*70e20d4eSConrad Meyer /* Free a struct fail_point_entry */
290*70e20d4eSConrad Meyer static void
291*70e20d4eSConrad Meyer fail_point_entry_destroy(struct fail_point_entry *fp_entry)
292*70e20d4eSConrad Meyer {
293*70e20d4eSConrad Meyer 
294*70e20d4eSConrad Meyer 	fp_free(fp_entry);
295*70e20d4eSConrad Meyer }
296*70e20d4eSConrad Meyer 
297*70e20d4eSConrad Meyer /* Get a ref on an fp's fp_setting */
298*70e20d4eSConrad Meyer static inline struct fail_point_setting *
299*70e20d4eSConrad Meyer fail_point_setting_get_ref(struct fail_point *fp)
300*70e20d4eSConrad Meyer {
301*70e20d4eSConrad Meyer 	struct fail_point_setting *fp_setting;
302*70e20d4eSConrad Meyer 
303*70e20d4eSConrad Meyer 	/* Invariant: if we have a ref, our pointer to fp_setting is safe */
304*70e20d4eSConrad Meyer 	atomic_add_acq_32(&fp->fp_ref_cnt, 1);
305*70e20d4eSConrad Meyer 	fp_setting = fp->fp_setting;
306*70e20d4eSConrad Meyer 
307*70e20d4eSConrad Meyer 	return (fp_setting);
308*70e20d4eSConrad Meyer }
309*70e20d4eSConrad Meyer 
310*70e20d4eSConrad Meyer /* Release a ref on an fp_setting */
311*70e20d4eSConrad Meyer static inline void
312*70e20d4eSConrad Meyer fail_point_setting_release_ref(struct fail_point *fp)
313*70e20d4eSConrad Meyer {
314*70e20d4eSConrad Meyer 
315*70e20d4eSConrad Meyer 	KASSERT(&fp->fp_ref_cnt > 0, ("Attempting to deref w/no refs"));
316*70e20d4eSConrad Meyer 	atomic_subtract_rel_32(&fp->fp_ref_cnt, 1);
317*70e20d4eSConrad Meyer }
318*70e20d4eSConrad Meyer 
319*70e20d4eSConrad Meyer /* Append fp entries to fp garbage list */
320*70e20d4eSConrad Meyer static inline void
321*70e20d4eSConrad Meyer fail_point_setting_garbage_append(struct fail_point_setting *fp_setting)
322*70e20d4eSConrad Meyer {
323*70e20d4eSConrad Meyer 
324*70e20d4eSConrad Meyer 	mtx_lock_spin(&mtx_garbage_list);
325*70e20d4eSConrad Meyer 	STAILQ_INSERT_TAIL(&fp_setting_garbage, fp_setting,
326*70e20d4eSConrad Meyer 	        fs_garbage_link);
327*70e20d4eSConrad Meyer 	mtx_unlock_spin(&mtx_garbage_list);
328*70e20d4eSConrad Meyer }
329*70e20d4eSConrad Meyer 
330*70e20d4eSConrad Meyer /* Swap fp's entries with fp_setting_new */
331*70e20d4eSConrad Meyer static struct fail_point_setting *
332*70e20d4eSConrad Meyer fail_point_swap_settings(struct fail_point *fp,
333*70e20d4eSConrad Meyer         struct fail_point_setting *fp_setting_new)
334*70e20d4eSConrad Meyer {
335*70e20d4eSConrad Meyer 	struct fail_point_setting *fp_setting_old;
336*70e20d4eSConrad Meyer 
337*70e20d4eSConrad Meyer 	fp_setting_old = fp->fp_setting;
338*70e20d4eSConrad Meyer 	fp->fp_setting = fp_setting_new;
339*70e20d4eSConrad Meyer 
340*70e20d4eSConrad Meyer 	return (fp_setting_old);
341*70e20d4eSConrad Meyer }
342*70e20d4eSConrad Meyer 
343*70e20d4eSConrad Meyer static inline void
344*70e20d4eSConrad Meyer fail_point_eval_swap_out(struct fail_point *fp,
345*70e20d4eSConrad Meyer         struct fail_point_setting *fp_setting)
346*70e20d4eSConrad Meyer {
347*70e20d4eSConrad Meyer 
348*70e20d4eSConrad Meyer 	/* We may have already been swapped out and replaced; ignore. */
349*70e20d4eSConrad Meyer 	if (fp->fp_setting == fp_setting)
350*70e20d4eSConrad Meyer 		fail_point_swap_settings(fp, NULL);
351*70e20d4eSConrad Meyer }
352*70e20d4eSConrad Meyer 
353*70e20d4eSConrad Meyer /* Free up any zero-ref entries in the garbage queue */
354*70e20d4eSConrad Meyer static void
355*70e20d4eSConrad Meyer fail_point_garbage_collect()
356*70e20d4eSConrad Meyer {
357*70e20d4eSConrad Meyer 	struct fail_point_setting *fs_current, *fs_next;
358*70e20d4eSConrad Meyer 	struct fail_point_setting_garbage fp_ents_free_list;
359*70e20d4eSConrad Meyer 
360*70e20d4eSConrad Meyer 	/**
361*70e20d4eSConrad Meyer 	  * We will transfer the entries to free to fp_ents_free_list while holding
362*70e20d4eSConrad Meyer 	  * the spin mutex, then free it after we drop the lock. This avoids
363*70e20d4eSConrad Meyer 	  * triggering witness due to sleepable mutexes in the memory
364*70e20d4eSConrad Meyer 	  * allocator.
365*70e20d4eSConrad Meyer 	  */
366*70e20d4eSConrad Meyer 	STAILQ_INIT(&fp_ents_free_list);
367*70e20d4eSConrad Meyer 
368*70e20d4eSConrad Meyer 	mtx_lock_spin(&mtx_garbage_list);
369*70e20d4eSConrad Meyer 	STAILQ_FOREACH_SAFE(fs_current, &fp_setting_garbage, fs_garbage_link,
370*70e20d4eSConrad Meyer 	    fs_next) {
371*70e20d4eSConrad Meyer 		if (fs_current->fs_parent->fp_setting != fs_current &&
372*70e20d4eSConrad Meyer 		        fs_current->fs_parent->fp_ref_cnt == 0) {
373*70e20d4eSConrad Meyer 			STAILQ_REMOVE(&fp_setting_garbage, fs_current,
374*70e20d4eSConrad Meyer 			        fail_point_setting, fs_garbage_link);
375*70e20d4eSConrad Meyer 			STAILQ_INSERT_HEAD(&fp_ents_free_list, fs_current,
376*70e20d4eSConrad Meyer 			        fs_garbage_link);
377*70e20d4eSConrad Meyer 		}
378*70e20d4eSConrad Meyer 	}
379*70e20d4eSConrad Meyer 	mtx_unlock_spin(&mtx_garbage_list);
380*70e20d4eSConrad Meyer 
381*70e20d4eSConrad Meyer 	STAILQ_FOREACH_SAFE(fs_current, &fp_ents_free_list, fs_garbage_link,
382*70e20d4eSConrad Meyer 	        fs_next)
383*70e20d4eSConrad Meyer 		fail_point_setting_destroy(fs_current);
384*70e20d4eSConrad Meyer }
385*70e20d4eSConrad Meyer 
386*70e20d4eSConrad Meyer /* Drain out all refs from this fail point */
387*70e20d4eSConrad Meyer static inline void
388*70e20d4eSConrad Meyer fail_point_drain(struct fail_point *fp, int expected_ref)
389*70e20d4eSConrad Meyer {
390*70e20d4eSConrad Meyer 	struct fail_point_setting *entries;
391*70e20d4eSConrad Meyer 
392*70e20d4eSConrad Meyer 	entries = fail_point_swap_settings(fp, NULL);
393*70e20d4eSConrad Meyer 	/**
394*70e20d4eSConrad Meyer 	 * We have unpaused all threads; so we will wait no longer
395*70e20d4eSConrad Meyer 	 * than the time taken for the longest remaining sleep, or
396*70e20d4eSConrad Meyer 	 * the length of time of a long-running code block.
397*70e20d4eSConrad Meyer 	 */
398*70e20d4eSConrad Meyer 	while (fp->fp_ref_cnt > expected_ref) {
399*70e20d4eSConrad Meyer 		wakeup(FP_PAUSE_CHANNEL(fp));
400*70e20d4eSConrad Meyer 		tsleep(&fp, PWAIT, "fail_point_drain", hz / 100);
401*70e20d4eSConrad Meyer 	}
402*70e20d4eSConrad Meyer 	fail_point_swap_settings(fp, entries);
403*70e20d4eSConrad Meyer }
404*70e20d4eSConrad Meyer 
405*70e20d4eSConrad Meyer static inline void
406*70e20d4eSConrad Meyer fail_point_pause(struct fail_point *fp, enum fail_point_return_code *pret,
407*70e20d4eSConrad Meyer         struct mtx *mtx_sleep)
408*70e20d4eSConrad Meyer {
409*70e20d4eSConrad Meyer 
410*70e20d4eSConrad Meyer 	if (fp->fp_pre_sleep_fn)
411*70e20d4eSConrad Meyer 		fp->fp_pre_sleep_fn(fp->fp_pre_sleep_arg);
412*70e20d4eSConrad Meyer 
413*70e20d4eSConrad Meyer 	msleep_spin(FP_PAUSE_CHANNEL(fp), mtx_sleep, "failpt", 0);
414*70e20d4eSConrad Meyer 
415*70e20d4eSConrad Meyer 	if (fp->fp_post_sleep_fn)
416*70e20d4eSConrad Meyer 		fp->fp_post_sleep_fn(fp->fp_post_sleep_arg);
417*70e20d4eSConrad Meyer }
418*70e20d4eSConrad Meyer 
419*70e20d4eSConrad Meyer static inline void
420*70e20d4eSConrad Meyer fail_point_sleep(struct fail_point *fp, int msecs,
421*70e20d4eSConrad Meyer         enum fail_point_return_code *pret)
422*70e20d4eSConrad Meyer {
423*70e20d4eSConrad Meyer 	int timo;
424*70e20d4eSConrad Meyer 
425*70e20d4eSConrad Meyer 	/* Convert from millisecs to ticks, rounding up */
426*70e20d4eSConrad Meyer 	timo = howmany(msecs * hz, 1000);
427*70e20d4eSConrad Meyer 
428*70e20d4eSConrad Meyer 	if (timo > 0) {
429*70e20d4eSConrad Meyer 		if (!(fp->fp_flags & FAIL_POINT_USE_TIMEOUT_PATH)) {
430*70e20d4eSConrad Meyer 			if (fp->fp_pre_sleep_fn)
431*70e20d4eSConrad Meyer 				fp->fp_pre_sleep_fn(fp->fp_pre_sleep_arg);
432*70e20d4eSConrad Meyer 
433*70e20d4eSConrad Meyer 			tsleep(FP_SLEEP_CHANNEL(fp), PWAIT, "failpt", timo);
434*70e20d4eSConrad Meyer 
435*70e20d4eSConrad Meyer 			if (fp->fp_post_sleep_fn)
436*70e20d4eSConrad Meyer 				fp->fp_post_sleep_fn(fp->fp_post_sleep_arg);
437*70e20d4eSConrad Meyer 		} else {
438*70e20d4eSConrad Meyer 			if (fp->fp_pre_sleep_fn)
439*70e20d4eSConrad Meyer 				fp->fp_pre_sleep_fn(fp->fp_pre_sleep_arg);
440*70e20d4eSConrad Meyer 
441*70e20d4eSConrad Meyer 			timeout(fp->fp_post_sleep_fn, fp->fp_post_sleep_arg,
442*70e20d4eSConrad Meyer 			        timo);
443*70e20d4eSConrad Meyer 			*pret = FAIL_POINT_RC_QUEUED;
444*70e20d4eSConrad Meyer 		}
445*70e20d4eSConrad Meyer 	}
446*70e20d4eSConrad Meyer }
447*70e20d4eSConrad Meyer 
448*70e20d4eSConrad Meyer static char *parse_fail_point(struct fail_point_setting *, char *);
449*70e20d4eSConrad Meyer static char *parse_term(struct fail_point_setting *, char *);
450cfeb7489SZachary Loafman static char *parse_number(int *out_units, int *out_decimal, char *);
451cfeb7489SZachary Loafman static char *parse_type(struct fail_point_entry *, char *);
452cfeb7489SZachary Loafman 
453cfeb7489SZachary Loafman /**
454cfeb7489SZachary Loafman  * Initialize a fail_point.  The name is formed in a printf-like fashion
455cfeb7489SZachary Loafman  * from "fmt" and subsequent arguments.  This function is generally used
456cfeb7489SZachary Loafman  * for custom failpoints located at odd places in the sysctl tree, and is
457cfeb7489SZachary Loafman  * not explicitly needed for standard in-line-declared failpoints.
458cfeb7489SZachary Loafman  *
459cfeb7489SZachary Loafman  * @ingroup failpoint
460cfeb7489SZachary Loafman  */
461cfeb7489SZachary Loafman void
462cfeb7489SZachary Loafman fail_point_init(struct fail_point *fp, const char *fmt, ...)
463cfeb7489SZachary Loafman {
464cfeb7489SZachary Loafman 	va_list ap;
465cfeb7489SZachary Loafman 	char *name;
466cfeb7489SZachary Loafman 	int n;
467cfeb7489SZachary Loafman 
468*70e20d4eSConrad Meyer 	fp->fp_setting = NULL;
469cfeb7489SZachary Loafman 	fp->fp_flags = 0;
470cfeb7489SZachary Loafman 
471cfeb7489SZachary Loafman 	/* Figure out the size of the name. */
472cfeb7489SZachary Loafman 	va_start(ap, fmt);
473cfeb7489SZachary Loafman 	n = vsnprintf(NULL, 0, fmt, ap);
474cfeb7489SZachary Loafman 	va_end(ap);
475cfeb7489SZachary Loafman 
476cfeb7489SZachary Loafman 	/* Allocate the name and fill it in. */
477cfeb7489SZachary Loafman 	name = fp_malloc(n + 1, M_WAITOK);
478cfeb7489SZachary Loafman 	if (name != NULL) {
479cfeb7489SZachary Loafman 		va_start(ap, fmt);
480cfeb7489SZachary Loafman 		vsnprintf(name, n + 1, fmt, ap);
481cfeb7489SZachary Loafman 		va_end(ap);
482cfeb7489SZachary Loafman 	}
483cfeb7489SZachary Loafman 	fp->fp_name = name;
4844b7c6844SMatthew D Fleming 	fp->fp_location = "";
485cfeb7489SZachary Loafman 	fp->fp_flags |= FAIL_POINT_DYNAMIC_NAME;
486*70e20d4eSConrad Meyer 	fp->fp_pre_sleep_fn = NULL;
487*70e20d4eSConrad Meyer 	fp->fp_pre_sleep_arg = NULL;
488*70e20d4eSConrad Meyer 	fp->fp_post_sleep_fn = NULL;
489*70e20d4eSConrad Meyer 	fp->fp_post_sleep_arg = NULL;
490cfeb7489SZachary Loafman }
491cfeb7489SZachary Loafman 
492cfeb7489SZachary Loafman /**
493*70e20d4eSConrad Meyer  * Free the resources held by a fail_point, and wake any paused threads.
494*70e20d4eSConrad Meyer  * Thou shalt not allow threads to hit this fail point after you enter this
495*70e20d4eSConrad Meyer  * function, nor shall you call this multiple times for a given fp.
496cfeb7489SZachary Loafman  * @ingroup failpoint
497cfeb7489SZachary Loafman  */
498cfeb7489SZachary Loafman void
499cfeb7489SZachary Loafman fail_point_destroy(struct fail_point *fp)
500cfeb7489SZachary Loafman {
501cfeb7489SZachary Loafman 
502*70e20d4eSConrad Meyer 	fail_point_drain(fp, 0);
503*70e20d4eSConrad Meyer 
5040894a9bcSMatthew D Fleming 	if ((fp->fp_flags & FAIL_POINT_DYNAMIC_NAME) != 0) {
5050894a9bcSMatthew D Fleming 		fp_free(__DECONST(void *, fp->fp_name));
506cfeb7489SZachary Loafman 		fp->fp_name = NULL;
507cfeb7489SZachary Loafman 	}
508cfeb7489SZachary Loafman 	fp->fp_flags = 0;
509*70e20d4eSConrad Meyer 
510*70e20d4eSConrad Meyer 	sx_xlock(&sx_fp_set);
511*70e20d4eSConrad Meyer 	fail_point_garbage_collect();
512*70e20d4eSConrad Meyer 	sx_xunlock(&sx_fp_set);
513cfeb7489SZachary Loafman }
514cfeb7489SZachary Loafman 
515cfeb7489SZachary Loafman /**
516cfeb7489SZachary Loafman  * This does the real work of evaluating a fail point. If the fail point tells
517cfeb7489SZachary Loafman  * us to return a value, this function returns 1 and fills in 'return_value'
518cfeb7489SZachary Loafman  * (return_value is allowed to be null). If the fail point tells us to panic,
519cfeb7489SZachary Loafman  * we never return. Otherwise we just return 0 after doing some work, which
520cfeb7489SZachary Loafman  * means "keep going".
521cfeb7489SZachary Loafman  */
522cfeb7489SZachary Loafman enum fail_point_return_code
523cfeb7489SZachary Loafman fail_point_eval_nontrivial(struct fail_point *fp, int *return_value)
524cfeb7489SZachary Loafman {
525*70e20d4eSConrad Meyer 	bool execute = false;
526*70e20d4eSConrad Meyer 	struct fail_point_entry *ent;
527*70e20d4eSConrad Meyer 	struct fail_point_setting *fp_setting;
528*70e20d4eSConrad Meyer 	enum fail_point_return_code ret;
529*70e20d4eSConrad Meyer 	int cont;
530*70e20d4eSConrad Meyer 	int count;
531cfeb7489SZachary Loafman 	int msecs;
532*70e20d4eSConrad Meyer 	int usecs;
533cfeb7489SZachary Loafman 
534*70e20d4eSConrad Meyer 	ret = FAIL_POINT_RC_CONTINUE;
535*70e20d4eSConrad Meyer 	cont = 0; /* don't continue by default */
536cfeb7489SZachary Loafman 
537*70e20d4eSConrad Meyer 	fp_setting = fail_point_setting_get_ref(fp);
538*70e20d4eSConrad Meyer 	if (fp_setting == NULL)
539*70e20d4eSConrad Meyer 		goto abort;
540*70e20d4eSConrad Meyer 
541*70e20d4eSConrad Meyer 	TAILQ_FOREACH(ent, &fp_setting->fp_entry_queue, fe_entries) {
542*70e20d4eSConrad Meyer 
543*70e20d4eSConrad Meyer 		if (ent->fe_stale)
544*70e20d4eSConrad Meyer 			continue;
545cfeb7489SZachary Loafman 
546cfeb7489SZachary Loafman 		if (ent->fe_prob < PROB_MAX &&
5470894a9bcSMatthew D Fleming 		    ent->fe_prob < random() % PROB_MAX)
5480894a9bcSMatthew D Fleming 			continue;
549*70e20d4eSConrad Meyer 
550b5bd50aeSMatthew D Fleming 		if (ent->fe_pid != NO_PID && ent->fe_pid != curproc->p_pid)
551b5bd50aeSMatthew D Fleming 			continue;
552cfeb7489SZachary Loafman 
553*70e20d4eSConrad Meyer 		if (ent->fe_count != FE_COUNT_UNTRACKED) {
554*70e20d4eSConrad Meyer 			count = ent->fe_count;
555*70e20d4eSConrad Meyer 			while (count > 0) {
556*70e20d4eSConrad Meyer 				if (atomic_cmpset_32(&ent->fe_count, count, count - 1)) {
557*70e20d4eSConrad Meyer 					count--;
558*70e20d4eSConrad Meyer 					execute = true;
559*70e20d4eSConrad Meyer 					break;
560*70e20d4eSConrad Meyer 				}
561*70e20d4eSConrad Meyer 				count = ent->fe_count;
562*70e20d4eSConrad Meyer 			}
563*70e20d4eSConrad Meyer 			if (execute == false)
564*70e20d4eSConrad Meyer 				/* We lost the race; consider the entry stale and bail now */
565*70e20d4eSConrad Meyer 				continue;
566*70e20d4eSConrad Meyer 			if (count == 0)
567*70e20d4eSConrad Meyer 				ent->fe_stale = true;
568*70e20d4eSConrad Meyer 		}
569*70e20d4eSConrad Meyer 
570cfeb7489SZachary Loafman 		switch (ent->fe_type) {
571cfeb7489SZachary Loafman 		case FAIL_POINT_PANIC:
572cfeb7489SZachary Loafman 			panic("fail point %s panicking", fp->fp_name);
573cfeb7489SZachary Loafman 			/* NOTREACHED */
574cfeb7489SZachary Loafman 
575cfeb7489SZachary Loafman 		case FAIL_POINT_RETURN:
5760894a9bcSMatthew D Fleming 			if (return_value != NULL)
577cfeb7489SZachary Loafman 				*return_value = ent->fe_arg;
578cfeb7489SZachary Loafman 			ret = FAIL_POINT_RC_RETURN;
579cfeb7489SZachary Loafman 			break;
580cfeb7489SZachary Loafman 
581cfeb7489SZachary Loafman 		case FAIL_POINT_BREAK:
5820894a9bcSMatthew D Fleming 			printf("fail point %s breaking to debugger\n",
5830894a9bcSMatthew D Fleming 			        fp->fp_name);
584cfeb7489SZachary Loafman 			breakpoint();
585cfeb7489SZachary Loafman 			break;
586cfeb7489SZachary Loafman 
587cfeb7489SZachary Loafman 		case FAIL_POINT_PRINT:
588cfeb7489SZachary Loafman 			printf("fail point %s executing\n", fp->fp_name);
589cfeb7489SZachary Loafman 			cont = ent->fe_arg;
590cfeb7489SZachary Loafman 			break;
591cfeb7489SZachary Loafman 
592cfeb7489SZachary Loafman 		case FAIL_POINT_SLEEP:
593cfeb7489SZachary Loafman 			msecs = ent->fe_arg;
594cfeb7489SZachary Loafman 			if (msecs)
595*70e20d4eSConrad Meyer 				fail_point_sleep(fp, msecs, &ret);
596*70e20d4eSConrad Meyer 			break;
597*70e20d4eSConrad Meyer 
598*70e20d4eSConrad Meyer 		case FAIL_POINT_PAUSE:
599*70e20d4eSConrad Meyer 			/**
600*70e20d4eSConrad Meyer 			 * Pausing is inherently strange with multiple
601*70e20d4eSConrad Meyer 			 * entries given our design.  That is because some
602*70e20d4eSConrad Meyer 			 * entries could be unreachable, for instance in cases like:
603*70e20d4eSConrad Meyer 			 * pause->return. We can never reach the return entry.
604*70e20d4eSConrad Meyer 			 * The sysctl layer actually truncates all entries after
605*70e20d4eSConrad Meyer 			 * a pause for this reason.
606*70e20d4eSConrad Meyer 			 */
607*70e20d4eSConrad Meyer 			mtx_lock_spin(&fp_setting->feq_mtx);
608*70e20d4eSConrad Meyer 			fail_point_pause(fp, &ret, &fp_setting->feq_mtx);
609*70e20d4eSConrad Meyer 			mtx_unlock_spin(&fp_setting->feq_mtx);
610*70e20d4eSConrad Meyer 			break;
611*70e20d4eSConrad Meyer 
612*70e20d4eSConrad Meyer 		case FAIL_POINT_YIELD:
613*70e20d4eSConrad Meyer 			kern_yield(-1);
614*70e20d4eSConrad Meyer 			break;
615*70e20d4eSConrad Meyer 
616*70e20d4eSConrad Meyer 		case FAIL_POINT_DELAY:
617*70e20d4eSConrad Meyer 			usecs = ent->fe_arg;
618*70e20d4eSConrad Meyer 			DELAY(usecs);
619cfeb7489SZachary Loafman 			break;
620cfeb7489SZachary Loafman 
621cfeb7489SZachary Loafman 		default:
622cfeb7489SZachary Loafman 			break;
623cfeb7489SZachary Loafman 		}
624cfeb7489SZachary Loafman 
6250894a9bcSMatthew D Fleming 		if (cont == 0)
626cfeb7489SZachary Loafman 			break;
627cfeb7489SZachary Loafman 	}
628cfeb7489SZachary Loafman 
629*70e20d4eSConrad Meyer 	if (fail_point_is_off(fp))
630*70e20d4eSConrad Meyer 		fail_point_eval_swap_out(fp, fp_setting);
631cfeb7489SZachary Loafman 
632*70e20d4eSConrad Meyer abort:
633*70e20d4eSConrad Meyer 	fail_point_setting_release_ref(fp);
634cfeb7489SZachary Loafman 
6350894a9bcSMatthew D Fleming 	return (ret);
636*70e20d4eSConrad Meyer 
637cfeb7489SZachary Loafman }
638cfeb7489SZachary Loafman 
639cfeb7489SZachary Loafman /**
640cfeb7489SZachary Loafman  * Translate internal fail_point structure into human-readable text.
641cfeb7489SZachary Loafman  */
642cfeb7489SZachary Loafman static void
643*70e20d4eSConrad Meyer fail_point_get(struct fail_point *fp, struct sbuf *sb,
644*70e20d4eSConrad Meyer         bool verbose)
645cfeb7489SZachary Loafman {
646cfeb7489SZachary Loafman 	struct fail_point_entry *ent;
647*70e20d4eSConrad Meyer 	struct fail_point_setting *fp_setting;
648*70e20d4eSConrad Meyer 	struct fail_point_entry *fp_entry_cpy;
649*70e20d4eSConrad Meyer 	int cnt_sleeping;
650*70e20d4eSConrad Meyer 	int idx;
651*70e20d4eSConrad Meyer 	int printed_entry_count;
652cfeb7489SZachary Loafman 
653*70e20d4eSConrad Meyer 	cnt_sleeping = 0;
654*70e20d4eSConrad Meyer 	idx = 0;
655*70e20d4eSConrad Meyer 	printed_entry_count = 0;
656cfeb7489SZachary Loafman 
657*70e20d4eSConrad Meyer 	fp_entry_cpy = fp_malloc(sizeof(struct fail_point_entry) *
658*70e20d4eSConrad Meyer 	        (FP_MAX_ENTRY_COUNT + 1), M_WAITOK);
659*70e20d4eSConrad Meyer 
660*70e20d4eSConrad Meyer 	fp_setting = fail_point_setting_get_ref(fp);
661*70e20d4eSConrad Meyer 
662*70e20d4eSConrad Meyer 	if (fp_setting != NULL) {
663*70e20d4eSConrad Meyer 		TAILQ_FOREACH(ent, &fp_setting->fp_entry_queue, fe_entries) {
664*70e20d4eSConrad Meyer 			if (ent->fe_stale)
665*70e20d4eSConrad Meyer 				continue;
666*70e20d4eSConrad Meyer 
667*70e20d4eSConrad Meyer 			KASSERT(printed_entry_count < FP_MAX_ENTRY_COUNT,
668*70e20d4eSConrad Meyer 			        ("FP entry list larger than allowed"));
669*70e20d4eSConrad Meyer 
670*70e20d4eSConrad Meyer 			fp_entry_cpy[printed_entry_count] = *ent;
671*70e20d4eSConrad Meyer 			++printed_entry_count;
672*70e20d4eSConrad Meyer 		}
673*70e20d4eSConrad Meyer 	}
674*70e20d4eSConrad Meyer 	fail_point_setting_release_ref(fp);
675*70e20d4eSConrad Meyer 
676*70e20d4eSConrad Meyer 	/* This is our equivalent of a NULL terminator */
677*70e20d4eSConrad Meyer 	fp_entry_cpy[printed_entry_count].fe_type = FAIL_POINT_INVALID;
678*70e20d4eSConrad Meyer 
679*70e20d4eSConrad Meyer 	while (idx < printed_entry_count) {
680*70e20d4eSConrad Meyer 		ent = &fp_entry_cpy[idx];
681*70e20d4eSConrad Meyer 		++idx;
682cfeb7489SZachary Loafman 		if (ent->fe_prob < PROB_MAX) {
683cfeb7489SZachary Loafman 			int decimal = ent->fe_prob % (PROB_MAX / 100);
684cfeb7489SZachary Loafman 			int units = ent->fe_prob / (PROB_MAX / 100);
685cfeb7489SZachary Loafman 			sbuf_printf(sb, "%d", units);
686cfeb7489SZachary Loafman 			if (decimal) {
687cfeb7489SZachary Loafman 				int digits = PROB_DIGITS - 2;
688cfeb7489SZachary Loafman 				while (!(decimal % 10)) {
689cfeb7489SZachary Loafman 					digits--;
690cfeb7489SZachary Loafman 					decimal /= 10;
691cfeb7489SZachary Loafman 				}
692cfeb7489SZachary Loafman 				sbuf_printf(sb, ".%0*d", digits, decimal);
693cfeb7489SZachary Loafman 			}
694cfeb7489SZachary Loafman 			sbuf_printf(sb, "%%");
695cfeb7489SZachary Loafman 		}
696*70e20d4eSConrad Meyer 		if (ent->fe_count >= 0)
697cfeb7489SZachary Loafman 			sbuf_printf(sb, "%d*", ent->fe_count);
6980894a9bcSMatthew D Fleming 		sbuf_printf(sb, "%s", fail_type_strings[ent->fe_type].name);
699cfeb7489SZachary Loafman 		if (ent->fe_arg)
700cfeb7489SZachary Loafman 			sbuf_printf(sb, "(%d)", ent->fe_arg);
701b5bd50aeSMatthew D Fleming 		if (ent->fe_pid != NO_PID)
702b5bd50aeSMatthew D Fleming 			sbuf_printf(sb, "[pid %d]", ent->fe_pid);
703cfeb7489SZachary Loafman 		if (TAILQ_NEXT(ent, fe_entries))
704cfeb7489SZachary Loafman 			sbuf_printf(sb, "->");
705cfeb7489SZachary Loafman 	}
706*70e20d4eSConrad Meyer 	if (!printed_entry_count)
707cfeb7489SZachary Loafman 		sbuf_printf(sb, "off");
708cfeb7489SZachary Loafman 
709*70e20d4eSConrad Meyer 	fp_free(fp_entry_cpy);
710*70e20d4eSConrad Meyer 	if (verbose) {
711*70e20d4eSConrad Meyer 		/* Print number of sleeping threads. queue=0 is the argument
712*70e20d4eSConrad Meyer 		 * used by msleep when sending our threads to sleep. */
713*70e20d4eSConrad Meyer 		sbuf_printf(sb, "\nsleeping_thread_stacks = {\n");
714*70e20d4eSConrad Meyer 		sleepq_sbuf_print_stacks(sb, FP_SLEEP_CHANNEL(fp), 0,
715*70e20d4eSConrad Meyer 		        &cnt_sleeping);
716*70e20d4eSConrad Meyer 
717*70e20d4eSConrad Meyer 		sbuf_printf(sb, "},\n");
718*70e20d4eSConrad Meyer 		sbuf_printf(sb, "sleeping_thread_count = %d,\n",
719*70e20d4eSConrad Meyer 		        cnt_sleeping);
720*70e20d4eSConrad Meyer 
721*70e20d4eSConrad Meyer 		sbuf_printf(sb, "paused_thread_stacks = {\n");
722*70e20d4eSConrad Meyer 		sleepq_sbuf_print_stacks(sb, FP_PAUSE_CHANNEL(fp), 0,
723*70e20d4eSConrad Meyer 		        &cnt_sleeping);
724*70e20d4eSConrad Meyer 
725*70e20d4eSConrad Meyer 		sbuf_printf(sb, "},\n");
726*70e20d4eSConrad Meyer 		sbuf_printf(sb, "paused_thread_count = %d\n",
727*70e20d4eSConrad Meyer 		        cnt_sleeping);
728*70e20d4eSConrad Meyer 	}
729cfeb7489SZachary Loafman }
730cfeb7489SZachary Loafman 
731cfeb7489SZachary Loafman /**
732cfeb7489SZachary Loafman  * Set an internal fail_point structure from a human-readable failpoint string
733cfeb7489SZachary Loafman  * in a lock-safe manner.
734cfeb7489SZachary Loafman  */
735cfeb7489SZachary Loafman static int
736cfeb7489SZachary Loafman fail_point_set(struct fail_point *fp, char *buf)
737cfeb7489SZachary Loafman {
738cfeb7489SZachary Loafman 	struct fail_point_entry *ent, *ent_next;
739*70e20d4eSConrad Meyer 	struct fail_point_setting *entries;
740*70e20d4eSConrad Meyer 	bool should_wake_paused;
741*70e20d4eSConrad Meyer 	bool should_truncate;
742*70e20d4eSConrad Meyer 	int error;
743*70e20d4eSConrad Meyer 
744*70e20d4eSConrad Meyer 	error = 0;
745*70e20d4eSConrad Meyer 	should_wake_paused = false;
746*70e20d4eSConrad Meyer 	should_truncate = false;
747cfeb7489SZachary Loafman 
748cfeb7489SZachary Loafman 	/* Parse new entries. */
749*70e20d4eSConrad Meyer 	/**
750*70e20d4eSConrad Meyer 	 * ref protects our new malloc'd stuff from being garbage collected
751*70e20d4eSConrad Meyer 	 * before we link it.
752*70e20d4eSConrad Meyer 	 */
753*70e20d4eSConrad Meyer 	fail_point_setting_get_ref(fp);
754*70e20d4eSConrad Meyer 	entries = fail_point_setting_new(fp);
755*70e20d4eSConrad Meyer 	if (parse_fail_point(entries, buf) == NULL) {
756*70e20d4eSConrad Meyer 		STAILQ_REMOVE(&fp_setting_garbage, entries,
757*70e20d4eSConrad Meyer 		        fail_point_setting, fs_garbage_link);
758*70e20d4eSConrad Meyer 		fail_point_setting_destroy(entries);
759cfeb7489SZachary Loafman 		error = EINVAL;
760cfeb7489SZachary Loafman 		goto end;
761cfeb7489SZachary Loafman 	}
762cfeb7489SZachary Loafman 
763*70e20d4eSConrad Meyer 	/**
764*70e20d4eSConrad Meyer 	 * Transfer the entries we are going to keep to a new list.
765*70e20d4eSConrad Meyer 	 * Get rid of useless zero probability entries, and entries with hit
766*70e20d4eSConrad Meyer 	 * count 0.
767*70e20d4eSConrad Meyer 	 * If 'off' is present, and it has no hit count set, then all entries
768*70e20d4eSConrad Meyer 	 *       after it are discarded since they are unreachable.
769*70e20d4eSConrad Meyer 	 */
770*70e20d4eSConrad Meyer 	TAILQ_FOREACH_SAFE(ent, &entries->fp_entry_queue, fe_entries, ent_next) {
771*70e20d4eSConrad Meyer 		if (ent->fe_prob == 0 || ent->fe_count == 0) {
772*70e20d4eSConrad Meyer 			printf("Discarding entry which cannot execute %s\n",
773*70e20d4eSConrad Meyer 			        fail_type_strings[ent->fe_type].name);
774*70e20d4eSConrad Meyer 			TAILQ_REMOVE(&entries->fp_entry_queue, ent,
775*70e20d4eSConrad Meyer 			        fe_entries);
776*70e20d4eSConrad Meyer 			fp_free(ent);
777*70e20d4eSConrad Meyer 			continue;
778*70e20d4eSConrad Meyer 		} else if (should_truncate) {
779*70e20d4eSConrad Meyer 			printf("Discarding unreachable entry %s\n",
780*70e20d4eSConrad Meyer 			        fail_type_strings[ent->fe_type].name);
781*70e20d4eSConrad Meyer 			TAILQ_REMOVE(&entries->fp_entry_queue, ent,
782*70e20d4eSConrad Meyer 			        fe_entries);
783*70e20d4eSConrad Meyer 			fp_free(ent);
784*70e20d4eSConrad Meyer 			continue;
785cfeb7489SZachary Loafman 		}
786cfeb7489SZachary Loafman 
787*70e20d4eSConrad Meyer 		if (ent->fe_type == FAIL_POINT_OFF) {
788*70e20d4eSConrad Meyer 			should_wake_paused = true;
789*70e20d4eSConrad Meyer 			if (ent->fe_count == FE_COUNT_UNTRACKED) {
790*70e20d4eSConrad Meyer 				should_truncate = true;
791*70e20d4eSConrad Meyer 				TAILQ_REMOVE(&entries->fp_entry_queue, ent,
792*70e20d4eSConrad Meyer 				        fe_entries);
793*70e20d4eSConrad Meyer 				fp_free(ent);
794*70e20d4eSConrad Meyer 			}
795*70e20d4eSConrad Meyer 		} else if (ent->fe_type == FAIL_POINT_PAUSE) {
796*70e20d4eSConrad Meyer 			should_truncate = true;
797*70e20d4eSConrad Meyer 		} else if (ent->fe_type == FAIL_POINT_SLEEP && (fp->fp_flags &
798*70e20d4eSConrad Meyer 		        FAIL_POINT_NONSLEEPABLE)) {
799*70e20d4eSConrad Meyer 			/**
800*70e20d4eSConrad Meyer 			 * If this fail point is annotated as being in a
801*70e20d4eSConrad Meyer 			 * non-sleepable ctx, convert sleep to delay and
802*70e20d4eSConrad Meyer 			 * convert the msec argument to usecs.
803*70e20d4eSConrad Meyer 			 */
804*70e20d4eSConrad Meyer 			printf("Sleep call request on fail point in "
805*70e20d4eSConrad Meyer 			        "non-sleepable context; using delay instead "
806*70e20d4eSConrad Meyer 			        "of sleep\n");
807*70e20d4eSConrad Meyer 			ent->fe_type = FAIL_POINT_DELAY;
808*70e20d4eSConrad Meyer 			ent->fe_arg *= 1000;
809*70e20d4eSConrad Meyer 		}
810*70e20d4eSConrad Meyer 	}
811cfeb7489SZachary Loafman 
812*70e20d4eSConrad Meyer 	if (TAILQ_EMPTY(&entries->fp_entry_queue)) {
813*70e20d4eSConrad Meyer 		entries = fail_point_swap_settings(fp, NULL);
814*70e20d4eSConrad Meyer 		if (entries != NULL)
815*70e20d4eSConrad Meyer 			wakeup(FP_PAUSE_CHANNEL(fp));
816*70e20d4eSConrad Meyer 	} else {
817*70e20d4eSConrad Meyer 		if (should_wake_paused)
818*70e20d4eSConrad Meyer 			wakeup(FP_PAUSE_CHANNEL(fp));
819*70e20d4eSConrad Meyer 		fail_point_swap_settings(fp, entries);
820*70e20d4eSConrad Meyer 	}
821cfeb7489SZachary Loafman 
822cfeb7489SZachary Loafman end:
823cfeb7489SZachary Loafman #ifdef IWARNING
824cfeb7489SZachary Loafman 	if (error)
8254b7c6844SMatthew D Fleming 		IWARNING("Failed to set %s %s to %s",
826cfeb7489SZachary Loafman 		    fp->fp_name, fp->fp_location, buf);
827cfeb7489SZachary Loafman 	else
8284b7c6844SMatthew D Fleming 		INOTICE("Set %s %s to %s",
829cfeb7489SZachary Loafman 		    fp->fp_name, fp->fp_location, buf);
830cfeb7489SZachary Loafman #endif /* IWARNING */
831cfeb7489SZachary Loafman 
832*70e20d4eSConrad Meyer 	fail_point_setting_release_ref(fp);
8330894a9bcSMatthew D Fleming 	return (error);
834cfeb7489SZachary Loafman }
835cfeb7489SZachary Loafman 
836cfeb7489SZachary Loafman #define MAX_FAIL_POINT_BUF	1023
837cfeb7489SZachary Loafman 
838cfeb7489SZachary Loafman /**
839cfeb7489SZachary Loafman  * Handle kernel failpoint set/get.
840cfeb7489SZachary Loafman  */
841*70e20d4eSConrad Meyer 
842cfeb7489SZachary Loafman int
843cfeb7489SZachary Loafman fail_point_sysctl(SYSCTL_HANDLER_ARGS)
844cfeb7489SZachary Loafman {
845*70e20d4eSConrad Meyer 	struct fail_point *fp;
846*70e20d4eSConrad Meyer 	char *buf;
847*70e20d4eSConrad Meyer 	struct sbuf *sb_check;
848cfeb7489SZachary Loafman 	struct sbuf sb;
849cfeb7489SZachary Loafman 	int error;
850cfeb7489SZachary Loafman 
851*70e20d4eSConrad Meyer 	error = 0;
852*70e20d4eSConrad Meyer 	fp = arg1;
853*70e20d4eSConrad Meyer 	buf = NULL;
854*70e20d4eSConrad Meyer 
855*70e20d4eSConrad Meyer 	sb_check = sbuf_new(&sb, NULL, 1024, SBUF_AUTOEXTEND);
856*70e20d4eSConrad Meyer 	if (sb_check != &sb)
857*70e20d4eSConrad Meyer 		return (ENOMEM);
858*70e20d4eSConrad Meyer 
859*70e20d4eSConrad Meyer 	sbuf_set_drain(&sb, (sbuf_drain_func *)fail_sysctl_drain_func, req);
860cfeb7489SZachary Loafman 
861cfeb7489SZachary Loafman 	/* Setting */
862*70e20d4eSConrad Meyer 	/**
863*70e20d4eSConrad Meyer 	 * Lock protects any new entries from being garbage collected before we
864*70e20d4eSConrad Meyer 	 * can link them to the fail point.
865*70e20d4eSConrad Meyer 	 */
866*70e20d4eSConrad Meyer 	sx_xlock(&sx_fp_set);
867*70e20d4eSConrad Meyer 	if (req->newptr) {
868cfeb7489SZachary Loafman 		if (req->newlen > MAX_FAIL_POINT_BUF) {
869cfeb7489SZachary Loafman 			error = EINVAL;
870cfeb7489SZachary Loafman 			goto out;
871cfeb7489SZachary Loafman 		}
872cfeb7489SZachary Loafman 
873cfeb7489SZachary Loafman 		buf = fp_malloc(req->newlen + 1, M_WAITOK);
874cfeb7489SZachary Loafman 
875cfeb7489SZachary Loafman 		error = SYSCTL_IN(req, buf, req->newlen);
876cfeb7489SZachary Loafman 		if (error)
877cfeb7489SZachary Loafman 			goto out;
878cfeb7489SZachary Loafman 		buf[req->newlen] = '\0';
879cfeb7489SZachary Loafman 
880cfeb7489SZachary Loafman 		error = fail_point_set(fp, buf);
881cfeb7489SZachary Loafman 	}
882cfeb7489SZachary Loafman 
883*70e20d4eSConrad Meyer 	fail_point_garbage_collect();
884*70e20d4eSConrad Meyer 	sx_xunlock(&sx_fp_set);
885*70e20d4eSConrad Meyer 
886*70e20d4eSConrad Meyer 	/* Retrieving. */
887*70e20d4eSConrad Meyer 	fail_point_get(fp, &sb, false);
888*70e20d4eSConrad Meyer 
889cfeb7489SZachary Loafman out:
890*70e20d4eSConrad Meyer 	sbuf_finish(&sb);
891*70e20d4eSConrad Meyer 	sbuf_delete(&sb);
892*70e20d4eSConrad Meyer 
893*70e20d4eSConrad Meyer 	if (buf)
894cfeb7489SZachary Loafman 		fp_free(buf);
895*70e20d4eSConrad Meyer 
8960894a9bcSMatthew D Fleming 	return (error);
897cfeb7489SZachary Loafman }
898cfeb7489SZachary Loafman 
899*70e20d4eSConrad Meyer int
900*70e20d4eSConrad Meyer fail_point_sysctl_status(SYSCTL_HANDLER_ARGS)
901*70e20d4eSConrad Meyer {
902*70e20d4eSConrad Meyer 	struct fail_point *fp;
903*70e20d4eSConrad Meyer 	struct sbuf sb, *sb_check;
904*70e20d4eSConrad Meyer 
905*70e20d4eSConrad Meyer 	fp = arg1;
906*70e20d4eSConrad Meyer 
907*70e20d4eSConrad Meyer 	sb_check = sbuf_new(&sb, NULL, 1024, SBUF_AUTOEXTEND);
908*70e20d4eSConrad Meyer 	if (sb_check != &sb)
909*70e20d4eSConrad Meyer 		return (ENOMEM);
910*70e20d4eSConrad Meyer 
911*70e20d4eSConrad Meyer 	sbuf_set_drain(&sb, (sbuf_drain_func *)fail_sysctl_drain_func, req);
912*70e20d4eSConrad Meyer 
913*70e20d4eSConrad Meyer 	/* Retrieving. */
914*70e20d4eSConrad Meyer 	fail_point_get(fp, &sb, true);
915*70e20d4eSConrad Meyer 
916*70e20d4eSConrad Meyer 	sbuf_finish(&sb);
917*70e20d4eSConrad Meyer 	sbuf_delete(&sb);
918*70e20d4eSConrad Meyer 
919*70e20d4eSConrad Meyer 	/**
920*70e20d4eSConrad Meyer 	 * Lock protects any new entries from being garbage collected before we
921*70e20d4eSConrad Meyer 	 * can link them to the fail point.
922*70e20d4eSConrad Meyer 	 */
923*70e20d4eSConrad Meyer 	sx_xlock(&sx_fp_set);
924*70e20d4eSConrad Meyer 	fail_point_garbage_collect();
925*70e20d4eSConrad Meyer 	sx_xunlock(&sx_fp_set);
926*70e20d4eSConrad Meyer 
927*70e20d4eSConrad Meyer 	return (0);
928*70e20d4eSConrad Meyer }
929*70e20d4eSConrad Meyer 
930*70e20d4eSConrad Meyer int
931*70e20d4eSConrad Meyer fail_sysctl_drain_func(void *sysctl_args, const char *buf, int len)
932*70e20d4eSConrad Meyer {
933*70e20d4eSConrad Meyer 	struct sysctl_req *sa;
934*70e20d4eSConrad Meyer 	int error;
935*70e20d4eSConrad Meyer 
936*70e20d4eSConrad Meyer 	sa = sysctl_args;
937*70e20d4eSConrad Meyer 
938*70e20d4eSConrad Meyer 	error = SYSCTL_OUT(sa, buf, len);
939*70e20d4eSConrad Meyer 
940*70e20d4eSConrad Meyer 	if (error == ENOMEM)
941*70e20d4eSConrad Meyer 		return (-1);
942*70e20d4eSConrad Meyer 	else
943*70e20d4eSConrad Meyer 		return (len);
944*70e20d4eSConrad Meyer }
945*70e20d4eSConrad Meyer 
946*70e20d4eSConrad Meyer 
947cfeb7489SZachary Loafman /**
948cfeb7489SZachary Loafman  * Internal helper function to translate a human-readable failpoint string
949cfeb7489SZachary Loafman  * into a internally-parsable fail_point structure.
950cfeb7489SZachary Loafman  */
951cfeb7489SZachary Loafman static char *
952*70e20d4eSConrad Meyer parse_fail_point(struct fail_point_setting *ents, char *p)
953cfeb7489SZachary Loafman {
954cfeb7489SZachary Loafman 	/*  <fail_point> ::
955cfeb7489SZachary Loafman 	 *      <term> ( "->" <term> )*
956cfeb7489SZachary Loafman 	 */
957*70e20d4eSConrad Meyer 	uint8_t term_count;
958*70e20d4eSConrad Meyer 
959*70e20d4eSConrad Meyer 	term_count = 1;
960*70e20d4eSConrad Meyer 
9610894a9bcSMatthew D Fleming 	p = parse_term(ents, p);
9620894a9bcSMatthew D Fleming 	if (p == NULL)
9630894a9bcSMatthew D Fleming 		return (NULL);
964*70e20d4eSConrad Meyer 
9650894a9bcSMatthew D Fleming 	while (*p != '\0') {
966*70e20d4eSConrad Meyer 		term_count++;
967*70e20d4eSConrad Meyer 		if (p[0] != '-' || p[1] != '>' ||
968*70e20d4eSConrad Meyer 		        (p = parse_term(ents, p+2)) == NULL ||
969*70e20d4eSConrad Meyer 		        term_count > FP_MAX_ENTRY_COUNT)
9700894a9bcSMatthew D Fleming 			return (NULL);
9710894a9bcSMatthew D Fleming 	}
9720894a9bcSMatthew D Fleming 	return (p);
973cfeb7489SZachary Loafman }
974cfeb7489SZachary Loafman 
975cfeb7489SZachary Loafman /**
976cfeb7489SZachary Loafman  * Internal helper function to parse an individual term from a failpoint.
977cfeb7489SZachary Loafman  */
978cfeb7489SZachary Loafman static char *
979*70e20d4eSConrad Meyer parse_term(struct fail_point_setting *ents, char *p)
980cfeb7489SZachary Loafman {
981cfeb7489SZachary Loafman 	struct fail_point_entry *ent;
982cfeb7489SZachary Loafman 
983*70e20d4eSConrad Meyer 	ent = fail_point_entry_new(ents);
984cfeb7489SZachary Loafman 
985cfeb7489SZachary Loafman 	/*
986cfeb7489SZachary Loafman 	 * <term> ::
987cfeb7489SZachary Loafman 	 *     ( (<float> "%") | (<integer> "*" ) )*
988cfeb7489SZachary Loafman 	 *     <type>
989cfeb7489SZachary Loafman 	 *     [ "(" <integer> ")" ]
990b5bd50aeSMatthew D Fleming 	 *     [ "[pid " <integer> "]" ]
991cfeb7489SZachary Loafman 	 */
992cfeb7489SZachary Loafman 
993cfeb7489SZachary Loafman 	/* ( (<float> "%") | (<integer> "*" ) )* */
9940894a9bcSMatthew D Fleming 	while (isdigit(*p) || *p == '.') {
995cfeb7489SZachary Loafman 		int units, decimal;
996cfeb7489SZachary Loafman 
9970894a9bcSMatthew D Fleming 		p = parse_number(&units, &decimal, p);
9980894a9bcSMatthew D Fleming 		if (p == NULL)
9990894a9bcSMatthew D Fleming 			return (NULL);
1000cfeb7489SZachary Loafman 
1001cfeb7489SZachary Loafman 		if (*p == '%') {
1002cfeb7489SZachary Loafman 			if (units > 100) /* prevent overflow early */
1003cfeb7489SZachary Loafman 				units = 100;
1004cfeb7489SZachary Loafman 			ent->fe_prob = units * (PROB_MAX / 100) + decimal;
1005cfeb7489SZachary Loafman 			if (ent->fe_prob > PROB_MAX)
1006cfeb7489SZachary Loafman 				ent->fe_prob = PROB_MAX;
1007cfeb7489SZachary Loafman 		} else if (*p == '*') {
1008*70e20d4eSConrad Meyer 			if (!units || units < 0 || decimal)
10090894a9bcSMatthew D Fleming 				return (NULL);
1010c2ede4b3SMartin Blapp 			ent->fe_count = units;
10110894a9bcSMatthew D Fleming 		} else
10120894a9bcSMatthew D Fleming 			return (NULL);
1013cfeb7489SZachary Loafman 		p++;
1014cfeb7489SZachary Loafman 	}
1015cfeb7489SZachary Loafman 
1016cfeb7489SZachary Loafman 	/* <type> */
10170894a9bcSMatthew D Fleming 	p = parse_type(ent, p);
10180894a9bcSMatthew D Fleming 	if (p == NULL)
10190894a9bcSMatthew D Fleming 		return (NULL);
1020cfeb7489SZachary Loafman 	if (*p == '\0')
10210894a9bcSMatthew D Fleming 		return (p);
1022cfeb7489SZachary Loafman 
1023cfeb7489SZachary Loafman 	/* [ "(" <integer> ")" ] */
1024cfeb7489SZachary Loafman 	if (*p != '(')
1025*70e20d4eSConrad Meyer 		return (p);
1026cfeb7489SZachary Loafman 	p++;
10270894a9bcSMatthew D Fleming 	if (!isdigit(*p) && *p != '-')
10280894a9bcSMatthew D Fleming 		return (NULL);
1029cfeb7489SZachary Loafman 	ent->fe_arg = strtol(p, &p, 0);
1030cfeb7489SZachary Loafman 	if (*p++ != ')')
10310894a9bcSMatthew D Fleming 		return (NULL);
1032cfeb7489SZachary Loafman 
1033b5bd50aeSMatthew D Fleming 	/* [ "[pid " <integer> "]" ] */
1034b5bd50aeSMatthew D Fleming #define PID_STRING "[pid "
1035b5bd50aeSMatthew D Fleming 	if (strncmp(p, PID_STRING, sizeof(PID_STRING) - 1) != 0)
1036b5bd50aeSMatthew D Fleming 		return (p);
1037b5bd50aeSMatthew D Fleming 	p += sizeof(PID_STRING) - 1;
1038b5bd50aeSMatthew D Fleming 	if (!isdigit(*p))
1039b5bd50aeSMatthew D Fleming 		return (NULL);
1040b5bd50aeSMatthew D Fleming 	ent->fe_pid = strtol(p, &p, 0);
1041b5bd50aeSMatthew D Fleming 	if (*p++ != ']')
1042b5bd50aeSMatthew D Fleming 		return (NULL);
1043b5bd50aeSMatthew D Fleming 
10440894a9bcSMatthew D Fleming 	return (p);
1045cfeb7489SZachary Loafman }
1046cfeb7489SZachary Loafman 
1047cfeb7489SZachary Loafman /**
1048cfeb7489SZachary Loafman  * Internal helper function to parse a numeric for a failpoint term.
1049cfeb7489SZachary Loafman  */
1050cfeb7489SZachary Loafman static char *
1051cfeb7489SZachary Loafman parse_number(int *out_units, int *out_decimal, char *p)
1052cfeb7489SZachary Loafman {
1053cfeb7489SZachary Loafman 	char *old_p;
1054cfeb7489SZachary Loafman 
1055*70e20d4eSConrad Meyer 	/**
1056cfeb7489SZachary Loafman 	 *  <number> ::
1057cfeb7489SZachary Loafman 	 *      <integer> [ "." <integer> ] |
1058cfeb7489SZachary Loafman 	 *      "." <integer>
1059cfeb7489SZachary Loafman 	 */
1060cfeb7489SZachary Loafman 
1061cfeb7489SZachary Loafman 	/* whole part */
1062cfeb7489SZachary Loafman 	old_p = p;
1063c2ede4b3SMartin Blapp 	*out_units = strtol(p, &p, 10);
1064cfeb7489SZachary Loafman 	if (p == old_p && *p != '.')
10650894a9bcSMatthew D Fleming 		return (NULL);
1066cfeb7489SZachary Loafman 
1067cfeb7489SZachary Loafman 	/* fractional part */
1068cfeb7489SZachary Loafman 	*out_decimal = 0;
1069cfeb7489SZachary Loafman 	if (*p == '.') {
1070cfeb7489SZachary Loafman 		int digits = 0;
1071cfeb7489SZachary Loafman 		p++;
10720894a9bcSMatthew D Fleming 		while (isdigit(*p)) {
1073cfeb7489SZachary Loafman 			int digit = *p - '0';
1074cfeb7489SZachary Loafman 			if (digits < PROB_DIGITS - 2)
1075cfeb7489SZachary Loafman 				*out_decimal = *out_decimal * 10 + digit;
1076cfeb7489SZachary Loafman 			else if (digits == PROB_DIGITS - 2 && digit >= 5)
1077cfeb7489SZachary Loafman 				(*out_decimal)++;
1078cfeb7489SZachary Loafman 			digits++;
1079cfeb7489SZachary Loafman 			p++;
1080cfeb7489SZachary Loafman 		}
1081cfeb7489SZachary Loafman 		if (!digits) /* need at least one digit after '.' */
10820894a9bcSMatthew D Fleming 			return (NULL);
1083cfeb7489SZachary Loafman 		while (digits++ < PROB_DIGITS - 2) /* add implicit zeros */
1084cfeb7489SZachary Loafman 			*out_decimal *= 10;
1085cfeb7489SZachary Loafman 	}
1086cfeb7489SZachary Loafman 
10870894a9bcSMatthew D Fleming 	return (p); /* success */
1088cfeb7489SZachary Loafman }
1089cfeb7489SZachary Loafman 
1090cfeb7489SZachary Loafman /**
1091cfeb7489SZachary Loafman  * Internal helper function to parse an individual type for a failpoint term.
1092cfeb7489SZachary Loafman  */
1093cfeb7489SZachary Loafman static char *
1094cfeb7489SZachary Loafman parse_type(struct fail_point_entry *ent, char *beg)
1095cfeb7489SZachary Loafman {
1096cfeb7489SZachary Loafman 	enum fail_point_t type;
10970894a9bcSMatthew D Fleming 	int len;
10980894a9bcSMatthew D Fleming 
10990894a9bcSMatthew D Fleming 	for (type = FAIL_POINT_OFF; type < FAIL_POINT_NUMTYPES; type++) {
11000894a9bcSMatthew D Fleming 		len = fail_type_strings[type].nmlen;
11010894a9bcSMatthew D Fleming 		if (strncmp(fail_type_strings[type].name, beg, len) == 0) {
1102cfeb7489SZachary Loafman 			ent->fe_type = type;
11030894a9bcSMatthew D Fleming 			return (beg + len);
1104cfeb7489SZachary Loafman 		}
1105cfeb7489SZachary Loafman 	}
11060894a9bcSMatthew D Fleming 	return (NULL);
1107cfeb7489SZachary Loafman }
1108cfeb7489SZachary Loafman 
1109cfeb7489SZachary Loafman /* The fail point sysctl tree. */
1110cfeb7489SZachary Loafman SYSCTL_NODE(_debug, OID_AUTO, fail_point, CTLFLAG_RW, 0, "fail points");
1111*70e20d4eSConrad Meyer 
1112*70e20d4eSConrad Meyer /* Debugging/testing stuff for fail point */
1113*70e20d4eSConrad Meyer static int
1114*70e20d4eSConrad Meyer sysctl_test_fail_point(SYSCTL_HANDLER_ARGS)
1115*70e20d4eSConrad Meyer {
1116*70e20d4eSConrad Meyer 
1117*70e20d4eSConrad Meyer 	KFAIL_POINT_RETURN(DEBUG_FP, test_fail_point);
1118*70e20d4eSConrad Meyer 	return (0);
1119*70e20d4eSConrad Meyer }
1120*70e20d4eSConrad Meyer SYSCTL_OID(_debug_fail_point, OID_AUTO, test_trigger_fail_point,
1121*70e20d4eSConrad Meyer         CTLTYPE_STRING | CTLFLAG_RD, NULL, 0, sysctl_test_fail_point, "A",
1122*70e20d4eSConrad Meyer         "Trigger test fail points");
1123