From patchwork Thu Nov 30 01:44:41 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Song Liu X-Patchwork-Id: 842850 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="d/or3Ljb"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3ynKz61Y2qz9sDB for ; Thu, 30 Nov 2017 12:47:30 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753809AbdK3BrY (ORCPT ); Wed, 29 Nov 2017 20:47:24 -0500 Received: from mx0b-00082601.pphosted.com ([67.231.153.30]:47982 "EHLO mx0b-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753109AbdK3Bo7 (ORCPT ); Wed, 29 Nov 2017 20:44:59 -0500 Received: from pps.filterd (m0109331.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id vAU1hBqd004318 for ; Wed, 29 Nov 2017 17:44:58 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=SYZyhsvnEtX98DHJv/w/1z7fnBoLRvdE3kQVAkzNhhQ=; b=d/or3Ljbzmd+pS3FygJibOGvb5KMqOC7c9mC9XS7NOmdzdmM9g8mg20G72gIg3iObvxf IPcJA9Kf5iip2Sug9FC4UvVKxFHOdD9uNa/MSRV1UMP7vTMgMQXZIQQ7iqkFrDwZOf4G rapOzULvrjonlDdmEATlPYIZO/+E/jBWgwo= Received: from mail.thefacebook.com ([199.201.64.23]) by mx0a-00082601.pphosted.com with ESMTP id 2ej6wa07nt-2 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT) for ; Wed, 29 Nov 2017 17:44:58 -0800 Received: from mx-out.facebook.com (192.168.52.123) by PRN-CHUB08.TheFacebook.com (192.168.16.18) with Microsoft SMTP Server id 14.3.361.1; Wed, 29 Nov 2017 17:44:57 -0800 Received: by devbig102.frc2.facebook.com (Postfix, from userid 4523) id C27B6428284A; Wed, 29 Nov 2017 17:44:56 -0800 (PST) Smtp-Origin-Hostprefix: devbig From: Song Liu Smtp-Origin-Hostname: devbig102.frc2.facebook.com To: , , , , , , CC: , Song Liu Smtp-Origin-Cluster: frc2c02 Subject: [PATCH v2 1/6] perf: Add new types PERF_TYPE_KPROBE and PERF_TYPE_UPROBE Date: Wed, 29 Nov 2017 17:44:41 -0800 Message-ID: <20171130014447.190229-3-songliubraving@fb.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20171130014447.190229-1-songliubraving@fb.com> References: <20171130014447.190229-1-songliubraving@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-11-29_09:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Two new perf types, PERF_TYPE_KPROBE and PERF_TYPE_UPROBE, are added to allow creating [k,u]probe with perf_event_open. These [k,u]probe are associated with the file decriptor created by perf_event_open, thus are easy to clean when the file descriptor is destroyed. kprobe_func and uprobe_path are added to union config1 for pointers to function name for kprobe or binary path for uprobe. kprobe_addr and probe_offset are added to union config2 for kernel address (when kprobe_func is NULL), or [k,u]probe offset. Signed-off-by: Song Liu Reviewed-by: Yonghong Song Reviewed-by: Josef Bacik Acked-by: Alexei Starovoitov --- include/uapi/linux/perf_event.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index 362493a..5220600 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h @@ -33,6 +33,8 @@ enum perf_type_id { PERF_TYPE_HW_CACHE = 3, PERF_TYPE_RAW = 4, PERF_TYPE_BREAKPOINT = 5, + PERF_TYPE_KPROBE = 6, + PERF_TYPE_UPROBE = 7, PERF_TYPE_MAX, /* non-ABI */ }; @@ -299,6 +301,8 @@ enum perf_event_read_format { #define PERF_ATTR_SIZE_VER4 104 /* add: sample_regs_intr */ #define PERF_ATTR_SIZE_VER5 112 /* add: aux_watermark */ +#define MAX_PROBE_FUNC_NAME_LEN 64 + /* * Hardware event_id to monitor via a performance monitoring event: * @@ -380,10 +384,14 @@ struct perf_event_attr { __u32 bp_type; union { __u64 bp_addr; + __u64 kprobe_func; /* for PERF_TYPE_KPROBE */ + __u64 uprobe_path; /* for PERF_TYPE_UPROBE */ __u64 config1; /* extension of config */ }; union { __u64 bp_len; + __u64 kprobe_addr; /* for PERF_TYPE_KPROBE, with kprobe_func == NULL */ + __u64 probe_offset; /* for PERF_TYPE_[K,U]PROBE */ __u64 config2; /* extension of config1 */ }; __u64 branch_sample_type; /* enum perf_branch_sample_type */ From patchwork Thu Nov 30 01:44:43 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Song Liu X-Patchwork-Id: 842848 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="h1GPB6lQ"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3ynKyp4680z9sDB for ; Thu, 30 Nov 2017 12:47:14 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753710AbdK3Bqn (ORCPT ); Wed, 29 Nov 2017 20:46:43 -0500 Received: from mx0b-00082601.pphosted.com ([67.231.153.30]:43238 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753353AbdK3BpA (ORCPT ); Wed, 29 Nov 2017 20:45:00 -0500 Received: from pps.filterd (m0001303.ppops.net [127.0.0.1]) by m0001303.ppops.net (8.16.0.21/8.16.0.21) with SMTP id vAU1fXHG011922 for ; Wed, 29 Nov 2017 17:44:59 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=e9tlnvruvLcMHsesW4QbVhkv1hSDjUVTL9vozA8C3A8=; b=h1GPB6lQxcOTs6fm7Ao5GdvSITb4r2f58xi8y4b129Xr1gwjzMuZAy5ORhjokBMutoE/ xpF/xzxoe/7e8xAKxogXets9OUue8qtdaHiGexG63Tajgz4XMmYsPakuwFK/QBl0243G iAhYhRxjZL/mVxVr371R5kvp4Y1D1CiP56w= Received: from mail.thefacebook.com ([199.201.64.23]) by m0001303.ppops.net with ESMTP id 2ej762r66h-4 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT) for ; Wed, 29 Nov 2017 17:44:59 -0800 Received: from mx-out.facebook.com (192.168.52.123) by PRN-CHUB09.TheFacebook.com (192.168.16.19) with Microsoft SMTP Server id 14.3.361.1; Wed, 29 Nov 2017 17:44:57 -0800 Received: by devbig102.frc2.facebook.com (Postfix, from userid 4523) id 0179C428284A; Wed, 29 Nov 2017 17:44:56 -0800 (PST) Smtp-Origin-Hostprefix: devbig From: Song Liu Smtp-Origin-Hostname: devbig102.frc2.facebook.com To: , , , , , , CC: , Song Liu Smtp-Origin-Cluster: frc2c02 Subject: [PATCH v2 2/6] perf: copy new perf_event.h to tools/include/uapi Date: Wed, 29 Nov 2017 17:44:43 -0800 Message-ID: <20171130014447.190229-5-songliubraving@fb.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20171130014447.190229-1-songliubraving@fb.com> References: <20171130014447.190229-1-songliubraving@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-11-29_09:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org perf_event.h is updated in previous patch, this patch applies same changes to the tools/ version. This is part is put in a separate patch in case the two files are back ported separately. Signed-off-by: Song Liu Reviewed-by: Yonghong Song Reviewed-by: Josef Bacik Acked-by: Alexei Starovoitov --- tools/include/uapi/linux/perf_event.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/include/uapi/linux/perf_event.h b/tools/include/uapi/linux/perf_event.h index b9a4953..c361442 100644 --- a/tools/include/uapi/linux/perf_event.h +++ b/tools/include/uapi/linux/perf_event.h @@ -33,6 +33,8 @@ enum perf_type_id { PERF_TYPE_HW_CACHE = 3, PERF_TYPE_RAW = 4, PERF_TYPE_BREAKPOINT = 5, + PERF_TYPE_KPROBE = 6, + PERF_TYPE_UPROBE = 7, PERF_TYPE_MAX, /* non-ABI */ }; @@ -299,6 +301,8 @@ enum perf_event_read_format { #define PERF_ATTR_SIZE_VER4 104 /* add: sample_regs_intr */ #define PERF_ATTR_SIZE_VER5 112 /* add: aux_watermark */ +#define MAX_PROBE_FUNC_NAME_LEN 64 + /* * Hardware event_id to monitor via a performance monitoring event: * @@ -380,10 +384,14 @@ struct perf_event_attr { __u32 bp_type; union { __u64 bp_addr; + __u64 kprobe_func; /* for PERF_TYPE_KPROBE */ + __u64 uprobe_path; /* for PERF_TYPE_UPROBE */ __u64 config1; /* extension of config */ }; union { __u64 bp_len; + __u64 kprobe_addr; /* for PERF_TYPE_KPROBE, with kprobe_func == NULL */ + __u64 probe_offset; /* for PERF_TYPE_[K,U]PROBE */ __u64 config2; /* extension of config1 */ }; __u64 branch_sample_type; /* enum perf_branch_sample_type */ From patchwork Thu Nov 30 01:44:44 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Song Liu X-Patchwork-Id: 842846 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="Rdnr/GNM"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3ynKxs5fpwz9s83 for ; Thu, 30 Nov 2017 12:46:25 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753652AbdK3BqX (ORCPT ); Wed, 29 Nov 2017 20:46:23 -0500 Received: from mx0b-00082601.pphosted.com ([67.231.153.30]:46032 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753361AbdK3BpA (ORCPT ); Wed, 29 Nov 2017 20:45:00 -0500 Received: from pps.filterd (m0001255.ppops.net [127.0.0.1]) by mx0b-00082601.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id vAU1gJ3q018225 for ; Wed, 29 Nov 2017 17:45:00 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=0LxX0CSy0JcFM6vbUn6sfcXWO024Sse45Uq0tmd8P3Y=; b=Rdnr/GNMkRkvaNMchcqwVUE4wtFvG0QxiAFNbvVBjVdcN010OEaXk+6sPKFCTV2kaRCy F+tk7So+CQrxzriinupY/JhxHyChY+cb9IPu5ylZwcgeIgngr4f6EDWINnx+Mzu5ZJfq I7QZSQ7tGYWNfvGqvXrH+wm0aoEuGwmRFfY= Received: from mail.thefacebook.com ([199.201.64.23]) by mx0b-00082601.pphosted.com with ESMTP id 2ehrrujrkr-6 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT) for ; Wed, 29 Nov 2017 17:44:59 -0800 Received: from mx-out.facebook.com (192.168.52.123) by PRN-CHUB05.TheFacebook.com (192.168.16.15) with Microsoft SMTP Server id 14.3.361.1; Wed, 29 Nov 2017 17:44:57 -0800 Received: by devbig102.frc2.facebook.com (Postfix, from userid 4523) id 1A12F428284A; Wed, 29 Nov 2017 17:44:57 -0800 (PST) Smtp-Origin-Hostprefix: devbig From: Song Liu Smtp-Origin-Hostname: devbig102.frc2.facebook.com To: , , , , , , CC: , Song Liu Smtp-Origin-Cluster: frc2c02 Subject: [PATCH v2 3/6] perf: implement support of PERF_TYPE_KPROBE Date: Wed, 29 Nov 2017 17:44:44 -0800 Message-ID: <20171130014447.190229-6-songliubraving@fb.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20171130014447.190229-1-songliubraving@fb.com> References: <20171130014447.190229-1-songliubraving@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-11-29_09:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org A new pmu, perf_kprobe, is created for PERF_TYPE_KPROBE. Based on input from perf_event_open(), perf_kprobe creates a kprobe (or kretprobe) for the perf_event. This kprobe is private to this perf_event, and thus not added to global lists, and not available in tracefs. Two functions, create_local_trace_kprobe() and destroy_local_trace_kprobe() are added to created and destroy these local trace_kprobe. Signed-off-by: Song Liu Reviewed-by: Yonghong Song Reviewed-by: Josef Bacik --- include/linux/trace_events.h | 2 + kernel/events/core.c | 41 +++++++++++++++++-- kernel/trace/trace_event_perf.c | 53 ++++++++++++++++++++++++ kernel/trace/trace_kprobe.c | 91 +++++++++++++++++++++++++++++++++++++---- kernel/trace/trace_probe.h | 7 ++++ 5 files changed, 183 insertions(+), 11 deletions(-) diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h index 2bcb4dc..51f748c9 100644 --- a/include/linux/trace_events.h +++ b/include/linux/trace_events.h @@ -494,6 +494,8 @@ extern int perf_trace_init(struct perf_event *event); extern void perf_trace_destroy(struct perf_event *event); extern int perf_trace_add(struct perf_event *event, int flags); extern void perf_trace_del(struct perf_event *event, int flags); +extern int perf_kprobe_init(struct perf_event *event); +extern void perf_kprobe_destroy(struct perf_event *event); extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, char *filter_str); extern void ftrace_profile_free_filter(struct perf_event *event); diff --git a/kernel/events/core.c b/kernel/events/core.c index 494eca1..daa6e0a 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7970,6 +7970,28 @@ static int perf_tp_event_init(struct perf_event *event) return 0; } +static int perf_kprobe_event_init(struct perf_event *event) +{ + int err; + + if (event->attr.type != PERF_TYPE_KPROBE) + return -ENOENT; + + /* + * no branch sampling for probe events + */ + if (has_branch_stack(event)) + return -EOPNOTSUPP; + + err = perf_kprobe_init(event); + if (err) + return err; + + event->destroy = perf_kprobe_destroy; + + return 0; +} + static struct pmu perf_tracepoint = { .task_ctx_nr = perf_sw_context, @@ -7981,9 +8003,20 @@ static struct pmu perf_tracepoint = { .read = perf_swevent_read, }; +static struct pmu perf_kprobe = { + .task_ctx_nr = perf_sw_context, + .event_init = perf_kprobe_event_init, + .add = perf_trace_add, + .del = perf_trace_del, + .start = perf_swevent_start, + .stop = perf_swevent_stop, + .read = perf_swevent_read, +}; + static inline void perf_tp_register(void) { perf_pmu_register(&perf_tracepoint, "tracepoint", PERF_TYPE_TRACEPOINT); + perf_pmu_register(&perf_kprobe, "kprobe", PERF_TYPE_KPROBE); } static void perf_event_free_filter(struct perf_event *event) @@ -8065,7 +8098,8 @@ static int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd) bool is_kprobe, is_tracepoint, is_syscall_tp; struct bpf_prog *prog; - if (event->attr.type != PERF_TYPE_TRACEPOINT) + if (event->attr.type != PERF_TYPE_TRACEPOINT && + event->attr.type != PERF_TYPE_KPROBE) return perf_event_set_bpf_handler(event, prog_fd); if (event->tp_event->prog) @@ -8537,8 +8571,9 @@ static int perf_event_set_filter(struct perf_event *event, void __user *arg) char *filter_str; int ret = -EINVAL; - if ((event->attr.type != PERF_TYPE_TRACEPOINT || - !IS_ENABLED(CONFIG_EVENT_TRACING)) && + if (((event->attr.type != PERF_TYPE_TRACEPOINT && + event->attr.type != PERF_TYPE_KPROBE) || + !IS_ENABLED(CONFIG_EVENT_TRACING)) && !has_addr_filter(event)) return -EINVAL; diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 13ba2d3..7cf0d99 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -8,6 +8,7 @@ #include #include #include "trace.h" +#include "trace_probe.h" static char __percpu *perf_trace_buf[PERF_NR_CONTEXTS]; @@ -229,6 +230,48 @@ int perf_trace_init(struct perf_event *p_event) return ret; } +int perf_kprobe_init(struct perf_event *p_event) +{ + int ret; + char *func = NULL; + struct trace_event_call *tp_event; + +#ifdef CONFIG_KPROBE_EVENTS + if (p_event->attr.kprobe_func) { + func = kzalloc(MAX_PROBE_FUNC_NAME_LEN, GFP_KERNEL); + if (!func) + return -ENOMEM; + ret = strncpy_from_user( + func, u64_to_user_ptr(p_event->attr.kprobe_func), + MAX_PROBE_FUNC_NAME_LEN); + if (ret < 0) + goto out; + + if (func[0] == '\0') { + kfree(func); + func = NULL; + } + } + + tp_event = create_local_trace_kprobe( + func, (void *)(unsigned long)(p_event->attr.kprobe_addr), + p_event->attr.probe_offset, p_event->attr.config != 0); + if (IS_ERR(tp_event)) { + ret = PTR_ERR(tp_event); + goto out; + } + + ret = perf_trace_event_init(tp_event, p_event); + if (ret) + destroy_local_trace_kprobe(tp_event); +out: + kfree(func); + return ret; +#else + return -EOPNOTSUPP; +#endif /* CONFIG_KPROBE_EVENTS */ +} + void perf_trace_destroy(struct perf_event *p_event) { mutex_lock(&event_mutex); @@ -237,6 +280,16 @@ void perf_trace_destroy(struct perf_event *p_event) mutex_unlock(&event_mutex); } +void perf_kprobe_destroy(struct perf_event *p_event) +{ + perf_trace_event_close(p_event); + perf_trace_event_unreg(p_event); + +#ifdef CONFIG_KPROBE_EVENTS + destroy_local_trace_kprobe(p_event->tp_event); +#endif +} + int perf_trace_add(struct perf_event *p_event, int flags) { struct trace_event_call *tp_event = p_event->tp_event; diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 8a907e1..16b334a 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -438,6 +438,14 @@ disable_trace_kprobe(struct trace_kprobe *tk, struct trace_event_file *file) disable_kprobe(&tk->rp.kp); wait = 1; } + + /* + * if tk is not added to any list, it must be a local trace_kprobe + * created with perf_event_open. We don't need to wait for these + * trace_kprobes + */ + if (list_empty(&tk->list)) + wait = 0; out: if (wait) { /* @@ -1315,12 +1323,9 @@ static struct trace_event_functions kprobe_funcs = { .trace = print_kprobe_event }; -static int register_kprobe_event(struct trace_kprobe *tk) +static inline void init_trace_event_call(struct trace_kprobe *tk, + struct trace_event_call *call) { - struct trace_event_call *call = &tk->tp.call; - int ret; - - /* Initialize trace_event_call */ INIT_LIST_HEAD(&call->class->fields); if (trace_kprobe_is_return(tk)) { call->event.funcs = &kretprobe_funcs; @@ -1329,6 +1334,19 @@ static int register_kprobe_event(struct trace_kprobe *tk) call->event.funcs = &kprobe_funcs; call->class->define_fields = kprobe_event_define_fields; } + + call->flags = TRACE_EVENT_FL_KPROBE; + call->class->reg = kprobe_register; + call->data = tk; +} + +static int register_kprobe_event(struct trace_kprobe *tk) +{ + struct trace_event_call *call = &tk->tp.call; + int ret = 0; + + init_trace_event_call(tk, call); + if (set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0) return -ENOMEM; ret = register_trace_event(&call->event); @@ -1336,9 +1354,6 @@ static int register_kprobe_event(struct trace_kprobe *tk) kfree(call->print_fmt); return -ENODEV; } - call->flags = TRACE_EVENT_FL_KPROBE; - call->class->reg = kprobe_register; - call->data = tk; ret = trace_add_event_call(call); if (ret) { pr_info("Failed to register kprobe event: %s\n", @@ -1360,6 +1375,66 @@ static int unregister_kprobe_event(struct trace_kprobe *tk) return ret; } +#ifdef CONFIG_PERF_EVENTS +/* create a trace_kprobe, but don't add it to global lists */ +struct trace_event_call * +create_local_trace_kprobe(char *func, void *addr, unsigned long offs, + bool is_return) +{ + struct trace_kprobe *tk; + int ret; + char *event; + + /* + * local trace_kprobes are not added to probe_list, so they are never + * searched in find_trace_kprobe(). Therefore, there is no concern of + * duplicated name here. + */ + event = func ? func : "DUMMY_EVENT"; + + tk = alloc_trace_kprobe(KPROBE_EVENT_SYSTEM, event, (void *)addr, func, + offs, 0 /* maxactive */, 0 /* nargs */, + is_return); + + if (IS_ERR(tk)) { + pr_info("Failed to allocate trace_probe.(%d)\n", + (int)PTR_ERR(tk)); + return ERR_CAST(tk); + } + + init_trace_event_call(tk, &tk->tp.call); + + if (set_print_fmt(&tk->tp, trace_kprobe_is_return(tk)) < 0) { + ret = -ENOMEM; + goto error; + } + + ret = __register_trace_kprobe(tk); + if (ret < 0) + goto error; + + return &tk->tp.call; +error: + free_trace_kprobe(tk); + return ERR_PTR(ret); +} + +void destroy_local_trace_kprobe(struct trace_event_call *event_call) +{ + struct trace_kprobe *tk; + + tk = container_of(event_call, struct trace_kprobe, tp.call); + + if (trace_probe_is_enabled(&tk->tp)) { + WARN_ON(1); + return; + } + + __unregister_trace_kprobe(tk); + free_trace_kprobe(tk); +} +#endif /* CONFIG_PERF_EVENTS */ + /* Make a tracefs interface for controlling probe points */ static __init int init_kprobe_trace(void) { diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 903273c..910ae1b 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -411,3 +411,10 @@ store_trace_args(int ent_size, struct trace_probe *tp, struct pt_regs *regs, } extern int set_print_fmt(struct trace_probe *tp, bool is_return); + +#ifdef CONFIG_PERF_EVENTS +extern struct trace_event_call * +create_local_trace_kprobe(char *func, void *addr, unsigned long offs, + bool is_return); +extern void destroy_local_trace_kprobe(struct trace_event_call *event_call); +#endif From patchwork Thu Nov 30 01:44:45 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Song Liu X-Patchwork-Id: 842851 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="BzONqvYp"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3ynKzB712Gz9sDB for ; Thu, 30 Nov 2017 12:47:34 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753375AbdK3BrW (ORCPT ); Wed, 29 Nov 2017 20:47:22 -0500 Received: from mx0b-00082601.pphosted.com ([67.231.153.30]:59726 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753197AbdK3Bo7 (ORCPT ); Wed, 29 Nov 2017 20:44:59 -0500 Received: from pps.filterd (m0089730.ppops.net [127.0.0.1]) by m0089730.ppops.net (8.16.0.21/8.16.0.21) with SMTP id vAU1hXES002333 for ; Wed, 29 Nov 2017 17:44:58 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=rm6sGg2fJhLjqqW/AiZ1TooXurLEobnhwZgjmxFJz+s=; b=BzONqvYpGKqA5BVzW4aO66gAFeTBbjJVr9PGsTmlxegPtiL0E6uXAYWMmfLMBPmeiPPf BH/fu+HLf9K7qfHOU74R8XW+SLkfsZpMZVBGLTY/u7O+mlN3HW2zMQ45x+D86NbJjImg /NSh1myu77L+8rDZg0dx+yQJR/VPls70Axk= Received: from mail.thefacebook.com ([199.201.64.23]) by m0089730.ppops.net with ESMTP id 2ej8ab0156-2 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT) for ; Wed, 29 Nov 2017 17:44:58 -0800 Received: from mx-out.facebook.com (192.168.52.123) by PRN-CHUB11.TheFacebook.com (192.168.16.21) with Microsoft SMTP Server id 14.3.319.2; Wed, 29 Nov 2017 17:44:57 -0800 Received: by devbig102.frc2.facebook.com (Postfix, from userid 4523) id 32A60428284A; Wed, 29 Nov 2017 17:44:57 -0800 (PST) Smtp-Origin-Hostprefix: devbig From: Song Liu Smtp-Origin-Hostname: devbig102.frc2.facebook.com To: , , , , , , CC: , Song Liu Smtp-Origin-Cluster: frc2c02 Subject: [PATCH v2 4/6] perf: implement support of PERF_TYPE_UPROBE Date: Wed, 29 Nov 2017 17:44:45 -0800 Message-ID: <20171130014447.190229-7-songliubraving@fb.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20171130014447.190229-1-songliubraving@fb.com> References: <20171130014447.190229-1-songliubraving@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-11-29_09:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This patch adds perf_uprobe support with similar pattern as previous patch (for kprobe). Two functions, create_local_trace_uprobe() and destroy_local_trace_uprobe(), are created so a uprobe can be created and attached to the file descriptor created by perf_event_open(). Signed-off-by: Song Liu Reviewed-by: Yonghong Song Reviewed-by: Josef Bacik --- include/linux/trace_events.h | 2 + kernel/events/core.c | 39 +++++++++++++++++- kernel/trace/trace_event_perf.c | 58 ++++++++++++++++++++++++++ kernel/trace/trace_probe.h | 4 ++ kernel/trace/trace_uprobe.c | 90 ++++++++++++++++++++++++++++++++++++----- 5 files changed, 181 insertions(+), 12 deletions(-) diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h index 51f748c9..9272fa6 100644 --- a/include/linux/trace_events.h +++ b/include/linux/trace_events.h @@ -496,6 +496,8 @@ extern int perf_trace_add(struct perf_event *event, int flags); extern void perf_trace_del(struct perf_event *event, int flags); extern int perf_kprobe_init(struct perf_event *event); extern void perf_kprobe_destroy(struct perf_event *event); +extern int perf_uprobe_init(struct perf_event *event); +extern void perf_uprobe_destroy(struct perf_event *event); extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, char *filter_str); extern void ftrace_profile_free_filter(struct perf_event *event); diff --git a/kernel/events/core.c b/kernel/events/core.c index daa6e0a..b566a53 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7992,6 +7992,28 @@ static int perf_kprobe_event_init(struct perf_event *event) return 0; } +static int perf_uprobe_event_init(struct perf_event *event) +{ + int err; + + if (event->attr.type != PERF_TYPE_UPROBE) + return -ENOENT; + + /* + * no branch sampling for probe events + */ + if (has_branch_stack(event)) + return -EOPNOTSUPP; + + err = perf_uprobe_init(event); + if (err) + return err; + + event->destroy = perf_uprobe_destroy; + + return 0; +} + static struct pmu perf_tracepoint = { .task_ctx_nr = perf_sw_context, @@ -8013,10 +8035,21 @@ static struct pmu perf_kprobe = { .read = perf_swevent_read, }; +static struct pmu perf_uprobe = { + .task_ctx_nr = perf_sw_context, + .event_init = perf_uprobe_event_init, + .add = perf_trace_add, + .del = perf_trace_del, + .start = perf_swevent_start, + .stop = perf_swevent_stop, + .read = perf_swevent_read, +}; + static inline void perf_tp_register(void) { perf_pmu_register(&perf_tracepoint, "tracepoint", PERF_TYPE_TRACEPOINT); perf_pmu_register(&perf_kprobe, "kprobe", PERF_TYPE_KPROBE); + perf_pmu_register(&perf_uprobe, "uprobe", PERF_TYPE_UPROBE); } static void perf_event_free_filter(struct perf_event *event) @@ -8099,7 +8132,8 @@ static int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd) struct bpf_prog *prog; if (event->attr.type != PERF_TYPE_TRACEPOINT && - event->attr.type != PERF_TYPE_KPROBE) + event->attr.type != PERF_TYPE_KPROBE && + event->attr.type != PERF_TYPE_UPROBE) return perf_event_set_bpf_handler(event, prog_fd); if (event->tp_event->prog) @@ -8572,7 +8606,8 @@ static int perf_event_set_filter(struct perf_event *event, void __user *arg) int ret = -EINVAL; if (((event->attr.type != PERF_TYPE_TRACEPOINT && - event->attr.type != PERF_TYPE_KPROBE) || + event->attr.type != PERF_TYPE_KPROBE && + event->attr.type != PERF_TYPE_UPROBE) || !IS_ENABLED(CONFIG_EVENT_TRACING)) && !has_addr_filter(event)) return -EINVAL; diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 7cf0d99..1b97ea2 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -272,6 +272,52 @@ int perf_kprobe_init(struct perf_event *p_event) #endif /* CONFIG_KPROBE_EVENTS */ } +int perf_uprobe_init(struct perf_event *p_event) +{ + int ret; + char *path = NULL; + struct trace_event_call *tp_event; + +#ifdef CONFIG_UPROBE_EVENTS + if (!p_event->attr.uprobe_path) + return -EINVAL; + path = kzalloc(PATH_MAX, GFP_KERNEL); + if (!path) + return -ENOMEM; + ret = strncpy_from_user( + path, u64_to_user_ptr(p_event->attr.uprobe_path), PATH_MAX); + if (ret < 0) + goto out; + if (path[0] == '\0') { + ret = -EINVAL; + goto out; + } + + tp_event = create_local_trace_uprobe( + path, p_event->attr.probe_offset, p_event->attr.config != 0); + if (IS_ERR(tp_event)) { + ret = PTR_ERR(tp_event); + goto out; + } + + /* + * local trace_uprobe need to hold event_mutex to call + * uprobe_buffer_enable() and uprobe_buffer_disable(). + * event_mutex is not required for local trace_kprobes. + */ + mutex_lock(&event_mutex); + ret = perf_trace_event_init(tp_event, p_event); + if (ret) + destroy_local_trace_uprobe(tp_event); + mutex_unlock(&event_mutex); +out: + kfree(path); + return ret; +#else + return -EOPNOTSUPP; +#endif /* CONFIG_UPROBE_EVENTS */ +} + void perf_trace_destroy(struct perf_event *p_event) { mutex_lock(&event_mutex); @@ -290,6 +336,18 @@ void perf_kprobe_destroy(struct perf_event *p_event) #endif } +void perf_uprobe_destroy(struct perf_event *p_event) +{ + mutex_lock(&event_mutex); + perf_trace_event_close(p_event); + perf_trace_event_unreg(p_event); + mutex_unlock(&event_mutex); + +#ifdef CONFIG_UPROBE_EVENTS + destroy_local_trace_uprobe(p_event->tp_event); +#endif +} + int perf_trace_add(struct perf_event *p_event, int flags) { struct trace_event_call *tp_event = p_event->tp_event; diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 910ae1b..86b5925 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -417,4 +417,8 @@ extern struct trace_event_call * create_local_trace_kprobe(char *func, void *addr, unsigned long offs, bool is_return); extern void destroy_local_trace_kprobe(struct trace_event_call *event_call); + +extern struct trace_event_call * +create_local_trace_uprobe(char *name, unsigned long offs, bool is_return); +extern void destroy_local_trace_uprobe(struct trace_event_call *event_call); #endif diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 4525e02..4d805d2 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c @@ -31,8 +31,8 @@ #define UPROBE_EVENT_SYSTEM "uprobes" struct uprobe_trace_entry_head { - struct trace_entry ent; - unsigned long vaddr[]; + struct trace_entry ent; + unsigned long vaddr[]; }; #define SIZEOF_TRACE_ENTRY(is_return) \ @@ -1293,16 +1293,25 @@ static struct trace_event_functions uprobe_funcs = { .trace = print_uprobe_event }; -static int register_uprobe_event(struct trace_uprobe *tu) +static inline void init_trace_event_call(struct trace_uprobe *tu, + struct trace_event_call *call) { - struct trace_event_call *call = &tu->tp.call; - int ret; - - /* Initialize trace_event_call */ INIT_LIST_HEAD(&call->class->fields); call->event.funcs = &uprobe_funcs; call->class->define_fields = uprobe_event_define_fields; + call->flags = TRACE_EVENT_FL_UPROBE; + call->class->reg = trace_uprobe_register; + call->data = tu; +} + +static int register_uprobe_event(struct trace_uprobe *tu) +{ + struct trace_event_call *call = &tu->tp.call; + int ret = 0; + + init_trace_event_call(tu, call); + if (set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) return -ENOMEM; @@ -1312,9 +1321,6 @@ static int register_uprobe_event(struct trace_uprobe *tu) return -ENODEV; } - call->flags = TRACE_EVENT_FL_UPROBE; - call->class->reg = trace_uprobe_register; - call->data = tu; ret = trace_add_event_call(call); if (ret) { @@ -1340,6 +1346,70 @@ static int unregister_uprobe_event(struct trace_uprobe *tu) return 0; } +#ifdef CONFIG_PERF_EVENTS +struct trace_event_call * +create_local_trace_uprobe(char *name, unsigned long offs, bool is_return) +{ + struct trace_uprobe *tu; + struct inode *inode; + struct path path; + int ret; + + ret = kern_path(name, LOOKUP_FOLLOW, &path); + if (ret) + return ERR_PTR(ret); + + inode = igrab(d_inode(path.dentry)); + path_put(&path); + + if (!inode || !S_ISREG(inode->i_mode)) { + iput(inode); + return ERR_PTR(-EINVAL); + } + + /* + * local trace_kprobes are not added to probe_list, so they are never + * searched in find_trace_kprobe(). Therefore, there is no concern of + * duplicated name "DUMMY_EVENT" here. + */ + tu = alloc_trace_uprobe(UPROBE_EVENT_SYSTEM, "DUMMY_EVENT", 0, + is_return); + + if (IS_ERR(tu)) { + pr_info("Failed to allocate trace_uprobe.(%d)\n", + (int)PTR_ERR(tu)); + return ERR_CAST(tu); + } + + tu->offset = offs; + tu->inode = inode; + tu->filename = kstrdup(name, GFP_KERNEL); + init_trace_event_call(tu, &tu->tp.call); + + if (set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) { + ret = -ENOMEM; + goto error; + } + + return &tu->tp.call; +error: + free_trace_uprobe(tu); + return ERR_PTR(ret); +} + +void destroy_local_trace_uprobe(struct trace_event_call *event_call) +{ + struct trace_uprobe *tu; + + tu = container_of(event_call, struct trace_uprobe, tp.call); + + kfree(tu->tp.call.print_fmt); + tu->tp.call.print_fmt = NULL; + + free_trace_uprobe(tu); +} +#endif /* CONFIG_PERF_EVENTS */ + /* Make a trace interface for controling probe points */ static __init int init_uprobe_trace(void) { From patchwork Thu Nov 30 01:44:46 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Song Liu X-Patchwork-Id: 842849 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="YEVV/4w/"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3ynKz21K2nz9sDB for ; Thu, 30 Nov 2017 12:47:26 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753815AbdK3BrZ (ORCPT ); Wed, 29 Nov 2017 20:47:25 -0500 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:47818 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752983AbdK3Bo7 (ORCPT ); Wed, 29 Nov 2017 20:44:59 -0500 Received: from pps.filterd (m0044012.ppops.net [127.0.0.1]) by mx0a-00082601.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id vAU1ik0k001822 for ; Wed, 29 Nov 2017 17:44:59 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=q1vWEuZ46OAahOSpxN5Vh4WoRJt+hOS2LnymrNaffqs=; b=YEVV/4w/ARy7EZDP83e/d0DgB8FHwu/i91qsOpd94aHb2sAvOH9q60b+P7XW+aty3Dbb 2UX8yeWXLzTsp2tQet+XgR5fkiPIjxPkoDjWc5DIb6+2hgtJ4Fj/+Po/h4ZiNIZH8AEX wU3H3l/LFMaXs0QdKT/3QxJwCNE1gr0uTvM= Received: from mail.thefacebook.com ([199.201.64.23]) by mx0a-00082601.pphosted.com with ESMTP id 2ej6x8092k-3 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT) for ; Wed, 29 Nov 2017 17:44:58 -0800 Received: from PRN-CHUB02.TheFacebook.com (2620:10d:c081:35::11) by PRN-CHUB10.TheFacebook.com (2620:10d:c081:35::19) with Microsoft SMTP Server (TLS) id 14.3.361.1; Wed, 29 Nov 2017 17:44:57 -0800 Received: from mx-out.facebook.com (192.168.52.123) by PRN-CHUB02.TheFacebook.com (192.168.16.12) with Microsoft SMTP Server id 14.3.361.1; Wed, 29 Nov 2017 17:44:57 -0800 Received: by devbig102.frc2.facebook.com (Postfix, from userid 4523) id 4B38E428284A; Wed, 29 Nov 2017 17:44:57 -0800 (PST) Smtp-Origin-Hostprefix: devbig From: Song Liu Smtp-Origin-Hostname: devbig102.frc2.facebook.com To: , , , , , , CC: , Song Liu Smtp-Origin-Cluster: frc2c02 Subject: [PATCH v2 5/6] bpf: add option for bpf_load.c to use PERF_TYPE_KPROBE Date: Wed, 29 Nov 2017 17:44:46 -0800 Message-ID: <20171130014447.190229-8-songliubraving@fb.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20171130014447.190229-1-songliubraving@fb.com> References: <20171130014447.190229-1-songliubraving@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-11-29_09:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Function load_and_attach() is updated to be able to create kprobes with either old text based API, or the new PERF_TYPE_KPROBE API. A global flag use_perf_type_probe is added to select between the two APIs. Signed-off-by: Song Liu Reviewed-by: Josef Bacik --- samples/bpf/bpf_load.c | 54 +++++++++++++++++++++++++++++++------------------- samples/bpf/bpf_load.h | 8 ++++++++ 2 files changed, 42 insertions(+), 20 deletions(-) diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c index 2325d7a..872510e 100644 --- a/samples/bpf/bpf_load.c +++ b/samples/bpf/bpf_load.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -42,6 +41,7 @@ int prog_array_fd = -1; struct bpf_map_data map_data[MAX_MAPS]; int map_data_count = 0; +bool use_perf_type_probe = true; static int populate_prog_array(const char *event, int prog_fd) { @@ -70,7 +70,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size) size_t insns_cnt = size / sizeof(struct bpf_insn); enum bpf_prog_type prog_type; char buf[256]; - int fd, efd, err, id; + int fd, efd, err, id = -1; struct perf_event_attr attr = {}; attr.type = PERF_TYPE_TRACEPOINT; @@ -128,7 +128,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size) return populate_prog_array(event, fd); } - if (is_kprobe || is_kretprobe) { + if (!use_perf_type_probe && (is_kprobe || is_kretprobe)) { if (is_kprobe) event += 7; else @@ -169,27 +169,41 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size) strcat(buf, "/id"); } - efd = open(buf, O_RDONLY, 0); - if (efd < 0) { - printf("failed to open event %s\n", event); - return -1; - } - - err = read(efd, buf, sizeof(buf)); - if (err < 0 || err >= sizeof(buf)) { - printf("read from '%s' failed '%s'\n", event, strerror(errno)); - return -1; + if (use_perf_type_probe && (is_kprobe || is_kretprobe)) { + attr.type = PERF_TYPE_KPROBE; + attr.kprobe_func = ptr_to_u64( + event + strlen(is_kprobe ? "kprobe/" : "kretprobe/")); + attr.probe_offset = 0; + attr.config = !!is_kretprobe; + } else { + efd = open(buf, O_RDONLY, 0); + if (efd < 0) { + printf("failed to open event %s\n", event); + return -1; + } + err = read(efd, buf, sizeof(buf)); + if (err < 0 || err >= sizeof(buf)) { + printf("read from '%s' failed '%s'\n", event, + strerror(errno)); + return -1; + } + close(efd); + buf[err] = 0; + id = atoi(buf); + attr.config = id; } - close(efd); - - buf[err] = 0; - id = atoi(buf); - attr.config = id; - efd = sys_perf_event_open(&attr, -1/*pid*/, 0/*cpu*/, -1/*group_fd*/, 0); if (efd < 0) { - printf("event %d fd %d err %s\n", id, efd, strerror(errno)); + if (use_perf_type_probe && (is_kprobe || is_kretprobe)) + printf("k%sprobe %s fd %d err %s\n", + is_kprobe ? "" : "ret", + event + strlen(is_kprobe ? "kprobe/" + : "kretprobe/"), + efd, strerror(errno)); + else + printf("event %d fd %d err %s\n", id, efd, + strerror(errno)); return -1; } event_fd[prog_cnt - 1] = efd; diff --git a/samples/bpf/bpf_load.h b/samples/bpf/bpf_load.h index 7d57a42..e7a8a21 100644 --- a/samples/bpf/bpf_load.h +++ b/samples/bpf/bpf_load.h @@ -2,6 +2,7 @@ #ifndef __BPF_LOAD_H #define __BPF_LOAD_H +#include #include "libbpf.h" #define MAX_MAPS 32 @@ -38,6 +39,8 @@ extern int map_fd[MAX_MAPS]; extern struct bpf_map_data map_data[MAX_MAPS]; extern int map_data_count; +extern bool use_perf_type_probe; + /* parses elf file compiled by llvm .c->.o * . parses 'maps' section and creates maps via BPF syscall * . parses 'license' section and passes it to syscall @@ -59,6 +62,11 @@ struct ksym { char *name; }; +static inline __u64 ptr_to_u64(const void *ptr) +{ + return (__u64) (unsigned long) ptr; +} + int load_kallsyms(void); struct ksym *ksym_search(long key); int set_link_xdp_fd(int ifindex, int fd, __u32 flags); From patchwork Thu Nov 30 01:44:47 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Song Liu X-Patchwork-Id: 842845 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=fb.com header.i=@fb.com header.b="XtufPM0d"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3ynKx60vcjz9s83 for ; Thu, 30 Nov 2017 12:45:46 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753082AbdK3Bpa (ORCPT ); Wed, 29 Nov 2017 20:45:30 -0500 Received: from mx0b-00082601.pphosted.com ([67.231.153.30]:43270 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752616AbdK3BpC (ORCPT ); Wed, 29 Nov 2017 20:45:02 -0500 Received: from pps.filterd (m0001303.ppops.net [127.0.0.1]) by m0001303.ppops.net (8.16.0.21/8.16.0.21) with SMTP id vAU1fxI8011999 for ; Wed, 29 Nov 2017 17:45:01 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fb.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-type; s=facebook; bh=jSgm3+sf6+Z3Zw8TH62IrjqCuzGIJNxb/6KyLVi5bgI=; b=XtufPM0diy7s/au1h6QZpw31IHd8bmbyR1KjwK2JVF04pc9tGtTcvCj6MToHNIXRlVwy GZ5X0cyCQbubf56Mqiynvlix40d/8ITC5cUqis4j+4E799UbesTf/Yq7dVSOg3qDfdHu mFlSDr5UBLRphqkNpG5wkN5Ez21jdBnhacQ= Received: from mail.thefacebook.com ([199.201.64.23]) by m0001303.ppops.net with ESMTP id 2ej762r66f-11 (version=TLSv1 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT) for ; Wed, 29 Nov 2017 17:45:01 -0800 Received: from mx-out.facebook.com (192.168.52.123) by PRN-CHUB13.TheFacebook.com (192.168.16.23) with Microsoft SMTP Server id 14.3.361.1; Wed, 29 Nov 2017 17:44:57 -0800 Received: by devbig102.frc2.facebook.com (Postfix, from userid 4523) id 65D96428284A; Wed, 29 Nov 2017 17:44:57 -0800 (PST) Smtp-Origin-Hostprefix: devbig From: Song Liu Smtp-Origin-Hostname: devbig102.frc2.facebook.com To: , , , , , , CC: , Song Liu Smtp-Origin-Cluster: frc2c02 Subject: [PATCH v2 6/6] bpf: add new test test_many_kprobe Date: Wed, 29 Nov 2017 17:44:47 -0800 Message-ID: <20171130014447.190229-9-songliubraving@fb.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20171130014447.190229-1-songliubraving@fb.com> References: <20171130014447.190229-1-songliubraving@fb.com> X-FB-Internal: Safe MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-11-29_09:, , signatures=0 X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The test compares old text based kprobe API with PERF_TYPE_KPROBE. Here is a sample output of this test: Creating 1000 kprobes with text-based API takes 6.979683 seconds Cleaning 1000 kprobes with text-based API takes 84.897687 seconds Creating 1000 kprobes with PERF_TYPE_KPROBE (function name) takes 5.077558 seconds Cleaning 1000 kprobes with PERF_TYPE_KPROBE (function name) takes 81.241354 seconds Creating 1000 kprobes with PERF_TYPE_KPROBE (function addr) takes 5.218255 seconds Cleaning 1000 kprobes with PERF_TYPE_KPROBE (function addr) takes 80.010731 seconds Signed-off-by: Song Liu Reviewed-by: Josef Bacik --- samples/bpf/Makefile | 3 + samples/bpf/bpf_load.c | 5 +- samples/bpf/bpf_load.h | 4 + samples/bpf/test_many_kprobe_user.c | 182 ++++++++++++++++++++++++++++++++++++ 4 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 samples/bpf/test_many_kprobe_user.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 9b4a66e..ec92f35 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -42,6 +42,7 @@ hostprogs-y += xdp_redirect hostprogs-y += xdp_redirect_map hostprogs-y += xdp_monitor hostprogs-y += syscall_tp +hostprogs-y += test_many_kprobe # Libbpf dependencies LIBBPF := ../../tools/lib/bpf/bpf.o @@ -87,6 +88,7 @@ xdp_redirect-objs := bpf_load.o $(LIBBPF) xdp_redirect_user.o xdp_redirect_map-objs := bpf_load.o $(LIBBPF) xdp_redirect_map_user.o xdp_monitor-objs := bpf_load.o $(LIBBPF) xdp_monitor_user.o syscall_tp-objs := bpf_load.o $(LIBBPF) syscall_tp_user.o +test_many_kprobe-objs := bpf_load.o $(LIBBPF) test_many_kprobe_user.o # Tell kbuild to always build the programs always := $(hostprogs-y) @@ -172,6 +174,7 @@ HOSTLOADLIBES_xdp_redirect += -lelf HOSTLOADLIBES_xdp_redirect_map += -lelf HOSTLOADLIBES_xdp_monitor += -lelf HOSTLOADLIBES_syscall_tp += -lelf +HOSTLOADLIBES_test_many_kprobe += -lelf # Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline: # make samples/bpf/ LLC=~/git/llvm/build/bin/llc CLANG=~/git/llvm/build/bin/clang diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c index 872510e..caba9bc 100644 --- a/samples/bpf/bpf_load.c +++ b/samples/bpf/bpf_load.c @@ -635,9 +635,8 @@ void read_trace_pipe(void) } } -#define MAX_SYMS 300000 -static struct ksym syms[MAX_SYMS]; -static int sym_cnt; +struct ksym syms[MAX_SYMS]; +int sym_cnt; static int ksym_cmp(const void *p1, const void *p2) { diff --git a/samples/bpf/bpf_load.h b/samples/bpf/bpf_load.h index e7a8a21..16bc263 100644 --- a/samples/bpf/bpf_load.h +++ b/samples/bpf/bpf_load.h @@ -67,6 +67,10 @@ static inline __u64 ptr_to_u64(const void *ptr) return (__u64) (unsigned long) ptr; } +#define MAX_SYMS 300000 +extern struct ksym syms[MAX_SYMS]; +extern int sym_cnt; + int load_kallsyms(void); struct ksym *ksym_search(long key); int set_link_xdp_fd(int ifindex, int fd, __u32 flags); diff --git a/samples/bpf/test_many_kprobe_user.c b/samples/bpf/test_many_kprobe_user.c new file mode 100644 index 0000000..1f3ee07 --- /dev/null +++ b/samples/bpf/test_many_kprobe_user.c @@ -0,0 +1,182 @@ +/* Copyright (c) 2017 Facebook + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "libbpf.h" +#include "bpf_load.h" +#include "perf-sys.h" + +#define MAX_KPROBES 1000 + +#define DEBUGFS "/sys/kernel/debug/tracing/" + +int kprobes[MAX_KPROBES] = {0}; +int kprobe_count; +int perf_event_fds[MAX_KPROBES]; +const char license[] = "GPL"; + +static __u64 time_get_ns(void) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000000000ull + ts.tv_nsec; +} + +static int kprobe_api(char *func, void *addr, bool use_new_api) +{ + int efd; + struct perf_event_attr attr = {}; + char buf[256]; + int err, id; + + attr.sample_type = PERF_SAMPLE_RAW; + attr.sample_period = 1; + attr.wakeup_events = 1; + + if (use_new_api) { + attr.type = PERF_TYPE_KPROBE; + if (func) { + attr.kprobe_func = ptr_to_u64(func); + attr.probe_offset = 0; + } else { + attr.kprobe_func = 0; + attr.kprobe_addr = ptr_to_u64(addr); + } + } else { + attr.type = PERF_TYPE_TRACEPOINT; + snprintf(buf, sizeof(buf), + "echo 'p:%s %s' >> /sys/kernel/debug/tracing/kprobe_events", + func, func); + err = system(buf); + if (err < 0) { + printf("failed to create kprobe '%s' error '%s'\n", + func, strerror(errno)); + return -1; + } + + strcpy(buf, DEBUGFS); + strcat(buf, "events/kprobes/"); + strcat(buf, func); + strcat(buf, "/id"); + efd = open(buf, O_RDONLY, 0); + if (efd < 0) { + printf("failed to open event %s\n", func); + return -1; + } + + err = read(efd, buf, sizeof(buf)); + if (err < 0 || err >= sizeof(buf)) { + printf("read from '%s' failed '%s'\n", func, + strerror(errno)); + return -1; + } + + close(efd); + buf[err] = 0; + id = atoi(buf); + attr.config = id; + } + + attr.size = sizeof(attr); + efd = sys_perf_event_open(&attr, -1/*pid*/, 0/*cpu*/, + -1/*group_fd*/, 0); + + return efd; +} + +static int select_kprobes(void) +{ + int fd; + int i; + + load_kallsyms(); + + kprobe_count = 0; + for (i = 0; i < sym_cnt; i++) { + if (strstr(syms[i].name, ".")) + continue; + fd = kprobe_api(syms[i].name, NULL, true); + if (fd < 0) + continue; + close(fd); + kprobes[kprobe_count] = i; + if (++kprobe_count >= MAX_KPROBES) + break; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + int i; + __u64 start_time; + + select_kprobes(); + + /* clean all trace_kprobe */ + i = system("echo \"\" > /sys/kernel/debug/tracing/kprobe_events"); + + /* test text based API */ + start_time = time_get_ns(); + for (i = 0; i < kprobe_count; i++) + perf_event_fds[i] = kprobe_api(syms[kprobes[i]].name, + NULL, false); + printf("Creating %d kprobes with text-based API takes %f seconds\n", + kprobe_count, (time_get_ns() - start_time) / 1000000000.0); + + start_time = time_get_ns(); + for (i = 0; i < kprobe_count; i++) + if (perf_event_fds[i] > 0) + close(perf_event_fds[i]); + i = system("echo \"\" > /sys/kernel/debug/tracing/kprobe_events"); + printf("Cleaning %d kprobes with text-based API takes %f seconds\n", + kprobe_count, (time_get_ns() - start_time) / 1000000000.0); + + /* test PERF_TYPE_KPROBE API, with function names */ + start_time = time_get_ns(); + for (i = 0; i < kprobe_count; i++) + perf_event_fds[i] = kprobe_api(syms[kprobes[i]].name, + NULL, true); + printf("Creating %d kprobes with PERF_TYPE_KPROBE (function name) takes %f seconds\n", + kprobe_count, (time_get_ns() - start_time) / 1000000000.0); + + start_time = time_get_ns(); + for (i = 0; i < kprobe_count; i++) + if (perf_event_fds[i] > 0) + close(perf_event_fds[i]); + printf("Cleaning %d kprobes with PERF_TYPE_KPROBE (function name) takes %f seconds\n", + kprobe_count, (time_get_ns() - start_time) / 1000000000.0); + + /* test PERF_TYPE_KPROBE API, with function address */ + start_time = time_get_ns(); + for (i = 0; i < kprobe_count; i++) + perf_event_fds[i] = kprobe_api( + NULL, (void *)(syms[kprobes[i]].addr), true); + printf("Creating %d kprobes with PERF_TYPE_KPROBE (function addr) takes %f seconds\n", + kprobe_count, (time_get_ns() - start_time) / 1000000000.0); + + start_time = time_get_ns(); + for (i = 0; i < kprobe_count; i++) + if (perf_event_fds[i] > 0) + close(perf_event_fds[i]); + printf("Cleaning %d kprobes with PERF_TYPE_KPROBE (function addr) takes %f seconds\n", + kprobe_count, (time_get_ns() - start_time) / 1000000000.0); + return 0; +}