Skip to content

Commit 0c8916c

Browse files
Steven Rostedtrostedt
authored andcommitted
tracing: Add rmdir to remove multibuffer instances
Add a method to the hijacked dentry descriptor of the "instances" directory to allow for rmdir to remove an instance of a multibuffer. Example: cd /debug/tracing/instances mkdir hello ls hello/ rmdir hello ls Like the mkdir method, the i_mutex is dropped for the instances directory. The instances directory is created at boot up and can not be renamed or removed. The trace_types_lock mutex is used to synchronize adding and removing of instances. I've run several stress tests with different threads trying to create and delete directories of the same name, and it has stood up fine. Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
1 parent 277ba04 commit 0c8916c

File tree

3 files changed

+102
-0
lines changed

3 files changed

+102
-0
lines changed

kernel/trace/trace.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5192,6 +5192,42 @@ static int new_instance_create(const char *name)
51925192

51935193
}
51945194

5195+
static int instance_delete(const char *name)
5196+
{
5197+
struct trace_array *tr;
5198+
int found = 0;
5199+
int ret;
5200+
5201+
mutex_lock(&trace_types_lock);
5202+
5203+
ret = -ENODEV;
5204+
list_for_each_entry(tr, &ftrace_trace_arrays, list) {
5205+
if (tr->name && strcmp(tr->name, name) == 0) {
5206+
found = 1;
5207+
break;
5208+
}
5209+
}
5210+
if (!found)
5211+
goto out_unlock;
5212+
5213+
list_del(&tr->list);
5214+
5215+
event_trace_del_tracer(tr);
5216+
debugfs_remove_recursive(tr->dir);
5217+
free_percpu(tr->data);
5218+
ring_buffer_free(tr->buffer);
5219+
5220+
kfree(tr->name);
5221+
kfree(tr);
5222+
5223+
ret = 0;
5224+
5225+
out_unlock:
5226+
mutex_unlock(&trace_types_lock);
5227+
5228+
return ret;
5229+
}
5230+
51955231
static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t mode)
51965232
{
51975233
struct dentry *parent;
@@ -5219,9 +5255,41 @@ static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t m
52195255
return ret;
52205256
}
52215257

5258+
static int instance_rmdir(struct inode *inode, struct dentry *dentry)
5259+
{
5260+
struct dentry *parent;
5261+
int ret;
5262+
5263+
/* Paranoid: Make sure the parent is the "instances" directory */
5264+
parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
5265+
if (WARN_ON_ONCE(parent != trace_instance_dir))
5266+
return -ENOENT;
5267+
5268+
/* The caller did a dget() on dentry */
5269+
mutex_unlock(&dentry->d_inode->i_mutex);
5270+
5271+
/*
5272+
* The inode mutex is locked, but debugfs_create_dir() will also
5273+
* take the mutex. As the instances directory can not be destroyed
5274+
* or changed in any other way, it is safe to unlock it, and
5275+
* let the dentry try. If two users try to make the same dir at
5276+
* the same time, then the instance_delete() will determine the
5277+
* winner.
5278+
*/
5279+
mutex_unlock(&inode->i_mutex);
5280+
5281+
ret = instance_delete(dentry->d_iname);
5282+
5283+
mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
5284+
mutex_lock(&dentry->d_inode->i_mutex);
5285+
5286+
return ret;
5287+
}
5288+
52225289
static const struct inode_operations instance_dir_inode_operations = {
52235290
.lookup = simple_lookup,
52245291
.mkdir = instance_mkdir,
5292+
.rmdir = instance_rmdir,
52255293
};
52265294

52275295
static __init void create_trace_instances(struct dentry *d_tracer)

kernel/trace/trace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,7 @@ filter_check_discard(struct ftrace_event_call *call, void *rec,
10011001

10021002
extern void trace_event_enable_cmd_record(bool enable);
10031003
extern int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr);
1004+
extern int event_trace_del_tracer(struct trace_array *tr);
10041005

10051006
extern struct mutex event_mutex;
10061007
extern struct list_head ftrace_events;

kernel/trace/trace_events.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1709,6 +1709,20 @@ __trace_add_event_dirs(struct trace_array *tr)
17091709
}
17101710
}
17111711

1712+
/* Remove the event directory structure for a trace directory. */
1713+
static void
1714+
__trace_remove_event_dirs(struct trace_array *tr)
1715+
{
1716+
struct ftrace_event_file *file, *next;
1717+
1718+
list_for_each_entry_safe(file, next, &tr->events, list) {
1719+
list_del(&file->list);
1720+
debugfs_remove_recursive(file->dir);
1721+
remove_subsystem(file->system);
1722+
kfree(file);
1723+
}
1724+
}
1725+
17121726
static void
17131727
__add_event_to_tracers(struct ftrace_event_call *call,
17141728
struct ftrace_module_file_ops *file_ops)
@@ -1793,6 +1807,25 @@ int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr)
17931807
return 0;
17941808
}
17951809

1810+
int event_trace_del_tracer(struct trace_array *tr)
1811+
{
1812+
/* Disable any running events */
1813+
__ftrace_set_clr_event(tr, NULL, NULL, NULL, 0);
1814+
1815+
mutex_lock(&event_mutex);
1816+
1817+
down_write(&trace_event_mutex);
1818+
__trace_remove_event_dirs(tr);
1819+
debugfs_remove_recursive(tr->event_dir);
1820+
up_write(&trace_event_mutex);
1821+
1822+
tr->event_dir = NULL;
1823+
1824+
mutex_unlock(&event_mutex);
1825+
1826+
return 0;
1827+
}
1828+
17961829
static __init int event_trace_enable(void)
17971830
{
17981831
struct trace_array *tr = top_trace_array();

0 commit comments

Comments
 (0)