diff options
author | Eduard - Gabriel Munteanu <eduard.munteanu@linux360.ro> | 2009-02-09 01:15:56 -0500 |
---|---|---|
committer | Steven Rostedt <srostedt@redhat.com> | 2009-02-09 12:24:34 -0500 |
commit | 3c56819b14b00dd449bd776303e61f8532fad09f (patch) | |
tree | 5a0617aa39fa441673382cf69d873b1906146e7e /kernel/trace/trace.c | |
parent | b91facc367366b3f71375f337eb5997ec9ab4e69 (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.c | 136 |
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 | ||
368 | ssize_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 | |||
367 | static void | 387 | static void |
368 | trace_print_seq(struct seq_file *m, struct trace_seq *s) | 388 | trace_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 | ||
2516 | static void tracing_pipe_buf_release(struct pipe_inode_info *pipe, | ||
2517 | struct pipe_buffer *buf) | ||
2518 | { | ||
2519 | __free_page(buf->page); | ||
2520 | } | ||
2521 | |||
2522 | static void tracing_spd_release_pipe(struct splice_pipe_desc *spd, | ||
2523 | unsigned int idx) | ||
2524 | { | ||
2525 | __free_page(spd->pages[idx]); | ||
2526 | } | ||
2527 | |||
2528 | static 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 | |||
2538 | static 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 | |||
2625 | out: | ||
2626 | mutex_unlock(&trace_types_lock); | ||
2627 | |||
2628 | return ret; | ||
2629 | } | ||
2630 | |||
2496 | static ssize_t | 2631 | static ssize_t |
2497 | tracing_entries_read(struct file *filp, char __user *ubuf, | 2632 | tracing_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 | ||