Skip to content

Commit 277ba04

Browse files
Steven Rostedtrostedt
authored andcommitted
tracing: Add interface to allow multiple trace buffers
Add the interface ("instances" directory) to add multiple buffers to ftrace. To create a new instance, simply do a mkdir in the instances directory: This will create a directory with the following: # cd instances # mkdir foo # ls foo buffer_size_kb free_buffer trace_clock trace_pipe buffer_total_size_kb set_event trace_marker tracing_enabled events/ trace trace_options tracing_on Currently only events are able to be set, and there isn't a way to delete a buffer when one is created (yet). Note, the i_mutex lock is dropped from the parent "instances" directory during the mkdir operation. As the "instances" directory can not be renamed or deleted (created on boot), I do not see any harm in dropping the lock. The creation of the sub directories is protected by trace_types_lock mutex, which only lets one instance get into the code path at a time. If two tasks try to create or delete directories of the same name, only one will occur and the other will fail with -EEXIST. Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
1 parent 12ab74e commit 277ba04

File tree

3 files changed

+142
-1
lines changed

3 files changed

+142
-1
lines changed

kernel/trace/trace.c

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5107,6 +5107,133 @@ static const struct file_operations rb_simple_fops = {
51075107
.llseek = default_llseek,
51085108
};
51095109

5110+
struct dentry *trace_instance_dir;
5111+
5112+
static void
5113+
init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer);
5114+
5115+
static int new_instance_create(const char *name)
5116+
{
5117+
enum ring_buffer_flags rb_flags;
5118+
struct trace_array *tr;
5119+
int ret;
5120+
int i;
5121+
5122+
mutex_lock(&trace_types_lock);
5123+
5124+
ret = -EEXIST;
5125+
list_for_each_entry(tr, &ftrace_trace_arrays, list) {
5126+
if (tr->name && strcmp(tr->name, name) == 0)
5127+
goto out_unlock;
5128+
}
5129+
5130+
ret = -ENOMEM;
5131+
tr = kzalloc(sizeof(*tr), GFP_KERNEL);
5132+
if (!tr)
5133+
goto out_unlock;
5134+
5135+
tr->name = kstrdup(name, GFP_KERNEL);
5136+
if (!tr->name)
5137+
goto out_free_tr;
5138+
5139+
raw_spin_lock_init(&tr->start_lock);
5140+
5141+
tr->current_trace = &nop_trace;
5142+
5143+
INIT_LIST_HEAD(&tr->systems);
5144+
INIT_LIST_HEAD(&tr->events);
5145+
5146+
rb_flags = trace_flags & TRACE_ITER_OVERWRITE ? RB_FL_OVERWRITE : 0;
5147+
5148+
tr->buffer = ring_buffer_alloc(trace_buf_size, rb_flags);
5149+
if (!tr->buffer)
5150+
goto out_free_tr;
5151+
5152+
tr->data = alloc_percpu(struct trace_array_cpu);
5153+
if (!tr->data)
5154+
goto out_free_tr;
5155+
5156+
for_each_tracing_cpu(i) {
5157+
memset(per_cpu_ptr(tr->data, i), 0, sizeof(struct trace_array_cpu));
5158+
per_cpu_ptr(tr->data, i)->trace_cpu.cpu = i;
5159+
per_cpu_ptr(tr->data, i)->trace_cpu.tr = tr;
5160+
}
5161+
5162+
/* Holder for file callbacks */
5163+
tr->trace_cpu.cpu = RING_BUFFER_ALL_CPUS;
5164+
tr->trace_cpu.tr = tr;
5165+
5166+
tr->dir = debugfs_create_dir(name, trace_instance_dir);
5167+
if (!tr->dir)
5168+
goto out_free_tr;
5169+
5170+
ret = event_trace_add_tracer(tr->dir, tr);
5171+
if (ret)
5172+
goto out_free_tr;
5173+
5174+
init_tracer_debugfs(tr, tr->dir);
5175+
5176+
list_add(&tr->list, &ftrace_trace_arrays);
5177+
5178+
mutex_unlock(&trace_types_lock);
5179+
5180+
return 0;
5181+
5182+
out_free_tr:
5183+
if (tr->buffer)
5184+
ring_buffer_free(tr->buffer);
5185+
kfree(tr->name);
5186+
kfree(tr);
5187+
5188+
out_unlock:
5189+
mutex_unlock(&trace_types_lock);
5190+
5191+
return ret;
5192+
5193+
}
5194+
5195+
static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t mode)
5196+
{
5197+
struct dentry *parent;
5198+
int ret;
5199+
5200+
/* Paranoid: Make sure the parent is the "instances" directory */
5201+
parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
5202+
if (WARN_ON_ONCE(parent != trace_instance_dir))
5203+
return -ENOENT;
5204+
5205+
/*
5206+
* The inode mutex is locked, but debugfs_create_dir() will also
5207+
* take the mutex. As the instances directory can not be destroyed
5208+
* or changed in any other way, it is safe to unlock it, and
5209+
* let the dentry try. If two users try to make the same dir at
5210+
* the same time, then the new_instance_create() will determine the
5211+
* winner.
5212+
*/
5213+
mutex_unlock(&inode->i_mutex);
5214+
5215+
ret = new_instance_create(dentry->d_iname);
5216+
5217+
mutex_lock(&inode->i_mutex);
5218+
5219+
return ret;
5220+
}
5221+
5222+
static const struct inode_operations instance_dir_inode_operations = {
5223+
.lookup = simple_lookup,
5224+
.mkdir = instance_mkdir,
5225+
};
5226+
5227+
static __init void create_trace_instances(struct dentry *d_tracer)
5228+
{
5229+
trace_instance_dir = debugfs_create_dir("instances", d_tracer);
5230+
if (WARN_ON(!trace_instance_dir))
5231+
return;
5232+
5233+
/* Hijack the dir inode operations, to allow mkdir */
5234+
trace_instance_dir->d_inode->i_op = &instance_dir_inode_operations;
5235+
}
5236+
51105237
static void
51115238
init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
51125239
{
@@ -5183,6 +5310,8 @@ static __init int tracer_init_debugfs(void)
51835310
(void *)&global_trace.trace_cpu, &snapshot_fops);
51845311
#endif
51855312

