52 #include <sys/cdefs.h>
55 #include <sys/ctype.h>
56 #include <sys/errno.h>
58 #include <sys/kernel.h>
59 #include <sys/libkern.h>
61 #include <sys/malloc.h>
62 #include <sys/mutex.h>
66 #include <machine/stdarg.h>
68 #ifdef ILOG_DEFINE_FOR_FILE
69 ILOG_DEFINE_FOR_FILE(L_ISI_FAIL_POINT, L_ILOG, fail_point);
72 static MALLOC_DEFINE(M_FAIL_POINT,
"Fail Points",
"fail points system");
73 #define fp_free(ptr) free(ptr, M_FAIL_POINT)
74 #define fp_malloc(size, flags) malloc((size), M_FAIL_POINT, (flags))
78 #define FP_LOCK() mtx_lock(&g_fp_mtx)
79 #define FP_UNLOCK() mtx_unlock(&g_fp_mtx)
100 #define FP_TYPE_NM_LEN(s) { s, sizeof(s) - 1 }
124 int msecs, enum fail_point_return_code *pret)
127 int timo = ((msecs *
hz) + 999) / 1000;
130 if (fp->fp_sleep_fn == NULL) {
131 msleep(fp, &
g_fp_mtx, PWAIT,
"failpt", timo);
133 timeout(fp->fp_sleep_fn, fp->fp_sleep_arg, timo);
134 *pret = FAIL_POINT_RC_QUEUED;
149 static char *
parse_term(
struct fail_point_entries *,
char *);
150 static char *
parse_number(
int *out_units,
int *out_decimal,
char *);
170 TAILQ_INIT(&fp->fp_entries);
186 fp->fp_location =
"";
187 fp->fp_flags |= FAIL_POINT_DYNAMIC_NAME;
188 fp->fp_sleep_fn = NULL;
189 fp->fp_sleep_arg = NULL;
201 if ((fp->fp_flags & FAIL_POINT_DYNAMIC_NAME) != 0) {
202 fp_free(__DECONST(
void *, fp->fp_name));
216 enum fail_point_return_code
219 enum fail_point_return_code ret = FAIL_POINT_RC_CONTINUE;
225 TAILQ_FOREACH_SAFE(ent, &fp->fp_entries, fe_entries, next) {
231 if (ent->
fe_pid != NO_PID && ent->
fe_pid != curproc->p_pid)
236 panic(
"fail point %s panicking", fp->fp_name);
240 if (return_value != NULL)
241 *return_value = ent->
fe_arg;
242 ret = FAIL_POINT_RC_RETURN;
246 printf(
"fail point %s breaking to debugger\n",
252 printf(
"fail point %s executing\n", fp->fp_name);
282 while ((ent = TAILQ_LAST(&fp->fp_entries, fail_point_entries)) &&
301 TAILQ_FOREACH(ent, &fp->fp_entries, fe_entries) {
308 while (!(decimal % 10)) {
321 if (ent->
fe_pid != NO_PID)
323 if (TAILQ_NEXT(ent, fe_entries))
326 if (TAILQ_EMPTY(&fp->fp_entries))
341 struct fail_point_entries new_entries;
344 TAILQ_INIT(&new_entries);
358 TAILQ_FOREACH_SAFE(ent, &fp->fp_entries, fe_entries, ent_next) {
364 while ((ent = TAILQ_LAST(&fp->fp_entries, fail_point_entries)) &&
373 IWARNING(
"Failed to set %s %s to %s",
374 fp->fp_name, fp->fp_location, buf);
376 INOTICE(
"Set %s %s to %s",
377 fp->fp_name, fp->fp_location, buf);
383 #define MAX_FAIL_POINT_BUF 1023
391 struct fail_point *fp = arg1;
397 sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND);
405 if (!error && req->newptr) {
411 buf =
fp_malloc(req->newlen + 1, M_WAITOK);
413 error = SYSCTL_IN(req, buf, req->newlen);
416 buf[req->newlen] =
'\0';
440 if (p[0] !=
'-' || p[1] !=
'>')
457 ent =
fp_malloc(
sizeof *ent, M_WAITOK | M_ZERO);
460 TAILQ_INSERT_TAIL(ents, ent, fe_entries);
471 while (isdigit(*p) || *p ==
'.') {
484 }
else if (*p ==
'*') {
485 if (!units || decimal)
504 if (!isdigit(*p) && *p !=
'-')
506 ent->
fe_arg = strtol(p, &p, 0);
511 #define PID_STRING "[pid "
517 ent->
fe_pid = strtol(p, &p, 0);
540 *out_units = strtol(p, &p, 10);
541 if (p == old_p && *p !=
'.')
549 while (isdigit(*p)) {
550 int digit = *p -
'0';
552 *out_decimal = *out_decimal * 10 + digit;
592 TAILQ_REMOVE(ents, ent, fe_entries);
605 TAILQ_FOREACH_SAFE(ent, ents, fe_entries, ent_next)
611 SYSCTL_NODE(_debug, OID_AUTO, fail_point, CTLFLAG_RW, 0,
"fail points");
MTX_SYSINIT(g_fp_mtx,&g_fp_mtx,"fail point mtx", MTX_DEF)
void fail_point_init(struct fail_point *fp, const char *fmt,...)
struct callout_handle timeout(timeout_t *ftn, void *arg, int to_ticks)
ssize_t sbuf_len(struct sbuf *s)
static void fail_point_get(struct fail_point *fp, struct sbuf *sb)
static void clear_entries(struct fail_point_entries *)
enum fail_point_return_code fail_point_eval_nontrivial(struct fail_point *fp, int *return_value)
void panic(const char *fmt,...)
static char * parse_number(int *out_units, int *out_decimal, char *)
static MALLOC_DEFINE(M_FAIL_POINT,"Fail Points","fail points system")
static struct mtx g_fp_mtx
static struct @2 fail_type_strings[]
static int fail_point_set(struct fail_point *fp, char *buf)
int vsnprintf(char *str, size_t size, const char *format, va_list ap)
enum fail_point_t fe_type
#define MAX_FAIL_POINT_BUF
void fail_point_destroy(struct fail_point *fp)
int sbuf_printf(struct sbuf *s, const char *fmt,...)
SYSCTL_NODE(_debug, OID_AUTO, fail_point, CTLFLAG_RW, 0,"fail points")
#define FP_TYPE_NM_LEN(s)
static char * parse_term(struct fail_point_entries *, char *)
struct sbuf * sbuf_new(struct sbuf *s, char *buf, int length, int flags)
#define fp_malloc(size, flags)
int printf(const char *fmt,...)
void sbuf_delete(struct sbuf *s)
static char * parse_fail_point(struct fail_point_entries *, char *)
int fail_point_sysctl(SYSCTL_HANDLER_ARGS)
char * sbuf_data(struct sbuf *s)
int sbuf_finish(struct sbuf *s)
int sbuf_trim(struct sbuf *s)
static char * parse_type(struct fail_point_entry *, char *)
static void fail_point_sleep(struct fail_point *fp, struct fail_point_entry *ent, int msecs, enum fail_point_return_code *pret)
static void free_entry(struct fail_point_entries *, struct fail_point_entry *)