|
31 | 31 | #include <linux/fs.h>
|
32 | 32 | #include <linux/kprobes.h>
|
33 | 33 | #include <linux/writeback.h>
|
| 34 | +#include <linux/splice.h> |
34 | 35 |
|
35 | 36 | #include <linux/stacktrace.h>
|
36 | 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 | 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 | 387 | static void
|
368 | 388 | trace_print_seq(struct seq_file *m, struct trace_seq *s)
|
369 | 389 | {
|
@@ -2493,6 +2513,121 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
|
2493 | 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 | 2631 | static ssize_t
|
2497 | 2632 | tracing_entries_read(struct file *filp, char __user *ubuf,
|
2498 | 2633 | size_t cnt, loff_t *ppos)
|
@@ -2656,6 +2791,7 @@ static struct file_operations tracing_pipe_fops = {
|
2656 | 2791 | .open = tracing_open_pipe,
|
2657 | 2792 | .poll = tracing_poll_pipe,
|
2658 | 2793 | .read = tracing_read_pipe,
|
| 2794 | + .splice_read = tracing_splice_read_pipe, |
2659 | 2795 | .release = tracing_release_pipe,
|
2660 | 2796 | };
|
2661 | 2797 |
|
|
0 commit comments