diff options
author | Steven Rostedt <srostedt@redhat.com> | 2012-08-03 16:10:49 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2013-03-15 00:34:44 -0400 |
commit | 277ba04461c2746cf935353474c0961161951b68 (patch) | |
tree | df2b8eb157c6725e606605f6acf40acbd4f13dd6 /kernel/trace | |
parent | 12ab74ee00d154bc05ea2fc659b7ce6519e5d5a6 (diff) |
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>
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/trace.c | 129 | ||||
-rw-r--r-- | kernel/trace/trace.h | 2 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 12 |
3 files changed, 142 insertions, 1 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 406adbc277a0..07a63114d938 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -5107,6 +5107,133 @@ static const struct file_operations rb_simple_fops = { | |||
5107 | .llseek = default_llseek, | 5107 | .llseek = default_llseek, |
5108 | }; | 5108 | }; |
5109 | 5109 | ||
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 | |||
5110 | static void | 5237 | static void |
5111 | init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer) | 5238 | init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer) |
5112 | { | 5239 | { |
@@ -5183,6 +5310,8 @@ static __init int tracer_init_debugfs(void) | |||
5183 | (void *)&global_trace.trace_cpu, &snapshot_fops); | 5310 | (void *)&global_trace.trace_cpu, &snapshot_fops); |
5184 | #endif | 5311 | #endif |
5185 | 5312 | ||
5313 | create_trace_instances(d_tracer); | ||
5314 | |||
5186 | create_trace_options_dir(&global_trace); | 5315 | create_trace_options_dir(&global_trace); |
5187 | 5316 | ||
5188 | for_each_tracing_cpu(cpu) | 5317 | for_each_tracing_cpu(cpu) |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 68cad7a9e089..883fe0b62f0a 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -175,6 +175,7 @@ struct tracer; | |||
175 | struct trace_array { | 175 | struct trace_array { |
176 | struct ring_buffer *buffer; | 176 | struct ring_buffer *buffer; |
177 | struct list_head list; | 177 | struct list_head list; |
178 | char *name; | ||
178 | int cpu; | 179 | int cpu; |
179 | int buffer_disabled; | 180 | int buffer_disabled; |
180 | struct trace_cpu trace_cpu; /* place holder */ | 181 | struct trace_cpu trace_cpu; /* place holder */ |
@@ -999,6 +1000,7 @@ filter_check_discard(struct ftrace_event_call *call, void *rec, | |||
999 | } | 1000 | } |
1000 | 1001 | ||
1001 | extern void trace_event_enable_cmd_record(bool enable); | 1002 | extern void trace_event_enable_cmd_record(bool enable); |
1003 | extern int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr); | ||
1002 | 1004 | ||
1003 | extern struct mutex event_mutex; | 1005 | extern struct mutex event_mutex; |
1004 | extern struct list_head ftrace_events; | 1006 | extern struct list_head ftrace_events; |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 439955239bae..58a61302a733 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -1754,16 +1754,22 @@ int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr) | |||
1754 | struct dentry *d_events; | 1754 | struct dentry *d_events; |
1755 | struct dentry *entry; | 1755 | struct dentry *entry; |
1756 | 1756 | ||
1757 | mutex_lock(&event_mutex); | ||
1758 | |||
1757 | entry = debugfs_create_file("set_event", 0644, parent, | 1759 | entry = debugfs_create_file("set_event", 0644, parent, |
1758 | tr, &ftrace_set_event_fops); | 1760 | tr, &ftrace_set_event_fops); |
1759 | if (!entry) { | 1761 | if (!entry) { |
1760 | pr_warning("Could not create debugfs 'set_event' entry\n"); | 1762 | pr_warning("Could not create debugfs 'set_event' entry\n"); |
1763 | mutex_unlock(&event_mutex); | ||
1761 | return -ENOMEM; | 1764 | return -ENOMEM; |
1762 | } | 1765 | } |
1763 | 1766 | ||
1764 | d_events = debugfs_create_dir("events", parent); | 1767 | d_events = debugfs_create_dir("events", parent); |
1765 | if (!d_events) | 1768 | if (!d_events) { |
1766 | pr_warning("Could not create debugfs 'events' directory\n"); | 1769 | pr_warning("Could not create debugfs 'events' directory\n"); |
1770 | mutex_unlock(&event_mutex); | ||
1771 | return -ENOMEM; | ||
1772 | } | ||
1767 | 1773 | ||
1768 | /* ring buffer internal formats */ | 1774 | /* ring buffer internal formats */ |
1769 | trace_create_file("header_page", 0444, d_events, | 1775 | trace_create_file("header_page", 0444, d_events, |
@@ -1778,7 +1784,11 @@ int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr) | |||
1778 | tr, &ftrace_tr_enable_fops); | 1784 | tr, &ftrace_tr_enable_fops); |
1779 | 1785 | ||
1780 | tr->event_dir = d_events; | 1786 | tr->event_dir = d_events; |
1787 | down_write(&trace_event_mutex); | ||
1781 | __trace_add_event_dirs(tr); | 1788 | __trace_add_event_dirs(tr); |
1789 | up_write(&trace_event_mutex); | ||
1790 | |||
1791 | mutex_unlock(&event_mutex); | ||
1782 | 1792 | ||
1783 | return 0; | 1793 | return 0; |
1784 | } | 1794 | } |