* [for-linus][PATCH 01/12] tracing: Have show_event_filters/triggers files take trace array ref
[not found] <20260905200827.773347757@kernel.org>
@ 2026-09-05 20:08 ` Steven Rostedt
2026-09-05 20:08 ` [for-linus][PATCH 02/12] ftrace: Take trace_array reference before accessing its ftrace_ops Steven Rostedt
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Steven Rostedt @ 2026-09-05 20:08 UTC (permalink / raw)
To: linux-kernel
Cc: Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
Vincent Donnefort, stable, Farhad Alemi, Aaron Tomlin
From: Steven Rostedt <rostedt@goodmis.org>
The newly added files show_event_filters and show_event_triggers that show
all filters or triggers that are set within the trace array do not take a
reference for the trace array it is showing. Without taking a reference,
the trace_array may be freed via "rmdir" while a task is reading one of
theses files. Those files iterate all the events within an instance
(trace_array) and nothing prevents that instance from being freed while
its data is being read. This causes a use-after-free crash.
Have the open of both those files take the trace_array reference via the
trace_array_get() that prevents the trace_array from being freed while the
files are opened.
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260828094153.17b95037@gandalf.local.home
Fixes: 729757b96a662 ("tracing: Add show_event_filters to expose active event filters")
Fixes: 6a80838814eea ("tracing: Add show_event_triggers to expose active event triggers")
Reported-by: Farhad Alemi <farhad.alemi@berkeley.edu>
Closes: https://lore.kernel.org/all/CA+0ovCjerKZJLwXScM9bF2ga2rLi4_XOpUfK41NDbENpeu98jA@mail.gmail.com/
Reviewed-by: Aaron Tomlin <atomlin@atomlin.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
kernel/trace/trace_events.c | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 1d39eaf6a0f7..9dbc2441763b 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2736,14 +2736,14 @@ static const struct file_operations ftrace_show_event_filters_fops = {
.open = ftrace_event_show_filters_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = ftrace_event_release,
};
static const struct file_operations ftrace_show_event_triggers_fops = {
.open = ftrace_event_show_triggers_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = ftrace_event_release,
};
static const struct file_operations ftrace_set_event_pid_fops = {
@@ -2908,7 +2908,17 @@ ftrace_event_set_open(struct inode *inode, struct file *file)
static int
ftrace_event_show_filters_open(struct inode *inode, struct file *file)
{
- return ftrace_event_open(inode, file, &show_show_event_filters_seq_ops);
+ struct trace_array *tr = inode->i_private;
+ int ret;
+
+ ret = tracing_check_open_get_tr(tr);
+ if (ret)
+ return ret;
+
+ ret = ftrace_event_open(inode, file, &show_show_event_filters_seq_ops);
+ if (ret < 0)
+ trace_array_put(tr);
+ return ret;
}
/**
@@ -2922,7 +2932,17 @@ ftrace_event_show_filters_open(struct inode *inode, struct file *file)
static int
ftrace_event_show_triggers_open(struct inode *inode, struct file *file)
{
- return ftrace_event_open(inode, file, &show_show_event_triggers_seq_ops);
+ struct trace_array *tr = inode->i_private;
+ int ret;
+
+ ret = tracing_check_open_get_tr(tr);
+ if (ret)
+ return ret;
+
+ ret = ftrace_event_open(inode, file, &show_show_event_triggers_seq_ops);
+ if (ret < 0)
+ trace_array_put(tr);
+ return ret;
}
static int
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [for-linus][PATCH 02/12] ftrace: Take trace_array reference before accessing its ftrace_ops
[not found] <20260905200827.773347757@kernel.org>
2026-09-05 20:08 ` [for-linus][PATCH 01/12] tracing: Have show_event_filters/triggers files take trace array ref Steven Rostedt
@ 2026-09-05 20:08 ` Steven Rostedt
2026-09-05 20:08 ` [for-linus][PATCH 03/12] ftrace: Synchronize the initialization of ftrace_ops Steven Rostedt
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Steven Rostedt @ 2026-09-05 20:08 UTC (permalink / raw)
To: linux-kernel
Cc: Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
Vincent Donnefort, stable, Breno Leitao
From: Steven Rostedt <rostedt@goodmis.org>
The trace instance files set_ftrace_filter and set_ftrace_notrace was
updated to work with specific trace instances (trace_arrays). The issue is
that when these files are opened, there is a small race window where it
will use the ftrace_ops from the inode->private pointer to get a reference
to the trace_array and then take its reference. The problem is that the
ftrace_ops itself could be freed. If the rmdir on the instance happens at
the same time the set_ftrace_filter file is opened, the rmdir could have
also freed the ftrace_ops and referencing it will cause a use-after-free
bug and crash the kernel.
Instead, pass in the trace_array as the file private data (NULL for the
top level instance), and then pass both the trace_array and the ftrace_ops
to the ftrace_regex_open() function. If the trace_array is NULL, then it
just uses the ftrace_ops without the need to take its reference (like
normal). If the ftrace_ops is NULL, that is only the case for the top
level instance and the global_ops can be used.
This allows the trace_array to have its reference incremented before
touching the ftrace_ops that could also be freed when the instance is.
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260828223901.29e26edb@robin
Fixes: 591dffdade9f0 ("ftrace: Allow for function tracing instance to filter functions")
Reported-by: Breno Leitao <leitao@debian.org>
Tested-by: Breno Leitao <leitao@debian.org>
Closes: https://lore.kernel.org/all/apGORjltZgAiAYHT@gmail.com/
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
include/linux/ftrace.h | 5 +--
kernel/trace/ftrace.c | 57 ++++++++++++++++++++++------------
kernel/trace/trace.h | 5 +--
kernel/trace/trace_functions.c | 2 +-
kernel/trace/trace_stack.c | 2 +-
5 files changed, 45 insertions(+), 26 deletions(-)
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 02bc5027523a..bd76a16a63af 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -866,8 +866,9 @@ unsigned long ftrace_get_addr_new(struct dyn_ftrace *rec);
unsigned long ftrace_get_addr_curr(struct dyn_ftrace *rec);
extern ftrace_func_t ftrace_trace_function;
+struct trace_array;
-int ftrace_regex_open(struct ftrace_ops *ops, int flag,
+int ftrace_regex_open(struct trace_array *tr, struct ftrace_ops *ops, int flag,
struct inode *inode, struct file *file);
ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf,
size_t cnt, loff_t *ppos);
@@ -1077,7 +1078,7 @@ static inline unsigned long ftrace_location(unsigned long ip)
* have them defined when ftrace is not enabled, but these
* functions may still be called. Use a macro instead of inline.
*/
-#define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; })
+#define ftrace_regex_open(tr, ops, flag, inode, file) ({ -ENODEV; })
#define ftrace_set_early_filter(ops, buf, enable) do { } while (0)
#define ftrace_set_filter_ip(ops, ip, remove, reset) ({ -ENODEV; })
#define ftrace_set_filter_ips(ops, ips, cnt, remove, reset) ({ -ENODEV; })
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index f9d80c7bd9f1..c7cf36f2dd7b 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -4677,7 +4677,8 @@ ftrace_avail_addrs_open(struct inode *inode, struct file *file)
/**
* ftrace_regex_open - initialize function tracer filter files
- * @ops: The ftrace_ops that hold the hash filters
+ * @tr: The trace_array that holds the ftrace_ops [optional]
+ * @ops: The ftrace_ops that hold the hash filters [optional]
* @flag: The type of filter to process
* @inode: The inode, usually passed in to your open routine
* @file: The file, usually passed in to your open routine
@@ -4691,26 +4692,45 @@ ftrace_avail_addrs_open(struct inode *inode, struct file *file)
* tracing_lseek() should be used as the lseek routine, and
* release must call ftrace_regex_release().
*
+ * Note, If @tr is not NULL, its reference has to be taken before
+ * @ops may be referenced.
+ * If @ops is NULL and @tr is not, then @tr->ops is used.
+ * If @tr is NULL and @ops is not then @ops->private is uesd for @tr.
+ * If both @tr and @ops are NULL, then the &global_ops is
+ * to be used, and @tr will be the global_ops.private pointer.
+ *
* Returns: 0 on success or a negative errno value on failure
*/
int
-ftrace_regex_open(struct ftrace_ops *ops, int flag,
+ftrace_regex_open(struct trace_array *tr, struct ftrace_ops *ops, int flag,
struct inode *inode, struct file *file)
{
- struct ftrace_iterator *iter;
+ struct ftrace_iterator *iter = NULL;
struct ftrace_hash *hash;
struct list_head *mod_head;
- struct trace_array *tr = ops->private;
- int ret = -ENOMEM;
-
- ftrace_ops_init(ops);
+ int ret = -ENODEV;
if (unlikely(ftrace_disabled))
return -ENODEV;
+ if (!tr) {
+ if (!ops)
+ ops = &global_ops;
+ tr = ops->private;
+ }
+
if (tracing_check_open_get_tr(tr))
return -ENODEV;
+ if (!ops)
+ ops = tr->ops;
+
+ if (WARN_ON_ONCE(!ops))
+ goto out;
+
+ ftrace_ops_init(ops);
+
+ ret = -ENOMEM;
iter = kzalloc_obj(*iter);
if (!iter)
goto out;
@@ -4788,21 +4808,19 @@ ftrace_regex_open(struct ftrace_ops *ops, int flag,
static int
ftrace_filter_open(struct inode *inode, struct file *file)
{
- struct ftrace_ops *ops = inode->i_private;
+ struct trace_array *tr = inode->i_private;
- /* Checks for tracefs lockdown */
- return ftrace_regex_open(ops,
- FTRACE_ITER_FILTER | FTRACE_ITER_DO_PROBES,
- inode, file);
+ return ftrace_regex_open(tr, NULL,
+ FTRACE_ITER_FILTER | FTRACE_ITER_DO_PROBES,
+ inode, file);
}
static int
ftrace_notrace_open(struct inode *inode, struct file *file)
{
- struct ftrace_ops *ops = inode->i_private;
+ struct trace_array *tr = inode->i_private;
- /* Checks for tracefs lockdown */
- return ftrace_regex_open(ops, FTRACE_ITER_NOTRACE,
+ return ftrace_regex_open(tr, NULL, FTRACE_ITER_NOTRACE,
inode, file);
}
@@ -7492,15 +7510,15 @@ static const struct file_operations ftrace_graph_notrace_fops = {
};
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
-void ftrace_create_filter_files(struct ftrace_ops *ops,
+void ftrace_create_filter_files(struct trace_array *tr,
struct dentry *parent)
{
trace_create_file("set_ftrace_filter", TRACE_MODE_WRITE, parent,
- ops, &ftrace_filter_fops);
+ tr, &ftrace_filter_fops);
trace_create_file("set_ftrace_notrace", TRACE_MODE_WRITE, parent,
- ops, &ftrace_notrace_fops);
+ tr, &ftrace_notrace_fops);
}
/*
@@ -7525,7 +7543,6 @@ void ftrace_destroy_filter_files(struct ftrace_ops *ops)
static __init int ftrace_init_dyn_tracefs(struct dentry *d_tracer)
{
-
trace_create_file("available_filter_functions", TRACE_MODE_READ,
d_tracer, NULL, &ftrace_avail_fops);
@@ -7538,7 +7555,7 @@ static __init int ftrace_init_dyn_tracefs(struct dentry *d_tracer)
trace_create_file("touched_functions", TRACE_MODE_READ,
d_tracer, NULL, &ftrace_touched_fops);
- ftrace_create_filter_files(&global_ops, d_tracer);
+ ftrace_create_filter_files(NULL, d_tracer);
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
trace_create_file("set_graph_function", TRACE_MODE_WRITE, d_tracer,
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 74a7a50d1e78..3c111ca88e32 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -1340,7 +1340,7 @@ extern void clear_ftrace_function_probes(struct trace_array *tr);
int register_ftrace_command(struct ftrace_func_command *cmd);
int unregister_ftrace_command(struct ftrace_func_command *cmd);
-void ftrace_create_filter_files(struct ftrace_ops *ops,
+void ftrace_create_filter_files(struct trace_array *tr,
struct dentry *parent);
void ftrace_destroy_filter_files(struct ftrace_ops *ops);
@@ -1363,11 +1363,12 @@ static inline void clear_ftrace_function_probes(struct trace_array *tr)
{
}
+static inline void ftrace_create_filter_files(struct trace_array *tr,
+ struct dentry *parent) { }
/*
* The ops parameter passed in is usually undefined.
* This must be a macro.
*/
-#define ftrace_create_filter_files(ops, parent) do { } while (0)
#define ftrace_destroy_filter_files(ops) do { } while (0)
#endif /* CONFIG_FUNCTION_TRACER && CONFIG_DYNAMIC_FTRACE */
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index cd37f2013758..c879d43a5fbb 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -101,7 +101,7 @@ int ftrace_create_function_files(struct trace_array *tr,
return ret;
}
- ftrace_create_filter_files(tr->ops, parent);
+ ftrace_create_filter_files(tr, parent);
return 0;
}
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c
index 0aa2514a6593..e7f4e523587d 100644
--- a/kernel/trace/trace_stack.c
+++ b/kernel/trace/trace_stack.c
@@ -499,7 +499,7 @@ stack_trace_filter_open(struct inode *inode, struct file *file)
struct ftrace_ops *ops = inode->i_private;
/* Checks for tracefs lockdown */
- return ftrace_regex_open(ops, FTRACE_ITER_FILTER,
+ return ftrace_regex_open(NULL, ops, FTRACE_ITER_FILTER,
inode, file);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [for-linus][PATCH 03/12] ftrace: Synchronize the initialization of ftrace_ops
[not found] <20260905200827.773347757@kernel.org>
2026-09-05 20:08 ` [for-linus][PATCH 01/12] tracing: Have show_event_filters/triggers files take trace array ref Steven Rostedt
2026-09-05 20:08 ` [for-linus][PATCH 02/12] ftrace: Take trace_array reference before accessing its ftrace_ops Steven Rostedt
@ 2026-09-05 20:08 ` Steven Rostedt
2026-09-05 20:08 ` [for-linus][PATCH 04/12] tracing: Take trace_array reference when opening options file Steven Rostedt
2026-09-05 20:08 ` [for-linus][PATCH 05/12] ring-buffer: Allow splice reads on static buffers Steven Rostedt
4 siblings, 0 replies; 6+ messages in thread
From: Steven Rostedt @ 2026-09-05 20:08 UTC (permalink / raw)
To: linux-kernel
Cc: Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
Vincent Donnefort, stable, sashiko-bot
From: Steven Rostedt <rostedt@goodmis.org>
There's some internal state that ftrace_ops needs to have set, but since
it can be declared outside of the ftrace.c code, it calls
ftrace_ops_init() on the ops in every global function. The issue is that
if two tasks call it on the same ops at the same time it is possible to
have the initialization of one corrupt the initialization of the other
call.
Create a ops_mutex to use to synchronize every initialization of the
ftrace_ops. The mutex is taken within checking the ftrace_ops flag that
states it was initializied but the flag is checked again after the mutex
has been taken. Checking first outside the mutex allows it to shortcut
having to take the mutex. But then the check needs to be done again after
the mute is taken in case of races.
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home
Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock")
Reported-by: sashiko-bot@kernel.org
Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
kernel/trace/ftrace.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index c7cf36f2dd7b..53d5db60bfa5 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -75,6 +75,8 @@
.func_hash = &opsname.local_hash, \
.local_hash.regex_lock = __MUTEX_INITIALIZER(opsname.local_hash.regex_lock), \
.subop_list = LIST_HEAD_INIT(opsname.subop_list),
+/* Used only to synchronize the initialization of ftrace_ops */
+static DEFINE_MUTEX(ops_mutex);
#else
#define INIT_OPS_HASH(opsname)
#endif
@@ -159,11 +161,18 @@ const struct ftrace_ops ftrace_nop_ops = {
static inline void ftrace_ops_init(struct ftrace_ops *ops)
{
#ifdef CONFIG_DYNAMIC_FTRACE
- if (!(ops->flags & FTRACE_OPS_FL_INITIALIZED)) {
+ unsigned long flags = smp_load_acquire(&ops->flags);
+
+ if (!(flags & FTRACE_OPS_FL_INITIALIZED)) {
+ guard(mutex)(&ops_mutex);
+ /* Could have been initialized before lock taken */
+ if (unlikely(ops->flags & FTRACE_OPS_FL_INITIALIZED))
+ return;
mutex_init(&ops->local_hash.regex_lock);
INIT_LIST_HEAD(&ops->subop_list);
ops->func_hash = &ops->local_hash;
- ops->flags |= FTRACE_OPS_FL_INITIALIZED;
+ flags = ops->flags | FTRACE_OPS_FL_INITIALIZED;
+ smp_store_release(&ops->flags, flags);
}
#endif
}
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [for-linus][PATCH 04/12] tracing: Take trace_array reference when opening options file
[not found] <20260905200827.773347757@kernel.org>
` (2 preceding siblings ...)
2026-09-05 20:08 ` [for-linus][PATCH 03/12] ftrace: Synchronize the initialization of ftrace_ops Steven Rostedt
@ 2026-09-05 20:08 ` Steven Rostedt
2026-09-05 20:08 ` [for-linus][PATCH 05/12] ring-buffer: Allow splice reads on static buffers Steven Rostedt
4 siblings, 0 replies; 6+ messages in thread
From: Steven Rostedt @ 2026-09-05 20:08 UTC (permalink / raw)
To: linux-kernel
Cc: Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
Vincent Donnefort, stable, sashiko-bot
From: Steven Rostedt <rostedt@goodmis.org>
The options files do not take the trace_array reference for the options
they represent. This could cause a use-after-free kernel crash if one of
these files is opened by one task and another task removes the instance
that the option is for. Because it doesn't take a reference upon opening,
it will not stop the removal which will free the options descriptor that
is being used.
As the options are somewhat dynamic in their creation at boot up, each
file represents a flag in the trace_array. The trace_array has an array of
indexes to represent each of these flags that is stored in the
trace_flags_index array. The address of the index array element is used to
pass to the inode->i_private pointer. Then that element is read which
holds the index (which represents the flag) and then the index is used to
calculate the trace_array descriptor from its trace_flags_index array.
One issue is that the index element can not be referenced until the
trace_array's reference is taken. To handle this, create a new helper
function called: trace_array_options_get() that will iterate all the
existing trace_arrays in the ftrace_trace_arrays list (under the
trace_types_lock), and compare the passed in address of the index element
with the entire array of the trace_array's trace_flags_index array.
If it matches, then up the corresponding trace_array's reference and
return.
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260902121918.5a9e9d1b@gandalf.local.home
Fixes: 577b785f55168 ("tracing: add tracer dependent options to options directory")
Reported-by: sashiko-bot@kernel.org
Closes: https://lore.kernel.org/linux-trace-kernel/20260828135858.2AC501F000E9@smtp.kernel.org/
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
kernel/trace/trace.c | 67 +++++++++++++++++++++++++++++++++++++++++---
1 file changed, 63 insertions(+), 4 deletions(-)
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index a946e0183fd1..722d0ba2d233 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -7842,11 +7842,70 @@ trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt,
return cnt;
}
+/*
+ * The tr_index is the address of a trace_array->trace_flags_index[]
+ * element that holds the index of the trace flag. But since the
+ * trace_array reference has not been taken yet, it cannot be referenced
+ * as it could have been freed by a rmdir of the instance the trace_array
+ * represents.
+ *
+ * Search the list of trace_arrays and compare the tr_index to the
+ * address of the entire trace_array trace_flags_index array for each
+ * trace_array in the list. If one is matched, then take the reference
+ * and return it. If not, the trace_array no longer exits.
+ */
+static int trace_array_options_get(void *tr_index)
+{
+ struct trace_array *tr;
+ int ret;
+
+ ret = security_locked_down(LOCKDOWN_TRACEFS);
+ if (ret)
+ return ret;
+
+ if (tracing_disabled)
+ return -ENODEV;
+
+ guard(mutex)(&trace_types_lock);
+ list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+ if (tr_index >= (void *)&tr->trace_flags_index[0] &&
+ tr_index < (void *)&tr->trace_flags_index[TRACE_FLAGS_MAX_SIZE])
+ return __trace_array_get(tr);
+ }
+ return -ENODEV;
+}
+
+static int trace_options_open(struct inode *inode, struct file *filp)
+{
+ void *tr_index = inode->i_private;
+
+ if (trace_array_options_get(tr_index) < 0)
+ return -ENODEV;
+
+ filp->private_data = tr_index;
+
+ return 0;
+}
+
+static int trace_options_release(struct inode *inode, struct file *filp)
+{
+ void *tr_index = filp->private_data;
+ struct trace_array *tr;
+ unsigned int index;
+
+ get_tr_index(tr_index, &tr, &index);
+
+ trace_array_put(tr);
+
+ return 0;
+}
+
static const struct file_operations trace_options_core_fops = {
- .open = tracing_open_generic,
- .read = trace_options_core_read,
- .write = trace_options_core_write,
- .llseek = generic_file_llseek,
+ .open = trace_options_open,
+ .read = trace_options_core_read,
+ .write = trace_options_core_write,
+ .llseek = generic_file_llseek,
+ .release = trace_options_release,
};
struct dentry *trace_create_file(const char *name,
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [for-linus][PATCH 05/12] ring-buffer: Allow splice reads on static buffers
[not found] <20260905200827.773347757@kernel.org>
` (3 preceding siblings ...)
2026-09-05 20:08 ` [for-linus][PATCH 04/12] tracing: Take trace_array reference when opening options file Steven Rostedt
@ 2026-09-05 20:08 ` Steven Rostedt
4 siblings, 0 replies; 6+ messages in thread
From: Steven Rostedt @ 2026-09-05 20:08 UTC (permalink / raw)
To: linux-kernel
Cc: Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
Vincent Donnefort, stable
From: Vincent Donnefort <vdonnefort@google.com>
ring_buffer_read_page() rejects splice (full=1) reads on static buffers
(that is user-mapped, persistent or remote) because !read check assumes
unread pages must be swapped. However for those buffers we have no other
choice than memcpy the data.
For the memcpy case, only return an error when the writer is still on
the reader page for the splice interface to wait.
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260901155445.1475405-2-vdonnefort@google.com
Fixes: 117c39200d9d ("ring-buffer: Introducing ring-buffer mapping functions")
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
kernel/trace/ring_buffer.c | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index b0963ac6fd16..84fd4cdd486f 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -7193,15 +7193,8 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
unsigned int event_size;
unsigned int flags = 0;
- /*
- * If a full page is expected, this can still be returned
- * if there's been a previous partial read and the
- * rest of the page can be read and the commit page is off
- * the reader page.
- */
- if (full &&
- (!read || (len < (size - read)) ||
- cpu_buffer->reader_page == cpu_buffer->commit_page))
+ /* If a full page is requested, it cannot be the commit page */
+ if (full && cpu_buffer->reader_page == cpu_buffer->commit_page)
return -1;
if (len > (size - read))
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [for-linus][PATCH 03/12] ftrace: Synchronize the initialization of ftrace_ops
[not found] <20260906014531.720267751@kernel.org>
@ 2026-09-06 1:45 ` Steven Rostedt
0 siblings, 0 replies; 6+ messages in thread
From: Steven Rostedt @ 2026-09-06 1:45 UTC (permalink / raw)
To: linux-kernel
Cc: Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
Vincent Donnefort, stable, sashiko-bot
From: Steven Rostedt <rostedt@goodmis.org>
There's some internal state that ftrace_ops needs to have set, but since
it can be declared outside of the ftrace.c code, it calls
ftrace_ops_init() on the ops in every global function. The issue is that
if two tasks call it on the same ops at the same time it is possible to
have the initialization of one corrupt the initialization of the other
call.
Create a ops_mutex to use to synchronize every initialization of the
ftrace_ops. The mutex is taken within checking the ftrace_ops flag that
states it was initializied but the flag is checked again after the mutex
has been taken. Checking first outside the mutex allows it to shortcut
having to take the mutex. But then the check needs to be done again after
the mute is taken in case of races.
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home
Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock")
Reported-by: sashiko-bot@kernel.org
Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
kernel/trace/ftrace.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index c7cf36f2dd7b..53d5db60bfa5 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -75,6 +75,8 @@
.func_hash = &opsname.local_hash, \
.local_hash.regex_lock = __MUTEX_INITIALIZER(opsname.local_hash.regex_lock), \
.subop_list = LIST_HEAD_INIT(opsname.subop_list),
+/* Used only to synchronize the initialization of ftrace_ops */
+static DEFINE_MUTEX(ops_mutex);
#else
#define INIT_OPS_HASH(opsname)
#endif
@@ -159,11 +161,18 @@ const struct ftrace_ops ftrace_nop_ops = {
static inline void ftrace_ops_init(struct ftrace_ops *ops)
{
#ifdef CONFIG_DYNAMIC_FTRACE
- if (!(ops->flags & FTRACE_OPS_FL_INITIALIZED)) {
+ unsigned long flags = smp_load_acquire(&ops->flags);
+
+ if (!(flags & FTRACE_OPS_FL_INITIALIZED)) {
+ guard(mutex)(&ops_mutex);
+ /* Could have been initialized before lock taken */
+ if (unlikely(ops->flags & FTRACE_OPS_FL_INITIALIZED))
+ return;
mutex_init(&ops->local_hash.regex_lock);
INIT_LIST_HEAD(&ops->subop_list);
ops->func_hash = &ops->local_hash;
- ops->flags |= FTRACE_OPS_FL_INITIALIZED;
+ flags = ops->flags | FTRACE_OPS_FL_INITIALIZED;
+ smp_store_release(&ops->flags, flags);
}
#endif
}
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-09-06 1:45 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260905200827.773347757@kernel.org>
2026-09-05 20:08 ` [for-linus][PATCH 01/12] tracing: Have show_event_filters/triggers files take trace array ref Steven Rostedt
2026-09-05 20:08 ` [for-linus][PATCH 02/12] ftrace: Take trace_array reference before accessing its ftrace_ops Steven Rostedt
2026-09-05 20:08 ` [for-linus][PATCH 03/12] ftrace: Synchronize the initialization of ftrace_ops Steven Rostedt
2026-09-05 20:08 ` [for-linus][PATCH 04/12] tracing: Take trace_array reference when opening options file Steven Rostedt
2026-09-05 20:08 ` [for-linus][PATCH 05/12] ring-buffer: Allow splice reads on static buffers Steven Rostedt
[not found] <20260906014531.720267751@kernel.org>
2026-09-06 1:45 ` [for-linus][PATCH 03/12] ftrace: Synchronize the initialization of ftrace_ops Steven Rostedt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).