Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
4282d606 SRRH |
2 | /* |
3 | * inode.c - part of tracefs, a pseudo file system for activating tracing | |
4 | * | |
5 | * Based on debugfs by: Greg Kroah-Hartman <greg@kroah.com> | |
6 | * | |
7 | * Copyright (C) 2014 Red Hat Inc, author: Steven Rostedt <srostedt@redhat.com> | |
8 | * | |
4282d606 | 9 | * tracefs is the file system that is used by the tracing infrastructure. |
4282d606 SRRH |
10 | */ |
11 | ||
12 | #include <linux/module.h> | |
13 | #include <linux/fs.h> | |
78ff6408 DH |
14 | #include <linux/fs_context.h> |
15 | #include <linux/fs_parser.h> | |
cc31004a | 16 | #include <linux/kobject.h> |
4282d606 SRRH |
17 | #include <linux/namei.h> |
18 | #include <linux/tracefs.h> | |
19 | #include <linux/fsnotify.h> | |
bf8e6021 | 20 | #include <linux/security.h> |
4282d606 | 21 | #include <linux/seq_file.h> |
4282d606 SRRH |
22 | #include <linux/magic.h> |
23 | #include <linux/slab.h> | |
ba37ff75 | 24 | #include "internal.h" |
4282d606 SRRH |
25 | |
26 | #define TRACEFS_DEFAULT_MODE 0700 | |
ba37ff75 | 27 | static struct kmem_cache *tracefs_inode_cachep __ro_after_init; |
4282d606 SRRH |
28 | |
29 | static struct vfsmount *tracefs_mount; | |
30 | static int tracefs_mount_count; | |
31 | static bool tracefs_registered; | |
32 | ||
baa23a8d SRG |
33 | /* |
34 | * Keep track of all tracefs_inodes in order to update their | |
35 | * flags if necessary on a remount. | |
36 | */ | |
37 | static DEFINE_SPINLOCK(tracefs_inode_lock); | |
38 | static LIST_HEAD(tracefs_inodes); | |
39 | ||
ba37ff75 AK |
40 | static struct inode *tracefs_alloc_inode(struct super_block *sb) |
41 | { | |
42 | struct tracefs_inode *ti; | |
baa23a8d | 43 | unsigned long flags; |
ba37ff75 | 44 | |
0df2ac59 | 45 | ti = alloc_inode_sb(sb, tracefs_inode_cachep, GFP_KERNEL); |
ba37ff75 AK |
46 | if (!ti) |
47 | return NULL; | |
48 | ||
baa23a8d SRG |
49 | spin_lock_irqsave(&tracefs_inode_lock, flags); |
50 | list_add_rcu(&ti->list, &tracefs_inodes); | |
51 | spin_unlock_irqrestore(&tracefs_inode_lock, flags); | |
52 | ||
ba37ff75 AK |
53 | return &ti->vfs_inode; |
54 | } | |
55 | ||
0b6743bd | 56 | static void tracefs_free_inode(struct inode *inode) |
baa23a8d | 57 | { |
0b6743bd | 58 | struct tracefs_inode *ti = get_tracefs(inode); |
baa23a8d | 59 | |
baa23a8d SRG |
60 | kmem_cache_free(tracefs_inode_cachep, ti); |
61 | } | |
62 | ||
0b6743bd | 63 | static void tracefs_destroy_inode(struct inode *inode) |
ba37ff75 | 64 | { |
baa23a8d SRG |
65 | struct tracefs_inode *ti = get_tracefs(inode); |
66 | unsigned long flags; | |
67 | ||
68 | spin_lock_irqsave(&tracefs_inode_lock, flags); | |
69 | list_del_rcu(&ti->list); | |
70 | spin_unlock_irqrestore(&tracefs_inode_lock, flags); | |
ba37ff75 AK |
71 | } |
72 | ||
4282d606 SRRH |
73 | static ssize_t default_read_file(struct file *file, char __user *buf, |
74 | size_t count, loff_t *ppos) | |
75 | { | |
76 | return 0; | |
77 | } | |
78 | ||
79 | static ssize_t default_write_file(struct file *file, const char __user *buf, | |
80 | size_t count, loff_t *ppos) | |
81 | { | |
82 | return count; | |
83 | } | |
84 | ||
85 | static const struct file_operations tracefs_file_operations = { | |
86 | .read = default_read_file, | |
87 | .write = default_write_file, | |
88 | .open = simple_open, | |
89 | .llseek = noop_llseek, | |
90 | }; | |
91 | ||
eae47358 SRRH |
92 | static struct tracefs_dir_ops { |
93 | int (*mkdir)(const char *name); | |
94 | int (*rmdir)(const char *name); | |
5248ee85 | 95 | } tracefs_ops __ro_after_init; |
eae47358 SRRH |
96 | |
97 | static char *get_dname(struct dentry *dentry) | |
98 | { | |
99 | const char *dname; | |
100 | char *name; | |
101 | int len = dentry->d_name.len; | |
102 | ||
103 | dname = dentry->d_name.name; | |
104 | name = kmalloc(len + 1, GFP_KERNEL); | |
105 | if (!name) | |
106 | return NULL; | |
107 | memcpy(name, dname, len); | |
108 | name[len] = 0; | |
109 | return name; | |
110 | } | |
111 | ||
c54bd91e | 112 | static int tracefs_syscall_mkdir(struct mnt_idmap *idmap, |
549c7297 CB |
113 | struct inode *inode, struct dentry *dentry, |
114 | umode_t mode) | |
eae47358 | 115 | { |
8186fff7 | 116 | struct tracefs_inode *ti; |
eae47358 SRRH |
117 | char *name; |
118 | int ret; | |
119 | ||
120 | name = get_dname(dentry); | |
121 | if (!name) | |
122 | return -ENOMEM; | |
123 | ||
8186fff7 SRG |
124 | /* |
125 | * This is a new directory that does not take the default of | |
126 | * the rootfs. It becomes the default permissions for all the | |
127 | * files and directories underneath it. | |
128 | */ | |
129 | ti = get_tracefs(inode); | |
130 | ti->flags |= TRACEFS_INSTANCE_INODE; | |
131 | ti->private = inode; | |
132 | ||
eae47358 SRRH |
133 | /* |
134 | * The mkdir call can call the generic functions that create | |
135 | * the files within the tracefs system. It is up to the individual | |
136 | * mkdir routine to handle races. | |
137 | */ | |
5955102c | 138 | inode_unlock(inode); |
eae47358 | 139 | ret = tracefs_ops.mkdir(name); |
5955102c | 140 | inode_lock(inode); |
eae47358 SRRH |
141 | |
142 | kfree(name); | |
143 | ||
144 | return ret; | |
145 | } | |
146 | ||
147 | static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry) | |
148 | { | |
149 | char *name; | |
150 | int ret; | |
151 | ||
152 | name = get_dname(dentry); | |
153 | if (!name) | |
154 | return -ENOMEM; | |
155 | ||
156 | /* | |
157 | * The rmdir call can call the generic functions that create | |
158 | * the files within the tracefs system. It is up to the individual | |
159 | * rmdir routine to handle races. | |
160 | * This time we need to unlock not only the parent (inode) but | |
161 | * also the directory that is being deleted. | |
162 | */ | |
5955102c | 163 | inode_unlock(inode); |
ee34c52c | 164 | inode_unlock(d_inode(dentry)); |
eae47358 SRRH |
165 | |
166 | ret = tracefs_ops.rmdir(name); | |
167 | ||
5955102c | 168 | inode_lock_nested(inode, I_MUTEX_PARENT); |
ee34c52c | 169 | inode_lock(d_inode(dentry)); |
eae47358 SRRH |
170 | |
171 | kfree(name); | |
172 | ||
173 | return ret; | |
174 | } | |
175 | ||
8186fff7 SRG |
176 | static void set_tracefs_inode_owner(struct inode *inode) |
177 | { | |
178 | struct tracefs_inode *ti = get_tracefs(inode); | |
179 | struct inode *root_inode = ti->private; | |
6599bd55 SRG |
180 | kuid_t uid; |
181 | kgid_t gid; | |
182 | ||
183 | uid = root_inode->i_uid; | |
184 | gid = root_inode->i_gid; | |
185 | ||
186 | /* | |
187 | * If the root is not the mount point, then check the root's | |
188 | * permissions. If it was never set, then default to the | |
189 | * mount point. | |
190 | */ | |
191 | if (root_inode != d_inode(root_inode->i_sb->s_root)) { | |
192 | struct tracefs_inode *rti; | |
193 | ||
194 | rti = get_tracefs(root_inode); | |
195 | root_inode = d_inode(root_inode->i_sb->s_root); | |
196 | ||
197 | if (!(rti->flags & TRACEFS_UID_PERM_SET)) | |
198 | uid = root_inode->i_uid; | |
199 | ||
200 | if (!(rti->flags & TRACEFS_GID_PERM_SET)) | |
201 | gid = root_inode->i_gid; | |
202 | } | |
8186fff7 SRG |
203 | |
204 | /* | |
205 | * If this inode has never been referenced, then update | |
206 | * the permissions to the superblock. | |
207 | */ | |
208 | if (!(ti->flags & TRACEFS_UID_PERM_SET)) | |
6599bd55 | 209 | inode->i_uid = uid; |
8186fff7 SRG |
210 | |
211 | if (!(ti->flags & TRACEFS_GID_PERM_SET)) | |
6599bd55 | 212 | inode->i_gid = gid; |
8186fff7 SRG |
213 | } |
214 | ||
215 | static int tracefs_permission(struct mnt_idmap *idmap, | |
216 | struct inode *inode, int mask) | |
217 | { | |
218 | set_tracefs_inode_owner(inode); | |
219 | return generic_permission(idmap, inode, mask); | |
220 | } | |
221 | ||
222 | static int tracefs_getattr(struct mnt_idmap *idmap, | |
223 | const struct path *path, struct kstat *stat, | |
224 | u32 request_mask, unsigned int flags) | |
225 | { | |
226 | struct inode *inode = d_backing_inode(path->dentry); | |
227 | ||
228 | set_tracefs_inode_owner(inode); | |
229 | generic_fillattr(idmap, request_mask, inode, stat); | |
230 | return 0; | |
231 | } | |
232 | ||
233 | static int tracefs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, | |
234 | struct iattr *attr) | |
235 | { | |
236 | unsigned int ia_valid = attr->ia_valid; | |
237 | struct inode *inode = d_inode(dentry); | |
238 | struct tracefs_inode *ti = get_tracefs(inode); | |
239 | ||
240 | if (ia_valid & ATTR_UID) | |
241 | ti->flags |= TRACEFS_UID_PERM_SET; | |
242 | ||
243 | if (ia_valid & ATTR_GID) | |
244 | ti->flags |= TRACEFS_GID_PERM_SET; | |
245 | ||
246 | return simple_setattr(idmap, dentry, attr); | |
247 | } | |
248 | ||
249 | static const struct inode_operations tracefs_instance_dir_inode_operations = { | |
eae47358 SRRH |
250 | .lookup = simple_lookup, |
251 | .mkdir = tracefs_syscall_mkdir, | |
252 | .rmdir = tracefs_syscall_rmdir, | |
8186fff7 SRG |
253 | .permission = tracefs_permission, |
254 | .getattr = tracefs_getattr, | |
255 | .setattr = tracefs_setattr, | |
256 | }; | |
257 | ||
258 | static const struct inode_operations tracefs_dir_inode_operations = { | |
259 | .lookup = simple_lookup, | |
260 | .permission = tracefs_permission, | |
261 | .getattr = tracefs_getattr, | |
262 | .setattr = tracefs_setattr, | |
263 | }; | |
264 | ||
265 | static const struct inode_operations tracefs_file_inode_operations = { | |
266 | .permission = tracefs_permission, | |
267 | .getattr = tracefs_getattr, | |
268 | .setattr = tracefs_setattr, | |
eae47358 SRRH |
269 | }; |
270 | ||
2c6b6b10 | 271 | struct inode *tracefs_get_inode(struct super_block *sb) |
4282d606 SRRH |
272 | { |
273 | struct inode *inode = new_inode(sb); | |
274 | if (inode) { | |
275 | inode->i_ino = get_next_ino(); | |
079cf91e | 276 | simple_inode_init_ts(inode); |
4282d606 SRRH |
277 | } |
278 | return inode; | |
279 | } | |
280 | ||
78ff6408 | 281 | struct tracefs_fs_info { |
4282d606 SRRH |
282 | kuid_t uid; |
283 | kgid_t gid; | |
284 | umode_t mode; | |
47311db8 BN |
285 | /* Opt_* bitfield. */ |
286 | unsigned int opts; | |
4282d606 SRRH |
287 | }; |
288 | ||
289 | enum { | |
290 | Opt_uid, | |
291 | Opt_gid, | |
292 | Opt_mode, | |
4282d606 SRRH |
293 | }; |
294 | ||
78ff6408 | 295 | static const struct fs_parameter_spec tracefs_param_specs[] = { |
b5482916 | 296 | fsparam_gid ("gid", Opt_gid), |
78ff6408 | 297 | fsparam_u32oct ("mode", Opt_mode), |
b5482916 | 298 | fsparam_uid ("uid", Opt_uid), |
78ff6408 | 299 | {} |
4282d606 SRRH |
300 | }; |
301 | ||
78ff6408 | 302 | static int tracefs_parse_param(struct fs_context *fc, struct fs_parameter *param) |
4282d606 | 303 | { |
78ff6408 DH |
304 | struct tracefs_fs_info *opts = fc->s_fs_info; |
305 | struct fs_parse_result result; | |
78ff6408 DH |
306 | int opt; |
307 | ||
308 | opt = fs_parse(fc, tracefs_param_specs, param, &result); | |
309 | if (opt < 0) | |
310 | return opt; | |
311 | ||
312 | switch (opt) { | |
313 | case Opt_uid: | |
b5482916 | 314 | opts->uid = result.uid; |
78ff6408 DH |
315 | break; |
316 | case Opt_gid: | |
b5482916 | 317 | opts->gid = result.gid; |
78ff6408 DH |
318 | break; |
319 | case Opt_mode: | |
320 | opts->mode = result.uint_32 & S_IALLUGO; | |
321 | break; | |
322 | /* | |
323 | * We might like to report bad mount options here; | |
324 | * but traditionally tracefs has ignored all mount options | |
325 | */ | |
4282d606 SRRH |
326 | } |
327 | ||
78ff6408 DH |
328 | opts->opts |= BIT(opt); |
329 | ||
4282d606 SRRH |
330 | return 0; |
331 | } | |
332 | ||
47311db8 | 333 | static int tracefs_apply_options(struct super_block *sb, bool remount) |
4282d606 SRRH |
334 | { |
335 | struct tracefs_fs_info *fsi = sb->s_fs_info; | |
ee34c52c | 336 | struct inode *inode = d_inode(sb->s_root); |
baa23a8d SRG |
337 | struct tracefs_inode *ti; |
338 | bool update_uid, update_gid; | |
08662977 | 339 | umode_t tmp_mode; |
4282d606 | 340 | |
47311db8 BN |
341 | /* |
342 | * On remount, only reset mode/uid/gid if they were provided as mount | |
343 | * options. | |
344 | */ | |
345 | ||
78ff6408 | 346 | if (!remount || fsi->opts & BIT(Opt_mode)) { |
08662977 | 347 | tmp_mode = READ_ONCE(inode->i_mode) & ~S_IALLUGO; |
78ff6408 | 348 | tmp_mode |= fsi->mode; |
08662977 | 349 | WRITE_ONCE(inode->i_mode, tmp_mode); |
47311db8 | 350 | } |
4282d606 | 351 | |
78ff6408 DH |
352 | if (!remount || fsi->opts & BIT(Opt_uid)) |
353 | inode->i_uid = fsi->uid; | |
851e99eb | 354 | |
78ff6408 DH |
355 | if (!remount || fsi->opts & BIT(Opt_gid)) |
356 | inode->i_gid = fsi->gid; | |
4282d606 | 357 | |
103fb219 | 358 | if (remount && (fsi->opts & BIT(Opt_uid) || fsi->opts & BIT(Opt_gid))) { |
baa23a8d | 359 | |
103fb219 LT |
360 | update_uid = fsi->opts & BIT(Opt_uid); |
361 | update_gid = fsi->opts & BIT(Opt_gid); | |
baa23a8d SRG |
362 | |
363 | rcu_read_lock(); | |
364 | list_for_each_entry_rcu(ti, &tracefs_inodes, list) { | |
27c04648 | 365 | if (update_uid) { |
baa23a8d | 366 | ti->flags &= ~TRACEFS_UID_PERM_SET; |
27c04648 SRG |
367 | ti->vfs_inode.i_uid = fsi->uid; |
368 | } | |
baa23a8d | 369 | |
27c04648 | 370 | if (update_gid) { |
baa23a8d | 371 | ti->flags &= ~TRACEFS_GID_PERM_SET; |
27c04648 SRG |
372 | ti->vfs_inode.i_gid = fsi->gid; |
373 | } | |
374 | ||
375 | /* | |
376 | * Note, the above ti->vfs_inode updates are | |
377 | * used in eventfs_remount() so they must come | |
378 | * before calling it. | |
379 | */ | |
baa23a8d SRG |
380 | if (ti->flags & TRACEFS_EVENT_INODE) |
381 | eventfs_remount(ti, update_uid, update_gid); | |
382 | } | |
383 | rcu_read_unlock(); | |
384 | } | |
385 | ||
4282d606 SRRH |
386 | return 0; |
387 | } | |
388 | ||
78ff6408 | 389 | static int tracefs_reconfigure(struct fs_context *fc) |
4282d606 | 390 | { |
78ff6408 DH |
391 | struct super_block *sb = fc->root->d_sb; |
392 | struct tracefs_fs_info *sb_opts = sb->s_fs_info; | |
393 | struct tracefs_fs_info *new_opts = fc->s_fs_info; | |
4282d606 | 394 | |
e4d32142 KS |
395 | if (!new_opts) |
396 | return 0; | |
397 | ||
4282d606 | 398 | sync_filesystem(sb); |
78ff6408 DH |
399 | /* structure copy of new mount options to sb */ |
400 | *sb_opts = *new_opts; | |
4282d606 | 401 | |
78ff6408 | 402 | return tracefs_apply_options(sb, true); |
4282d606 SRRH |
403 | } |
404 | ||
405 | static int tracefs_show_options(struct seq_file *m, struct dentry *root) | |
406 | { | |
407 | struct tracefs_fs_info *fsi = root->d_sb->s_fs_info; | |
4282d606 | 408 | |
78ff6408 | 409 | if (!uid_eq(fsi->uid, GLOBAL_ROOT_UID)) |
4282d606 | 410 | seq_printf(m, ",uid=%u", |
78ff6408 DH |
411 | from_kuid_munged(&init_user_ns, fsi->uid)); |
412 | if (!gid_eq(fsi->gid, GLOBAL_ROOT_GID)) | |
4282d606 | 413 | seq_printf(m, ",gid=%u", |
78ff6408 DH |
414 | from_kgid_munged(&init_user_ns, fsi->gid)); |
415 | if (fsi->mode != TRACEFS_DEFAULT_MODE) | |
416 | seq_printf(m, ",mode=%o", fsi->mode); | |
4282d606 SRRH |
417 | |
418 | return 0; | |
419 | } | |
420 | ||
0bcfd9aa SRG |
421 | static int tracefs_drop_inode(struct inode *inode) |
422 | { | |
423 | struct tracefs_inode *ti = get_tracefs(inode); | |
424 | ||
425 | /* | |
426 | * This inode is being freed and cannot be used for | |
427 | * eventfs. Clear the flag so that it doesn't call into | |
428 | * eventfs during the remount flag updates. The eventfs_inode | |
429 | * gets freed after an RCU cycle, so the content will still | |
430 | * be safe if the iteration is going on now. | |
431 | */ | |
432 | ti->flags &= ~TRACEFS_EVENT_INODE; | |
433 | ||
434 | return 1; | |
435 | } | |
436 | ||
4282d606 | 437 | static const struct super_operations tracefs_super_operations = { |
ba37ff75 AK |
438 | .alloc_inode = tracefs_alloc_inode, |
439 | .free_inode = tracefs_free_inode, | |
0b6743bd | 440 | .destroy_inode = tracefs_destroy_inode, |
0bcfd9aa | 441 | .drop_inode = tracefs_drop_inode, |
4282d606 | 442 | .statfs = simple_statfs, |
4282d606 SRRH |
443 | .show_options = tracefs_show_options, |
444 | }; | |
445 | ||
8dce06e9 LT |
446 | /* |
447 | * It would be cleaner if eventfs had its own dentry ops. | |
448 | * | |
449 | * Note that d_revalidate is called potentially under RCU, | |
450 | * so it can't take the eventfs mutex etc. It's fine - if | |
451 | * we open a file just as it's marked dead, things will | |
452 | * still work just fine, and just see the old stale case. | |
453 | */ | |
454 | static void tracefs_d_release(struct dentry *dentry) | |
27152bce | 455 | { |
8dce06e9 LT |
456 | if (dentry->d_fsdata) |
457 | eventfs_d_release(dentry); | |
458 | } | |
27152bce | 459 | |
5be1fa8a AV |
460 | static int tracefs_d_revalidate(struct inode *inode, const struct qstr *name, |
461 | struct dentry *dentry, unsigned int flags) | |
8dce06e9 LT |
462 | { |
463 | struct eventfs_inode *ei = dentry->d_fsdata; | |
27152bce | 464 | |
8dce06e9 | 465 | return !(ei && ei->is_freed); |
27152bce AK |
466 | } |
467 | ||
468 | static const struct dentry_operations tracefs_dentry_operations = { | |
8dce06e9 LT |
469 | .d_revalidate = tracefs_d_revalidate, |
470 | .d_release = tracefs_d_release, | |
27152bce AK |
471 | }; |
472 | ||
78ff6408 | 473 | static int tracefs_fill_super(struct super_block *sb, struct fs_context *fc) |
4282d606 | 474 | { |
cda37124 | 475 | static const struct tree_descr trace_files[] = {{""}}; |
4282d606 SRRH |
476 | int err; |
477 | ||
78ff6408 | 478 | err = simple_fill_super(sb, TRACEFS_MAGIC, trace_files); |
4282d606 | 479 | if (err) |
78ff6408 | 480 | return err; |
4282d606 SRRH |
481 | |
482 | sb->s_op = &tracefs_super_operations; | |
27152bce | 483 | sb->s_d_op = &tracefs_dentry_operations; |
4282d606 | 484 | |
4282d606 | 485 | return 0; |
78ff6408 DH |
486 | } |
487 | ||
488 | static int tracefs_get_tree(struct fs_context *fc) | |
489 | { | |
e4d32142 KS |
490 | int err = get_tree_single(fc, tracefs_fill_super); |
491 | ||
492 | if (err) | |
493 | return err; | |
494 | ||
495 | return tracefs_reconfigure(fc); | |
78ff6408 | 496 | } |
4282d606 | 497 | |
78ff6408 DH |
498 | static void tracefs_free_fc(struct fs_context *fc) |
499 | { | |
500 | kfree(fc->s_fs_info); | |
4282d606 SRRH |
501 | } |
502 | ||
78ff6408 DH |
503 | static const struct fs_context_operations tracefs_context_ops = { |
504 | .free = tracefs_free_fc, | |
505 | .parse_param = tracefs_parse_param, | |
506 | .get_tree = tracefs_get_tree, | |
507 | .reconfigure = tracefs_reconfigure, | |
508 | }; | |
509 | ||
510 | static int tracefs_init_fs_context(struct fs_context *fc) | |
4282d606 | 511 | { |
78ff6408 DH |
512 | struct tracefs_fs_info *fsi; |
513 | ||
514 | fsi = kzalloc(sizeof(struct tracefs_fs_info), GFP_KERNEL); | |
515 | if (!fsi) | |
516 | return -ENOMEM; | |
517 | ||
518 | fsi->mode = TRACEFS_DEFAULT_MODE; | |
519 | ||
520 | fc->s_fs_info = fsi; | |
521 | fc->ops = &tracefs_context_ops; | |
522 | return 0; | |
4282d606 SRRH |
523 | } |
524 | ||
525 | static struct file_system_type trace_fs_type = { | |
526 | .owner = THIS_MODULE, | |
527 | .name = "tracefs", | |
78ff6408 DH |
528 | .init_fs_context = tracefs_init_fs_context, |
529 | .parameters = tracefs_param_specs, | |
4282d606 SRRH |
530 | .kill_sb = kill_litter_super, |
531 | }; | |
532 | MODULE_ALIAS_FS("tracefs"); | |
533 | ||
2c6b6b10 | 534 | struct dentry *tracefs_start_creating(const char *name, struct dentry *parent) |
4282d606 SRRH |
535 | { |
536 | struct dentry *dentry; | |
537 | int error; | |
538 | ||
539 | pr_debug("tracefs: creating file '%s'\n",name); | |
540 | ||
541 | error = simple_pin_fs(&trace_fs_type, &tracefs_mount, | |
542 | &tracefs_mount_count); | |
543 | if (error) | |
544 | return ERR_PTR(error); | |
545 | ||
546 | /* If the parent is not specified, we create it in the root. | |
547 | * We need the root dentry to do this, which is in the super | |
548 | * block. A pointer to that is in the struct vfsmount that we | |
549 | * have around. | |
550 | */ | |
551 | if (!parent) | |
552 | parent = tracefs_mount->mnt_root; | |
553 | ||
ee34c52c SRV |
554 | inode_lock(d_inode(parent)); |
555 | if (unlikely(IS_DEADDIR(d_inode(parent)))) | |
a3d1e7eb AV |
556 | dentry = ERR_PTR(-ENOENT); |
557 | else | |
558 | dentry = lookup_one_len(name, parent, strlen(name)); | |
ee34c52c | 559 | if (!IS_ERR(dentry) && d_inode(dentry)) { |
4282d606 SRRH |
560 | dput(dentry); |
561 | dentry = ERR_PTR(-EEXIST); | |
562 | } | |
d227c3ae DB |
563 | |
564 | if (IS_ERR(dentry)) { | |
ee34c52c | 565 | inode_unlock(d_inode(parent)); |
d227c3ae DB |
566 | simple_release_fs(&tracefs_mount, &tracefs_mount_count); |
567 | } | |
568 | ||
4282d606 SRRH |
569 | return dentry; |
570 | } | |
571 | ||
2c6b6b10 | 572 | struct dentry *tracefs_failed_creating(struct dentry *dentry) |
4282d606 | 573 | { |
ee34c52c | 574 | inode_unlock(d_inode(dentry->d_parent)); |
4282d606 SRRH |
575 | dput(dentry); |
576 | simple_release_fs(&tracefs_mount, &tracefs_mount_count); | |
577 | return NULL; | |
578 | } | |
579 | ||
2c6b6b10 | 580 | struct dentry *tracefs_end_creating(struct dentry *dentry) |
4282d606 | 581 | { |
ee34c52c | 582 | inode_unlock(d_inode(dentry->d_parent)); |
4282d606 SRRH |
583 | return dentry; |
584 | } | |
585 | ||
8186fff7 SRG |
586 | /* Find the inode that this will use for default */ |
587 | static struct inode *instance_inode(struct dentry *parent, struct inode *inode) | |
588 | { | |
589 | struct tracefs_inode *ti; | |
590 | ||
591 | /* If parent is NULL then use root inode */ | |
592 | if (!parent) | |
593 | return d_inode(inode->i_sb->s_root); | |
594 | ||
595 | /* Find the inode that is flagged as an instance or the root inode */ | |
596 | while (!IS_ROOT(parent)) { | |
597 | ti = get_tracefs(d_inode(parent)); | |
598 | if (ti->flags & TRACEFS_INSTANCE_INODE) | |
599 | break; | |
600 | parent = parent->d_parent; | |
601 | } | |
602 | ||
603 | return d_inode(parent); | |
604 | } | |
605 | ||
4282d606 SRRH |
606 | /** |
607 | * tracefs_create_file - create a file in the tracefs filesystem | |
608 | * @name: a pointer to a string containing the name of the file to create. | |
609 | * @mode: the permission that the file should have. | |
610 | * @parent: a pointer to the parent dentry for this file. This should be a | |
611 | * directory dentry if set. If this parameter is NULL, then the | |
612 | * file will be created in the root of the tracefs filesystem. | |
613 | * @data: a pointer to something that the caller will want to get to later | |
614 | * on. The inode.i_private pointer will point to this value on | |
615 | * the open() call. | |
616 | * @fops: a pointer to a struct file_operations that should be used for | |
617 | * this file. | |
618 | * | |
619 | * This is the basic "create a file" function for tracefs. It allows for a | |
620 | * wide range of flexibility in creating a file, or a directory (if you want | |
621 | * to create a directory, the tracefs_create_dir() function is | |
622 | * recommended to be used instead.) | |
623 | * | |
624 | * This function will return a pointer to a dentry if it succeeds. This | |
625 | * pointer must be passed to the tracefs_remove() function when the file is | |
626 | * to be removed (no automatic cleanup happens if your module is unloaded, | |
627 | * you are responsible here.) If an error occurs, %NULL will be returned. | |
628 | * | |
629 | * If tracefs is not enabled in the kernel, the value -%ENODEV will be | |
630 | * returned. | |
631 | */ | |
632 | struct dentry *tracefs_create_file(const char *name, umode_t mode, | |
633 | struct dentry *parent, void *data, | |
634 | const struct file_operations *fops) | |
635 | { | |
8186fff7 | 636 | struct tracefs_inode *ti; |
4282d606 SRRH |
637 | struct dentry *dentry; |
638 | struct inode *inode; | |
639 | ||
bf8e6021 SRV |
640 | if (security_locked_down(LOCKDOWN_TRACEFS)) |
641 | return NULL; | |
642 | ||
4282d606 SRRH |
643 | if (!(mode & S_IFMT)) |
644 | mode |= S_IFREG; | |
645 | BUG_ON(!S_ISREG(mode)); | |
2c6b6b10 | 646 | dentry = tracefs_start_creating(name, parent); |
4282d606 SRRH |
647 | |
648 | if (IS_ERR(dentry)) | |
649 | return NULL; | |
650 | ||
651 | inode = tracefs_get_inode(dentry->d_sb); | |
652 | if (unlikely(!inode)) | |
2c6b6b10 | 653 | return tracefs_failed_creating(dentry); |
4282d606 | 654 | |
8186fff7 SRG |
655 | ti = get_tracefs(inode); |
656 | ti->private = instance_inode(parent, inode); | |
657 | ||
4282d606 | 658 | inode->i_mode = mode; |
8186fff7 | 659 | inode->i_op = &tracefs_file_inode_operations; |
3ed270b1 | 660 | inode->i_fop = fops ? fops : &tracefs_file_operations; |
4282d606 | 661 | inode->i_private = data; |
ee7f3666 SRV |
662 | inode->i_uid = d_inode(dentry->d_parent)->i_uid; |
663 | inode->i_gid = d_inode(dentry->d_parent)->i_gid; | |
4282d606 | 664 | d_instantiate(dentry, inode); |
ee34c52c | 665 | fsnotify_create(d_inode(dentry->d_parent), dentry); |
2c6b6b10 | 666 | return tracefs_end_creating(dentry); |
4282d606 SRRH |
667 | } |
668 | ||
eae47358 SRRH |
669 | static struct dentry *__create_dir(const char *name, struct dentry *parent, |
670 | const struct inode_operations *ops) | |
671 | { | |
8186fff7 | 672 | struct tracefs_inode *ti; |
2c6b6b10 | 673 | struct dentry *dentry = tracefs_start_creating(name, parent); |
eae47358 SRRH |
674 | struct inode *inode; |
675 | ||
676 | if (IS_ERR(dentry)) | |
677 | return NULL; | |
678 | ||
679 | inode = tracefs_get_inode(dentry->d_sb); | |
680 | if (unlikely(!inode)) | |
2c6b6b10 | 681 | return tracefs_failed_creating(dentry); |
eae47358 | 682 | |
49d67e44 SRV |
683 | /* Do not set bits for OTH */ |
684 | inode->i_mode = S_IFDIR | S_IRWXU | S_IRUSR| S_IRGRP | S_IXUSR | S_IXGRP; | |
eae47358 SRRH |
685 | inode->i_op = ops; |
686 | inode->i_fop = &simple_dir_operations; | |
ee7f3666 SRV |
687 | inode->i_uid = d_inode(dentry->d_parent)->i_uid; |
688 | inode->i_gid = d_inode(dentry->d_parent)->i_gid; | |
eae47358 | 689 | |
8186fff7 SRG |
690 | ti = get_tracefs(inode); |
691 | ti->private = instance_inode(parent, inode); | |
692 | ||
eae47358 SRRH |
693 | /* directory inodes start off with i_nlink == 2 (for "." entry) */ |
694 | inc_nlink(inode); | |
695 | d_instantiate(dentry, inode); | |
ee34c52c SRV |
696 | inc_nlink(d_inode(dentry->d_parent)); |
697 | fsnotify_mkdir(d_inode(dentry->d_parent), dentry); | |
2c6b6b10 | 698 | return tracefs_end_creating(dentry); |
eae47358 SRRH |
699 | } |
700 | ||
4282d606 SRRH |
701 | /** |
702 | * tracefs_create_dir - create a directory in the tracefs filesystem | |
703 | * @name: a pointer to a string containing the name of the directory to | |
704 | * create. | |
705 | * @parent: a pointer to the parent dentry for this file. This should be a | |
706 | * directory dentry if set. If this parameter is NULL, then the | |
707 | * directory will be created in the root of the tracefs filesystem. | |
708 | * | |
709 | * This function creates a directory in tracefs with the given name. | |
710 | * | |
711 | * This function will return a pointer to a dentry if it succeeds. This | |
712 | * pointer must be passed to the tracefs_remove() function when the file is | |
713 | * to be removed. If an error occurs, %NULL will be returned. | |
714 | * | |
715 | * If tracing is not enabled in the kernel, the value -%ENODEV will be | |
716 | * returned. | |
717 | */ | |
718 | struct dentry *tracefs_create_dir(const char *name, struct dentry *parent) | |
719 | { | |
51aab5ff SRG |
720 | if (security_locked_down(LOCKDOWN_TRACEFS)) |
721 | return NULL; | |
722 | ||
8186fff7 | 723 | return __create_dir(name, parent, &tracefs_dir_inode_operations); |
eae47358 | 724 | } |
4282d606 | 725 | |
eae47358 SRRH |
726 | /** |
727 | * tracefs_create_instance_dir - create the tracing instances directory | |
728 | * @name: The name of the instances directory to create | |
729 | * @parent: The parent directory that the instances directory will exist | |
730 | * @mkdir: The function to call when a mkdir is performed. | |
731 | * @rmdir: The function to call when a rmdir is performed. | |
732 | * | |
733 | * Only one instances directory is allowed. | |
734 | * | |
93a8c044 | 735 | * The instances directory is special as it allows for mkdir and rmdir |
eae47358 | 736 | * to be done by userspace. When a mkdir or rmdir is performed, the inode |
f2cc020d | 737 | * locks are released and the methods passed in (@mkdir and @rmdir) are |
eae47358 SRRH |
738 | * called without locks and with the name of the directory being created |
739 | * within the instances directory. | |
740 | * | |
741 | * Returns the dentry of the instances directory. | |
742 | */ | |
5248ee85 ZM |
743 | __init struct dentry *tracefs_create_instance_dir(const char *name, |
744 | struct dentry *parent, | |
eae47358 SRRH |
745 | int (*mkdir)(const char *name), |
746 | int (*rmdir)(const char *name)) | |
747 | { | |
748 | struct dentry *dentry; | |
749 | ||
750 | /* Only allow one instance of the instances directory. */ | |
751 | if (WARN_ON(tracefs_ops.mkdir || tracefs_ops.rmdir)) | |
4282d606 SRRH |
752 | return NULL; |
753 | ||
8186fff7 | 754 | dentry = __create_dir(name, parent, &tracefs_instance_dir_inode_operations); |
eae47358 SRRH |
755 | if (!dentry) |
756 | return NULL; | |
4282d606 | 757 | |
eae47358 SRRH |
758 | tracefs_ops.mkdir = mkdir; |
759 | tracefs_ops.rmdir = rmdir; | |
4282d606 | 760 | |
eae47358 | 761 | return dentry; |
4282d606 SRRH |
762 | } |
763 | ||
a3d1e7eb | 764 | static void remove_one(struct dentry *victim) |
4282d606 | 765 | { |
a3d1e7eb | 766 | simple_release_fs(&tracefs_mount, &tracefs_mount_count); |
4282d606 SRRH |
767 | } |
768 | ||
769 | /** | |
a3d1e7eb | 770 | * tracefs_remove - recursively removes a directory |
4282d606 SRRH |
771 | * @dentry: a pointer to a the dentry of the directory to be removed. |
772 | * | |
773 | * This function recursively removes a directory tree in tracefs that | |
774 | * was previously created with a call to another tracefs function | |
775 | * (like tracefs_create_file() or variants thereof.) | |
776 | */ | |
a3d1e7eb | 777 | void tracefs_remove(struct dentry *dentry) |
4282d606 | 778 | { |
4282d606 SRRH |
779 | if (IS_ERR_OR_NULL(dentry)) |
780 | return; | |
781 | ||
a3d1e7eb AV |
782 | simple_pin_fs(&trace_fs_type, &tracefs_mount, &tracefs_mount_count); |
783 | simple_recursive_removal(dentry, remove_one); | |
784 | simple_release_fs(&tracefs_mount, &tracefs_mount_count); | |
4282d606 SRRH |
785 | } |
786 | ||
787 | /** | |
788 | * tracefs_initialized - Tells whether tracefs has been registered | |
789 | */ | |
790 | bool tracefs_initialized(void) | |
791 | { | |
792 | return tracefs_registered; | |
793 | } | |
794 | ||
ba37ff75 AK |
795 | static void init_once(void *foo) |
796 | { | |
797 | struct tracefs_inode *ti = (struct tracefs_inode *) foo; | |
798 | ||
d81786f5 | 799 | /* inode_init_once() calls memset() on the vfs_inode portion */ |
ba37ff75 | 800 | inode_init_once(&ti->vfs_inode); |
d81786f5 SRG |
801 | |
802 | /* Zero out the rest */ | |
803 | memset_after(ti, 0, vfs_inode); | |
ba37ff75 AK |
804 | } |
805 | ||
4282d606 SRRH |
806 | static int __init tracefs_init(void) |
807 | { | |
808 | int retval; | |
809 | ||
ba37ff75 AK |
810 | tracefs_inode_cachep = kmem_cache_create("tracefs_inode_cache", |
811 | sizeof(struct tracefs_inode), | |
812 | 0, (SLAB_RECLAIM_ACCOUNT| | |
ba37ff75 AK |
813 | SLAB_ACCOUNT), |
814 | init_once); | |
815 | if (!tracefs_inode_cachep) | |
816 | return -ENOMEM; | |
817 | ||
f9bb4882 EB |
818 | retval = sysfs_create_mount_point(kernel_kobj, "tracing"); |
819 | if (retval) | |
cc31004a SRRH |
820 | return -EINVAL; |
821 | ||
4282d606 SRRH |
822 | retval = register_filesystem(&trace_fs_type); |
823 | if (!retval) | |
824 | tracefs_registered = true; | |
825 | ||
826 | return retval; | |
827 | } | |
828 | core_initcall(tracefs_init); |