1 // SPDX-License-Identifier: GPL-2.0
11 #include <sys/types.h>
16 #include <sys/mount.h>
19 #include "debug-internal.h"
22 #define STR(x) _STR(x)
25 #define SYSFS_MAGIC 0x62656572
28 #ifndef PROC_SUPER_MAGIC
29 #define PROC_SUPER_MAGIC 0x9fa0
33 #define DEBUGFS_MAGIC 0x64626720
37 #define TRACEFS_MAGIC 0x74726163
40 #ifndef HUGETLBFS_MAGIC
41 #define HUGETLBFS_MAGIC 0x958458f6
45 #define BPF_FS_MAGIC 0xcafe4a11
48 static const char * const sysfs__known_mountpoints[] = {
53 static const char * const procfs__known_mountpoints[] = {
58 #ifndef DEBUGFS_DEFAULT_PATH
59 #define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug"
62 static const char * const debugfs__known_mountpoints[] = {
69 #ifndef TRACEFS_DEFAULT_PATH
70 #define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing"
73 static const char * const tracefs__known_mountpoints[] = {
75 "/sys/kernel/debug/tracing",
81 static const char * const hugetlbfs__known_mountpoints[] = {
85 static const char * const bpf_fs__known_mountpoints[] = {
91 const char * const name;
92 const char * const * const mounts;
94 pthread_mutex_t mount_mutex;
99 #define TRACEFS_MAGIC 0x74726163
102 static void fs__init_once(struct fs *fs);
103 static const char *fs__mountpoint(const struct fs *fs);
104 static const char *fs__mount(struct fs *fs);
106 #define FS(lower_name, fs_name, upper_name) \
107 static struct fs fs__##lower_name = { \
109 .mounts = lower_name##__known_mountpoints, \
110 .magic = upper_name##_MAGIC, \
111 .mount_mutex = PTHREAD_MUTEX_INITIALIZER, \
114 static void lower_name##_init_once(void) \
116 struct fs *fs = &fs__##lower_name; \
121 const char *lower_name##__mountpoint(void) \
123 static pthread_once_t init_once = PTHREAD_ONCE_INIT; \
124 struct fs *fs = &fs__##lower_name; \
126 pthread_once(&init_once, lower_name##_init_once); \
127 return fs__mountpoint(fs); \
130 const char *lower_name##__mount(void) \
132 const char *mountpoint = lower_name##__mountpoint(); \
133 struct fs *fs = &fs__##lower_name; \
138 return fs__mount(fs); \
141 bool lower_name##__configured(void) \
143 return lower_name##__mountpoint() != NULL; \
146 FS(sysfs, sysfs, SYSFS);
147 FS(procfs, procfs, PROC_SUPER);
148 FS(debugfs, debugfs, DEBUGFS);
149 FS(tracefs, tracefs, TRACEFS);
150 FS(hugetlbfs, hugetlbfs, HUGETLBFS);
151 FS(bpf_fs, bpf, BPF_FS);
153 static bool fs__read_mounts(struct fs *fs)
157 char path[PATH_MAX + 1];
159 fp = fopen("/proc/mounts", "r");
163 while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
166 if (strcmp(type, fs->name) == 0) {
167 fs->path = strdup(path);
169 return fs->path != NULL;
176 static int fs__valid_mount(const char *fs, long magic)
180 if (statfs(fs, &st_fs) < 0)
182 else if ((long)st_fs.f_type != magic)
188 static bool fs__check_mounts(struct fs *fs)
190 const char * const *ptr;
194 if (fs__valid_mount(*ptr, fs->magic) == 0) {
195 fs->path = strdup(*ptr);
206 static void mem_toupper(char *f, size_t len)
216 * Check for "NAME_PATH" environment variable to override fs location (for
217 * testing). This matches the recommendation in Documentation/admin-guide/sysfs-rules.rst
220 static bool fs__env_override(struct fs *fs)
223 size_t name_len = strlen(fs->name);
224 /* name + "_PATH" + '\0' */
225 char upper_name[name_len + 5 + 1];
227 memcpy(upper_name, fs->name, name_len);
228 mem_toupper(upper_name, name_len);
229 strcpy(&upper_name[name_len], "_PATH");
231 override_path = getenv(upper_name);
235 fs->path = strdup(override_path);
241 static void fs__init_once(struct fs *fs)
243 if (!fs__env_override(fs) &&
244 !fs__check_mounts(fs) &&
245 !fs__read_mounts(fs)) {
252 static const char *fs__mountpoint(const struct fs *fs)
257 static const char *mount_overload(struct fs *fs)
259 size_t name_len = strlen(fs->name);
260 /* "PERF_" + name + "_ENVIRONMENT" + '\0' */
261 char upper_name[5 + name_len + 12 + 1];
263 snprintf(upper_name, name_len, "PERF_%s_ENVIRONMENT", fs->name);
264 mem_toupper(upper_name, name_len);
266 return getenv(upper_name) ?: *fs->mounts;
269 static const char *fs__mount(struct fs *fs)
271 const char *mountpoint;
273 pthread_mutex_lock(&fs->mount_mutex);
275 /* Check if path found inside the mutex to avoid races with other callers of mount. */
276 mountpoint = fs__mountpoint(fs);
280 mountpoint = mount_overload(fs);
282 if (mount(NULL, mountpoint, fs->name, 0, NULL) == 0 &&
283 fs__valid_mount(mountpoint, fs->magic) == 0) {
284 fs->path = strdup(mountpoint);
285 mountpoint = fs->path;
288 pthread_mutex_unlock(&fs->mount_mutex);
292 int filename__read_int(const char *filename, int *value)
295 int fd = open(filename, O_RDONLY), err = -1;
300 if (read(fd, line, sizeof(line)) > 0) {
309 static int filename__read_ull_base(const char *filename,
310 unsigned long long *value, int base)
313 int fd = open(filename, O_RDONLY), err = -1;
318 if (read(fd, line, sizeof(line)) > 0) {
319 *value = strtoull(line, NULL, base);
320 if (*value != ULLONG_MAX)
329 * Parses @value out of @filename with strtoull.
330 * By using 16 for base to treat the number as hex.
332 int filename__read_xll(const char *filename, unsigned long long *value)
334 return filename__read_ull_base(filename, value, 16);
338 * Parses @value out of @filename with strtoull.
339 * By using 0 for base, the strtoull detects the
340 * base automatically (see man strtoull).
342 int filename__read_ull(const char *filename, unsigned long long *value)
344 return filename__read_ull_base(filename, value, 0);
347 #define STRERR_BUFSIZE 128 /* For the buffer size of strerror_r */
349 int filename__read_str(const char *filename, char **buf, size_t *sizep)
351 size_t size = 0, alloc_size = 0;
352 void *bf = NULL, *nbf;
354 char sbuf[STRERR_BUFSIZE];
356 fd = open(filename, O_RDONLY);
361 if (size == alloc_size) {
362 alloc_size += BUFSIZ;
363 nbf = realloc(bf, alloc_size);
372 n = read(fd, bf + size, alloc_size - size);
375 pr_warn("read failed %d: %s\n", errno,
376 strerror_r(errno, sbuf, sizeof(sbuf)));
397 int filename__write_int(const char *filename, int value)
399 int fd = open(filename, O_WRONLY), err = -1;
405 sprintf(buf, "%d", value);
406 if (write(fd, buf, sizeof(buf)) == sizeof(buf))
413 int procfs__read_str(const char *entry, char **buf, size_t *sizep)
416 const char *procfs = procfs__mountpoint();
421 snprintf(path, sizeof(path), "%s/%s", procfs, entry);
423 return filename__read_str(path, buf, sizep);
426 static int sysfs__read_ull_base(const char *entry,
427 unsigned long long *value, int base)
430 const char *sysfs = sysfs__mountpoint();
435 snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
437 return filename__read_ull_base(path, value, base);
440 int sysfs__read_xll(const char *entry, unsigned long long *value)
442 return sysfs__read_ull_base(entry, value, 16);
445 int sysfs__read_ull(const char *entry, unsigned long long *value)
447 return sysfs__read_ull_base(entry, value, 0);
450 int sysfs__read_int(const char *entry, int *value)
453 const char *sysfs = sysfs__mountpoint();
458 snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
460 return filename__read_int(path, value);
463 int sysfs__read_str(const char *entry, char **buf, size_t *sizep)
466 const char *sysfs = sysfs__mountpoint();
471 snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
473 return filename__read_str(path, buf, sizep);
476 int sysfs__read_bool(const char *entry, bool *value)
482 ret = sysfs__read_str(entry, &buf, &size);
505 int sysctl__read_int(const char *sysctl, int *value)
508 const char *procfs = procfs__mountpoint();
513 snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
515 return filename__read_int(path, value);
518 int sysfs__write_int(const char *entry, int value)
521 const char *sysfs = sysfs__mountpoint();
526 if (snprintf(path, sizeof(path), "%s/%s", sysfs, entry) >= PATH_MAX)
529 return filename__write_int(path, value);