aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/tracefs/inode.c151
-rw-r--r--include/linux/tracefs.h4
-rw-r--r--kernel/trace/trace.c75
3 files changed, 145 insertions, 85 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)
diff --git a/include/linux/tracefs.h b/include/linux/tracefs.h
index 23e04ce21749..5b727a17beee 100644
--- a/include/linux/tracefs.h
+++ b/include/linux/tracefs.h
@@ -34,6 +34,10 @@ struct dentry *tracefs_create_dir(const char *name, struct dentry *parent);
34void tracefs_remove(struct dentry *dentry); 34void tracefs_remove(struct dentry *dentry);
35void tracefs_remove_recursive(struct dentry *dentry); 35void tracefs_remove_recursive(struct dentry *dentry);
36 36
37struct dentry *tracefs_create_instance_dir(const char *name, struct dentry *parent,
38 int (*mkdir)(const char *name),
39 int (*rmdir)(const char *name));
40
37bool tracefs_initialized(void); 41bool tracefs_initialized(void);
38 42
39#endif /* CONFIG_TRACING */ 43#endif /* CONFIG_TRACING */
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index b4aa936509d2..3c8913bac204 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -6292,7 +6292,7 @@ static void free_trace_buffers(struct trace_array *tr)
6292#endif 6292#endif
6293} 6293}
6294 6294
6295static int new_instance_create(const char *name) 6295static int instance_mkdir(const char *name)
6296{ 6296{
6297 struct trace_array *tr; 6297 struct trace_array *tr;
6298 int ret; 6298 int ret;
@@ -6362,7 +6362,7 @@ static int new_instance_create(const char *name)
6362 6362
6363} 6363}
6364 6364
6365static int instance_delete(const char *name) 6365static int instance_rmdir(const char *name)
6366{ 6366{
6367 struct trace_array *tr; 6367 struct trace_array *tr;
6368 int found = 0; 6368 int found = 0;
@@ -6403,78 +6403,13 @@ static int instance_delete(const char *name)
6403 return ret; 6403 return ret;
6404} 6404}
6405 6405
6406static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t mode)
6407{
6408 struct dentry *parent;
6409 int ret;
6410
6411 /* Paranoid: Make sure the parent is the "instances" directory */
6412 parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
6413 if (WARN_ON_ONCE(parent != trace_instance_dir))
6414 return -ENOENT;
6415
6416 /*
6417 * The inode mutex is locked, but tracefs_create_dir() will also
6418 * take the mutex. As the instances directory can not be destroyed
6419 * or changed in any other way, it is safe to unlock it, and
6420 * let the dentry try. If two users try to make the same dir at
6421 * the same time, then the new_instance_create() will determine the
6422 * winner.
6423 */
6424 mutex_unlock(&inode->i_mutex);
6425
6426 ret = new_instance_create(dentry->d_iname);
6427
6428 mutex_lock(&inode->i_mutex);
6429
6430 return ret;
6431}
6432
6433static int instance_rmdir(struct inode *inode, struct dentry *dentry)
6434{
6435 struct dentry *parent;
6436 int ret;
6437
6438 /* Paranoid: Make sure the parent is the "instances" directory */
6439 parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
6440 if (WARN_ON_ONCE(parent != trace_instance_dir))
6441 return -ENOENT;
6442
6443 /* The caller did a dget() on dentry */
6444 mutex_unlock(&dentry->d_inode->i_mutex);
6445
6446 /*
6447 * The inode mutex is locked, but tracefs_create_dir() will also
6448 * take the mutex. As the instances directory can not be destroyed
6449 * or changed in any other way, it is safe to unlock it, and
6450 * let the dentry try. If two users try to make the same dir at
6451 * the same time, then the instance_delete() will determine the
6452 * winner.
6453 */
6454 mutex_unlock(&inode->i_mutex);
6455
6456 ret = instance_delete(dentry->d_iname);
6457
6458 mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
6459 mutex_lock(&dentry->d_inode->i_mutex);
6460
6461 return ret;
6462}
6463
6464static const struct inode_operations instance_dir_inode_operations = {
6465 .lookup = simple_lookup,
6466 .mkdir = instance_mkdir,
6467 .rmdir = instance_rmdir,
6468};
6469
6470static __init void create_trace_instances(struct dentry *d_tracer) 6406static __init void create_trace_instances(struct dentry *d_tracer)
6471{ 6407{
6472 trace_instance_dir = tracefs_create_dir("instances", d_tracer); 6408 trace_instance_dir = tracefs_create_instance_dir("instances", d_tracer,
6409 instance_mkdir,
6410 instance_rmdir);
6473 if (WARN_ON(!trace_instance_dir)) 6411 if (WARN_ON(!trace_instance_dir))
6474 return; 6412 return;
6475
6476 /* Hijack the dir inode operations, to allow mkdir */
6477 trace_instance_dir->d_inode->i_op = &instance_dir_inode_operations;
6478} 6413}
6479 6414
6480static void 6415static void