aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace.c
diff options
context:
space:
mode:
authorEduard - Gabriel Munteanu <eduard.munteanu@linux360.ro>2009-02-09 01:15:56 -0500
committerSteven Rostedt <srostedt@redhat.com>2009-02-09 12:24:34 -0500
commit3c56819b14b00dd449bd776303e61f8532fad09f (patch)
tree5a0617aa39fa441673382cf69d873b1906146e7e /kernel/trace/trace.c
parentb91facc367366b3f71375f337eb5997ec9ab4e69 (diff)
tracing: splice support for tracing_pipe
Added and implemented tracing_pipe_fops->splice_read(). This allows userspace programs to get tracing data more efficiently. Signed-off-by: Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro> Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Diffstat (limited to 'kernel/trace/trace.c')
-rw-r--r--kernel/trace/trace.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 5b1e9a9e9906..9e29fdb0dfe5 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -31,6 +31,7 @@
31#include <linux/fs.h> 31#include <linux/fs.h>
32#include <linux/kprobes.h> 32#include <linux/kprobes.h>
33#include <linux/writeback.h> 33#include <linux/writeback.h>
34#include <linux/splice.h>
34 35
35#include <linux/stacktrace.h> 36#include <linux/stacktrace.h>
36#include <linux/ring_buffer.h> 37#include <linux/ring_buffer.h>
@@ -364,6 +365,25 @@ ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt)
364 return cnt; 365 return cnt;
365} 366}
366 367
368ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt)
369{
370 int len;
371 void *ret;
372
373 if (s->len <= s->readpos)
374 return -EBUSY;
375
376 len = s->len - s->readpos;
377 if (cnt > len)
378 cnt = len;
379 ret = memcpy(buf, s->buffer + s->readpos, cnt);
380 if (!ret)
381 return -EFAULT;
382
383 s->readpos += len;
384 return cnt;
385}
386
367static void 387static void
368trace_print_seq(struct seq_file *m, struct trace_seq *s) 388trace_print_seq(struct seq_file *m, struct trace_seq *s)
369{ 389{
@@ -2493,6 +2513,121 @@ out:
2493 return sret; 2513 return sret;
2494} 2514}
2495 2515
2516static void tracing_pipe_buf_release(struct pipe_inode_info *pipe,
2517 struct pipe_buffer *buf)
2518{
2519 __free_page(buf->page);
2520}
2521
2522static void tracing_spd_release_pipe(struct splice_pipe_desc *spd,
2523 unsigned int idx)
2524{
2525 __free_page(spd->pages[idx]);
2526}
2527
2528static struct pipe_buf_operations tracing_pipe_buf_ops = {
2529 .can_merge = 0,
2530 .map = generic_pipe_buf_map,
2531 .unmap = generic_pipe_buf_unmap,
2532 .confirm = generic_pipe_buf_confirm,
2533 .release = tracing_pipe_buf_release,
2534 .steal = generic_pipe_buf_steal,
2535 .get = generic_pipe_buf_get,
2536};
2537
2538static ssize_t tracing_splice_read_pipe(struct file *filp,
2539 loff_t *ppos,
2540 struct pipe_inode_info *pipe,
2541 size_t len,
2542 unsigned int flags)
2543{
2544 struct page *pages[PIPE_BUFFERS];
2545 struct partial_page partial[PIPE_BUFFERS];
2546 struct trace_iterator *iter = filp->private_data;
2547 struct splice_pipe_desc spd = {
2548 .pages = pages,
2549 .partial = partial,
2550 .nr_pages = 0, /* This gets updated below. */
2551 .flags = flags,
2552 .ops = &tracing_pipe_buf_ops,
2553 .spd_release = tracing_spd_release_pipe,
2554 };
2555 ssize_t ret;
2556 size_t count, rem;
2557 unsigned int i;
2558
2559 mutex_lock(&trace_types_lock);
2560
2561 if (iter->trace->splice_read) {
2562 ret = iter->trace->splice_read(iter, filp,
2563 ppos, pipe, len, flags);
2564 if (ret)
2565 goto out;
2566 }
2567
2568 ret = tracing_wait_pipe(filp);
2569 if (ret <= 0)
2570 goto out;
2571
2572 if (!iter->ent && !find_next_entry_inc(iter)) {
2573 ret = -EFAULT;
2574 goto out;
2575 }
2576
2577 /* Fill as many pages as possible. */
2578 for (i = 0, rem = len; i < PIPE_BUFFERS && rem; i++) {
2579 pages[i] = alloc_page(GFP_KERNEL);
2580
2581 /* Seq buffer is page-sized, exactly what we need. */
2582 for (;;) {
2583 count = iter->seq.len;
2584 ret = print_trace_line(iter);
2585 count = iter->seq.len - count;
2586 if (rem < count) {
2587 rem = 0;
2588 iter->seq.len -= count;
2589 break;
2590 }
2591 if (ret == TRACE_TYPE_PARTIAL_LINE) {
2592 iter->seq.len -= count;
2593 break;
2594 }
2595
2596 trace_consume(iter);
2597 rem -= count;
2598 if (!find_next_entry_inc(iter)) {
2599 rem = 0;
2600 iter->ent = NULL;
2601 break;
2602 }
2603 }
2604
2605 /* Copy the data into the page, so we can start over. */
2606 ret = trace_seq_to_buffer(&iter->seq,
2607 page_address(pages[i]),
2608 iter->seq.len);
2609 if (ret < 0) {
2610 __free_page(pages[i]);
2611 break;
2612 }
2613 partial[i].offset = 0;
2614 partial[i].len = iter->seq.len;
2615
2616 trace_seq_reset(&iter->seq);
2617 }
2618
2619 mutex_unlock(&trace_types_lock);
2620
2621 spd.nr_pages = i;
2622
2623 return splice_to_pipe(pipe, &spd);
2624
2625out:
2626 mutex_unlock(&trace_types_lock);
2627
2628 return ret;
2629}
2630
2496static ssize_t 2631static ssize_t
2497tracing_entries_read(struct file *filp, char __user *ubuf, 2632tracing_entries_read(struct file *filp, char __user *ubuf,
2498 size_t cnt, loff_t *ppos) 2633 size_t cnt, loff_t *ppos)
@@ -2656,6 +2791,7 @@ static struct file_operations tracing_pipe_fops = {
2656 .open = tracing_open_pipe, 2791 .open = tracing_open_pipe,
2657 .poll = tracing_poll_pipe, 2792 .poll = tracing_poll_pipe,
2658 .read = tracing_read_pipe, 2793 .read = tracing_read_pipe,
2794 .splice_read = tracing_splice_read_pipe,
2659 .release = tracing_release_pipe, 2795 .release = tracing_release_pipe,
2660}; 2796};
2661 2797