Skip to content

Commit

Permalink
tracing: Add rmdir to remove multibuffer instances
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Steven Rostedt authored and rostedt committed Mar 15, 2013
1 parent 277ba04 commit 0c8916c
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 0 deletions.
68 changes: 68 additions & 0 deletions kernel/trace/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -5192,6 +5192,42 @@ static int new_instance_create(const char *name)

}

static int instance_delete(const char *name)
{
struct trace_array *tr;
int found = 0;
int ret;

mutex_lock(&trace_types_lock);

ret = -ENODEV;
list_for_each_entry(tr, &ftrace_trace_arrays, list) {
if (tr->name && strcmp(tr->name, name) == 0) {
found = 1;
break;
}
}
if (!found)
goto out_unlock;

list_del(&tr->list);

event_trace_del_tracer(tr);
debugfs_remove_recursive(tr->dir);
free_percpu(tr->data);
ring_buffer_free(tr->buffer);

kfree(tr->name);
kfree(tr);

ret = 0;

out_unlock:
mutex_unlock(&trace_types_lock);

return ret;
}

static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t mode)
{
struct dentry *parent;
Expand Down Expand Up @@ -5219,9 +5255,41 @@ static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t m
return ret;
}

static int instance_rmdir(struct inode *inode, struct dentry *dentry)
{
struct dentry *parent;
int ret;

/* Paranoid: Make sure the parent is the "instances" directory */
parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
if (WARN_ON_ONCE(parent != trace_instance_dir))
return -ENOENT;

/* The caller did a dget() on dentry */
mutex_unlock(&dentry->d_inode->i_mutex);

/*
* The inode mutex is locked, but debugfs_create_dir() will also
* take the mutex. As the instances directory can not be destroyed
* or changed in any other way, it is safe to unlock it, and
* let the dentry try. If two users try to make the same dir at
* the same time, then the instance_delete() will determine the
* winner.
*/
mutex_unlock(&inode->i_mutex);

ret = instance_delete(dentry->d_iname);

mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
mutex_lock(&dentry->d_inode->i_mutex);

return ret;
}

static const struct inode_operations instance_dir_inode_operations = {
.lookup = simple_lookup,
.mkdir = instance_mkdir,
.rmdir = instance_rmdir,
};

static __init void create_trace_instances(struct dentry *d_tracer)
Expand Down
1 change: 1 addition & 0 deletions kernel/trace/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,7 @@ filter_check_discard(struct ftrace_event_call *call, void *rec,

extern void trace_event_enable_cmd_record(bool enable);
extern int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr);
extern int event_trace_del_tracer(struct trace_array *tr);

extern struct mutex event_mutex;
extern struct list_head ftrace_events;
Expand Down
33 changes: 33 additions & 0 deletions kernel/trace/trace_events.c
Original file line number Diff line number Diff line change
Expand Up @@ -1709,6 +1709,20 @@ __trace_add_event_dirs(struct trace_array *tr)
}
}

/* Remove the event directory structure for a trace directory. */
static void
__trace_remove_event_dirs(struct trace_array *tr)
{
struct ftrace_event_file *file, *next;

list_for_each_entry_safe(file, next, &tr->events, list) {
list_del(&file->list);
debugfs_remove_recursive(file->dir);
remove_subsystem(file->system);
kfree(file);
}
}

static void
__add_event_to_tracers(struct ftrace_event_call *call,
struct ftrace_module_file_ops *file_ops)
Expand Down Expand Up @@ -1793,6 +1807,25 @@ int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr)
return 0;
}

int event_trace_del_tracer(struct trace_array *tr)
{
/* Disable any running events */
__ftrace_set_clr_event(tr, NULL, NULL, NULL, 0);

mutex_lock(&event_mutex);

down_write(&trace_event_mutex);
__trace_remove_event_dirs(tr);
debugfs_remove_recursive(tr->event_dir);
up_write(&trace_event_mutex);

tr->event_dir = NULL;

mutex_unlock(&event_mutex);

return 0;
}

static __init int event_trace_enable(void)
{
struct trace_array *tr = top_trace_array();
Expand Down

0 comments on commit 0c8916c

Please sign in to comment.