Skip to content

Commit 696ced4

Browse files
albanrostedt
authored andcommitted
tracing/kprobes: expose maxactive for kretprobe in kprobe_events
When a kretprobe is installed on a kernel function, there is a maximum limit of how many calls in parallel it can catch (aka "maxactive"). A kernel module could call register_kretprobe() and initialize maxactive (see example in samples/kprobes/kretprobe_example.c). But that is not exposed to userspace and it is currently not possible to choose maxactive when writing to /sys/kernel/debug/tracing/kprobe_events The default maxactive can be as low as 1 on single-core with a non-preemptive kernel. This is too low and we need to increase it not only for recursive functions, but for functions that sleep or resched. This patch updates the format of the command that can be written to kprobe_events so that maxactive can be optionally specified. I need this for a bpf program attached to the kretprobe of inet_csk_accept, which can sleep for a long time. This patch includes a basic selftest: > # ./ftracetest -v test.d/kprobe/ > === Ftrace unit tests === > [1] Kprobe dynamic event - adding and removing [PASS] > [2] Kprobe dynamic event - busy event check [PASS] > [3] Kprobe dynamic event with arguments [PASS] > [4] Kprobes event arguments with types [PASS] > [5] Kprobe dynamic event with function tracer [PASS] > [6] Kretprobe dynamic event with arguments [PASS] > [7] Kretprobe dynamic event with maxactive [PASS] > > # of passed: 7 > # of failed: 0 > # of unresolved: 0 > # of untested: 0 > # of unsupported: 0 > # of xfailed: 0 > # of undefined(test bug): 0 BugLink: iovisor/bcc#1072 Link: http://lkml.kernel.org/r/1491215782-15490-1-git-send-email-alban@kinvolk.io Acked-by: Masami Hiramatsu <mhiramat@kernel.org> Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
1 parent b80f0f6 commit 696ced4

File tree

3 files changed

+76
-7
lines changed

3 files changed

+76
-7
lines changed

Documentation/trace/kprobetrace.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ current_tracer. Instead of that, add probe points via
2323
Synopsis of kprobe_events
2424
-------------------------
2525
p[:[GRP/]EVENT] [MOD:]SYM[+offs]|MEMADDR [FETCHARGS] : Set a probe
26-
r[:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe
26+
r[MAXACTIVE][:[GRP/]EVENT] [MOD:]SYM[+0] [FETCHARGS] : Set a return probe
2727
-:[GRP/]EVENT : Clear a probe
2828

2929
GRP : Group name. If omitted, use "kprobes" for it.
@@ -32,6 +32,9 @@ Synopsis of kprobe_events
3232
MOD : Module name which has given SYM.
3333
SYM[+offs] : Symbol+offset where the probe is inserted.
3434
MEMADDR : Address where the probe is inserted.
35+
MAXACTIVE : Maximum number of instances of the specified function that
36+
can be probed simultaneously, or 0 for the default value
37+
as defined in Documentation/kprobes.txt section 1.3.1.
3538

3639
FETCHARGS : Arguments. Each probe can have up to 128 args.
3740
%REG : Fetch register REG

kernel/trace/trace_kprobe.c

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "trace_probe.h"
2626

2727
#define KPROBE_EVENT_SYSTEM "kprobes"
28+
#define KRETPROBE_MAXACTIVE_MAX 4096
2829

2930
/**
3031
* Kprobe event core functions
@@ -282,6 +283,7 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
282283
void *addr,
283284
const char *symbol,
284285
unsigned long offs,
286+
int maxactive,
285287
int nargs, bool is_return)
286288
{
287289
struct trace_kprobe *tk;
@@ -309,6 +311,8 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
309311
else
310312
tk->rp.kp.pre_handler = kprobe_dispatcher;
311313

314+
tk->rp.maxactive = maxactive;
315+
312316
if (!event || !is_good_name(event)) {
313317
ret = -EINVAL;
314318
goto error;
@@ -598,8 +602,10 @@ static int create_trace_kprobe(int argc, char **argv)
598602
{
599603
/*
600604
* Argument syntax:
601-
* - Add kprobe: p[:[GRP/]EVENT] [MOD:]KSYM[+OFFS]|KADDR [FETCHARGS]
602-
* - Add kretprobe: r[:[GRP/]EVENT] [MOD:]KSYM[+0] [FETCHARGS]
605+
* - Add kprobe:
606+
* p[:[GRP/]EVENT] [MOD:]KSYM[+OFFS]|KADDR [FETCHARGS]
607+
* - Add kretprobe:
608+
* r[MAXACTIVE][:[GRP/]EVENT] [MOD:]KSYM[+0] [FETCHARGS]
603609
* Fetch args:
604610
* $retval : fetch return value
605611
* $stack : fetch stack address
@@ -619,6 +625,7 @@ static int create_trace_kprobe(int argc, char **argv)
619625
int i, ret = 0;
620626
bool is_return = false, is_delete = false;
621627
char *symbol = NULL, *event = NULL, *group = NULL;
628+
int maxactive = 0;
622629
char *arg;
623630
unsigned long offset = 0;
624631
void *addr = NULL;
@@ -637,8 +644,28 @@ static int create_trace_kprobe(int argc, char **argv)
637644
return -EINVAL;
638645
}
639646

640-
if (argv[0][1] == ':') {
641-
event = &argv[0][2];
647+
event = strchr(&argv[0][1], ':');
648+
if (event) {
649+
event[0] = '\0';
650+
event++;
651+
}
652+
if (is_return && isdigit(argv[0][1])) {
653+
ret = kstrtouint(&argv[0][1], 0, &maxactive);
654+
if (ret) {
655+
pr_info("Failed to parse maxactive.\n");
656+
return ret;
657+
}
658+
/* kretprobes instances are iterated over via a list. The
659+
* maximum should stay reasonable.
660+
*/
661+
if (maxactive > KRETPROBE_MAXACTIVE_MAX) {
662+
pr_info("Maxactive is too big (%d > %d).\n",
663+
maxactive, KRETPROBE_MAXACTIVE_MAX);
664+
return -E2BIG;
665+
}
666+
}
667+
668+
if (event) {
642669
if (strchr(event, '/')) {
643670
group = event;
644671
event = strchr(group, '/') + 1;
@@ -718,8 +745,8 @@ static int create_trace_kprobe(int argc, char **argv)
718745
is_return ? 'r' : 'p', addr);
719746
event = buf;
720747
}
721-
tk = alloc_trace_kprobe(group, event, addr, symbol, offset, argc,
722-
is_return);
748+
tk = alloc_trace_kprobe(group, event, addr, symbol, offset, maxactive,
749+
argc, is_return);
723750
if (IS_ERR(tk)) {
724751
pr_info("Failed to allocate trace_probe.(%d)\n",
725752
(int)PTR_ERR(tk));
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/bin/sh
2+
# description: Kretprobe dynamic event with maxactive
3+
4+
[ -f kprobe_events ] || exit_unsupported # this is configurable
5+
6+
echo > kprobe_events
7+
8+
# Test if we successfully reject unknown messages
9+
if echo 'a:myprobeaccept inet_csk_accept' > kprobe_events; then false; else true; fi
10+
11+
# Test if we successfully reject too big maxactive
12+
if echo 'r1000000:myprobeaccept inet_csk_accept' > kprobe_events; then false; else true; fi
13+
14+
# Test if we successfully reject unparsable numbers for maxactive
15+
if echo 'r10fuzz:myprobeaccept inet_csk_accept' > kprobe_events; then false; else true; fi
16+
17+
# Test for kretprobe with event name without maxactive
18+
echo 'r:myprobeaccept inet_csk_accept' > kprobe_events
19+
grep myprobeaccept kprobe_events
20+
test -d events/kprobes/myprobeaccept
21+
echo '-:myprobeaccept' >> kprobe_events
22+
23+
# Test for kretprobe with event name with a small maxactive
24+
echo 'r10:myprobeaccept inet_csk_accept' > kprobe_events
25+
grep myprobeaccept kprobe_events
26+
test -d events/kprobes/myprobeaccept
27+
echo '-:myprobeaccept' >> kprobe_events
28+
29+
# Test for kretprobe without event name without maxactive
30+
echo 'r inet_csk_accept' > kprobe_events
31+
grep inet_csk_accept kprobe_events
32+
echo > kprobe_events
33+
34+
# Test for kretprobe without event name with a small maxactive
35+
echo 'r10 inet_csk_accept' > kprobe_events
36+
grep inet_csk_accept kprobe_events
37+
echo > kprobe_events
38+
39+
clear_trace

0 commit comments

Comments
 (0)