From: Petr Pavlu <petr.pavlu@suse.com> Date: 2026-02-16 13:43:10
This series includes several patches related to accessing
trace_event_file from a file struct. The first patch is a fix for an
edge case, the remaining patches are minor cleanups.
Changes since v1 [1]:
* Fix a compilation error when CONFIG_HIST_TRIGGERS is not set.
* Drop a patch that references the trace_event_file data in
event_file_data() and keep the simpler implementation of storing the
id in i_private.
* Inline event_file_data() into event_id_read() to enable adding
additional checks to the former.
Petr Pavlu (4):
tracing: Fix checking of freed trace_event_file for hist files
tracing: Remove unnecessary check for EVENT_FILE_FL_FREED
tracing: Clean up access to trace_event_file from a file pointer
tracing: Free up file->private_data for use by individual events
include/linux/trace_events.h | 5 +++++
kernel/trace/trace.c | 2 --
kernel/trace/trace.h | 17 +++++++++++------
kernel/trace/trace_events.c | 17 ++++++++---------
kernel/trace/trace_events_hist.c | 8 ++------
5 files changed, 26 insertions(+), 23 deletions(-)
base-commit: cee73b1e840c154f64ace682cb477c1ae2e29cc4
--
2.52.0
From: Petr Pavlu <petr.pavlu@suse.com> Date: 2026-02-16 13:43:11
The event_hist_open() and event_hist_poll() functions currently retrieve
a trace_event_file pointer from a file struct by invoking
event_file_data(), which simply returns file->f_inode->i_private. The
functions then check if the pointer is NULL to determine whether the event
is still valid. This approach is flawed because i_private is assigned when
an eventfs inode is allocated and remains set throughout its lifetime.
Instead, the code should call event_file_file(), which checks for
EVENT_FILE_FL_FREED. Using the incorrect access function may result in the
code potentially opening a hist file for an event that is being removed or
becoming stuck while polling on this file.
A related issue is that although event_hist_poll() attempts to verify
whether an event file is being removed, this check may not occur or could
be unnecessarily delayed. This happens because hist_poll_wakeup() is
currently invoked only from event_hist_trigger() when a hist command is
triggered. If the event file is being removed, no associated hist command
will be triggered and a waiter will be woken up only after an unrelated
hist command is triggered.
Fix these issues by changing the access method to event_file_file() and
adding a call to hist_poll_wakeup() in remove_event_file_dir() after
setting the EVENT_FILE_FL_FREED flag. This ensures that a task polling on
a hist file is woken up and receives EPOLLERR.
Fixes: 1bd13edbbed6 ("tracing/hist: Add poll(POLLIN) support on hist file")
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
include/linux/trace_events.h | 5 +++++
kernel/trace/trace_events.c | 3 +++
kernel/trace/trace_events_hist.c | 4 ++--
3 files changed, 10 insertions(+), 2 deletions(-)
@@ -1295,6 +1295,9 @@ static void remove_event_file_dir(struct trace_event_file *file)free_event_filter(file->filter);file->flags|=EVENT_FILE_FL_FREED;event_file_put(file);++/* Wake up hist poll waiters to notice the EVENT_FILE_FL_FREED flag. */+hist_poll_wakeup();}/*
From: Petr Pavlu <petr.pavlu@suse.com> Date: 2026-02-16 13:43:11
The event_filter_write() function calls event_file_file() to retrieve
a trace_event_file associated with a given file struct. If a non-NULL
pointer is returned, the function then checks whether the trace_event_file
instance has the EVENT_FILE_FL_FREED flag set. This check is redundant
because event_file_file() already performs this validation and returns NULL
if the flag is set. The err value is also already initialized to -ENODEV.
Remove the unnecessary check for EVENT_FILE_FL_FREED in
event_filter_write().
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
---
kernel/trace/trace_events.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
From: Petr Pavlu <petr.pavlu@suse.com> Date: 2026-02-16 13:43:12
The tracing code provides two functions event_file_file() and
event_file_data() to obtain a trace_event_file pointer from a file struct.
The primary method to use is event_file_file(), as it checks for the
EVENT_FILE_FL_FREED flag to determine whether the event is being removed.
The second function event_file_data() is an optimization for retrieving the
same data when the event_mutex is still held.
In the past, when removing an event directory in remove_event_file_dir(),
the code set i_private to NULL for all event files and readers were
expected to check for this state to recognize that the event is being
removed. In the case of event_id_read(), the value was read using
event_file_data() without acquiring the event_mutex. This required
event_file_data() to use READ_ONCE() when retrieving the i_private data.
With the introduction of eventfs, i_private is assigned when an eventfs
inode is allocated and remains set throughout its lifetime.
Remove the now unnecessary READ_ONCE() access to i_private in both
event_file_file() and event_file_data(). Inline the access to i_private in
remove_event_file_dir(), which allows event_file_data() to handle i_private
solely as a trace_event_file pointer. Add a check in event_file_data() to
ensure that the event_mutex is held and that file->flags doesn't have the
EVENT_FILE_FL_FREED flag set. Finally, move event_file_data() immediately
after event_file_code() since the latter provides a comment explaining how
both functions should be used together.
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
---
kernel/trace/trace.h | 17 +++++++++++------
kernel/trace/trace_events.c | 6 +++---
2 files changed, 14 insertions(+), 9 deletions(-)
@@ -2090,12 +2090,12 @@ static int trace_format_open(struct inode *inode, struct file *file)staticssize_tevent_id_read(structfile*filp,char__user*ubuf,size_tcnt,loff_t*ppos){-intid=(long)event_file_data(filp);+/* id is directly in i_private and available for inode's lifetime. */+intid=(long)file_inode(filp)->i_private;charbuf[32];intlen;-if(unlikely(!id))-return-ENODEV;+WARN_ON(!id);len=sprintf(buf,"%d\n",id);
From: Petr Pavlu <petr.pavlu@suse.com> Date: 2026-02-16 13:43:13
The tracing_open_file_tr() function currently copies the trace_event_file
pointer from inode->i_private to file->private_data when the file is
successfully opened. This duplication is not particularly useful, as all
event code should utilize event_file_file() or event_file_data() to
retrieve a trace_event_file pointer from a file struct and these access
functions read file->f_inode->i_private. Moreover, this setup requires the
code for opening hist files to explicitly clear file->private_data before
calling single_open(), since this function expects the private_data member
to be set to NULL and uses it to store a pointer to a seq_file.
Remove the unnecessary setting of file->private_data in
tracing_open_file_tr() and simplify the hist code.
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
---
kernel/trace/trace.c | 2 --
kernel/trace/trace_events_hist.c | 4 ----
2 files changed, 6 deletions(-)
@@ -1295,6 +1295,9 @@ static void remove_event_file_dir(struct trace_event_file *file)free_event_filter(file->filter);file->flags|=EVENT_FILE_FL_FREED;event_file_put(file);++/* Wake up hist poll waiters to notice the EVENT_FILE_FL_FREED flag. */+hist_poll_wakeup();}/*
@@ -1295,6 +1295,9 @@ static void remove_event_file_dir(struct trace_event_file *file)free_event_filter(file->filter);file->flags|=EVENT_FILE_FL_FREED;event_file_put(file);++/* Wake up hist poll waiters to notice the EVENT_FILE_FL_FREED flag. */+hist_poll_wakeup();}/*