From: Vincent Donnefort <vdonnefort@google.com>
To: rostedt@goodmis.org, mhiramat@kernel.org,
linux-trace-kernel@vger.kernel.org
Cc: mathieu.desnoyers@efficios.com, kernel-team@android.com,
linux-kernel@vger.kernel.org,
Vincent Donnefort <vdonnefort@google.com>
Subject: [PATCH v4 02/18] tracing/remotes: Release tracefs,eventfs on registration failure
Date: Tue, 4 Aug 2026 15:03:17 +0100 [thread overview]
Message-ID: <20260804140333.797210-3-vdonnefort@google.com> (raw)
In-Reply-To: <20260804140333.797210-1-vdonnefort@google.com>
In trace_remote_register(), if registration of events or the init
callback fails, the created tracefs and eventfs directories are leaked.
Release the entire eventfs and tracefs hierarchy on trace_remote
registration failure.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
diff --git a/kernel/trace/trace_remote.c b/kernel/trace/trace_remote.c
index ce2d517183b7..0384277070b9 100644
--- a/kernel/trace/trace_remote.c
+++ b/kernel/trace/trace_remote.c
@@ -45,7 +45,8 @@ struct trace_remote {
struct trace_buffer *trace_buffer;
struct trace_buffer_desc *trace_buffer_desc;
struct dentry *dentry;
- struct eventfs_inode *eventfs;
+ struct eventfs_inode *eventfs_root;
+ struct eventfs_inode *eventfs_subdir;
struct remote_event *events;
unsigned long nr_events;
unsigned long trace_buffer_size;
@@ -60,6 +61,7 @@ struct trace_remote {
static DEFINE_MUTEX(trace_remotes_lock);
static LIST_HEAD(trace_remotes);
+static struct dentry *trace_remotes_root;
static bool trace_remote_loaded(struct trace_remote *remote)
{
@@ -865,23 +867,21 @@ static const struct file_operations trace_fops = {
static int trace_remote_init_tracefs(const char *name, struct trace_remote *remote)
{
struct dentry *remote_d, *percpu_d, *d;
- static struct dentry *root;
- static DEFINE_MUTEX(lock);
bool root_inited = false;
int cpu;
- guard(mutex)(&lock);
+ lockdep_assert_held(&trace_remotes_lock);
- if (!root) {
- root = tracefs_create_dir(TRACEFS_DIR, NULL);
- if (!root) {
+ if (!trace_remotes_root) {
+ trace_remotes_root = tracefs_create_dir(TRACEFS_DIR, NULL);
+ if (!trace_remotes_root) {
pr_err("Failed to create tracefs dir "TRACEFS_DIR"\n");
return -ENOMEM;
}
root_inited = true;
}
- remote_d = tracefs_create_dir(name, root);
+ remote_d = tracefs_create_dir(name, trace_remotes_root);
if (!remote_d) {
pr_err("Failed to create tracefs dir "TRACEFS_DIR"%s/\n", name);
goto err;
@@ -939,8 +939,8 @@ static int trace_remote_init_tracefs(const char *name, struct trace_remote *remo
err:
if (root_inited) {
- tracefs_remove(root);
- root = NULL;
+ tracefs_remove(trace_remotes_root);
+ trace_remotes_root = NULL;
} else {
tracefs_remove(remote_d);
}
@@ -948,8 +948,26 @@ static int trace_remote_init_tracefs(const char *name, struct trace_remote *remo
return -ENOMEM;
}
+static void trace_remote_remove_tracefs(struct trace_remote *remote)
+{
+ lockdep_assert_held(&trace_remotes_lock);
+
+ if (!remote->dentry)
+ return;
+
+ tracefs_remove(remote->dentry);
+ remote->dentry = NULL;
+
+ if (!list_empty(&trace_remotes))
+ return;
+
+ tracefs_remove(trace_remotes_root);
+ trace_remotes_root = NULL;
+}
+
static int trace_remote_register_events(const char *remote_name, struct trace_remote *remote,
struct remote_event *events, size_t nr_events);
+static void trace_remote_unregister_events(struct trace_remote *remote);
/**
* trace_remote_register() - Register a Tracefs remote
@@ -972,10 +990,9 @@ static int trace_remote_register_events(const char *remote_name, struct trace_re
int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv,
struct remote_event *events, size_t nr_events)
{
- struct trace_remote *remote;
+ struct trace_remote *remote __free(kfree) = kzalloc_obj(*remote);
int ret;
- remote = kzalloc_obj(*remote);
if (!remote)
return -ENOMEM;
@@ -986,13 +1003,15 @@ int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs,
mutex_init(&remote->lock);
init_rwsem(&remote->reader_lock);
- if (trace_remote_init_tracefs(name, remote)) {
- kfree(remote);
- return -ENOMEM;
- }
+ guard(mutex)(&trace_remotes_lock);
+
+ ret = trace_remote_init_tracefs(name, remote);
+ if (ret)
+ return ret;
ret = trace_remote_register_events(name, remote, events, nr_events);
if (ret) {
+ trace_remote_remove_tracefs(remote);
pr_err("Failed to register events for trace remote '%s' (%d)\n",
name, ret);
return ret;
@@ -1000,13 +1019,16 @@ int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs,
ret = cbs->init ? cbs->init(remote->dentry, priv) : 0;
if (ret) {
+ trace_remote_unregister_events(remote);
+ trace_remote_remove_tracefs(remote);
pr_err("Init failed for trace remote '%s' (%d)\n", name, ret);
- } else {
- guard(mutex)(&trace_remotes_lock);
- list_add(&remote->node, &trace_remotes);
+ return ret;
}
- return ret;
+ list_add(&remote->node, &trace_remotes);
+ retain_and_null_ptr(remote);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(trace_remote_register);
@@ -1345,7 +1367,6 @@ static int remote_events_dir_callback(const char *name, umode_t *mode, void **da
static int trace_remote_init_eventfs(const char *remote_name, struct trace_remote *remote,
struct remote_event *evt)
{
- struct eventfs_inode *eventfs = remote->eventfs;
static struct eventfs_entry dir_entries[] = {
{
.name = "enable",
@@ -1370,35 +1391,37 @@ static int trace_remote_init_eventfs(const char *remote_name, struct trace_remot
.callback = remote_event_callback,
}
};
- bool eventfs_create = false;
+ struct eventfs_inode *eventfs_root, *eventfs_subdir, *e;
- if (!eventfs) {
- eventfs = eventfs_create_events_dir("events", remote->dentry, dir_entries,
- ARRAY_SIZE(dir_entries), remote);
- if (IS_ERR(eventfs))
- return PTR_ERR(eventfs);
+ eventfs_root = remote->eventfs_root;
+ eventfs_subdir = remote->eventfs_subdir;
+ if (!eventfs_root) {
+ eventfs_root = eventfs_create_events_dir("events", remote->dentry, dir_entries,
+ ARRAY_SIZE(dir_entries), remote);
+ if (IS_ERR(eventfs_root))
+ return PTR_ERR(eventfs_root);
/*
* Create similar hierarchy as local events even if a single system is supported at
* the moment
*/
- eventfs = eventfs_create_dir(remote_name, eventfs, NULL, 0, NULL);
- if (IS_ERR(eventfs))
- return PTR_ERR(eventfs);
-
- remote->eventfs = eventfs;
- eventfs_create = true;
- }
-
- eventfs = eventfs_create_dir(evt->name, eventfs, entries, ARRAY_SIZE(entries), evt);
- if (IS_ERR(eventfs)) {
- if (eventfs_create) {
- eventfs_remove_events_dir(remote->eventfs);
- remote->eventfs = NULL;
+ eventfs_subdir = eventfs_create_dir(remote_name, eventfs_root, NULL, 0, NULL);
+ if (IS_ERR(eventfs_subdir)) {
+ eventfs_remove_events_dir(eventfs_root);
+ return PTR_ERR(eventfs_subdir);
}
- return PTR_ERR(eventfs);
}
+ e = eventfs_create_dir(evt->name, eventfs_subdir, entries, ARRAY_SIZE(entries), evt);
+ if (IS_ERR(e)) {
+ if (!remote->eventfs_root)
+ eventfs_remove_events_dir(eventfs_root);
+ return PTR_ERR(e);
+ }
+
+ remote->eventfs_root = eventfs_root;
+ remote->eventfs_subdir = eventfs_subdir;
+
return 0;
}
@@ -1413,11 +1436,11 @@ static int trace_remote_attach_events(struct trace_remote *remote, struct remote
if (evt->remote)
return -EEXIST;
- evt->remote = remote;
-
/* We need events to be sorted for efficient lookup */
if (i && evt->id <= events[i - 1].id)
return -EINVAL;
+
+ evt->remote = remote;
}
remote->events = events;
@@ -1426,14 +1449,33 @@ static int trace_remote_attach_events(struct trace_remote *remote, struct remote
return 0;
}
+static void trace_remote_detach_events(struct trace_remote *remote, struct remote_event *events,
+ size_t nr_events)
+{
+ int i;
+
+ for (i = 0; i < nr_events; i++) {
+ struct remote_event *evt = &events[i];
+
+ if (evt->remote == remote)
+ evt->remote = NULL;
+ }
+
+ remote->events = NULL;
+ remote->nr_events = 0;
+}
+
static int trace_remote_register_events(const char *remote_name, struct trace_remote *remote,
struct remote_event *events, size_t nr_events)
{
int i, ret;
ret = trace_remote_attach_events(remote, events, nr_events);
- if (ret)
+ if (ret) {
+ /* It is safe to call detach on a half-registered array */
+ trace_remote_detach_events(remote, events, nr_events);
return ret;
+ }
for (i = 0; i < nr_events; i++) {
struct remote_event *evt = &events[i];
@@ -1447,6 +1489,13 @@ static int trace_remote_register_events(const char *remote_name, struct trace_re
return 0;
}
+static void trace_remote_unregister_events(struct trace_remote *remote)
+{
+ trace_remote_detach_events(remote, remote->events, remote->nr_events);
+ if (remote->eventfs_root)
+ eventfs_remove_events_dir(remote->eventfs_root);
+}
+
static int __cmp_events(const void *key, const void *data)
{
const struct remote_event *evt = data;
--
2.55.0.571.g244d577d93-goog
next prev parent reply other threads:[~2026-08-04 14:03 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-04 14:03 [PATCH v4 00/18] tracing/remotes: Add printk, dump_on_panic and boot parameters Vincent Donnefort
2026-08-04 14:03 ` [PATCH v4 01/18] tracing/remotes: Gate tracefs files opening on trace remote registration Vincent Donnefort
2026-08-04 14:03 ` Vincent Donnefort [this message]
2026-08-04 14:03 ` [PATCH v4 03/18] tracing/remotes: Use kstrtobool for boolean tracefs files Vincent Donnefort
2026-08-04 14:03 ` [PATCH v4 04/18] tracing/remotes: Use a single per-remote polling work Vincent Donnefort
2026-08-04 14:03 ` [PATCH v4 05/18] tracing/simple_ring_buffer: Add support for compressed length Vincent Donnefort
2026-08-04 14:03 ` [PATCH v4 06/18] tracing/remotes: Add dmesg tracefs file Vincent Donnefort
2026-08-10 22:42 ` Steven Rostedt
2026-08-11 9:09 ` Vincent Donnefort
2026-08-04 14:03 ` [PATCH v4 07/18] tracing/remotes: selftests: Add a test for the " Vincent Donnefort
2026-08-10 22:46 ` Steven Rostedt
2026-08-04 14:03 ` [PATCH v4 08/18] tracing/remotes: selftests: Prefix hypervisor folder Vincent Donnefort
2026-08-04 14:03 ` [PATCH v4 09/18] ring-buffer: Use irqsave for the reader lock in ring_buffer_poll_remote Vincent Donnefort
2026-08-04 14:03 ` [PATCH v4 10/18] ring-buffer: Use panic-friendly locking in ring_buffer_iter interface Vincent Donnefort
2026-08-04 14:03 ` [PATCH v4 11/18] ring-buffer: Add ring_buffer_read_remote_meta_page() Vincent Donnefort
2026-08-04 14:03 ` [PATCH v4 12/18] ring-buffer: Add kerneldoc for ring_buffer_poll_remote Vincent Donnefort
2026-08-04 14:03 ` [PATCH v4 13/18] tracing/remotes: Add dump_on_panic tracefs file Vincent Donnefort
2026-08-04 14:03 ` [PATCH v4 14/18] tracing/remotes: selftests: Add a test for the " Vincent Donnefort
2026-08-04 14:03 ` [PATCH v4 15/18] tracing/remotes: Add poll_ms " Vincent Donnefort
2026-08-04 14:03 ` [PATCH v4 16/18] tracing/remotes: Add trace_remote cmdline options Vincent Donnefort
2026-08-04 14:03 ` [PATCH v4 17/18] Documentation: tracing/remotes: Add detailed tracefs layout Vincent Donnefort
2026-08-04 14:03 ` [PATCH v4 18/18] Documentation/kernel-parameters: Add trace_remote Vincent Donnefort
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=20260804140333.797210-3-vdonnefort@google.com \
--to=vdonnefort@google.com \
--cc=kernel-team@android.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mathieu.desnoyers@efficios.com \
--cc=mhiramat@kernel.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.