Skip to content

Commit eae4735

Browse files
committed
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>
1 parent cc31004 commit eae4735

File tree

3 files changed

+145
-85
lines changed

3 files changed

+145
-85
lines changed

fs/tracefs/inode.c

Lines changed: 136 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,84 @@ static const struct file_operations tracefs_file_operations = {
5050
.llseek = noop_llseek,
5151
};
5252

53+
static struct tracefs_dir_ops {
54+
int (*mkdir)(const char *name);
55+
int (*rmdir)(const char *name);
56+
} tracefs_ops;
57+
58+
static 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+
73+
static 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+
96+
static 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+
125+
static const struct inode_operations tracefs_dir_inode_operations = {
126+
.lookup = simple_lookup,
127+
.mkdir = tracefs_syscall_mkdir,
128+
.rmdir = tracefs_syscall_rmdir,
129+
};
130+
53131
static struct inode *tracefs_get_inode(struct super_block *sb)
54132
{
55133
struct inode *inode = new_inode(sb);
@@ -334,6 +412,31 @@ struct dentry *tracefs_create_file(const char *name, umode_t mode,
334412
return end_creating(dentry);
335413
}
336414

415+
static 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+
337440
/**
338441
* tracefs_create_dir - create a directory in the tracefs filesystem
339442
* @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,
353456
*/
354457
struct dentry *tracefs_create_dir(const char *name, struct dentry *parent)
355458
{
356-
struct dentry *dentry = start_creating(name, parent);
357-
struct inode *inode;
459+
return __create_dir(name, parent, &simple_dir_inode_operations);
460+
}
358461

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+
*/
479+
struct 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))
360487
return NULL;
361488

362-
inode = tracefs_get_inode(dentry->d_sb);
363-
if (unlikely(!inode))
364-
return failed_creating(dentry);
489+
dentry = __create_dir(name, parent, &tracefs_dir_inode_operations);
490+
if (!dentry)
491+
return NULL;
365492

366-
inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
367-
inode->i_op = &simple_dir_inode_operations;
368-
inode->i_fop = &simple_dir_operations;
493+
tracefs_ops.mkdir = mkdir;
494+
tracefs_ops.rmdir = rmdir;
369495

370-
/* directory inodes start off with i_nlink == 2 (for "." entry) */
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);
496+
return dentry;
376497
}
377498

378499
static inline int tracefs_positive(struct dentry *dentry)

include/linux/tracefs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ struct dentry *tracefs_create_dir(const char *name, struct dentry *parent);
3434
void tracefs_remove(struct dentry *dentry);
3535
void tracefs_remove_recursive(struct dentry *dentry);
3636

37+
struct dentry *tracefs_create_instance_dir(const char *name, struct dentry *parent,
38+
int (*mkdir)(const char *name),
39+
int (*rmdir)(const char *name));
40+
3741
bool tracefs_initialized(void);
3842

3943
#endif /* CONFIG_TRACING */

kernel/trace/trace.c

Lines changed: 5 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -6292,7 +6292,7 @@ static void free_trace_buffers(struct trace_array *tr)
62926292
#endif
62936293
}
62946294

6295-
static int new_instance_create(const char *name)
6295+
static int instance_mkdir(const char *name)
62966296
{
62976297
struct trace_array *tr;
62986298
int ret;
@@ -6362,7 +6362,7 @@ static int new_instance_create(const char *name)
63626362

63636363
}
63646364

6365-
static int instance_delete(const char *name)
6365+
static int instance_rmdir(const char *name)
63666366
{
63676367
struct trace_array *tr;
63686368
int found = 0;
@@ -6403,78 +6403,13 @@ static int instance_delete(const char *name)
64036403
return ret;
64046404
}
64056405

6406-
static 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-
6433-
static 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-
6464-
static const struct inode_operations instance_dir_inode_operations = {
6465-
.lookup = simple_lookup,
6466-
.mkdir = instance_mkdir,
6467-
.rmdir = instance_rmdir,
6468-
};
6469-
64706406
static __init void create_trace_instances(struct dentry *d_tracer)
64716407
{
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);
64736411
if (WARN_ON(!trace_instance_dir))
64746412
return;
6475-
6476-
/* Hijack the dir inode operations, to allow mkdir */
6477-
trace_instance_dir->d_inode->i_op = &instance_dir_inode_operations;
64786413
}
64796414

64806415
static void

0 commit comments

Comments
 (0)