Re: [PATCH v4 2/8] rv: add generic uprobe infrastructure for RV monitors

Gabriele Monaco <[email protected]>
Newsgroups org.kernel.vger.linux-trace-kernel,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
On Wed, 2026-07-08 at 23:38 +0800, [email protected] wrote:
> From: Wen Yang <[email protected]>
>
> +++ b/kernel/trace/rv/Kconfig
> @@ -59,6 +59,13 @@ config RV_PER_TASK_MONITORS
>  	  This option configures the maximum number of per-task RV monitors
> that can run
>  	  simultaneously.
>  
> +config RV_UPROBE
> +	bool
> +	depends on RV && UPROBES
> +	help
> +	  Generic uprobe infrastructure for RV monitors.  Provides path
> +	  resolution, registration, and safe synchronous teardown.

This isn't exposed, it's selected automatically when required, I don't
even think the help text is visible (menuconfig doesn't show it), do we
really need it?

> +
>  source "kernel/trace/rv/monitors/wip/Kconfig"
>  source "kernel/trace/rv/monitors/wwnr/Kconfig"
>  

...

> +++ b/kernel/trace/rv/rv_uprobe.c
> @@ -0,0 +1,104 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Generic uprobe infrastructure for RV monitors.
> + *
> + * struct rv_uprobe embeds struct uprobe_consumer directly.  This is safe
> + * because rv_uprobe_sync() calls uprobe_unregister_sync(), which calls
> + * synchronize_rcu_tasks_trace().  handler_chain() runs under
> + * rcu_read_lock_trace(), so after synchronize_rcu_tasks_trace() returns,
> + * all in-flight handler_chain() iterations, including any pending
> + * uc->cons_node.next reads, have completed on all CPUs.  The caller may
> + * then free the struct containing rv_uprobe immediately.
> + */
> +#include <linux/dcache.h>
> +#include <linux/fs.h>
> +#include <linux/namei.h>
> +#include <linux/uprobes.h>
> +#include <rv/rv_uprobe.h>
> +
> +/**
> + * rv_uprobe_register - initialise and register an uprobe
> + */
> +int rv_uprobe_register(const char *binpath, loff_t offset, struct rv_uprobe
> *p)
> +{
> +	struct inode *inode;
> +	struct path path;
> +	int ret;
> +
> +	if (!p->uc.handler && !p->uc.ret_handler)
> +		return -EINVAL;

uprobe_register() does this already, do we need it here too?

> +
> +	ret = kern_path(binpath, LOOKUP_FOLLOW, &path);
> +	if (ret)
> +		return ret;
> +
> +	if (!d_is_reg(path.dentry)) {
> +		path_put(&path);
> +		return -EINVAL;
> +	}
> +
> +	inode = d_real_inode(path.dentry);
> +	p->inode = inode;
> +
> +	/*
> +	 * uprobe_register() requires the inode (and mount) to remain
> +	 * referenced across the call.  Keep the path alive until after
> +	 * uprobe_register() has stored its own reference, then release it.
> +	 */
> +	p->uprobe = uprobe_register(inode, offset, 0, &p->uc);
> +	path_put(&path);

I believe I was mistaken here, as sashiko pointed out, uprobe_register()
doesn't keep a reference to the inode, (explicitly stated in it's docs:
"Caller of uprobe_register() is required to keep @inode (and the
containing mount) referenced.").

We should probably revert back to holding path instead of inode and
putting it after synchronous cleanup. That's also what BPF does.

Thanks,
Gabriele

> +	if (IS_ERR(p->uprobe)) {
> +		ret = PTR_ERR(p->uprobe);
> +		p->uprobe = NULL;
> +		p->inode = NULL;
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(rv_uprobe_register);
> +
> +/**
> + * rv_uprobe_is_registered - test whether an uprobe is currently active
> + */
> +bool rv_uprobe_is_registered(const struct rv_uprobe *p)
> +{
> +	return p && p->uprobe;
> +}
> +EXPORT_SYMBOL_GPL(rv_uprobe_is_registered);
> +
> +/**
> + * rv_uprobe_unregister - synchronously unregister a uprobe
> + */
> +void rv_uprobe_unregister(struct rv_uprobe *p)
> +{
> +	if (!p || !p->uprobe)
> +		return;
> +
> +	rv_uprobe_unregister_nosync(p);
> +	rv_uprobe_sync();
> +}
> +EXPORT_SYMBOL_GPL(rv_uprobe_unregister);
> +
> +/**
> + * rv_uprobe_unregister_nosync - dequeue an uprobe without waiting
> + */
> +void rv_uprobe_unregister_nosync(struct rv_uprobe *p)
> +{
> +	if (!p || !p->uprobe)
> +		return;
> +
> +	uprobe_unregister_nosync(p->uprobe, &p->uc);
> +	p->uprobe = NULL;
> +	p->inode = NULL;
> +}
> +EXPORT_SYMBOL_GPL(rv_uprobe_unregister_nosync);
> +
> +/**
> + * rv_uprobe_sync - wait for all in-flight uprobe handlers to complete
> + */
> +void rv_uprobe_sync(void)
> +{
> +	uprobe_unregister_sync();
> +}
> +EXPORT_SYMBOL_GPL(rv_uprobe_sync);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.