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 <[email protected]> --- 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
