From: Song Liu <songliubraving@fb.com>
To: <peterz@infradead.org>, <rostedt@goodmis.org>, <mingo@redhat.com>,
<davem@davemloft.net>, <netdev@vger.kernel.org>,
<linux-kernel@vger.kernel.org>, <daniel@iogearbox.net>
Cc: <kernel-team@fb.com>, Song Liu <songliubraving@fb.com>
Subject: [PATCH] bcc: Try use new API to create [k,u]probe with perf_event_open
Date: Wed, 15 Nov 2017 09:23:32 -0800 [thread overview]
Message-ID: <20171115172339.1791161-2-songliubraving@fb.com> (raw)
In-Reply-To: <20171115172339.1791161-1-songliubraving@fb.com>
New kernel API allows creating [k,u]probe with perf_event_open.
This patch tries to use the new API. If the new API doesn't work,
we fall back to old API.
bpf_detach_probe() looks up the event being removed. If the event
is not found, we skip the clean up procedure.
Signed-off-by: Song Liu <songliubraving@fb.com>
---
src/cc/libbpf.c | 224 +++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 155 insertions(+), 69 deletions(-)
diff --git a/src/cc/libbpf.c b/src/cc/libbpf.c
index 77413df..d7be0a9 100644
--- a/src/cc/libbpf.c
+++ b/src/cc/libbpf.c
@@ -520,38 +520,66 @@ int bpf_attach_socket(int sock, int prog) {
return setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &prog, sizeof(prog));
}
+/*
+ * new kernel API allows creating [k,u]probe with perf_event_open, which
+ * makes it easier to clean up the [k,u]probe. This function tries to
+ * create pfd with the new API.
+ */
+static int bpf_try_perf_event_open_with_probe(struct probe_desc *pd, int pid,
+ int cpu, int group_fd, int is_uprobe, int is_return)
+{
+ struct perf_event_attr attr = {};
+
+ attr.type = PERF_TYPE_PROBE;
+ attr.probe_desc = ptr_to_u64(pd);
+ attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN;
+ attr.sample_period = 1;
+ attr.wakeup_events = 1;
+ attr.is_uprobe = is_uprobe;
+ attr.is_return = is_return;
+ return syscall(__NR_perf_event_open, &attr, pid, cpu, group_fd,
+ PERF_FLAG_FD_CLOEXEC);
+}
+
static int bpf_attach_tracing_event(int progfd, const char *event_path,
- struct perf_reader *reader, int pid, int cpu, int group_fd) {
- int efd, pfd;
+ struct perf_reader *reader, int pid, int cpu, int group_fd, int pfd) {
+ int efd;
ssize_t bytes;
char buf[256];
struct perf_event_attr attr = {};
- snprintf(buf, sizeof(buf), "%s/id", event_path);
- efd = open(buf, O_RDONLY, 0);
- if (efd < 0) {
- fprintf(stderr, "open(%s): %s\n", buf, strerror(errno));
- return -1;
- }
+ /*
+ * Only look up id and call perf_event_open when
+ * bpf_try_perf_event_open_with_probe() didn't returns valid pfd.
+ */
+ if (pfd < 0) {
+ snprintf(buf, sizeof(buf), "%s/id", event_path);
+ efd = open(buf, O_RDONLY, 0);
+ if (efd < 0) {
+ fprintf(stderr, "open(%s): %s\n", buf, strerror(errno));
+ return -1;
+ }
- bytes = read(efd, buf, sizeof(buf));
- if (bytes <= 0 || bytes >= sizeof(buf)) {
- fprintf(stderr, "read(%s): %s\n", buf, strerror(errno));
+ bytes = read(efd, buf, sizeof(buf));
+ if (bytes <= 0 || bytes >= sizeof(buf)) {
+ fprintf(stderr, "read(%s): %s\n", buf, strerror(errno));
+ close(efd);
+ return -1;
+ }
close(efd);
- return -1;
- }
- close(efd);
- buf[bytes] = '\0';
- attr.config = strtol(buf, NULL, 0);
- attr.type = PERF_TYPE_TRACEPOINT;
- attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN;
- attr.sample_period = 1;
- attr.wakeup_events = 1;
- pfd = syscall(__NR_perf_event_open, &attr, pid, cpu, group_fd, PERF_FLAG_FD_CLOEXEC);
- if (pfd < 0) {
- fprintf(stderr, "perf_event_open(%s/id): %s\n", event_path, strerror(errno));
- return -1;
+ buf[bytes] = '\0';
+ attr.config = strtol(buf, NULL, 0);
+ attr.type = PERF_TYPE_TRACEPOINT;
+ attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN;
+ attr.sample_period = 1;
+ attr.wakeup_events = 1;
+ pfd = syscall(__NR_perf_event_open, &attr, pid, cpu, group_fd, PERF_FLAG_FD_CLOEXEC);
+ if (pfd < 0) {
+ fprintf(stderr, "perf_event_open(%s/id): %s\n", event_path, strerror(errno));
+ return -1;
+ }
}
+
perf_reader_set_fd(reader, pfd);
if (perf_reader_mmap(reader, attr.type, attr.sample_type) < 0)
@@ -579,31 +607,41 @@ void * bpf_attach_kprobe(int progfd, enum bpf_probe_attach_type attach_type, con
char event_alias[128];
struct perf_reader *reader = NULL;
static char *event_type = "kprobe";
+ struct probe_desc pd;
+ int pfd;
reader = perf_reader_new(cb, NULL, NULL, cb_cookie, probe_perf_reader_page_cnt);
if (!reader)
goto error;
- snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type);
- kfd = open(buf, O_WRONLY | O_APPEND, 0);
- if (kfd < 0) {
- fprintf(stderr, "open(%s): %s\n", buf, strerror(errno));
- goto error;
- }
+ /* try use new API to create kprobe */
+ pd.func = ptr_to_u64((void *)fn_name);
+ pd.offset = 0;
+ pfd = bpf_try_perf_event_open_with_probe(&pd, pid, cpu, group_fd, 0,
+ attach_type != BPF_PROBE_ENTRY);
- snprintf(event_alias, sizeof(event_alias), "%s_bcc_%d", ev_name, getpid());
- snprintf(buf, sizeof(buf), "%c:%ss/%s %s", attach_type==BPF_PROBE_ENTRY ? 'p' : 'r',
- event_type, event_alias, fn_name);
- if (write(kfd, buf, strlen(buf)) < 0) {
- if (errno == EINVAL)
- fprintf(stderr, "check dmesg output for possible cause\n");
+ if (pfd < 0) {
+ snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type);
+ kfd = open(buf, O_WRONLY | O_APPEND, 0);
+ if (kfd < 0) {
+ fprintf(stderr, "open(%s): %s\n", buf, strerror(errno));
+ goto error;
+ }
+
+ snprintf(event_alias, sizeof(event_alias), "%s_bcc_%d", ev_name, getpid());
+ snprintf(buf, sizeof(buf), "%c:%ss/%s %s", attach_type==BPF_PROBE_ENTRY ? 'p' : 'r',
+ event_type, event_alias, fn_name);
+ if (write(kfd, buf, strlen(buf)) < 0) {
+ if (errno == EINVAL)
+ fprintf(stderr, "check dmesg output for possible cause\n");
+ close(kfd);
+ goto error;
+ }
close(kfd);
- goto error;
+ snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s", event_type, event_alias);
}
- close(kfd);
- snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s", event_type, event_alias);
- if (bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd) < 0)
+ if (bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd, pfd) < 0)
goto error;
return reader;
@@ -685,42 +723,53 @@ void * bpf_attach_uprobe(int progfd, enum bpf_probe_attach_type attach_type, con
struct perf_reader *reader = NULL;
static char *event_type = "uprobe";
int res, kfd = -1, ns_fd = -1;
+ struct probe_desc pd;
+ int pfd;
reader = perf_reader_new(cb, NULL, NULL, cb_cookie, probe_perf_reader_page_cnt);
if (!reader)
goto error;
- snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type);
- kfd = open(buf, O_WRONLY | O_APPEND, 0);
- if (kfd < 0) {
- fprintf(stderr, "open(%s): %s\n", buf, strerror(errno));
- goto error;
- }
+ /* try use new API to create uprobe */
+ pd.path = ptr_to_u64((void *)binary_path);
+ pd.offset = offset;
+ pfd = bpf_try_perf_event_open_with_probe(&pd, pid, cpu, group_fd, 1,
+ attach_type != BPF_PROBE_ENTRY);
- res = snprintf(event_alias, sizeof(event_alias), "%s_bcc_%d", ev_name, getpid());
- if (res < 0 || res >= sizeof(event_alias)) {
- fprintf(stderr, "Event name (%s) is too long for buffer\n", ev_name);
- goto error;
- }
- res = snprintf(buf, sizeof(buf), "%c:%ss/%s %s:0x%lx", attach_type==BPF_PROBE_ENTRY ? 'p' : 'r',
- event_type, event_alias, binary_path, offset);
- if (res < 0 || res >= sizeof(buf)) {
- fprintf(stderr, "Event alias (%s) too long for buffer\n", event_alias);
- goto error;
- }
+ if (pfd < 0) {
+ snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type);
+ kfd = open(buf, O_WRONLY | O_APPEND, 0);
+ if (kfd < 0) {
+ fprintf(stderr, "open(%s): %s\n", buf, strerror(errno));
+ goto error;
+ }
- ns_fd = enter_mount_ns(pid);
- if (write(kfd, buf, strlen(buf)) < 0) {
- if (errno == EINVAL)
- fprintf(stderr, "check dmesg output for possible cause\n");
- goto error;
+ res = snprintf(event_alias, sizeof(event_alias), "%s_bcc_%d", ev_name, getpid());
+ if (res < 0 || res >= sizeof(event_alias)) {
+ fprintf(stderr, "Event name (%s) is too long for buffer\n", ev_name);
+ goto error;
+ }
+ res = snprintf(buf, sizeof(buf), "%c:%ss/%s %s:0x%lx", attach_type==BPF_PROBE_ENTRY ? 'p' : 'r',
+ event_type, event_alias, binary_path, offset);
+ if (res < 0 || res >= sizeof(buf)) {
+ fprintf(stderr, "Event alias (%s) too long for buffer\n", event_alias);
+ goto error;
+ }
+
+ ns_fd = enter_mount_ns(pid);
+ if (write(kfd, buf, strlen(buf)) < 0) {
+ if (errno == EINVAL)
+ fprintf(stderr, "check dmesg output for possible cause\n");
+ goto error;
+ }
+ close(kfd);
+ exit_mount_ns(ns_fd);
+ ns_fd = -1;
+
+ snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s", event_type, event_alias);
}
- close(kfd);
- exit_mount_ns(ns_fd);
- ns_fd = -1;
- snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%ss/%s", event_type, event_alias);
- if (bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd) < 0)
+ if (bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd, pfd) < 0)
goto error;
return reader;
@@ -735,8 +784,43 @@ error:
static int bpf_detach_probe(const char *ev_name, const char *event_type)
{
- int kfd, res;
+ int kfd = -1, res;
char buf[PATH_MAX];
+ int found_event = 0;
+ size_t bufsize = 0;
+ char *cptr = NULL;
+ FILE *fp;
+
+ /*
+ * For [k,u]probe created with perf_event_open (on newer kernel), it is
+ * not necessary to clean it up in [k,u]probe_events. We first look up
+ * the %s_bcc_%d line in [k,u]probe_events. If the event is not found,
+ * it is safe to skip the cleaning up process (write -:... to the file).
+ */
+ snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type);
+ fp = fopen(buf, "r");
+ if (!fp) {
+ fprintf(stderr, "open(%s): %s\n", buf, strerror(errno));
+ goto error;
+ }
+
+ res = snprintf(buf, sizeof(buf), "%ss/%s_bcc_%d", event_type, ev_name, getpid());
+ if (res < 0 || res >= sizeof(buf)) {
+ fprintf(stderr, "snprintf(%s): %d\n", ev_name, res);
+ goto error;
+ }
+
+ while (getline(&cptr, &bufsize, fp) != -1)
+ if (strstr(cptr, buf) != NULL) {
+ found_event = 1;
+ break;
+ }
+ fclose(fp);
+ fp = NULL;
+
+ if (!found_event)
+ return 0;
+
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/%s_events", event_type);
kfd = open(buf, O_WRONLY | O_APPEND, 0);
if (kfd < 0) {
@@ -760,6 +844,8 @@ static int bpf_detach_probe(const char *ev_name, const char *event_type)
error:
if (kfd >= 0)
close(kfd);
+ if (fp)
+ fclose(fp);
return -1;
}
@@ -786,7 +872,7 @@ void * bpf_attach_tracepoint(int progfd, const char *tp_category,
snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/%s",
tp_category, tp_name);
- if (bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd) < 0)
+ if (bpf_attach_tracing_event(progfd, buf, reader, pid, cpu, group_fd, -1) < 0)
goto error;
return reader;
--
2.9.5
next prev parent reply other threads:[~2017-11-15 17:25 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-11-15 17:23 [PATCH 0/6] enable creating [k,u]probe with perf_event_open Song Liu
2017-11-15 17:23 ` Song Liu [this message]
2017-11-15 17:23 ` [PATCH 1/6] perf: Add new type PERF_TYPE_PROBE Song Liu
2017-11-23 10:02 ` Peter Zijlstra
2017-11-24 6:31 ` Alexei Starovoitov
2017-11-24 8:28 ` Peter Zijlstra
2017-11-26 1:59 ` Alexei Starovoitov
2017-11-27 7:58 ` Peter Zijlstra
2017-11-23 10:22 ` Peter Zijlstra
2017-11-30 1:43 ` Song Liu
2017-11-30 13:37 ` Peter Zijlstra
2017-11-15 17:23 ` [PATCH] perf_event_open.2: add " Song Liu
2017-11-15 17:23 ` [PATCH 2/6] perf: copy new perf_event.h to tools/include/uapi Song Liu
2017-11-15 17:23 ` [PATCH 3/6] perf: implement kprobe support to PERF_TYPE_PROBE Song Liu
2017-11-23 10:06 ` Peter Zijlstra
2017-11-15 17:23 ` [PATCH 4/6] perf: implement uprobe " Song Liu
2017-11-15 17:23 ` [PATCH 5/6] bpf: add option for bpf_load.c to use PERF_TYPE_PROBE Song Liu
2017-11-15 17:23 ` [PATCH 6/6] bpf: add new test test_many_kprobe Song Liu
2017-11-22 5:00 ` [PATCH 0/6] enable creating [k,u]probe with perf_event_open Alexei Starovoitov
2017-11-23 9:02 ` Christoph Hellwig
2017-11-23 9:49 ` Peter Zijlstra
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20171115172339.1791161-2-songliubraving@fb.com \
--to=songliubraving@fb.com \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=kernel-team@fb.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=netdev@vger.kernel.org \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).