aboutsummaryrefslogtreecommitdiffstats
path: root/fs/tracefs
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2015-01-21 10:01:39 -0500
committerSteven Rostedt <rostedt@goodmis.org>2015-02-03 12:48:43 -0500
commiteae473581cf93dad94ca833aa961c033c6a43924 (patch)
treeea0a8bbf8a30940b497dad43a858be8d1b5efb26 /fs/tracefs
parentcc31004a4aa784d89054ec07b87eae05cecf7121 (diff)
tracing: Have mkdir and rmdir be part of tracefs
The tracing "instances" directory can create sub tracing buffers with mkdir, and remove them with rmdir. As a mkdir will also create all the files and directories that control the sub buffer the inode mutexes need to be released before this is done, to avoid deadlocks. It is better to let the tracing system unlock the inode mutexes before calling the functions that create the files within the new directory (or deletes the files from the one being destroyed). Now that tracing has been converted over to tracefs, the tracefs file system can be modified to accommodate this feature. It still releases the locks, but the filesystem itself can take care of the ugly business and let the user just do what it needs. The tracing system now attaches a descriptor to the directory dentry that can have userspace create or remove sub directories. If this descriptor does not exist for a dentry, then that dentry can not be used to create other directories. This descriptor holds a mkdir and rmdir method that only takes a character string as an argument. The tracefs file system will first make a copy of the dentry name before releasing the locks. Then it will pass the copied name to the methods. It is up to the tracing system that supplied the methods to handle races with duplicate names and such as all the inode mutexes would be released when the functions are called. Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'fs/tracefs')
-rw-r--r--fs/tracefs/inode.c151
1 files changed, 136 insertions, 15 deletions
diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c
index 0b9cf5cf24c9..d92bdf3b079a 100644
--- a/fs/tracefs/inode.c
+++ b/fs/tracefs/inode.c
@@ -50,6 +50,84 @@ static const struct file_operations tracefs_file_operations = {
50 .llseek = noop_llseek, 50 .llseek = noop_llseek,
51}; 51};
52 52
53static struct tracefs_dir_ops {
54 int (*mkdir)(const char *name);
55 int (*rmdir)(const char *name);
56} tracefs_ops;
57
58static char *get_dname(struct dentry *dentry)
59{
60 const char *dname;
61 char *name;
62 int len = dentry->d_name.len;
63
64 dname = dentry->d_name.name;
65 name = kmalloc(len + 1, GFP_KERNEL);
66 if (!name)
67 return NULL;
68 memcpy(name, dname, len);
69 name[len] = 0;
70 return name;
71}
72
73static int tracefs_syscall_mkdir(struct inode *inode, struct dentry *dentry, umode_t mode)
74{
75 char *name;
76 int ret;
77
78 name = get_dname(dentry);
79 if (!name)
80 return -ENOMEM;
81
82 /*
83 * The mkdir call can call the generic functions that create
84 * the files within the tracefs system. It is up to the individual
85 * mkdir routine to handle races.
86 */
87 mutex_unlock(&inode->i_mutex);
88 ret = tracefs_ops.mkdir(name);
89 mutex_lock(&inode->i_mutex);
90
91 kfree(name);
92
93 return ret;
94}
95
96static int tracefs_syscall_rmdir(struct inode *inode, struct dentry *dentry)
97{
98 char *name;
99 int ret;
100
101 name = get_dname(dentry);
102 if (!name)
103 return -ENOMEM;
104
105 /*
106 * The rmdir call can call the generic functions that create
107 * the files within the tracefs system. It is up to the individual
108 * rmdir routine to handle races.
109 * This time we need to unlock not only the parent (inode) but
110 * also the directory that is being deleted.
111 */
112 mutex_unlock(&inode->i_mutex);
113 mutex_unlock(&dentry->d_inode->i_mutex);
114
115 ret = tracefs_ops.rmdir(name);
116
117 mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
118 mutex_lock(&dentry->d_inode->i_mutex);
119
120 kfree(name);
121
122 return ret;
123}
124
125static const struct inode_operations tracefs_dir_inode_operations = {
126 .lookup = simple_lookup,
127 .mkdir = tracefs_syscall_mkdir,
128 .rmdir = tracefs_syscall_rmdir,
129};
130
53static struct inode *tracefs_get_inode(struct super_block *sb) 131static struct inode *tracefs_get_inode(struct super_block *sb)
54{ 132{
55 struct inode *inode = new_inode(sb); 133 struct inode *inode = new_inode(sb);
@@ -334,6 +412,31 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
334 return end_creating(dentry); 412 return end_creating(dentry);
335} 413}
336 414
415static struct dentry *__create_dir(const char *name, struct dentry *parent,
416 const struct inode_operations *ops)
417{
418 struct dentry *dentry = start_creating(name, parent);
419 struct inode *inode;
420
421 if (IS_ERR(dentry))
422 return NULL;
423
424 inode = tracefs_get_inode(dentry->d_sb);
425 if (unlikely(!inode))
426 return failed_creating(dentry);
427
428 inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
429 inode->i_op = ops;
430 inode->i_fop = &simple_dir_operations;
431
432 /* directory inodes start off with i_nlink == 2 (for "." entry) */
433 inc_nlink(inode);
434 d_instantiate(dentry, inode);
435 inc_nlink(dentry->d_parent->d_inode);
436 fsnotify_mkdir(dentry->d_parent->d_inode, dentry);
437 return end_creating(dentry);
438}
439
337/** 440/**
338 * tracefs_create_dir - create a directory in the tracefs filesystem 441 * tracefs_create_dir - create a directory in the tracefs filesystem
339 * @name: a pointer to a string containing the name of the directory to 442 * @name: a pointer to a string containing the name of the directory to
@@ -353,26 +456,44 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
353 */ 456 */
354struct dentry *tracefs_create_dir(const char *name, struct dentry *parent) 457struct dentry *tracefs_create_dir(const char *name, struct dentry *parent)
355{ 458{
356 struct dentry *dentry = start_creating(name, parent); 459 return __create_dir(name, parent, &simple_dir_inode_operations);
357 struct inode *inode; 460}
358 461
359 if (IS_ERR(dentry)) 462/**
463 * tracefs_create_instance_dir - create the tracing instances directory
464 * @name: The name of the instances directory to create
465 * @parent: The parent directory that the instances directory will exist
466 * @mkdir: The function to call when a mkdir is performed.
467 * @rmdir: The function to call when a rmdir is performed.
468 *
469 * Only one instances directory is allowed.
470 *
471 * The instances directory is special as it allows for mkdir and rmdir to
472 * to be done by userspace. When a mkdir or rmdir is performed, the inode
473 * locks are released and the methhods passed in (@mkdir and @rmdir) are
474 * called without locks and with the name of the directory being created
475 * within the instances directory.
476 *
477 * Returns the dentry of the instances directory.
478 */
479struct dentry *tracefs_create_instance_dir(const char *name, struct dentry *parent,
480 int (*mkdir)(const char *name),
481 int (*rmdir)(const char *name))
482{
483 struct dentry *dentry;
484
485 /* Only allow one instance of the instances directory. */
486 if (WARN_ON(tracefs_ops.mkdir || tracefs_ops.rmdir))
360 return NULL; 487 return NULL;
361 488
362 inode = tracefs_get_inode(dentry->d_sb); 489 dentry = __create_dir(name, parent, &tracefs_dir_inode_operations);
363 if (unlikely(!inode)) 490 if (!dentry)
364 return failed_creating(dentry); 491 return NULL;
365 492
366 inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; 493 tracefs_ops.mkdir = mkdir;
367 inode->i_op = &simple_dir_inode_operations; 494 tracefs_ops.rmdir = rmdir;
368 inode->i_fop = &simple_dir_operations;
369 495
370 /* directory inodes start off with i_nlink == 2 (for "." entry) */ 496 return dentry;
371 inc_nlink(inode);
372 d_instantiate(dentry, inode);
373 inc_nlink(dentry->d_parent->d_inode);
374 fsnotify_mkdir(dentry->d_parent->d_inode, dentry);
375 return end_creating(dentry);
376} 497}
377 498
378static inline int tracefs_positive(struct dentry *dentry) 499static inline int tracefs_positive(struct dentry *dentry)