diff options
author | Steven Rostedt (Red Hat) <srostedt@redhat.com> | 2013-03-05 16:18:16 -0500 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2013-03-15 00:35:47 -0400 |
commit | 6de58e6269cd0568ca5fbae14423914eff0f7811 (patch) | |
tree | 3ce4d96d1549925a2724ed713d76cf2f9683ff72 /kernel/trace | |
parent | 0b85ffc293044393623059eda9904a7d5b644e36 (diff) |
tracing: Add snapshot_raw to extract the raw data from snapshot
Add a 'snapshot_raw' per_cpu file that allows tools to read the raw
binary data of the snapshot buffer.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/trace.c | 113 |
1 files changed, 95 insertions, 18 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 303932688964..9bb0b52cbd32 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -4206,6 +4206,12 @@ static int tracing_clock_open(struct inode *inode, struct file *file) | |||
4206 | return single_open(file, tracing_clock_show, inode->i_private); | 4206 | return single_open(file, tracing_clock_show, inode->i_private); |
4207 | } | 4207 | } |
4208 | 4208 | ||
4209 | struct ftrace_buffer_info { | ||
4210 | struct trace_iterator iter; | ||
4211 | void *spare; | ||
4212 | unsigned int read; | ||
4213 | }; | ||
4214 | |||
4209 | #ifdef CONFIG_TRACER_SNAPSHOT | 4215 | #ifdef CONFIG_TRACER_SNAPSHOT |
4210 | static int tracing_snapshot_open(struct inode *inode, struct file *file) | 4216 | static int tracing_snapshot_open(struct inode *inode, struct file *file) |
4211 | { | 4217 | { |
@@ -4336,6 +4342,35 @@ static int tracing_snapshot_release(struct inode *inode, struct file *file) | |||
4336 | return 0; | 4342 | return 0; |
4337 | } | 4343 | } |
4338 | 4344 | ||
4345 | static int tracing_buffers_open(struct inode *inode, struct file *filp); | ||
4346 | static ssize_t tracing_buffers_read(struct file *filp, char __user *ubuf, | ||
4347 | size_t count, loff_t *ppos); | ||
4348 | static int tracing_buffers_release(struct inode *inode, struct file *file); | ||
4349 | static ssize_t tracing_buffers_splice_read(struct file *file, loff_t *ppos, | ||
4350 | struct pipe_inode_info *pipe, size_t len, unsigned int flags); | ||
4351 | |||
4352 | static int snapshot_raw_open(struct inode *inode, struct file *filp) | ||
4353 | { | ||
4354 | struct ftrace_buffer_info *info; | ||
4355 | int ret; | ||
4356 | |||
4357 | ret = tracing_buffers_open(inode, filp); | ||
4358 | if (ret < 0) | ||
4359 | return ret; | ||
4360 | |||
4361 | info = filp->private_data; | ||
4362 | |||
4363 | if (info->iter.trace->use_max_tr) { | ||
4364 | tracing_buffers_release(inode, filp); | ||
4365 | return -EBUSY; | ||
4366 | } | ||
4367 | |||
4368 | info->iter.snapshot = true; | ||
4369 | info->iter.trace_buffer = &info->iter.tr->max_buffer; | ||
4370 | |||
4371 | return ret; | ||
4372 | } | ||
4373 | |||
4339 | #endif /* CONFIG_TRACER_SNAPSHOT */ | 4374 | #endif /* CONFIG_TRACER_SNAPSHOT */ |
4340 | 4375 | ||
4341 | 4376 | ||
@@ -4402,14 +4437,17 @@ static const struct file_operations snapshot_fops = { | |||
4402 | .llseek = tracing_seek, | 4437 | .llseek = tracing_seek, |
4403 | .release = tracing_snapshot_release, | 4438 | .release = tracing_snapshot_release, |
4404 | }; | 4439 | }; |
4405 | #endif /* CONFIG_TRACER_SNAPSHOT */ | ||
4406 | 4440 | ||
4407 | struct ftrace_buffer_info { | 4441 | static const struct file_operations snapshot_raw_fops = { |
4408 | struct trace_iterator iter; | 4442 | .open = snapshot_raw_open, |
4409 | void *spare; | 4443 | .read = tracing_buffers_read, |
4410 | unsigned int read; | 4444 | .release = tracing_buffers_release, |
4445 | .splice_read = tracing_buffers_splice_read, | ||
4446 | .llseek = no_llseek, | ||
4411 | }; | 4447 | }; |
4412 | 4448 | ||
4449 | #endif /* CONFIG_TRACER_SNAPSHOT */ | ||
4450 | |||
4413 | static int tracing_buffers_open(struct inode *inode, struct file *filp) | 4451 | static int tracing_buffers_open(struct inode *inode, struct file *filp) |
4414 | { | 4452 | { |
4415 | struct trace_cpu *tc = inode->i_private; | 4453 | struct trace_cpu *tc = inode->i_private; |
@@ -4452,16 +4490,26 @@ tracing_buffers_read(struct file *filp, char __user *ubuf, | |||
4452 | struct ftrace_buffer_info *info = filp->private_data; | 4490 | struct ftrace_buffer_info *info = filp->private_data; |
4453 | struct trace_iterator *iter = &info->iter; | 4491 | struct trace_iterator *iter = &info->iter; |
4454 | ssize_t ret; | 4492 | ssize_t ret; |
4455 | size_t size; | 4493 | ssize_t size; |
4456 | 4494 | ||
4457 | if (!count) | 4495 | if (!count) |
4458 | return 0; | 4496 | return 0; |
4459 | 4497 | ||
4498 | mutex_lock(&trace_types_lock); | ||
4499 | |||
4500 | #ifdef CONFIG_TRACER_MAX_TRACE | ||
4501 | if (iter->snapshot && iter->tr->current_trace->use_max_tr) { | ||
4502 | size = -EBUSY; | ||
4503 | goto out_unlock; | ||
4504 | } | ||
4505 | #endif | ||
4506 | |||
4460 | if (!info->spare) | 4507 | if (!info->spare) |
4461 | info->spare = ring_buffer_alloc_read_page(iter->trace_buffer->buffer, | 4508 | info->spare = ring_buffer_alloc_read_page(iter->trace_buffer->buffer, |
4462 | iter->cpu_file); | 4509 | iter->cpu_file); |
4510 | size = -ENOMEM; | ||
4463 | if (!info->spare) | 4511 | if (!info->spare) |
4464 | return -ENOMEM; | 4512 | goto out_unlock; |
4465 | 4513 | ||
4466 | /* Do we have previous read data to read? */ | 4514 | /* Do we have previous read data to read? */ |
4467 | if (info->read < PAGE_SIZE) | 4515 | if (info->read < PAGE_SIZE) |
@@ -4477,31 +4525,42 @@ tracing_buffers_read(struct file *filp, char __user *ubuf, | |||
4477 | 4525 | ||
4478 | if (ret < 0) { | 4526 | if (ret < 0) { |
4479 | if (trace_empty(iter)) { | 4527 | if (trace_empty(iter)) { |
4480 | if ((filp->f_flags & O_NONBLOCK)) | 4528 | if ((filp->f_flags & O_NONBLOCK)) { |
4481 | return -EAGAIN; | 4529 | size = -EAGAIN; |
4530 | goto out_unlock; | ||
4531 | } | ||
4532 | mutex_unlock(&trace_types_lock); | ||
4482 | iter->trace->wait_pipe(iter); | 4533 | iter->trace->wait_pipe(iter); |
4483 | if (signal_pending(current)) | 4534 | mutex_lock(&trace_types_lock); |
4484 | return -EINTR; | 4535 | if (signal_pending(current)) { |
4536 | size = -EINTR; | ||
4537 | goto out_unlock; | ||
4538 | } | ||
4485 | goto again; | 4539 | goto again; |
4486 | } | 4540 | } |
4487 | return 0; | 4541 | size = 0; |
4542 | goto out_unlock; | ||
4488 | } | 4543 | } |
4489 | 4544 | ||
4490 | info->read = 0; | 4545 | info->read = 0; |
4491 | |||
4492 | read: | 4546 | read: |
4493 | size = PAGE_SIZE - info->read; | 4547 | size = PAGE_SIZE - info->read; |
4494 | if (size > count) | 4548 | if (size > count) |
4495 | size = count; | 4549 | size = count; |
4496 | 4550 | ||
4497 | ret = copy_to_user(ubuf, info->spare + info->read, size); | 4551 | ret = copy_to_user(ubuf, info->spare + info->read, size); |
4498 | if (ret == size) | 4552 | if (ret == size) { |
4499 | return -EFAULT; | 4553 | size = -EFAULT; |
4554 | goto out_unlock; | ||
4555 | } | ||
4500 | size -= ret; | 4556 | size -= ret; |
4501 | 4557 | ||
4502 | *ppos += size; | 4558 | *ppos += size; |
4503 | info->read += size; | 4559 | info->read += size; |
4504 | 4560 | ||
4561 | out_unlock: | ||
4562 | mutex_unlock(&trace_types_lock); | ||
4563 | |||
4505 | return size; | 4564 | return size; |
4506 | } | 4565 | } |
4507 | 4566 | ||
@@ -4591,10 +4650,21 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, | |||
4591 | }; | 4650 | }; |
4592 | struct buffer_ref *ref; | 4651 | struct buffer_ref *ref; |
4593 | int entries, size, i; | 4652 | int entries, size, i; |
4594 | size_t ret; | 4653 | ssize_t ret; |
4595 | 4654 | ||
4596 | if (splice_grow_spd(pipe, &spd)) | 4655 | mutex_lock(&trace_types_lock); |
4597 | return -ENOMEM; | 4656 | |
4657 | #ifdef CONFIG_TRACER_MAX_TRACE | ||
4658 | if (iter->snapshot && iter->tr->current_trace->use_max_tr) { | ||
4659 | ret = -EBUSY; | ||
4660 | goto out; | ||
4661 | } | ||
4662 | #endif | ||
4663 | |||
4664 | if (splice_grow_spd(pipe, &spd)) { | ||
4665 | ret = -ENOMEM; | ||
4666 | goto out; | ||
4667 | } | ||
4598 | 4668 | ||
4599 | if (*ppos & (PAGE_SIZE - 1)) { | 4669 | if (*ppos & (PAGE_SIZE - 1)) { |
4600 | ret = -EINVAL; | 4670 | ret = -EINVAL; |
@@ -4666,7 +4736,9 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, | |||
4666 | ret = -EAGAIN; | 4736 | ret = -EAGAIN; |
4667 | goto out; | 4737 | goto out; |
4668 | } | 4738 | } |
4739 | mutex_unlock(&trace_types_lock); | ||
4669 | iter->trace->wait_pipe(iter); | 4740 | iter->trace->wait_pipe(iter); |
4741 | mutex_lock(&trace_types_lock); | ||
4670 | if (signal_pending(current)) { | 4742 | if (signal_pending(current)) { |
4671 | ret = -EINTR; | 4743 | ret = -EINTR; |
4672 | goto out; | 4744 | goto out; |
@@ -4677,6 +4749,8 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos, | |||
4677 | ret = splice_to_pipe(pipe, &spd); | 4749 | ret = splice_to_pipe(pipe, &spd); |
4678 | splice_shrink_spd(&spd); | 4750 | splice_shrink_spd(&spd); |
4679 | out: | 4751 | out: |
4752 | mutex_unlock(&trace_types_lock); | ||
4753 | |||
4680 | return ret; | 4754 | return ret; |
4681 | } | 4755 | } |
4682 | 4756 | ||
@@ -4880,6 +4954,9 @@ tracing_init_debugfs_percpu(struct trace_array *tr, long cpu) | |||
4880 | #ifdef CONFIG_TRACER_SNAPSHOT | 4954 | #ifdef CONFIG_TRACER_SNAPSHOT |
4881 | trace_create_file("snapshot", 0644, d_cpu, | 4955 | trace_create_file("snapshot", 0644, d_cpu, |
4882 | (void *)&data->trace_cpu, &snapshot_fops); | 4956 | (void *)&data->trace_cpu, &snapshot_fops); |
4957 | |||
4958 | trace_create_file("snapshot_raw", 0444, d_cpu, | ||
4959 | (void *)&data->trace_cpu, &snapshot_raw_fops); | ||
4883 | #endif | 4960 | #endif |
4884 | } | 4961 | } |
4885 | 4962 | ||