1
1
// SPDX-License-Identifier: GPL-2.0
2
+ #include <assert.h>
2
3
#include <ctype.h>
3
4
#include <errno.h>
4
5
#include <limits.h>
10
11
#include <sys/types.h>
11
12
#include <sys/stat.h>
12
13
#include <fcntl.h>
14
+ #include <pthread.h>
13
15
#include <unistd.h>
14
16
#include <sys/mount.h>
15
17
43
45
#define BPF_FS_MAGIC 0xcafe4a11
44
46
#endif
45
47
46
- static const char * const sysfs__fs_known_mountpoints [] = {
48
+ static const char * const sysfs__known_mountpoints [] = {
47
49
"/sys" ,
48
50
0 ,
49
51
};
@@ -86,69 +88,70 @@ static const char * const bpf_fs__known_mountpoints[] = {
86
88
};
87
89
88
90
struct fs {
89
- const char * name ;
90
- const char * const * mounts ;
91
+ const char * const name ;
92
+ const char * const * const mounts ;
91
93
char * path ;
92
- bool found ;
93
- bool checked ;
94
- long magic ;
95
- };
96
-
97
- enum {
98
- FS__SYSFS = 0 ,
99
- FS__PROCFS = 1 ,
100
- FS__DEBUGFS = 2 ,
101
- FS__TRACEFS = 3 ,
102
- FS__HUGETLBFS = 4 ,
103
- FS__BPF_FS = 5 ,
94
+ pthread_mutex_t mount_mutex ;
95
+ const long magic ;
104
96
};
105
97
106
98
#ifndef TRACEFS_MAGIC
107
99
#define TRACEFS_MAGIC 0x74726163
108
100
#endif
109
101
110
- static struct fs fs__entries [] = {
111
- [FS__SYSFS ] = {
112
- .name = "sysfs" ,
113
- .mounts = sysfs__fs_known_mountpoints ,
114
- .magic = SYSFS_MAGIC ,
115
- .checked = false,
116
- },
117
- [FS__PROCFS ] = {
118
- .name = "proc" ,
119
- .mounts = procfs__known_mountpoints ,
120
- .magic = PROC_SUPER_MAGIC ,
121
- .checked = false,
122
- },
123
- [FS__DEBUGFS ] = {
124
- .name = "debugfs" ,
125
- .mounts = debugfs__known_mountpoints ,
126
- .magic = DEBUGFS_MAGIC ,
127
- .checked = false,
128
- },
129
- [FS__TRACEFS ] = {
130
- .name = "tracefs" ,
131
- .mounts = tracefs__known_mountpoints ,
132
- .magic = TRACEFS_MAGIC ,
133
- .checked = false,
134
- },
135
- [FS__HUGETLBFS ] = {
136
- .name = "hugetlbfs" ,
137
- .mounts = hugetlbfs__known_mountpoints ,
138
- .magic = HUGETLBFS_MAGIC ,
139
- .checked = false,
140
- },
141
- [FS__BPF_FS ] = {
142
- .name = "bpf" ,
143
- .mounts = bpf_fs__known_mountpoints ,
144
- .magic = BPF_FS_MAGIC ,
145
- .checked = false,
146
- },
147
- };
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 );
105
+
106
+ #define FS (lower_name , fs_name , upper_name ) \
107
+ static struct fs fs__##lower_name = { \
108
+ .name = #fs_name, \
109
+ .mounts = lower_name##__known_mountpoints, \
110
+ .magic = upper_name##_MAGIC, \
111
+ .mount_mutex = PTHREAD_MUTEX_INITIALIZER, \
112
+ }; \
113
+ \
114
+ static void lower_name##_init_once(void) \
115
+ { \
116
+ struct fs *fs = &fs__##lower_name; \
117
+ \
118
+ fs__init_once(fs); \
119
+ } \
120
+ \
121
+ const char *lower_name##__mountpoint(void) \
122
+ { \
123
+ static pthread_once_t init_once = PTHREAD_ONCE_INIT; \
124
+ struct fs *fs = &fs__##lower_name; \
125
+ \
126
+ pthread_once(&init_once, lower_name##_init_once); \
127
+ return fs__mountpoint(fs); \
128
+ } \
129
+ \
130
+ const char *lower_name##__mount(void) \
131
+ { \
132
+ const char *mountpoint = lower_name##__mountpoint(); \
133
+ struct fs *fs = &fs__##lower_name; \
134
+ \
135
+ if (mountpoint) \
136
+ return mountpoint; \
137
+ \
138
+ return fs__mount(fs); \
139
+ } \
140
+ \
141
+ bool lower_name##__configured(void) \
142
+ { \
143
+ return lower_name##__mountpoint() != NULL; \
144
+ }
145
+
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 );
148
152
149
153
static bool fs__read_mounts (struct fs * fs )
150
154
{
151
- bool found = false;
152
155
char type [100 ];
153
156
FILE * fp ;
154
157
char path [PATH_MAX + 1 ];
@@ -157,22 +160,17 @@ static bool fs__read_mounts(struct fs *fs)
157
160
if (fp == NULL )
158
161
return false;
159
162
160
- while (!found &&
161
- fscanf (fp , "%*s %" STR (PATH_MAX ) "s %99s %*s %*d %*d\n" ,
163
+ while (fscanf (fp , "%*s %" STR (PATH_MAX ) "s %99s %*s %*d %*d\n" ,
162
164
path , type ) == 2 ) {
163
165
164
166
if (strcmp (type , fs -> name ) == 0 ) {
165
- free (fs -> path );
166
167
fs -> path = strdup (path );
167
- if (!fs -> path )
168
- return false;
169
- found = true;
168
+ fclose (fp );
169
+ return fs -> path != NULL ;
170
170
}
171
171
}
172
-
173
172
fclose (fp );
174
- fs -> checked = true;
175
- return fs -> found = found ;
173
+ return false;
176
174
}
177
175
178
176
static int fs__valid_mount (const char * fs , long magic )
@@ -194,11 +192,9 @@ static bool fs__check_mounts(struct fs *fs)
194
192
ptr = fs -> mounts ;
195
193
while (* ptr ) {
196
194
if (fs__valid_mount (* ptr , fs -> magic ) == 0 ) {
197
- free (fs -> path );
198
195
fs -> path = strdup (* ptr );
199
196
if (!fs -> path )
200
197
return false;
201
- fs -> found = true;
202
198
return true;
203
199
}
204
200
ptr ++ ;
@@ -236,45 +232,26 @@ static bool fs__env_override(struct fs *fs)
236
232
if (!override_path )
237
233
return false;
238
234
239
- free (fs -> path );
240
235
fs -> path = strdup (override_path );
241
236
if (!fs -> path )
242
237
return false;
243
- fs -> found = true;
244
- fs -> checked = true;
245
238
return true;
246
239
}
247
240
248
- static const char * fs__get_mountpoint (struct fs * fs )
241
+ static void fs__init_once (struct fs * fs )
249
242
{
250
- if (fs__env_override (fs ))
251
- return fs -> path ;
252
-
253
- if (fs__check_mounts (fs ))
254
- return fs -> path ;
255
-
256
- if (fs__read_mounts (fs ))
257
- return fs -> path ;
258
-
259
- return NULL ;
243
+ if (!fs__env_override (fs ) &&
244
+ !fs__check_mounts (fs ) &&
245
+ !fs__read_mounts (fs )) {
246
+ assert (!fs -> path );
247
+ } else {
248
+ assert (fs -> path );
249
+ }
260
250
}
261
251
262
- static const char * fs__mountpoint (int idx )
252
+ static const char * fs__mountpoint (const struct fs * fs )
263
253
{
264
- struct fs * fs = & fs__entries [idx ];
265
-
266
- if (fs -> found )
267
- return (const char * )fs -> path ;
268
-
269
- /* the mount point was already checked for the mount point
270
- * but and did not exist, so return NULL to avoid scanning again.
271
- * This makes the found and not found paths cost equivalent
272
- * in case of multiple calls.
273
- */
274
- if (fs -> checked )
275
- return NULL ;
276
-
277
- return fs__get_mountpoint (fs );
254
+ return fs -> path ;
278
255
}
279
256
280
257
static const char * mount_overload (struct fs * fs )
@@ -289,45 +266,29 @@ static const char *mount_overload(struct fs *fs)
289
266
return getenv (upper_name ) ?: * fs -> mounts ;
290
267
}
291
268
292
- static const char * fs__mount (int idx )
269
+ static const char * fs__mount (struct fs * fs )
293
270
{
294
- struct fs * fs = & fs__entries [idx ];
295
271
const char * mountpoint ;
296
272
297
- if (fs__mountpoint (idx ))
298
- return (const char * )fs -> path ;
273
+ pthread_mutex_lock (& fs -> mount_mutex );
299
274
300
- mountpoint = mount_overload (fs );
275
+ /* Check if path found inside the mutex to avoid races with other callers of mount. */
276
+ mountpoint = fs__mountpoint (fs );
277
+ if (mountpoint )
278
+ goto out ;
301
279
302
- if (mount (NULL , mountpoint , fs -> name , 0 , NULL ) < 0 )
303
- return NULL ;
304
-
305
- return fs__check_mounts (fs ) ? fs -> path : NULL ;
306
- }
280
+ mountpoint = mount_overload (fs );
307
281
308
- #define FS (name , idx ) \
309
- const char *name##__mountpoint(void) \
310
- { \
311
- return fs__mountpoint(idx); \
312
- } \
313
- \
314
- const char *name##__mount(void) \
315
- { \
316
- return fs__mount(idx); \
317
- } \
318
- \
319
- bool name##__configured(void) \
320
- { \
321
- return name##__mountpoint() != NULL; \
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 ;
286
+ }
287
+ out :
288
+ pthread_mutex_unlock (& fs -> mount_mutex );
289
+ return mountpoint ;
322
290
}
323
291
324
- FS (sysfs , FS__SYSFS );
325
- FS (procfs , FS__PROCFS );
326
- FS (debugfs , FS__DEBUGFS );
327
- FS (tracefs , FS__TRACEFS );
328
- FS (hugetlbfs , FS__HUGETLBFS );
329
- FS (bpf_fs , FS__BPF_FS );
330
-
331
292
int filename__read_int (const char * filename , int * value )
332
293
{
333
294
char line [64 ];
0 commit comments