tracing: Add 'delete' file to remove multibuffer instances
Add a 'delete' file that is used to remove multibuffer instances.
Example:
echo hello > /debug/tracing/instances/new
ls /debug/tracing/instances
delete hello/ new
echo hello > /debug/tracing/instances/delete
ls /debug/tracing/instances
delete new
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index a45b9f9..15d9f07 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4885,6 +4885,83 @@
return ret;
}
+static ssize_t
+trace_del_instance_read(struct file *filp, char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ static char text[] =
+ "\nWrite into this file to delete an instance\n\n";
+
+ return simple_read_from_buffer(ubuf, cnt, ppos, text, sizeof(text));
+}
+
+static ssize_t
+trace_del_instance_write(struct file *filp, const char __user *ubuf,
+ size_t cnt, loff_t *ppos)
+{
+ struct trace_array *tr;
+ char *buf;
+ char *name;
+ int found = 0;
+ int ret;
+
+ /* Don't let names be bigger than 1024 */
+ if (cnt > 1024)
+ return -EINVAL;
+
+ name = kmalloc(cnt+1, GFP_KERNEL);
+ if (!name)
+ return -ENOMEM;
+
+ ret = -EFAULT;
+ if (strncpy_from_user(name, ubuf, cnt) < 0)
+ goto out_free_name;
+
+ name[cnt] = '\0';
+
+ /* remove leading and trailing whitespace */
+ buf = strstrip(name);
+ buf = kstrdup(buf, GFP_KERNEL);
+ if (!buf)
+ goto out_free_name;
+ kfree(name);
+ name = buf;
+
+ 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);
+ mutex_unlock(&trace_types_lock);
+
+ (*ppos) += cnt;
+
+ return cnt;
+
+ out_unlock:
+ mutex_unlock(&trace_types_lock);
+
+ out_free_name:
+ kfree(name);
+ return ret;
+}
+
static const struct file_operations trace_new_instance_fops = {
.open = tracing_open_generic,
.read = trace_new_instance_read,
@@ -4892,6 +4969,13 @@
.llseek = default_llseek,
};
+static const struct file_operations trace_del_instance_fops = {
+ .open = tracing_open_generic,
+ .read = trace_del_instance_read,
+ .write = trace_del_instance_write,
+ .llseek = default_llseek,
+};
+
static __init void create_trace_instances(struct dentry *d_tracer)
{
trace_instance_dir = debugfs_create_dir("instances", d_tracer);
@@ -4900,6 +4984,9 @@
trace_create_file("new", 0644, trace_instance_dir, NULL,
&trace_new_instance_fops);
+
+ trace_create_file("delete", 0644, trace_instance_dir, NULL,
+ &trace_del_instance_fops);
}
static void
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 4ec5c57..ce46423 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -890,6 +890,7 @@
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;
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 777a108..f421085 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1691,6 +1691,20 @@
}
}
+/* 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)
@@ -1775,6 +1789,22 @@
return 0;
}
+int event_trace_del_tracer(struct trace_array *tr)
+{
+ 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_init(void)
{
struct ftrace_event_call **call;