Received: by 2002:a25:8b12:0:0:0:0:0 with SMTP id i18csp836074ybl; Fri, 9 Aug 2019 14:48:30 -0700 (PDT) X-Google-Smtp-Source: APXvYqxNWFKUvK8BFLmPOJiTZrt1TGpSy4rKJUkY5BLf06In5Z27wE5TMD0xiutUHZIO8tTgsYb/ X-Received: by 2002:a63:6205:: with SMTP id w5mr17767875pgb.199.1565387309938; Fri, 09 Aug 2019 14:48:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1565387309; cv=none; d=google.com; s=arc-20160816; b=dFnx396bsJwAy5YEsB46tmR25paZgalsJudw1TXJkm3rKMv4mcvTv5v7IqPLNZm8XA PHsHYhoHBYrQVeDvrRiJIbWstKM3yjLZN2yBZZepdPW7zwwkfLG+LlJflALIc91HIIjS OMAjcsxCSmPOvjwrY0adfARakWJaCzwUGif8VqtNTe+Hd3jRaf5XMCuYbLTnfWCRzW3v 2oFS98BU8Nl9dQ66eCjBlZuBAevxaV5dpgjFWLfG157k4gd81em90VdNaXoO8qpoWBeD 05xAcV/398fzmmgeogdUXAlGoSq9Xc52HBvoxKdHK0cV2SuKnzxlpC8uohOs47UQT6n3 Erog== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature:dkim-signature; bh=iSQMMbGOyK35Zpi3epLBW+Ua8ZuM4GNSQRMB+9j5e0E=; b=GuyEhHfwoI7ETWUZQExjVEDmWZAD9Ex0zguPLKO9xaV1rfQNCAXHsfg5sjJ1lMhfl2 HWZ7dy68le1unGnMmNxNN89VmiAeTvxIaCDPJgpL9T4Fh2jTsZ/FAZ9RsklvB13zc0gP 6WoaYW3rfSb3NRg5P5ZLuvzMZSJJ8EeduK1yJ9sKVkrGuehhOolsO70qJkKhsBoPDGIt jsVaL0ojI+Irl/DAHXyUdvVkpYDizBuh/yd66amSPedPOlGjsxyNh0nlZg2ET9R28Hbd 5eF8mD+iS9e3ywCylpA+ARQ9f6yWl4bZGBTLuGO3zFSM1bF6cuwlo5e8Y9A2HhBsaNFM 9t5w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@dxuuu.xyz header.s=fm1 header.b=eb5GWFAn; dkim=pass header.i=@messagingengine.com header.s=fm3 header.b=VoxY5jWY; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s24si49318597pgi.450.2019.08.09.14.48.14; Fri, 09 Aug 2019 14:48:29 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@dxuuu.xyz header.s=fm1 header.b=eb5GWFAn; dkim=pass header.i=@messagingengine.com header.s=fm3 header.b=VoxY5jWY; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728261AbfHIVra (ORCPT + 99 others); Fri, 9 Aug 2019 17:47:30 -0400 Received: from new1-smtp.messagingengine.com ([66.111.4.221]:52635 "EHLO new1-smtp.messagingengine.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726137AbfHIVr3 (ORCPT ); Fri, 9 Aug 2019 17:47:29 -0400 Received: from compute4.internal (compute4.nyi.internal [10.202.2.44]) by mailnew.nyi.internal (Postfix) with ESMTP id 846F720C1; Fri, 9 Aug 2019 17:47:28 -0400 (EDT) Received: from mailfrontend2 ([10.202.2.163]) by compute4.internal (MEProxy); Fri, 09 Aug 2019 17:47:28 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=dxuuu.xyz; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; s=fm1; bh=iSQMMbGOyK35Z pi3epLBW+Ua8ZuM4GNSQRMB+9j5e0E=; b=eb5GWFAnuibwE0HmsRAmqCYJXvFVY 1hgQMqOTqGaiTewg+LnPJe9zv+g45Qor+NZOvO202illoM3Eo9eiwpIrSxd91iRX ZNiINxw/vg5umzTcDrnkRjcqaqPzhxu/qffaVSe9KtULe6n3MLmWRk8okpfFXFPZ vKqEmcLHA/hZOMyr/PBpIAyo6n6G22Is5kZ/xF+dAKX4kTbgG67BTTEfZq/LFJxl v4NLwD6NAeijgRx8au+44UCioIbBl9l3dT/fdEDzo/GnywvAlDQQRe0YD19OerwG KqB3Z5UO/Y5EHKMSE418dvq5M4v8J2c0NyGusrUquMaTWWiGRVcf2+c2g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm3; bh=iSQMMbGOyK35Zpi3epLBW+Ua8ZuM4GNSQRMB+9j5e0E=; b=VoxY5jWY Jm97B9wyX1qhIT9TzKWwycNGwwP9AqxUwn6B+hP9uO/INGuGDpnR2QCvTMzQIkBj G1P8JpVCTXhVBJm+XJZQN0u8qZ2DRafbbm6Etx3CgR+XiZh62qFaQANU1GsXb74F zBAq3RMtj81u5Hq13sfeeRVmzw7uHCbBLNXvldb0HoblQisnYS8zyDv/rb73av5a xbwBE9hnmemiNl0sjjmdtEmvYopZM3gCjETcoQyVZPwthUYQJDdWUCiPaKbW1C6M sXO6WI3SEybpyjibSQ+ykmU85iSDMiPQ0u6AhyeA+m3hO2ejm9BSG4a/syd8iLb7 6dVPjgHkoRbRdg== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduvddruddukedgtdegucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucgfrhhlucfvnfffucdljedtmdenucfjughrpefhvf fufffkofgjfhgggfestdekredtredttdenucfhrhhomhepffgrnhhivghlucgiuhcuoegu gihusegugihuuhhurdighiiiqeenucfkphepudelledrvddtuddrieegrddufeeknecurf grrhgrmhepmhgrihhlfhhrohhmpegugihusegugihuuhhurdighiiinecuvehluhhsthgv rhfuihiivgeptd X-ME-Proxy: Received: from dlxu-fedora-R90QNFJV.thefacebook.com (unknown [199.201.64.138]) by mail.messagingengine.com (Postfix) with ESMTPA id D4F50380083; Fri, 9 Aug 2019 17:47:26 -0400 (EDT) From: Daniel Xu To: songliubraving@fb.com, yhs@fb.com, andriin@fb.com, peterz@infraded.org, mingo@redhat.com, acme@kernel.org Cc: Daniel Xu , ast@fb.com, alexander.shishkin@linux.intel.com, jolsa@redhat.com, namhyung@kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 bpf-next 1/4] tracing/probe: Add PERF_EVENT_IOC_QUERY_PROBE ioctl Date: Fri, 9 Aug 2019 14:46:39 -0700 Message-Id: <20190809214642.12078-2-dxu@dxuuu.xyz> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190809214642.12078-1-dxu@dxuuu.xyz> References: <20190809214642.12078-1-dxu@dxuuu.xyz> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org It's useful to know [uk]probe's nmissed and nhit stats. For example with tracing tools, it's important to know when events may have been lost. debugfs currently exposes a control file to get this information, but it is not compatible with probes registered with the perf API. While bpf programs may be able to manually count nhit, there is no way to gather nmissed. In other words, it is currently not possible to retrieve information about FD-based probes. This patch adds a new ioctl that lets users query nmissed (as well as nhit for completeness). We currently only add support for [uk]probes but leave the possibility open for other probes like tracepoint. Signed-off-by: Daniel Xu --- include/linux/trace_events.h | 12 ++++++++++++ include/uapi/linux/perf_event.h | 19 +++++++++++++++++++ kernel/events/core.c | 20 ++++++++++++++++++++ kernel/trace/trace_kprobe.c | 23 +++++++++++++++++++++++ kernel/trace/trace_uprobe.c | 23 +++++++++++++++++++++++ 5 files changed, 97 insertions(+) diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h index 5150436783e8..61558f19696a 100644 --- a/include/linux/trace_events.h +++ b/include/linux/trace_events.h @@ -586,6 +586,12 @@ extern int bpf_get_kprobe_info(const struct perf_event *event, u32 *fd_type, const char **symbol, u64 *probe_offset, u64 *probe_addr, bool perf_type_tracepoint); +extern int perf_kprobe_event_query(struct perf_event *event, void __user *info); +#else +int perf_kprobe_event_query(struct perf_event *event, void __user *info) +{ + return -EOPNOTSUPP; +} #endif #ifdef CONFIG_UPROBE_EVENTS extern int perf_uprobe_init(struct perf_event *event, @@ -594,6 +600,12 @@ extern void perf_uprobe_destroy(struct perf_event *event); extern int bpf_get_uprobe_info(const struct perf_event *event, u32 *fd_type, const char **filename, u64 *probe_offset, bool perf_type_tracepoint); +extern int perf_uprobe_event_query(struct perf_event *event, void __user *info); +#else +int perf_uprobe_event_query(struct perf_event *event, void __user *info) +{ + return -EOPNOTSUPP; +} #endif extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, char *filter_str); diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h index 7198ddd0c6b1..65faa9b2a3b4 100644 --- a/include/uapi/linux/perf_event.h +++ b/include/uapi/linux/perf_event.h @@ -447,6 +447,24 @@ struct perf_event_query_bpf { __u32 ids[0]; }; +/* + * Structure used by below PERF_EVENT_IOC_QUERY_PROBE command + * to query information about the probe attached to the perf + * event. Currently only supports [uk]probes. + */ +struct perf_event_query_probe { + /* + * Set by the kernel to indicate number of times this probe + * was temporarily disabled + */ + __u64 nmissed; + /* + * Set by the kernel to indicate number of times this probe + * was hit + */ + __u64 nhit; +}; + /* * Ioctls that can be done on a perf event fd: */ @@ -462,6 +480,7 @@ struct perf_event_query_bpf { #define PERF_EVENT_IOC_PAUSE_OUTPUT _IOW('$', 9, __u32) #define PERF_EVENT_IOC_QUERY_BPF _IOWR('$', 10, struct perf_event_query_bpf *) #define PERF_EVENT_IOC_MODIFY_ATTRIBUTES _IOW('$', 11, struct perf_event_attr *) +#define PERF_EVENT_IOC_QUERY_PROBE _IOR('$', 12, struct perf_event_query_probe *) enum perf_event_ioc_flags { PERF_IOC_FLAG_GROUP = 1U << 0, diff --git a/kernel/events/core.c b/kernel/events/core.c index 026a14541a38..3e0fe6eaaad0 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -5060,6 +5060,8 @@ static int perf_event_set_filter(struct perf_event *event, void __user *arg); static int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd); static int perf_copy_attr(struct perf_event_attr __user *uattr, struct perf_event_attr *attr); +static int perf_probe_event_query(struct perf_event *event, + void __user *info); static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned long arg) { @@ -5143,6 +5145,10 @@ static long _perf_ioctl(struct perf_event *event, unsigned int cmd, unsigned lon return perf_event_modify_attr(event, &new_attr); } +#if defined(CONFIG_KPROBE_EVENTS) || defined(CONFIG_UPROBE_EVENTS) + case PERF_EVENT_IOC_QUERY_PROBE: + return perf_probe_event_query(event, (void __user *)arg); +#endif default: return -ENOTTY; } @@ -8833,6 +8839,20 @@ static inline void perf_tp_register(void) #endif } +static int perf_probe_event_query(struct perf_event *event, + void __user *info) +{ +#ifdef CONFIG_KPROBE_EVENTS + if (event->attr.type == perf_kprobe.type) + return perf_kprobe_event_query(event, (void __user *)info); +#endif +#ifdef CONFIG_UPROBE_EVENTS + if (event->attr.type == perf_uprobe.type) + return perf_uprobe_event_query(event, (void __user *)info); +#endif + return -EINVAL; +} + static void perf_event_free_filter(struct perf_event *event) { ftrace_profile_free_filter(event); diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 9d483ad9bb6c..a734c2d506be 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -196,6 +196,29 @@ bool trace_kprobe_error_injectable(struct trace_event_call *call) return within_error_injection_list(trace_kprobe_address(tk)); } +int perf_kprobe_event_query(struct perf_event *event, void __user *info) +{ + struct perf_event_query_probe __user *uquery = info; + struct perf_event_query_probe query = {}; + struct trace_event_call *call = event->tp_event; + struct trace_kprobe *tk = (struct trace_kprobe *)call->data; + u64 nmissed, nhit; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user(&query, uquery, sizeof(query))) + return -EFAULT; + + nhit = trace_kprobe_nhit(tk); + nmissed = tk->rp.kp.nmissed; + + if (put_user(nmissed, &uquery->nmissed) || + put_user(nhit, &uquery->nhit)) + return -EFAULT; + + return 0; +} + static int register_kprobe_event(struct trace_kprobe *tk); static int unregister_kprobe_event(struct trace_kprobe *tk); diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 1ceedb9146b1..5f50386ada59 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c @@ -1333,6 +1333,29 @@ static inline void init_trace_event_call(struct trace_uprobe *tu) call->data = tu; } +int perf_uprobe_event_query(struct perf_event *event, void __user *info) +{ + struct perf_event_query_probe __user *uquery = info; + struct perf_event_query_probe query = {}; + struct trace_event_call *call = event->tp_event; + struct trace_uprobe *tu = (struct trace_uprobe *)call->data; + u64 nmissed, nhit; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user(&query, uquery, sizeof(query))) + return -EFAULT; + + nhit = tu->nhit; + nmissed = 0; + + if (put_user(nmissed, &uquery->nmissed) || + put_user(nhit, &uquery->nhit)) + return -EFAULT; + + return 0; +} + static int register_uprobe_event(struct trace_uprobe *tu) { init_trace_event_call(tu); -- 2.20.1