Skip to content

Commit 3c56819

Browse files
edgmntSteven Rostedt
authored andcommitted
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 <[email protected]> Signed-off-by: Steven Rostedt <[email protected]>
1 parent b91facc commit 3c56819

File tree

2 files changed

+142
-0
lines changed

2 files changed

+142
-0
lines changed

kernel/trace/trace.c

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <linux/fs.h>
3232
#include <linux/kprobes.h>
3333
#include <linux/writeback.h>
34+
#include <linux/splice.h>
3435

3536
#include <linux/stacktrace.h>
3637
#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)
364365
return cnt;
365366
}
366367

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+
367387
static void
368388
trace_print_seq(struct seq_file *m, struct trace_seq *s)
369389
{
@@ -2493,6 +2513,121 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
24932513
return sret;
24942514
}
24952515

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+
24962631
static ssize_t
24972632
tracing_entries_read(struct file *filp, char __user *ubuf,
24982633
size_t cnt, loff_t *ppos)
@@ -2656,6 +2791,7 @@ static struct file_operations tracing_pipe_fops = {
26562791
.open = tracing_open_pipe,
26572792
.poll = tracing_poll_pipe,
26582793
.read = tracing_read_pipe,
2794+
.splice_read = tracing_splice_read_pipe,
26592795
.release = tracing_release_pipe,
26602796
};
26612797

kernel/trace/trace.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,12 @@ struct tracer {
353353
ssize_t (*read)(struct trace_iterator *iter,
354354
struct file *filp, char __user *ubuf,
355355
size_t cnt, loff_t *ppos);
356+
ssize_t (*splice_read)(struct trace_iterator *iter,
357+
struct file *filp,
358+
loff_t *ppos,
359+
struct pipe_inode_info *pipe,
360+
size_t len,
361+
unsigned int flags);
356362
#ifdef CONFIG_FTRACE_STARTUP_TEST
357363
int (*selftest)(struct tracer *trace,
358364
struct trace_array *tr);

0 commit comments

Comments
 (0)