[PATCH perf/core 03/11] perf: Add support to attach standard unique uprobe

Jiri Olsa posted 11 patches 1 month ago
[PATCH perf/core 03/11] perf: Add support to attach standard unique uprobe
Posted by Jiri Olsa 1 month ago
Adding support to attach unique probe through perf uprobe pmu.

Adding new 'unique' format attribute that allows to pass the
request to create unique uprobe the uprobe consumer.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 include/linux/trace_events.h    | 2 +-
 kernel/events/core.c            | 8 ++++++--
 kernel/trace/trace_event_perf.c | 4 ++--
 kernel/trace/trace_probe.h      | 2 +-
 kernel/trace/trace_uprobe.c     | 9 +++++----
 5 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
index 04307a19cde3..1d35727fda27 100644
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -877,7 +877,7 @@ extern int bpf_get_kprobe_info(const struct perf_event *event,
 #endif
 #ifdef CONFIG_UPROBE_EVENTS
 extern int  perf_uprobe_init(struct perf_event *event,
-			     unsigned long ref_ctr_offset, bool is_retprobe);
+			     unsigned long ref_ctr_offset, bool is_retprobe, bool is_unique);
 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,
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 28de3baff792..10a9341c638f 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -11046,11 +11046,13 @@ EXPORT_SYMBOL_GPL(perf_tp_event);
  */
 enum perf_probe_config {
 	PERF_PROBE_CONFIG_IS_RETPROBE = 1U << 0,  /* [k,u]retprobe */
+	PERF_PROBE_CONFIG_IS_UNIQUE   = 1U << 1,  /* unique uprobe */
 	PERF_UPROBE_REF_CTR_OFFSET_BITS = 32,
 	PERF_UPROBE_REF_CTR_OFFSET_SHIFT = 64 - PERF_UPROBE_REF_CTR_OFFSET_BITS,
 };
 
 PMU_FORMAT_ATTR(retprobe, "config:0");
+PMU_FORMAT_ATTR(unique, "config:1");
 #endif
 
 #ifdef CONFIG_KPROBE_EVENTS
@@ -11114,6 +11116,7 @@ PMU_FORMAT_ATTR(ref_ctr_offset, "config:32-63");
 
 static struct attribute *uprobe_attrs[] = {
 	&format_attr_retprobe.attr,
+	&format_attr_unique.attr,
 	&format_attr_ref_ctr_offset.attr,
 	NULL,
 };
@@ -11144,7 +11147,7 @@ static int perf_uprobe_event_init(struct perf_event *event)
 {
 	int err;
 	unsigned long ref_ctr_offset;
-	bool is_retprobe;
+	bool is_retprobe, is_unique;
 
 	if (event->attr.type != perf_uprobe.type)
 		return -ENOENT;
@@ -11159,8 +11162,9 @@ static int perf_uprobe_event_init(struct perf_event *event)
 		return -EOPNOTSUPP;
 
 	is_retprobe = event->attr.config & PERF_PROBE_CONFIG_IS_RETPROBE;
+	is_unique = event->attr.config & PERF_PROBE_CONFIG_IS_UNIQUE;
 	ref_ctr_offset = event->attr.config >> PERF_UPROBE_REF_CTR_OFFSET_SHIFT;
-	err = perf_uprobe_init(event, ref_ctr_offset, is_retprobe);
+	err = perf_uprobe_init(event, ref_ctr_offset, is_retprobe, is_unique);
 	if (err)
 		return err;
 
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index a6bb7577e8c5..b4383ab21d88 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -296,7 +296,7 @@ void perf_kprobe_destroy(struct perf_event *p_event)
 
 #ifdef CONFIG_UPROBE_EVENTS
 int perf_uprobe_init(struct perf_event *p_event,
-		     unsigned long ref_ctr_offset, bool is_retprobe)
+		     unsigned long ref_ctr_offset, bool is_retprobe, bool is_unique)
 {
 	int ret;
 	char *path = NULL;
@@ -317,7 +317,7 @@ int perf_uprobe_init(struct perf_event *p_event,
 	}
 
 	tp_event = create_local_trace_uprobe(path, p_event->attr.probe_offset,
-					     ref_ctr_offset, is_retprobe);
+					     ref_ctr_offset, is_retprobe, is_unique);
 	if (IS_ERR(tp_event)) {
 		ret = PTR_ERR(tp_event);
 		goto out;
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 842383fbc03b..92870b98b296 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -469,7 +469,7 @@ 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,
-			  unsigned long ref_ctr_offset, bool is_return);
+			  unsigned long ref_ctr_offset, bool is_return, bool is_unique);
 extern void destroy_local_trace_uprobe(struct trace_event_call *event_call);
 #endif
 extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 8b0bcc0d8f41..4ecb6083f949 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -333,7 +333,7 @@ trace_uprobe_primary_from_call(struct trace_event_call *call)
  * Allocate new trace_uprobe and initialize it (including uprobes).
  */
 static struct trace_uprobe *
-alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
+alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret, bool is_unique)
 {
 	struct trace_uprobe *tu;
 	int ret;
@@ -356,6 +356,7 @@ alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
 	tu->consumer.handler = uprobe_dispatcher;
 	if (is_ret)
 		tu->consumer.ret_handler = uretprobe_dispatcher;
+	tu->consumer.is_unique = is_unique;
 	init_trace_uprobe_filter(tu->tp.event->filter);
 	return tu;
 
@@ -688,7 +689,7 @@ static int __trace_uprobe_create(int argc, const char **argv)
 	argc -= 2;
 	argv += 2;
 
-	tu = alloc_trace_uprobe(group, event, argc, is_return);
+	tu = alloc_trace_uprobe(group, event, argc, is_return, false /* unique */);
 	if (IS_ERR(tu)) {
 		ret = PTR_ERR(tu);
 		/* This must return -ENOMEM otherwise there is a bug */
@@ -1636,7 +1637,7 @@ static int unregister_uprobe_event(struct trace_uprobe *tu)
 #ifdef CONFIG_PERF_EVENTS
 struct trace_event_call *
 create_local_trace_uprobe(char *name, unsigned long offs,
-			  unsigned long ref_ctr_offset, bool is_return)
+			  unsigned long ref_ctr_offset, bool is_return, bool is_unique)
 {
 	enum probe_print_type ptype;
 	struct trace_uprobe *tu;
@@ -1658,7 +1659,7 @@ create_local_trace_uprobe(char *name, unsigned long offs,
 	 * duplicated name "DUMMY_EVENT" here.
 	 */
 	tu = alloc_trace_uprobe(UPROBE_EVENT_SYSTEM, "DUMMY_EVENT", 0,
-				is_return);
+				is_return, is_unique);
 
 	if (IS_ERR(tu)) {
 		pr_info("Failed to allocate trace_uprobe.(%d)\n",
-- 
2.51.0
Re: [PATCH perf/core 03/11] perf: Add support to attach standard unique uprobe
Posted by Oleg Nesterov 4 weeks, 1 day ago
Slightly off-topic, but

On 09/02, Jiri Olsa wrote:
>
> @@ -11144,7 +11147,7 @@ static int perf_uprobe_event_init(struct perf_event *event)
>  {
>  	int err;
>  	unsigned long ref_ctr_offset;
> -	bool is_retprobe;
> +	bool is_retprobe, is_unique;
>  
>  	if (event->attr.type != perf_uprobe.type)
>  		return -ENOENT;
> @@ -11159,8 +11162,9 @@ static int perf_uprobe_event_init(struct perf_event *event)
>  		return -EOPNOTSUPP;
>  
>  	is_retprobe = event->attr.config & PERF_PROBE_CONFIG_IS_RETPROBE;
> +	is_unique = event->attr.config & PERF_PROBE_CONFIG_IS_UNIQUE;
>  	ref_ctr_offset = event->attr.config >> PERF_UPROBE_REF_CTR_OFFSET_SHIFT;
> -	err = perf_uprobe_init(event, ref_ctr_offset, is_retprobe);
> +	err = perf_uprobe_init(event, ref_ctr_offset, is_retprobe, is_unique);

I am wondering why (with or without this change) perf_uprobe_init() needs
the additional arguments besides "event". It can look at event->attr.config
itself?

Same for perf_kprobe_init()...

Oleg.
Re: [PATCH perf/core 03/11] perf: Add support to attach standard unique uprobe
Posted by Jiri Olsa 4 weeks, 1 day ago
On Wed, Sep 03, 2025 at 01:59:13PM +0200, Oleg Nesterov wrote:
> Slightly off-topic, but
> 
> On 09/02, Jiri Olsa wrote:
> >
> > @@ -11144,7 +11147,7 @@ static int perf_uprobe_event_init(struct perf_event *event)
> >  {
> >  	int err;
> >  	unsigned long ref_ctr_offset;
> > -	bool is_retprobe;
> > +	bool is_retprobe, is_unique;
> >  
> >  	if (event->attr.type != perf_uprobe.type)
> >  		return -ENOENT;
> > @@ -11159,8 +11162,9 @@ static int perf_uprobe_event_init(struct perf_event *event)
> >  		return -EOPNOTSUPP;
> >  
> >  	is_retprobe = event->attr.config & PERF_PROBE_CONFIG_IS_RETPROBE;
> > +	is_unique = event->attr.config & PERF_PROBE_CONFIG_IS_UNIQUE;
> >  	ref_ctr_offset = event->attr.config >> PERF_UPROBE_REF_CTR_OFFSET_SHIFT;
> > -	err = perf_uprobe_init(event, ref_ctr_offset, is_retprobe);
> > +	err = perf_uprobe_init(event, ref_ctr_offset, is_retprobe, is_unique);
> 
> I am wondering why (with or without this change) perf_uprobe_init() needs
> the additional arguments besides "event". It can look at event->attr.config
> itself?
> 
> Same for perf_kprobe_init()...

I think that's because we define enum perf_probe_config together
with PMU_FORMAT_ATTRs and code for attr->config parsing, which
makes sense to me

otherwise I think we could pass perf_event_attr all the way to
create_local_trace_[ku]probe 

jirka
Re: [PATCH perf/core 03/11] perf: Add support to attach standard unique uprobe
Posted by Oleg Nesterov 4 weeks, 1 day ago
On 09/03, Jiri Olsa wrote:
>
> On Wed, Sep 03, 2025 at 01:59:13PM +0200, Oleg Nesterov wrote:
> >
> > I am wondering why (with or without this change) perf_uprobe_init() needs
> > the additional arguments besides "event". It can look at event->attr.config
> > itself?
> >
> > Same for perf_kprobe_init()...
>
> I think that's because we define enum perf_probe_config together
> with PMU_FORMAT_ATTRs and code for attr->config parsing, which
> makes sense to me

Ah, and "enum perf_probe_config" is not exported...

Thanks, please forget then.

Oleg.
Re: [PATCH perf/core 03/11] perf: Add support to attach standard unique uprobe
Posted by kernel test robot 1 month ago
Hi Jiri,

kernel test robot noticed the following build warnings:

[auto build test WARNING on tip/perf/core]
[also build test WARNING on next-20250902]
[cannot apply to bpf-next/net bpf-next/master bpf/master perf-tools-next/perf-tools-next perf-tools/perf-tools trace/for-next linus/master acme/perf/core v6.17-rc4]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Jiri-Olsa/uprobes-Add-unique-flag-to-uprobe-consumer/20250902-224356
base:   tip/perf/core
patch link:    https://lore.kernel.org/r/20250902143504.1224726-4-jolsa%40kernel.org
patch subject: [PATCH perf/core 03/11] perf: Add support to attach standard unique uprobe
config: x86_64-randconfig-001-20250903 (https://download.01.org/0day-ci/archive/20250903/202509031116.yIcyjvUx-lkp@intel.com/config)
compiler: gcc-11 (Debian 11.3.0-12) 11.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250903/202509031116.yIcyjvUx-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202509031116.yIcyjvUx-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from include/linux/trace_events.h:10,
                    from include/trace/syscall.h:7,
                    from include/linux/syscalls.h:95,
                    from kernel/events/core.c:34:
>> include/linux/perf_event.h:2073:32: warning: 'format_attr_unique' defined but not used [-Wunused-variable]
    2073 | static struct device_attribute format_attr_##_name = __ATTR_RO(_name)
         |                                ^~~~~~~~~~~~
   kernel/events/core.c:11055:1: note: in expansion of macro 'PMU_FORMAT_ATTR'
   11055 | PMU_FORMAT_ATTR(unique, "config:1");
         | ^~~~~~~~~~~~~~~


vim +/format_attr_unique +2073 include/linux/perf_event.h

b6c00fb9949fbd0 Kan Liang 2023-01-04  2069  
b6c00fb9949fbd0 Kan Liang 2023-01-04  2070  #define PMU_FORMAT_ATTR(_name, _format)					\
b6c00fb9949fbd0 Kan Liang 2023-01-04  2071  	PMU_FORMAT_ATTR_SHOW(_name, _format)				\
641cc938815dfd0 Jiri Olsa 2012-03-15  2072  									\
641cc938815dfd0 Jiri Olsa 2012-03-15 @2073  static struct device_attribute format_attr_##_name = __ATTR_RO(_name)
641cc938815dfd0 Jiri Olsa 2012-03-15  2074  

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Re: [PATCH perf/core 03/11] perf: Add support to attach standard unique uprobe
Posted by Alexei Starovoitov 1 month ago
On Tue, Sep 2, 2025 at 7:38 AM Jiri Olsa <jolsa@kernel.org> wrote:
>
> Adding support to attach unique probe through perf uprobe pmu.
>
> Adding new 'unique' format attribute that allows to pass the
> request to create unique uprobe the uprobe consumer.
>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> ---
>  include/linux/trace_events.h    | 2 +-
>  kernel/events/core.c            | 8 ++++++--
>  kernel/trace/trace_event_perf.c | 4 ++--
>  kernel/trace/trace_probe.h      | 2 +-
>  kernel/trace/trace_uprobe.c     | 9 +++++----
>  5 files changed, 15 insertions(+), 10 deletions(-)
>
> diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
> index 04307a19cde3..1d35727fda27 100644
> --- a/include/linux/trace_events.h
> +++ b/include/linux/trace_events.h
> @@ -877,7 +877,7 @@ extern int bpf_get_kprobe_info(const struct perf_event *event,
>  #endif
>  #ifdef CONFIG_UPROBE_EVENTS
>  extern int  perf_uprobe_init(struct perf_event *event,
> -                            unsigned long ref_ctr_offset, bool is_retprobe);
> +                            unsigned long ref_ctr_offset, bool is_retprobe, bool is_unique);

In bpf land we don't allow multiple bool arguments any more.
It makes callsites hard to read/review/maintain.
Here I recommend to use enum flags as well.