summaryrefslogtreecommitdiffstats
path: root/fs/tracefs/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/tracefs/inode.c')
-rw-r--r--fs/tracefs/inode.c42
1 files changed, 41 insertions, 1 deletions
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index eeeae0475da9..9fc14e38927f 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c
@@ -20,6 +20,7 @@
20#include <linux/parser.h> 20#include <linux/parser.h>
21#include <linux/magic.h> 21#include <linux/magic.h>
22#include <linux/slab.h> 22#include <linux/slab.h>
23#include <linux/security.h>
23 24
24#define TRACEFS_DEFAULT_MODE 0700 25#define TRACEFS_DEFAULT_MODE 0700
25 26
@@ -27,6 +28,25 @@ static struct vfsmount *tracefs_mount;
27static int tracefs_mount_count; 28static int tracefs_mount_count;
28static bool tracefs_registered; 29static bool tracefs_registered;
29 30
31static int default_open_file(struct inode *inode, struct file *filp)
32{
33 struct dentry *dentry = filp->f_path.dentry;
34 struct file_operations *real_fops;
35 int ret;
36
37 if (!dentry)
38 return -EINVAL;
39
40 ret = security_locked_down(LOCKDOWN_TRACEFS);
41 if (ret)
42 return ret;
43
44 real_fops = dentry->d_fsdata;
45 if (!real_fops->open)
46 return 0;
47 return real_fops->open(inode, filp);
48}
49
30static ssize_t default_read_file(struct file *file, char __user *buf, 50static ssize_t default_read_file(struct file *file, char __user *buf,
31 size_t count, loff_t *ppos) 51 size_t count, loff_t *ppos)
32{ 52{
@@ -221,6 +241,12 @@ static int tracefs_apply_options(struct super_block *sb)
221 return 0; 241 return 0;
222} 242}
223 243
244static void tracefs_destroy_inode(struct inode *inode)
245{
246 if (S_ISREG(inode->i_mode))
247 kfree(inode->i_fop);
248}
249
224static int tracefs_remount(struct super_block *sb, int *flags, char *data) 250static int tracefs_remount(struct super_block *sb, int *flags, char *data)
225{ 251{
226 int err; 252 int err;
@@ -257,6 +283,7 @@ static int tracefs_show_options(struct seq_file *m, struct dentry *root)
257static const struct super_operations tracefs_super_operations = { 283static const struct super_operations tracefs_super_operations = {
258 .statfs = simple_statfs, 284 .statfs = simple_statfs,
259 .remount_fs = tracefs_remount, 285 .remount_fs = tracefs_remount,
286 .destroy_inode = tracefs_destroy_inode,
260 .show_options = tracefs_show_options, 287 .show_options = tracefs_show_options,
261}; 288};
262 289
@@ -387,6 +414,7 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
387 struct dentry *parent, void *data, 414 struct dentry *parent, void *data,
388 const struct file_operations *fops) 415 const struct file_operations *fops)
389{ 416{
417 struct file_operations *proxy_fops;
390 struct dentry *dentry; 418 struct dentry *dentry;
391 struct inode *inode; 419 struct inode *inode;
392 420
@@ -402,8 +430,20 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
402 if (unlikely(!inode)) 430 if (unlikely(!inode))
403 return failed_creating(dentry); 431 return failed_creating(dentry);
404 432
433 proxy_fops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
434 if (unlikely(!proxy_fops)) {
435 iput(inode);
436 return failed_creating(dentry);
437 }
438
439 if (!fops)
440 fops = &tracefs_file_operations;
441
442 dentry->d_fsdata = (void *)fops;
443 memcpy(proxy_fops, fops, sizeof(*proxy_fops));
444 proxy_fops->open = default_open_file;
405 inode->i_mode = mode; 445 inode->i_mode = mode;
406 inode->i_fop = fops ? fops : &tracefs_file_operations; 446 inode->i_fop = proxy_fops;
407 inode->i_private = data; 447 inode->i_private = data;
408 d_instantiate(dentry, inode); 448 d_instantiate(dentry, inode);
409 fsnotify_create(dentry->d_parent->d_inode, dentry); 449 fsnotify_create(dentry->d_parent->d_inode, dentry);