diff options
| author | Fedor Pchelkin <pchelkin@ispras.ru> | 2026-08-31 10:58:09 +0300 |
|---|---|---|
| committer | Mika Westerberg <mika.westerberg@linux.intel.com> | 2026-09-02 09:07:46 +0200 |
| commit | 4310c6b8e75d6a47f7548e5948fbe6318aa4440a (patch) | |
| tree | 0032b584d8e218681a48126eb91f57091c351b83 /tools/lib/api/fs | |
| download | linux-stable-4310c6b8e75d6a47f7548e5948fbe6318aa4440a.tar.gz linux-stable-4310c6b8e75d6a47f7548e5948fbe6318aa4440a.zip | |
thunderbolt: Fix NULL dereference in tb_remove_work()grafted
There is a slight race between tb_remove_work() and tb_domain_remove()
which leads to dereferencing a NULL tb->root_switch pointer inside
tb_free_unplugged_xdomains():
Thread A Thread B
tb_remove_work()
tb_domain_remove()
mutex_lock(&tb->lock)
tb_stop()
/* doesn't cancel a running callback */
cancel_delayed_work(&tcm->remove_work)
...
tb_switch_remove(tb->root_switch)
tb->root_switch = NULL
mutex_unlock(&tb->lock)
mutex_lock(&tb->lock)
...
/* without checking ->root_switch */
tb_free_unplugged_xdomains(tb->root_switch)
mutex_unlock(&tb->lock)
Commit a8937f35cf39 ("thunderbolt: Remove XDomain from the bus without
holding tb->lock") doesn't seem right to move tb_free_unplugged_xdomains()
out of the &tb->lock section and the check for tb->root_switch, in
particular. It states:
For this reason separate removing the XDomain from the topology data
structures (where we need the lock) from unregistering the device from
the bus (where remove callbacks of the drivers are being called).
tb_free_unplugged_xdomains() belongs to the former group of functions
requiring the lock. And it also calls tb_xdomain_remove() which should
only be called with &tb->lock held.
Found by Linux Verification Center (linuxtesting.org) with Svace static
analysis tool.
Fixes: a8937f35cf39 ("thunderbolt: Remove XDomain from the bus without holding tb->lock")
Cc: stable@vger.kernel.org
Signed-off-by: Fedor Pchelkin <pchelkin@ispras.ru>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Diffstat (limited to 'tools/lib/api/fs')
| -rw-r--r-- | tools/lib/api/fs/Build | 3 | ||||
| -rw-r--r-- | tools/lib/api/fs/cgroup.c | 107 | ||||
| -rw-r--r-- | tools/lib/api/fs/fs.c | 515 | ||||
| -rw-r--r-- | tools/lib/api/fs/fs.h | 62 | ||||
| -rw-r--r-- | tools/lib/api/fs/tracing_path.c | 178 | ||||
| -rw-r--r-- | tools/lib/api/fs/tracing_path.h | 23 |
6 files changed, 888 insertions, 0 deletions
diff --git a/tools/lib/api/fs/Build b/tools/lib/api/fs/Build new file mode 100644 index 000000000..0f75b2865 --- /dev/null +++ b/tools/lib/api/fs/Build @@ -0,0 +1,3 @@ +libapi-y += fs.o +libapi-y += tracing_path.o +libapi-y += cgroup.o diff --git a/tools/lib/api/fs/cgroup.c b/tools/lib/api/fs/cgroup.c new file mode 100644 index 000000000..250629a09 --- /dev/null +++ b/tools/lib/api/fs/cgroup.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/stringify.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "fs.h" + +struct cgroupfs_cache_entry { + char subsys[32]; + char mountpoint[PATH_MAX]; +}; + +/* just cache last used one */ +static struct cgroupfs_cache_entry *cached; + +int cgroupfs_find_mountpoint(char *buf, size_t maxlen, const char *subsys) +{ + FILE *fp; + char *line = NULL; + size_t len = 0; + char *p, *path; + char mountpoint[PATH_MAX]; + + if (cached && !strcmp(cached->subsys, subsys)) { + if (strlen(cached->mountpoint) < maxlen) { + strcpy(buf, cached->mountpoint); + return 0; + } + return -1; + } + + fp = fopen("/proc/mounts", "r"); + if (!fp) + return -1; + + /* + * in order to handle split hierarchy, we need to scan /proc/mounts + * and inspect every cgroupfs mount point to find one that has + * the given subsystem. If we found v1, just use it. If not we can + * use v2 path as a fallback. + */ + mountpoint[0] = '\0'; + + /* + * The /proc/mounts has the follow format: + * + * <devname> <mount point> <fs type> <options> ... + * + */ + while (getline(&line, &len, fp) != -1) { + /* skip devname */ + p = strchr(line, ' '); + if (p == NULL) + continue; + + /* save the mount point */ + path = ++p; + p = strchr(p, ' '); + if (p == NULL) + continue; + + *p++ = '\0'; + + /* check filesystem type */ + if (strncmp(p, "cgroup", 6)) + continue; + + if (p[6] == '2') { + /* save cgroup v2 path */ + strcpy(mountpoint, path); + continue; + } + + /* now we have cgroup v1, check the options for subsystem */ + p += 7; + + p = strstr(p, subsys); + if (p == NULL) + continue; + + /* sanity check: it should be separated by a space or a comma */ + if (!strchr(" ,", p[-1]) || !strchr(" ,", p[strlen(subsys)])) + continue; + + strcpy(mountpoint, path); + break; + } + free(line); + fclose(fp); + + if (!cached) + cached = calloc(1, sizeof(*cached)); + + if (cached) { + strncpy(cached->subsys, subsys, sizeof(cached->subsys) - 1); + strcpy(cached->mountpoint, mountpoint); + } + + if (mountpoint[0] && strlen(mountpoint) < maxlen) { + strcpy(buf, mountpoint); + return 0; + } + return -1; +} diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c new file mode 100644 index 000000000..cbd8eab0d --- /dev/null +++ b/tools/lib/api/fs/fs.c @@ -0,0 +1,515 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/vfs.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <pthread.h> +#include <unistd.h> +#include <sys/mount.h> + +#include "fs.h" +#include "../io.h" +#include "debug-internal.h" + +#define _STR(x) #x +#define STR(x) _STR(x) + +#ifndef SYSFS_MAGIC +#define SYSFS_MAGIC 0x62656572 +#endif + +#ifndef PROC_SUPER_MAGIC +#define PROC_SUPER_MAGIC 0x9fa0 +#endif + +#ifndef DEBUGFS_MAGIC +#define DEBUGFS_MAGIC 0x64626720 +#endif + +#ifndef TRACEFS_MAGIC +#define TRACEFS_MAGIC 0x74726163 +#endif + +#ifndef HUGETLBFS_MAGIC +#define HUGETLBFS_MAGIC 0x958458f6 +#endif + +#ifndef BPF_FS_MAGIC +#define BPF_FS_MAGIC 0xcafe4a11 +#endif + +static const char * const sysfs__known_mountpoints[] = { + "/sys", + 0, +}; + +static const char * const procfs__known_mountpoints[] = { + "/proc", + 0, +}; + +#ifndef DEBUGFS_DEFAULT_PATH +#define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug" +#endif + +static const char * const debugfs__known_mountpoints[] = { + DEBUGFS_DEFAULT_PATH, + "/debug", + 0, +}; + + +#ifndef TRACEFS_DEFAULT_PATH +#define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing" +#endif + +static const char * const tracefs__known_mountpoints[] = { + TRACEFS_DEFAULT_PATH, + "/sys/kernel/debug/tracing", + "/tracing", + "/trace", + 0, +}; + +static const char * const hugetlbfs__known_mountpoints[] = { + 0, +}; + +static const char * const bpf_fs__known_mountpoints[] = { + "/sys/fs/bpf", + 0, +}; + +struct fs { + const char * const name; + const char * const * const mounts; + char *path; + pthread_mutex_t mount_mutex; + const long magic; +}; + +#ifndef TRACEFS_MAGIC +#define TRACEFS_MAGIC 0x74726163 +#endif + +static void fs__init_once(struct fs *fs); +static const char *fs__mountpoint(const struct fs *fs); +static const char *fs__mount(struct fs *fs); + +#define FS(lower_name, fs_name, upper_name) \ +static struct fs fs__##lower_name = { \ + .name = #fs_name, \ + .mounts = lower_name##__known_mountpoints, \ + .magic = upper_name##_MAGIC, \ + .mount_mutex = PTHREAD_MUTEX_INITIALIZER, \ +}; \ + \ +static void lower_name##_init_once(void) \ +{ \ + struct fs *fs = &fs__##lower_name; \ + \ + fs__init_once(fs); \ +} \ + \ +const char *lower_name##__mountpoint(void) \ +{ \ + static pthread_once_t init_once = PTHREAD_ONCE_INIT; \ + struct fs *fs = &fs__##lower_name; \ + \ + pthread_once(&init_once, lower_name##_init_once); \ + return fs__mountpoint(fs); \ +} \ + \ +const char *lower_name##__mount(void) \ +{ \ + const char *mountpoint = lower_name##__mountpoint(); \ + struct fs *fs = &fs__##lower_name; \ + \ + if (mountpoint) \ + return mountpoint; \ + \ + return fs__mount(fs); \ +} \ + \ +bool lower_name##__configured(void) \ +{ \ + return lower_name##__mountpoint() != NULL; \ +} + +FS(sysfs, sysfs, SYSFS); +FS(procfs, procfs, PROC_SUPER); +FS(debugfs, debugfs, DEBUGFS); +FS(tracefs, tracefs, TRACEFS); +FS(hugetlbfs, hugetlbfs, HUGETLBFS); +FS(bpf_fs, bpf, BPF_FS); + +static bool fs__read_mounts(struct fs *fs) +{ + char type[100]; + FILE *fp; + char path[PATH_MAX + 1]; + + fp = fopen("/proc/mounts", "r"); + if (fp == NULL) + return false; + + while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", + path, type) == 2) { + + if (strcmp(type, fs->name) == 0) { + fs->path = strdup(path); + fclose(fp); + return fs->path != NULL; + } + } + fclose(fp); + return false; +} + +static int fs__valid_mount(const char *fs, long magic) +{ + struct statfs st_fs; + + if (statfs(fs, &st_fs) < 0) + return -ENOENT; + else if ((long)st_fs.f_type != magic) + return -ENOENT; + + return 0; +} + +static bool fs__check_mounts(struct fs *fs) +{ + const char * const *ptr; + + ptr = fs->mounts; + while (*ptr) { + if (fs__valid_mount(*ptr, fs->magic) == 0) { + fs->path = strdup(*ptr); + if (!fs->path) + return false; + return true; + } + ptr++; + } + + return false; +} + +static void mem_toupper(char *f, size_t len) +{ + while (len) { + *f = toupper(*f); + f++; + len--; + } +} + +/* + * Check for "NAME_PATH" environment variable to override fs location (for + * testing). This matches the recommendation in Documentation/admin-guide/sysfs-rules.rst + * for SYSFS_PATH. + */ +static bool fs__env_override(struct fs *fs) +{ + char *override_path; + size_t name_len = strlen(fs->name); + /* name + "_PATH" + '\0' */ + char upper_name[name_len + 5 + 1]; + + memcpy(upper_name, fs->name, name_len); + mem_toupper(upper_name, name_len); + strcpy(&upper_name[name_len], "_PATH"); + + override_path = getenv(upper_name); + if (!override_path) + return false; + + fs->path = strdup(override_path); + if (!fs->path) + return false; + return true; +} + +static void fs__init_once(struct fs *fs) +{ + if (!fs__env_override(fs) && + !fs__check_mounts(fs) && + !fs__read_mounts(fs)) { + assert(!fs->path); + } else { + assert(fs->path); + } +} + +static const char *fs__mountpoint(const struct fs *fs) +{ + return fs->path; +} + +static const char *mount_overload(struct fs *fs) +{ + size_t name_len = strlen(fs->name); + /* "PERF_" + name + "_ENVIRONMENT" + '\0' */ + char upper_name[5 + name_len + 12 + 1]; + + snprintf(upper_name, sizeof(upper_name), "PERF_%s_ENVIRONMENT", fs->name); + mem_toupper(upper_name, strlen(upper_name)); + + return getenv(upper_name) ?: *fs->mounts; +} + +static const char *fs__mount(struct fs *fs) +{ + const char *mountpoint; + + pthread_mutex_lock(&fs->mount_mutex); + + /* Check if path found inside the mutex to avoid races with other callers of mount. */ + mountpoint = fs__mountpoint(fs); + if (mountpoint) + goto out; + + mountpoint = mount_overload(fs); + + if (mount(NULL, mountpoint, fs->name, 0, NULL) == 0 && + fs__valid_mount(mountpoint, fs->magic) == 0) { + fs->path = strdup(mountpoint); + mountpoint = fs->path; + } +out: + pthread_mutex_unlock(&fs->mount_mutex); + return mountpoint; +} + +int filename__read_int(const char *filename, int *value) +{ + char line[64]; + int fd = open(filename, O_RDONLY), err = -1; + ssize_t n; + + if (fd < 0) + return -errno; + + n = read(fd, line, sizeof(line) - 1); + if (n > 0) { + line[n] = '\0'; + *value = atoi(line); + err = 0; + } + + close(fd); + return err; +} + +static int filename__read_ull_base(const char *filename, + unsigned long long *value, int base) +{ + char line[64]; + int fd = open(filename, O_RDONLY), err = -1; + ssize_t n; + + if (fd < 0) + return -errno; + + n = read(fd, line, sizeof(line) - 1); + if (n > 0) { + line[n] = '\0'; + *value = strtoull(line, NULL, base); + if (*value != ULLONG_MAX) + err = 0; + } + + close(fd); + return err; +} + +/* + * Parses @value out of @filename with strtoull. + * By using 16 for base to treat the number as hex. + */ +int filename__read_xll(const char *filename, unsigned long long *value) +{ + return filename__read_ull_base(filename, value, 16); +} + +/* + * Parses @value out of @filename with strtoull. + * By using 0 for base, the strtoull detects the + * base automatically (see man strtoull). + */ +int filename__read_ull(const char *filename, unsigned long long *value) +{ + return filename__read_ull_base(filename, value, 0); +} + +int filename__read_str(const char *filename, char **buf, size_t *sizep) +{ + struct io io; + char bf[128]; + int err; + + io.fd = open(filename, O_RDONLY); + if (io.fd < 0) + return -errno; + io__init(&io, io.fd, bf, sizeof(bf)); + *buf = NULL; + err = io__getdelim(&io, buf, sizep, /*delim=*/-1); + if (err < 0) { + free(*buf); + *buf = NULL; + } else + err = 0; + close(io.fd); + return err; +} + +int filename__write_int(const char *filename, int value) +{ + int fd = open(filename, O_WRONLY), err = -1; + char buf[64]; + int len; + + if (fd < 0) + return -errno; + + len = sprintf(buf, "%d", value); + if (write(fd, buf, len) == len) + err = 0; + + close(fd); + return err; +} + +int procfs__read_str(const char *entry, char **buf, size_t *sizep) +{ + char path[PATH_MAX]; + const char *procfs = procfs__mountpoint(); + + if (!procfs) + return -1; + + snprintf(path, sizeof(path), "%s/%s", procfs, entry); + + return filename__read_str(path, buf, sizep); +} + +static int sysfs__read_ull_base(const char *entry, + unsigned long long *value, int base) +{ + char path[PATH_MAX]; + const char *sysfs = sysfs__mountpoint(); + + if (!sysfs) + return -1; + + snprintf(path, sizeof(path), "%s/%s", sysfs, entry); + + return filename__read_ull_base(path, value, base); +} + +int sysfs__read_xll(const char *entry, unsigned long long *value) +{ + return sysfs__read_ull_base(entry, value, 16); +} + +int sysfs__read_ull(const char *entry, unsigned long long *value) +{ + return sysfs__read_ull_base(entry, value, 0); +} + +int sysfs__read_int(const char *entry, int *value) +{ + char path[PATH_MAX]; + const char *sysfs = sysfs__mountpoint(); + + if (!sysfs) + return -1; + + snprintf(path, sizeof(path), "%s/%s", sysfs, entry); + + return filename__read_int(path, value); +} + +int sysfs__read_str(const char *entry, char **buf, size_t *sizep) +{ + char path[PATH_MAX]; + const char *sysfs = sysfs__mountpoint(); + + if (!sysfs) + return -1; + + snprintf(path, sizeof(path), "%s/%s", sysfs, entry); + + return filename__read_str(path, buf, sizep); +} + +int sysfs__read_bool(const char *entry, bool *value) +{ + struct io io; + char bf[16]; + int ret = 0; + char path[PATH_MAX]; + const char *sysfs = sysfs__mountpoint(); + + if (!sysfs) + return -1; + + snprintf(path, sizeof(path), "%s/%s", sysfs, entry); + io.fd = open(path, O_RDONLY); + if (io.fd < 0) + return -errno; + + io__init(&io, io.fd, bf, sizeof(bf)); + switch (io__get_char(&io)) { + case '1': + case 'y': + case 'Y': + *value = true; + break; + case '0': + case 'n': + case 'N': + *value = false; + break; + default: + ret = -1; + } + close(io.fd); + + return ret; +} +int sysctl__read_int(const char *sysctl, int *value) +{ + char path[PATH_MAX]; + const char *procfs = procfs__mountpoint(); + + if (!procfs) + return -1; + + snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl); + + return filename__read_int(path, value); +} + +int sysfs__write_int(const char *entry, int value) +{ + char path[PATH_MAX]; + const char *sysfs = sysfs__mountpoint(); + + if (!sysfs) + return -1; + + if (snprintf(path, sizeof(path), "%s/%s", sysfs, entry) >= PATH_MAX) + return -1; + + return filename__write_int(path, value); +} diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h new file mode 100644 index 000000000..aa222ca30 --- /dev/null +++ b/tools/lib/api/fs/fs.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __API_FS__ +#define __API_FS__ + +#include <stdbool.h> +#include <unistd.h> + +/* + * On most systems <limits.h> would have given us this, but not on some systems + * (e.g. GNU/Hurd). + */ +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +#define FS(name) \ + const char *name##__mountpoint(void); \ + const char *name##__mount(void); \ + bool name##__configured(void); \ + +/* + * The xxxx__mountpoint() entry points find the first match mount point for each + * filesystems listed below, where xxxx is the filesystem type. + * + * The interface is as follows: + * + * - If a mount point is found on first call, it is cached and used for all + * subsequent calls. + * + * - If a mount point is not found, NULL is returned on first call and all + * subsequent calls. + */ +FS(sysfs) +FS(procfs) +FS(debugfs) +FS(tracefs) +FS(hugetlbfs) +FS(bpf_fs) + +#undef FS + + +int cgroupfs_find_mountpoint(char *buf, size_t maxlen, const char *subsys); + +int filename__read_int(const char *filename, int *value); +int filename__read_ull(const char *filename, unsigned long long *value); +int filename__read_xll(const char *filename, unsigned long long *value); +int filename__read_str(const char *filename, char **buf, size_t *sizep); + +int filename__write_int(const char *filename, int value); + +int procfs__read_str(const char *entry, char **buf, size_t *sizep); + +int sysctl__read_int(const char *sysctl, int *value); +int sysfs__read_int(const char *entry, int *value); +int sysfs__read_ull(const char *entry, unsigned long long *value); +int sysfs__read_xll(const char *entry, unsigned long long *value); +int sysfs__read_str(const char *entry, char **buf, size_t *sizep); +int sysfs__read_bool(const char *entry, bool *value); + +int sysfs__write_int(const char *entry, int value); +#endif /* __API_FS__ */ diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_path.c new file mode 100644 index 000000000..834fd64c7 --- /dev/null +++ b/tools/lib/api/fs/tracing_path.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <linux/string.h> +#include <errno.h> +#include <unistd.h> +#include "fs.h" + +#include "tracing_path.h" + +static char tracing_path[PATH_MAX] = "/sys/kernel/tracing"; + +static void __tracing_path_set(const char *tracing, const char *mountpoint) +{ + snprintf(tracing_path, sizeof(tracing_path), "%s/%s", + mountpoint, tracing); +} + +static const char *tracing_path_tracefs_mount(void) +{ + const char *mnt; + + mnt = tracefs__mount(); + if (!mnt) + return NULL; + + __tracing_path_set("", mnt); + + return tracing_path; +} + +static const char *tracing_path_debugfs_mount(void) +{ + const char *mnt; + + mnt = debugfs__mount(); + if (!mnt) + return NULL; + + __tracing_path_set("tracing/", mnt); + + return tracing_path; +} + +const char *tracing_path_mount(void) +{ + const char *mnt; + + mnt = tracing_path_tracefs_mount(); + if (mnt) + return mnt; + + mnt = tracing_path_debugfs_mount(); + + return mnt; +} + +void tracing_path_set(const char *mntpt) +{ + __tracing_path_set("tracing/", mntpt); +} + +char *get_tracing_file(const char *name) +{ + char *file; + + if (asprintf(&file, "%s%s", tracing_path_mount(), name) < 0) + return NULL; + + return file; +} + +void put_tracing_file(char *file) +{ + free(file); +} + +char *get_events_file(const char *name) +{ + char *file; + + if (asprintf(&file, "%s/events/%s", tracing_path_mount(), name) < 0) + return NULL; + + return file; +} + +void put_events_file(char *file) +{ + free(file); +} + +DIR *tracing_events__opendir(void) +{ + DIR *dir = NULL; + char *path = get_tracing_file("events"); + + if (path) { + dir = opendir(path); + put_events_file(path); + } + + return dir; +} + +int tracing_events__scandir_alphasort(struct dirent ***namelist) +{ + char *path = get_tracing_file("events"); + int ret; + + if (!path) { + *namelist = NULL; + return 0; + } + + ret = scandir(path, namelist, NULL, alphasort); + put_events_file(path); + + return ret; +} + +int tracing_path__strerror_open_tp(int err, char *buf, size_t size, + const char *sys, const char *name) +{ + char sbuf[128]; + char filename[PATH_MAX]; + + snprintf(filename, PATH_MAX, "%s/%s", sys, name ?: "*"); + + switch (err) { + case ENOENT: + /* + * We will get here if we can't find the tracepoint, but one of + * debugfs or tracefs is configured, which means you probably + * want some tracepoint which wasn't compiled in your kernel. + * - jirka + */ + if (debugfs__configured() || tracefs__configured()) { + /* sdt markers */ + if (!strncmp(filename, "sdt_", 4)) { + snprintf(buf, size, + "Error:\tFile %s/events/%s not found.\n" + "Hint:\tSDT event cannot be directly recorded on.\n" + "\tPlease first use 'perf probe %s:%s' before recording it.\n", + tracing_path, filename, sys, name); + } else { + snprintf(buf, size, + "Error:\tFile %s/events/%s not found.\n" + "Hint:\tPerhaps this kernel misses some CONFIG_ setting to enable this feature?.\n", + tracing_path, filename); + } + break; + } + snprintf(buf, size, "%s", + "Error:\tUnable to find debugfs/tracefs\n" + "Hint:\tWas your kernel compiled with debugfs/tracefs support?\n" + "Hint:\tIs the debugfs/tracefs filesystem mounted?\n" + "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'"); + break; + case EACCES: { + snprintf(buf, size, + "Error:\tNo permissions to read %s/events/%s\n" + "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n", + tracing_path, filename, tracing_path_mount()); + } + break; + default: + snprintf(buf, size, "%s", str_error_r(err, sbuf, sizeof(sbuf))); + break; + } + + return 0; +} diff --git a/tools/lib/api/fs/tracing_path.h b/tools/lib/api/fs/tracing_path.h new file mode 100644 index 000000000..fc6347c11 --- /dev/null +++ b/tools/lib/api/fs/tracing_path.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __API_FS_TRACING_PATH_H +#define __API_FS_TRACING_PATH_H + +#include <linux/types.h> +#include <dirent.h> + +DIR *tracing_events__opendir(void); +int tracing_events__scandir_alphasort(struct dirent ***namelist); + +void tracing_path_set(const char *mountpoint); +const char *tracing_path_mount(void); + +char *get_tracing_file(const char *name); +void put_tracing_file(char *file); + +char *get_events_file(const char *name); +void put_events_file(char *file); + +#define zput_events_file(ptr) ({ free(*ptr); *ptr = NULL; }) + +int tracing_path__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name); +#endif /* __API_FS_TRACING_PATH_H */ |
