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