5313+
create_trace_instances(d_tracer);
5314+
51865315
create_trace_options_dir(&global_trace);
51875316

51885317
for_each_tracing_cpu(cpu)

kernel/trace/trace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ struct tracer;
175175
struct trace_array {
176176
struct ring_buffer *buffer;
177177
struct list_head list;
178+
char *name;
178179
int cpu;
179180
int buffer_disabled;
180181
struct trace_cpu trace_cpu; /* place holder */
@@ -999,6 +1000,7 @@ filter_check_discard(struct ftrace_event_call *call, void *rec,
9991000
}
10001001

10011002
extern void trace_event_enable_cmd_record(bool enable);
1003+
extern int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr);
10021004

10031005
extern struct mutex event_mutex;
10041006
extern struct list_head ftrace_events;

kernel/trace/trace_events.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1754,16 +1754,22 @@ int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr)
17541754
struct dentry *d_events;
17551755
struct dentry *entry;
17561756

1757+
mutex_lock(&event_mutex);
1758+
17571759
entry = debugfs_create_file("set_event", 0644, parent,
17581760
tr, &ftrace_set_event_fops);
17591761
if (!entry) {
17601762
pr_warning("Could not create debugfs 'set_event' entry\n");
1763+
mutex_unlock(&event_mutex);
17611764
return -ENOMEM;
17621765
}
17631766

17641767
d_events = debugfs_create_dir("events", parent);
1765-
if (!d_events)
1768+
if (!d_events) {
17661769
pr_warning("Could not create debugfs 'events' directory\n");
1770+
mutex_unlock(&event_mutex);
1771+
return -ENOMEM;
1772+
}
17671773

17681774
/* ring buffer internal formats */
17691775
trace_create_file("header_page", 0444, d_events,
@@ -1778,7 +1784,11 @@ int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr)
17781784
tr, &ftrace_tr_enable_fops);
17791785

17801786
tr->event_dir = d_events;
1787+
down_write(&trace_event_mutex);
17811788
__trace_add_event_dirs(tr);
1789+
up_write(&trace_event_mutex);
1790+
1791+
mutex_unlock(&event_mutex);
17821792

17831793
return 0;
17841794
}

0 commit comments

Comments
 (0)