1 // SPDX-License-Identifier: GPL-2.0
11 #include <sys/types.h>
16 #include <sys/mount.h>
20 #include "debug-internal.h"
23 #define STR(x) _STR(x)
26 #define SYSFS_MAGIC 0x62656572
29 #ifndef PROC_SUPER_MAGIC
30 #define PROC_SUPER_MAGIC 0x9fa0
34 #define DEBUGFS_MAGIC 0x64626720
38 #define TRACEFS_MAGIC 0x74726163
41 #ifndef HUGETLBFS_MAGIC
42 #define HUGETLBFS_MAGIC 0x958458f6
46 #define BPF_FS_MAGIC 0xcafe4a11
49 static const char * const sysfs__known_mountpoints[] = {
54 static const char * const procfs__known_mountpoints[] = {
59 #ifndef DEBUGFS_DEFAULT_PATH
60 #define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug"
63 static const char * const debugfs__known_mountpoints[] = {
70 #ifndef TRACEFS_DEFAULT_PATH
71 #define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing"
74 static const char * const tracefs__known_mountpoints[] = {
76 "/sys/kernel/debug/tracing",
82 static const char * const hugetlbfs__known_mountpoints[] = {
86 static const char * const bpf_fs__known_mountpoints[] = {
92 const char * const name;
93 const char * const * const mounts;
95 pthread_mutex_t mount_mutex;
100 #define TRACEFS_MAGIC 0x74726163
103 static void fs__init_once(struct fs *fs);
104 static const char *fs__mountpoint(const struct fs *fs);
105 static const char *fs__mount(struct fs *fs);
107 #define FS(lower_name, fs_name, upper_name) \
108 static struct fs fs__##lower_name = { \
110 .mounts = lower_name##__known_mountpoints, \
111 .magic = upper_name##_MAGIC, \
112 .mount_mutex = PTHREAD_MUTEX_INITIALIZER, \
115 static void lower_name##_init_once(void) \
117 struct fs *fs = &fs__##lower_name; \
122 const char *lower_name##__mountpoint(void) \
124 static pthread_once_t init_once = PTHREAD_ONCE_INIT; \
125 struct fs *fs = &fs__##lower_name; \
127 pthread_once(&init_once, lower_name##_init_once); \
128 return fs__mountpoint(fs); \
131 const char *lower_name##__mount(void) \
133 const char *mountpoint = lower_name##__mountpoint(); \
134 struct fs *fs = &fs__##lower_name; \
139 return fs__mount(fs); \
142 bool lower_name##__configured(void) \
144 return lower_name##__mountpoint() != NULL; \
147 FS(sysfs, sysfs, SYSFS);
148 FS(procfs, procfs, PROC_SUPER);
149 FS(debugfs, debugfs, DEBUGFS);
150 FS(tracefs, tracefs, TRACEFS);
151 FS(hugetlbfs, hugetlbfs, HUGETLBFS);
152 FS(bpf_fs, bpf, BPF_FS);
154 static bool fs__read_mounts(struct fs *fs)
158 char path[PATH_MAX + 1];
160 fp = fopen("/proc/mounts", "r");
164 while (fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
167 if (strcmp(type, fs->name) == 0) {
168 fs->path = strdup(path);
170 return fs->path != NULL;
177 static int fs__valid_mount(const char *fs, long magic)
181 if (statfs(fs, &st_fs) < 0)
183 else if ((long)st_fs.f_type != magic)
189 static bool fs__check_mounts(struct fs *fs)
191 const char * const *ptr;
195 if (fs__valid_mount(*ptr, fs->magic) == 0) {
196 fs->path = strdup(*ptr);
207 static void mem_toupper(char *f, size_t len)
217 * Check for "NAME_PATH" environment variable to override fs location (for
218 * testing). This matches the recommendation in Documentation/admin-guide/sysfs-rules.rst
221 static bool fs__env_override(struct fs *fs)
224 size_t name_len = strlen(fs->name);
225 /* name + "_PATH" + '\0' */
226 char upper_name[name_len + 5 + 1];
228 memcpy(upper_name, fs->name, name_len);
229 mem_toupper(upper_name, name_len);
230 strcpy(&upper_name[name_len], "_PATH");
232 override_path = getenv(upper_name);
236 fs->path = strdup(override_path);
242 static void fs__init_once(struct fs *fs)
244 if (!fs__env_override(fs) &&
245 !fs__check_mounts(fs) &&
246 !fs__read_mounts(fs)) {
253 static const char *fs__mountpoint(const struct fs *fs)
258 static const char *mount_overload(struct fs *fs)
260 size_t name_len = strlen(fs->name);
261 /* "PERF_" + name + "_ENVIRONMENT" + '\0' */
262 char upper_name[5 + name_len + 12 + 1];
264 snprintf(upper_name, name_len, "PERF_%s_ENVIRONMENT", fs->name);
265 mem_toupper(upper_name, name_len);
267 return getenv(upper_name) ?: *fs->mounts;
270 static const char *fs__mount(struct fs *fs)
272 const char *mountpoint;
274 pthread_mutex_lock(&fs->mount_mutex);
276 /* Check if path found inside the mutex to avoid races with other callers of mount. */
277 mountpoint = fs__mountpoint(fs);
281 mountpoint = mount_overload(fs);
283 if (mount(NULL, mountpoint, fs->name, 0, NULL) == 0 &&
284 fs__valid_mount(mountpoint, fs->magic) == 0) {
285 fs->path = strdup(mountpoint);
286 mountpoint = fs->path;
289 pthread_mutex_unlock(&fs->mount_mutex);
293 int filename__read_int(const char *filename, int *value)
296 int fd = open(filename, O_RDONLY), err = -1;
301 if (read(fd, line, sizeof(line)) > 0) {
310 static int filename__read_ull_base(const char *filename,
311 unsigned long long *value, int base)
314 int fd = open(filename, O_RDONLY), err = -1;
319 if (read(fd, line, sizeof(line)) > 0) {
320 *value = strtoull(line, NULL, base);
321 if (*value != ULLONG_MAX)
330 * Parses @value out of @filename with strtoull.
331 * By using 16 for base to treat the number as hex.
333 int filename__read_xll(const char *filename, unsigned long long *value)
335 return filename__read_ull_base(filename, value, 16);
339 * Parses @value out of @filename with strtoull.
340 * By using 0 for base, the strtoull detects the
341 * base automatically (see man strtoull).
343 int filename__read_ull(const char *filename, unsigned long long *value)
345 return filename__read_ull_base(filename, value, 0);
348 int filename__read_str(const char *filename, char **buf, size_t *sizep)
354 io.fd = open(filename, O_RDONLY);
357 io__init(&io, io.fd, bf, sizeof(bf));
359 err = io__getdelim(&io, buf, sizep, /*delim=*/-1);
369 int filename__write_int(const char *filename, int value)
371 int fd = open(filename, O_WRONLY), err = -1;
377 sprintf(buf, "%d", value);
378 if (write(fd, buf, sizeof(buf)) == sizeof(buf))
385 int procfs__read_str(const char *entry, char **buf, size_t *sizep)
388 const char *procfs = procfs__mountpoint();
393 snprintf(path, sizeof(path), "%s/%s", procfs, entry);
395 return filename__read_str(path, buf, sizep);
398 static int sysfs__read_ull_base(const char *entry,
399 unsigned long long *value, int base)
402 const char *sysfs = sysfs__mountpoint();
407 snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
409 return filename__read_ull_base(path, value, base);
412 int sysfs__read_xll(const char *entry, unsigned long long *value)
414 return sysfs__read_ull_base(entry, value, 16);
417 int sysfs__read_ull(const char *entry, unsigned long long *value)
419 return sysfs__read_ull_base(entry, value, 0);
422 int sysfs__read_int(const char *entry, int *value)
425 const char *sysfs = sysfs__mountpoint();
430 snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
432 return filename__read_int(path, value);
435 int sysfs__read_str(const char *entry, char **buf, size_t *sizep)
438 const char *sysfs = sysfs__mountpoint();
443 snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
445 return filename__read_str(path, buf, sizep);
448 int sysfs__read_bool(const char *entry, bool *value)
454 const char *sysfs = sysfs__mountpoint();
459 snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
460 io.fd = open(path, O_RDONLY);
464 io__init(&io, io.fd, bf, sizeof(bf));
465 switch (io__get_char(&io)) {
483 int sysctl__read_int(const char *sysctl, int *value)
486 const char *procfs = procfs__mountpoint();
491 snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
493 return filename__read_int(path, value);
496 int sysfs__write_int(const char *entry, int value)
499 const char *sysfs = sysfs__mountpoint();
504 if (snprintf(path, sizeof(path), "%s/%s", sysfs, entry) >= PATH_MAX)
507 return filename__write_int(path, value);