From b5bd50ae40085c9fa935b1e89f5c70eb0558bbf7 Mon Sep 17 00:00:00 2001 From: Matthew D Fleming Date: Fri, 8 Jul 2011 20:41:12 +0000 Subject: [PATCH] Add an option to have a fail point term only execute when run by a specified pid. This is helpful for automated testing involving a global knob that would otherwise be executed by many other threads. MFC after: 1 week --- share/man/man9/fail.9 | 7 +++++++ sys/kern/kern_fail.c | 20 +++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/share/man/man9/fail.9 b/share/man/man9/fail.9 index e367effa257b..0973ceacf9bf 100644 --- a/share/man/man9/fail.9 +++ b/share/man/man9/fail.9 @@ -116,6 +116,7 @@ The sysctl variable may be set using the following grammar: ( ( "%") | ( "*" ) )* [ "(" ")" ] + [ "[pid " "]" ] :: [ "." ] | @@ -161,6 +162,10 @@ For the purpose of this operator, the return() and print() operators are the only types that cascade. A return() term only cascades if the code executes, and a print() term only cascades when passed a non-zero argument. +A pid can optionally be specified. +The fail point term is only executed when invoked by a process with a +matching p_pid. +.Pp .Sh EXAMPLES .Bl -tag .It Sy sysctl debug.fail_point.foobar="2.1%return(5)" @@ -181,6 +186,8 @@ After that, 1/1000th of the time, return 22. Return 5 for 1 in 1000 executions, but only 5 times total. .It Sy sysctl debug.fail_point.foobar="1%*sleep(50)" 1/100th of the time, sleep 50ms. +.It Sy sysctl debug.fail_point.foobar="1*return(5)[pid 1234]" +Return 5 once, when pid 1234 executes the fail point. .El .Sh AUTHORS .An -nosplit diff --git a/sys/kern/kern_fail.c b/sys/kern/kern_fail.c index 6a96534244d5..f1924718ef55 100644 --- a/sys/kern/kern_fail.c +++ b/sys/kern/kern_fail.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -114,7 +115,7 @@ struct fail_point_entry { int fe_arg; /**< argument to type (e.g. return value) */ int fe_prob; /**< likelihood of firing in millionths */ int fe_count; /**< number of times to fire, 0 means always */ - + pid_t fe_pid; /**< only fail for this process */ TAILQ_ENTRY(fail_point_entry) fe_entries; /**< next entry in fail point */ }; @@ -227,6 +228,8 @@ fail_point_eval_nontrivial(struct fail_point *fp, int *return_value) if (ent->fe_prob < PROB_MAX && ent->fe_prob < random() % PROB_MAX) continue; + if (ent->fe_pid != NO_PID && ent->fe_pid != curproc->p_pid) + continue; switch (ent->fe_type) { case FAIL_POINT_PANIC: @@ -315,6 +318,8 @@ fail_point_get(struct fail_point *fp, struct sbuf *sb) sbuf_printf(sb, "%s", fail_type_strings[ent->fe_type].name); if (ent->fe_arg) sbuf_printf(sb, "(%d)", ent->fe_arg); + if (ent->fe_pid != NO_PID) + sbuf_printf(sb, "[pid %d]", ent->fe_pid); if (TAILQ_NEXT(ent, fe_entries)) sbuf_printf(sb, "->"); } @@ -451,6 +456,7 @@ parse_term(struct fail_point_entries *ents, char *p) ent = fp_malloc(sizeof *ent, M_WAITOK | M_ZERO); ent->fe_prob = PROB_MAX; + ent->fe_pid = NO_PID; TAILQ_INSERT_TAIL(ents, ent, fe_entries); /* @@ -458,6 +464,7 @@ parse_term(struct fail_point_entries *ents, char *p) * ( ( "%") | ( "*" ) )* * * [ "(" ")" ] + * [ "[pid " "]" ] */ /* ( ( "%") | ( "*" ) )* */ @@ -500,6 +507,17 @@ parse_term(struct fail_point_entries *ents, char *p) if (*p++ != ')') return (NULL); + /* [ "[pid " "]" ] */ +#define PID_STRING "[pid " + if (strncmp(p, PID_STRING, sizeof(PID_STRING) - 1) != 0) + return (p); + p += sizeof(PID_STRING) - 1; + if (!isdigit(*p)) + return (NULL); + ent->fe_pid = strtol(p, &p, 0); + if (*p++ != ']') + return (NULL); + return (p); }