From: Anubhav Shelat <ashelat@redhat.com>
To: rostedt@goodmis.org, acme@kernel.org, peterz@infradead.org,
Ingo Molnar <mingo@redhat.com>,
Namhyung Kim <namhyung@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Jiri Olsa <jolsa@kernel.org>, Ian Rogers <irogers@google.com>,
Adrian Hunter <adrian.hunter@intel.com>,
James Clark <james.clark@linaro.org>,
Anubhav Shelat <ashelat@redhat.com>,
linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org
Cc: linux-trace-kernel@vger.kernel.org
Subject: [PATCH v5 3/5] perf tools: fall back to eventfs for unprivileged event discovery
Date: Wed, 15 Jul 2026 09:52:24 -0400 [thread overview]
Message-ID: <20260715135231.338535-5-ashelat@redhat.com> (raw)
In-Reply-To: <20260715135231.338535-2-ashelat@redhat.com>
When tracefs events are not readable by unprivileged users, fall back
to /sys/kernel/events (the read-only eventfs mount) for tracepoint
format and id file discovery. This allows perf trace to work for
unprivileged users on kernels that expose the eventfs filesystem.
The fallback is transparent: get_events_file() tries the tracefs path
first and only switches to eventfs when access() fails. On kernels
without eventfs, the existing error path is preserved.
Assisted-by: CLAUDE:claude-opus-4 Apogee
Signed-off-by: Anubhav Shelat <ashelat@redhat.com>
---
tools/lib/api/fs/fs.c | 10 ++++++
tools/lib/api/fs/fs.h | 1 +
tools/lib/api/fs/tracing_path.c | 52 ++++++++++++++++++++++++++----
tools/lib/api/fs/tracing_path.h | 1 +
tools/perf/util/tp_pmu.c | 5 +--
tools/perf/util/trace-event-info.c | 19 ++++++-----
6 files changed, 71 insertions(+), 17 deletions(-)
diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c
index cbd8eab0d1df..abc3581a9703 100644
--- a/tools/lib/api/fs/fs.c
+++ b/tools/lib/api/fs/fs.c
@@ -46,6 +46,10 @@
#define BPF_FS_MAGIC 0xcafe4a11
#endif
+#ifndef EVENTFS_SUPER_MAGIC
+#define EVENTFS_SUPER_MAGIC 0x65766673
+#endif
+
static const char * const sysfs__known_mountpoints[] = {
"/sys",
0,
@@ -88,6 +92,11 @@ static const char * const bpf_fs__known_mountpoints[] = {
0,
};
+static const char * const eventfs__known_mountpoints[] = {
+ "/sys/kernel/events",
+ 0,
+};
+
struct fs {
const char * const name;
const char * const * const mounts;
@@ -150,6 +159,7 @@ FS(debugfs, debugfs, DEBUGFS);
FS(tracefs, tracefs, TRACEFS);
FS(hugetlbfs, hugetlbfs, HUGETLBFS);
FS(bpf_fs, bpf, BPF_FS);
+FS(eventfs, eventfs, EVENTFS_SUPER);
static bool fs__read_mounts(struct fs *fs)
{
diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h
index aa222ca30311..57790c93f80e 100644
--- a/tools/lib/api/fs/fs.h
+++ b/tools/lib/api/fs/fs.h
@@ -36,6 +36,7 @@ FS(debugfs)
FS(tracefs)
FS(hugetlbfs)
FS(bpf_fs)
+FS(eventfs)
#undef FS
diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c
index 834fd64c7130..de4ed7c61415 100644
--- a/tools/lib/api/fs/tracing_path.c
+++ b/tools/lib/api/fs/tracing_path.c
@@ -3,6 +3,8 @@
# define _GNU_SOURCE
#endif
+#include <dirent.h>
+#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -80,13 +82,46 @@ void put_tracing_file(char *file)
free(file);
}
+char *get_events_dir(void)
+{
+ const char *eventfs;
+ char *path;
+ int saved_errno;
+
+ path = get_tracing_file("events");
+ if (path && faccessat(AT_FDCWD, path, R_OK, AT_EACCESS) == 0)
+ return path;
+
+ saved_errno = errno;
+ put_tracing_file(path);
+
+ eventfs = eventfs__mount();
+ if (eventfs && faccessat(AT_FDCWD, eventfs, R_OK, AT_EACCESS) == 0 &&
+ eventfs__configured())
+ return strdup(eventfs);
+
+ /*
+ * Prefer EACCES over other errors: it tells the user that events
+ * exist but are not accessible, which is more actionable than
+ * ENOENT from a missing filesystem.
+ */
+ if (errno != EACCES)
+ errno = saved_errno;
+ return NULL;
+}
+
char *get_events_file(const char *name)
{
- char *file;
+ char *dir, *file;
- if (asprintf(&file, "%s/events/%s", tracing_path_mount(), name) < 0)
+ dir = get_events_dir();
+ if (!dir)
return NULL;
+ if (asprintf(&file, "%s/%s", dir, name) < 0)
+ file = NULL;
+
+ free(dir);
return file;
}
@@ -97,8 +132,8 @@ void put_events_file(char *file)
DIR *tracing_events__opendir(void)
{
+ char *path = get_events_dir();
DIR *dir = NULL;
- char *path = get_tracing_file("events");
if (path) {
dir = opendir(path);
@@ -110,7 +145,7 @@ DIR *tracing_events__opendir(void)
int tracing_events__scandir_alphasort(struct dirent ***namelist)
{
- char *path = get_tracing_file("events");
+ char *path = get_events_dir();
int ret;
if (!path) {
@@ -121,6 +156,9 @@ int tracing_events__scandir_alphasort(struct dirent ***namelist)
ret = scandir(path, namelist, NULL, alphasort);
put_events_file(path);
+ if (ret < 0)
+ *namelist = NULL;
+
return ret;
}
@@ -162,12 +200,12 @@ int tracing_path__strerror_open_tp(int err, char *buf, size_t size,
"Hint:\tIs the debugfs/tracefs filesystem mounted?\n"
"Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'");
break;
- case EACCES: {
+ case EACCES:
snprintf(buf, size,
"Error:\tNo permissions to read %s/events/%s\n"
- "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
+ "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n"
+ "Hint:\tOr check if /sys/kernel/events is available\n",
tracing_path, filename, tracing_path_mount());
- }
break;
default:
snprintf(buf, size, "%s", str_error_r(err, sbuf, sizeof(sbuf)));
diff --git a/tools/lib/api/fs/tracing_path.h b/tools/lib/api/fs/tracing_path.h
index fc6347c11deb..a93befb38f80 100644
--- a/tools/lib/api/fs/tracing_path.h
+++ b/tools/lib/api/fs/tracing_path.h
@@ -14,6 +14,7 @@ const char *tracing_path_mount(void);
char *get_tracing_file(const char *name);
void put_tracing_file(char *file);
+char *get_events_dir(void);
char *get_events_file(const char *name);
void put_events_file(char *file);
diff --git a/tools/perf/util/tp_pmu.c b/tools/perf/util/tp_pmu.c
index c2be8c9f9084..4f45bd816945 100644
--- a/tools/perf/util/tp_pmu.c
+++ b/tools/perf/util/tp_pmu.c
@@ -6,6 +6,7 @@
#include <api/io_dir.h>
#include <linux/kernel.h>
#include <errno.h>
+#include <stdlib.h>
#include <string.h>
int tp_pmu__id(const char *sys, const char *name)
@@ -15,7 +16,7 @@ int tp_pmu__id(const char *sys, const char *name)
int id, err;
if (!tp_dir)
- return -1;
+ return -errno;
scnprintf(path, PATH_MAX, "%s/%s/id", tp_dir, name);
put_events_file(tp_dir);
@@ -66,7 +67,7 @@ int tp_pmu__for_each_tp_sys(void *state, tp_sys_callback cb)
struct io_dirent64 *events_ent;
struct io_dir events_dir;
int ret = 0;
- char *events_dir_path = get_tracing_file("events");
+ char *events_dir_path = get_events_dir();
if (!events_dir_path)
return -errno;
diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-event-info.c
index 45774722f249..643451d2c08d 100644
--- a/tools/perf/util/trace-event-info.c
+++ b/tools/perf/util/trace-event-info.c
@@ -92,8 +92,9 @@ static int record_header_files(void)
int err = -EIO;
if (!path) {
+ err = -errno;
pr_debug("can't get tracing/events/header_page");
- return -ENOMEM;
+ return err;
}
if (stat(path, &st) < 0) {
@@ -115,8 +116,8 @@ static int record_header_files(void)
path = get_events_file("header_event");
if (!path) {
+ err = -errno;
pr_debug("can't get tracing/events/header_event");
- err = -ENOMEM;
goto out;
}
@@ -228,13 +229,14 @@ static int record_ftrace_files(struct tracepoint_path *tps)
path = get_events_file("ftrace");
if (!path) {
+ ret = -errno;
pr_debug("can't get tracing/events/ftrace");
- return -ENOMEM;
+ return ret;
}
ret = copy_event_system(path, tps);
- put_tracing_file(path);
+ put_events_file(path);
return ret;
}
@@ -256,15 +258,16 @@ static int record_event_files(struct tracepoint_path *tps)
struct stat st;
char *path;
char *sys;
- DIR *dir;
+ DIR *dir = NULL;
int count = 0;
int ret;
int err;
- path = get_tracing_file("events");
+ path = get_events_dir();
if (!path) {
+ err = -errno;
pr_debug("can't get tracing/events");
- return -ENOMEM;
+ goto out;
}
dir = opendir(path);
@@ -315,7 +318,7 @@ static int record_event_files(struct tracepoint_path *tps)
out:
if (dir)
closedir(dir);
- put_tracing_file(path);
+ put_events_file(path);
return err;
}
--
2.54.0
next prev parent reply other threads:[~2026-07-15 13:53 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-15 13:52 [PATCH v5 0/5] Enable perf tracing for unprivileged users Anubhav Shelat
2026-07-15 13:52 ` [PATCH v5 1/5] eventfs: define event fields before directory creation Anubhav Shelat
2026-07-15 13:52 ` [PATCH v5 2/5] tracefs: add read-only eventfs filesystem at /sys/kernel/events Anubhav Shelat
2026-07-15 13:52 ` Anubhav Shelat [this message]
2026-07-15 13:52 ` [PATCH v5 4/5] perf evsel: don't set PERF_SAMPLE_IP for unprivileged tracepoints Anubhav Shelat
2026-07-15 13:52 ` [PATCH v5 5/5] perf: enable unprivileged syscall tracing with perf trace Anubhav Shelat
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=20260715135231.338535-5-ashelat@redhat.com \
--to=ashelat@redhat.com \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=irogers@google.com \
--cc=james.clark@linaro.org \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mingo@redhat.com \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox