The code for reading an event id currently uses file->f_inode->i_private to
store the value of trace_event_file->event_call->event.type, unlike all
other event files which use it to store a pointer to the associated
trace_event_file data. The event_id_read() function retrieves this id value
from i_private and checks if it is non-0/NULL to determine whether the
event is still valid. This approach worked in the past when
remove_event_file_dir() would set i_private to NULL for all files in an
event directory upon removal. However, with the introduction of eventfs,
i_private is assigned when an eventfs inode is allocated and remains set
throughout its lifetime. As a result, event_id_read() may fail to detect
that an event is being removed.

Fix this issue by changing the event id file to use i_private to store
a trace_event_file pointer and utilize event_file_file() to check for the
EVENT_FILE_FL_FREED flag.

Fixes: 6fdac58c560e ("tracing: Remove unused trace_event_file dir field")
Signed-off-by: Petr Pavlu <[email protected]>
---
 kernel/trace/trace_events.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index e8ed6ba155cf..3d272b3cd688 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2090,11 +2090,18 @@ static int trace_format_open(struct inode *inode, 
struct file *file)
 static ssize_t
 event_id_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
 {
-       int id = (long)event_file_data(filp);
+       struct trace_event_file *file;
+       int id;
        char buf[32];
        int len;
 
-       if (unlikely(!id))
+       mutex_lock(&event_mutex);
+       file = event_file_file(filp);
+       if (likely(file))
+               id = file->event_call->event.type;
+       mutex_unlock(&event_mutex);
+
+       if (!file)
                return -ENODEV;
 
        len = sprintf(buf, "%d\n", id);
@@ -2572,7 +2579,9 @@ static const struct file_operations 
ftrace_event_format_fops = {
 
 #ifdef CONFIG_PERF_EVENTS
 static const struct file_operations ftrace_event_id_fops = {
+       .open = tracing_open_file_tr,
        .read = event_id_read,
+       .release = tracing_release_file_tr,
        .llseek = default_llseek,
 };
 #endif
@@ -2936,7 +2945,6 @@ static int event_callback(const char *name, umode_t 
*mode, void **data,
        if (call->event.type && call->class->reg &&
            strcmp(name, "id") == 0) {
                *mode = TRACE_MODE_READ;
-               *data = (void *)(long)call->event.type;
                *fops = &ftrace_event_id_fops;
                return 1;
        }
-- 
2.52.0


Reply via email to