Loading kernel/trace/trace.c +190 −29 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #include <linux/fs.h> #include <linux/kprobes.h> #include <linux/writeback.h> #include <linux/splice.h> #include <linux/stacktrace.h> #include <linux/ring_buffer.h> Loading Loading @@ -364,6 +365,25 @@ ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) return cnt; } ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt) { int len; void *ret; if (s->len <= s->readpos) return -EBUSY; len = s->len - s->readpos; if (cnt > len) cnt = len; ret = memcpy(buf, s->buffer + s->readpos, cnt); if (!ret) return -EFAULT; s->readpos += len; return cnt; } static void trace_print_seq(struct seq_file *m, struct trace_seq *s) { Loading Loading @@ -2368,37 +2388,15 @@ tracing_poll_pipe(struct file *filp, poll_table *poll_table) } } /* * Consumer reader. */ static ssize_t tracing_read_pipe(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) /* Must be called with trace_types_lock mutex held. */ static int tracing_wait_pipe(struct file *filp) { struct trace_iterator *iter = filp->private_data; ssize_t sret; /* return any leftover data */ sret = trace_seq_to_user(&iter->seq, ubuf, cnt); if (sret != -EBUSY) return sret; trace_seq_reset(&iter->seq); mutex_lock(&trace_types_lock); if (iter->trace->read) { sret = iter->trace->read(iter, filp, ubuf, cnt, ppos); if (sret) goto out; } waitagain: sret = 0; while (trace_empty(iter)) { if ((filp->f_flags & O_NONBLOCK)) { sret = -EAGAIN; goto out; return -EAGAIN; } /* Loading @@ -2423,12 +2421,11 @@ waitagain: iter->tr->waiter = NULL; if (signal_pending(current)) { sret = -EINTR; goto out; return -EINTR; } if (iter->trace != current_trace) goto out; return 0; /* * We block until we read something and tracing is disabled. Loading @@ -2445,9 +2442,43 @@ waitagain: continue; } return 1; } /* * Consumer reader. */ static ssize_t tracing_read_pipe(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { struct trace_iterator *iter = filp->private_data; ssize_t sret; /* return any leftover data */ sret = trace_seq_to_user(&iter->seq, ubuf, cnt); if (sret != -EBUSY) return sret; trace_seq_reset(&iter->seq); mutex_lock(&trace_types_lock); if (iter->trace->read) { sret = iter->trace->read(iter, filp, ubuf, cnt, ppos); if (sret) goto out; } waitagain: sret = tracing_wait_pipe(filp); if (sret <= 0) goto out; /* stop when tracing is finished */ if (trace_empty(iter)) if (trace_empty(iter)) { sret = 0; goto out; } if (cnt >= PAGE_SIZE) cnt = PAGE_SIZE - 1; Loading Loading @@ -2493,6 +2524,135 @@ out: return sret; } static void tracing_pipe_buf_release(struct pipe_inode_info *pipe, struct pipe_buffer *buf) { __free_page(buf->page); } static void tracing_spd_release_pipe(struct splice_pipe_desc *spd, unsigned int idx) { __free_page(spd->pages[idx]); } static struct pipe_buf_operations tracing_pipe_buf_ops = { .can_merge = 0, .map = generic_pipe_buf_map, .unmap = generic_pipe_buf_unmap, .confirm = generic_pipe_buf_confirm, .release = tracing_pipe_buf_release, .steal = generic_pipe_buf_steal, .get = generic_pipe_buf_get, }; static size_t tracing_fill_pipe_page(struct page *pages, size_t rem, struct trace_iterator *iter) { size_t count; int ret; /* Seq buffer is page-sized, exactly what we need. */ for (;;) { count = iter->seq.len; ret = print_trace_line(iter); count = iter->seq.len - count; if (rem < count) { rem = 0; iter->seq.len -= count; break; } if (ret == TRACE_TYPE_PARTIAL_LINE) { iter->seq.len -= count; break; } trace_consume(iter); rem -= count; if (!find_next_entry_inc(iter)) { rem = 0; iter->ent = NULL; break; } } return rem; } static ssize_t tracing_splice_read_pipe(struct file *filp, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags) { struct page *pages[PIPE_BUFFERS]; struct partial_page partial[PIPE_BUFFERS]; struct trace_iterator *iter = filp->private_data; struct splice_pipe_desc spd = { .pages = pages, .partial = partial, .nr_pages = 0, /* This gets updated below. */ .flags = flags, .ops = &tracing_pipe_buf_ops, .spd_release = tracing_spd_release_pipe, }; ssize_t ret; size_t rem; unsigned int i; mutex_lock(&trace_types_lock); if (iter->trace->splice_read) { ret = iter->trace->splice_read(iter, filp, ppos, pipe, len, flags); if (ret) goto out_err; } ret = tracing_wait_pipe(filp); if (ret <= 0) goto out_err; if (!iter->ent && !find_next_entry_inc(iter)) { ret = -EFAULT; goto out_err; } /* Fill as many pages as possible. */ for (i = 0, rem = len; i < PIPE_BUFFERS && rem; i++) { pages[i] = alloc_page(GFP_KERNEL); if (!pages[i]) break; rem = tracing_fill_pipe_page(pages[i], rem, iter); /* Copy the data into the page, so we can start over. */ ret = trace_seq_to_buffer(&iter->seq, page_address(pages[i]), iter->seq.len); if (ret < 0) { __free_page(pages[i]); break; } partial[i].offset = 0; partial[i].len = iter->seq.len; trace_seq_reset(&iter->seq); } mutex_unlock(&trace_types_lock); spd.nr_pages = i; return splice_to_pipe(pipe, &spd); out_err: mutex_unlock(&trace_types_lock); return ret; } static ssize_t tracing_entries_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) Loading Loading @@ -2656,6 +2816,7 @@ static struct file_operations tracing_pipe_fops = { .open = tracing_open_pipe, .poll = tracing_poll_pipe, .read = tracing_read_pipe, .splice_read = tracing_splice_read_pipe, .release = tracing_release_pipe, }; Loading kernel/trace/trace.h +6 −0 Original line number Diff line number Diff line Loading @@ -353,6 +353,12 @@ struct tracer { ssize_t (*read)(struct trace_iterator *iter, struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos); ssize_t (*splice_read)(struct trace_iterator *iter, struct file *filp, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); #ifdef CONFIG_FTRACE_STARTUP_TEST int (*selftest)(struct tracer *trace, struct trace_array *tr); Loading Loading
kernel/trace/trace.c +190 −29 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #include <linux/fs.h> #include <linux/kprobes.h> #include <linux/writeback.h> #include <linux/splice.h> #include <linux/stacktrace.h> #include <linux/ring_buffer.h> Loading Loading @@ -364,6 +365,25 @@ ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) return cnt; } ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt) { int len; void *ret; if (s->len <= s->readpos) return -EBUSY; len = s->len - s->readpos; if (cnt > len) cnt = len; ret = memcpy(buf, s->buffer + s->readpos, cnt); if (!ret) return -EFAULT; s->readpos += len; return cnt; } static void trace_print_seq(struct seq_file *m, struct trace_seq *s) { Loading Loading @@ -2368,37 +2388,15 @@ tracing_poll_pipe(struct file *filp, poll_table *poll_table) } } /* * Consumer reader. */ static ssize_t tracing_read_pipe(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) /* Must be called with trace_types_lock mutex held. */ static int tracing_wait_pipe(struct file *filp) { struct trace_iterator *iter = filp->private_data; ssize_t sret; /* return any leftover data */ sret = trace_seq_to_user(&iter->seq, ubuf, cnt); if (sret != -EBUSY) return sret; trace_seq_reset(&iter->seq); mutex_lock(&trace_types_lock); if (iter->trace->read) { sret = iter->trace->read(iter, filp, ubuf, cnt, ppos); if (sret) goto out; } waitagain: sret = 0; while (trace_empty(iter)) { if ((filp->f_flags & O_NONBLOCK)) { sret = -EAGAIN; goto out; return -EAGAIN; } /* Loading @@ -2423,12 +2421,11 @@ waitagain: iter->tr->waiter = NULL; if (signal_pending(current)) { sret = -EINTR; goto out; return -EINTR; } if (iter->trace != current_trace) goto out; return 0; /* * We block until we read something and tracing is disabled. Loading @@ -2445,9 +2442,43 @@ waitagain: continue; } return 1; } /* * Consumer reader. */ static ssize_t tracing_read_pipe(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) { struct trace_iterator *iter = filp->private_data; ssize_t sret; /* return any leftover data */ sret = trace_seq_to_user(&iter->seq, ubuf, cnt); if (sret != -EBUSY) return sret; trace_seq_reset(&iter->seq); mutex_lock(&trace_types_lock); if (iter->trace->read) { sret = iter->trace->read(iter, filp, ubuf, cnt, ppos); if (sret) goto out; } waitagain: sret = tracing_wait_pipe(filp); if (sret <= 0) goto out; /* stop when tracing is finished */ if (trace_empty(iter)) if (trace_empty(iter)) { sret = 0; goto out; } if (cnt >= PAGE_SIZE) cnt = PAGE_SIZE - 1; Loading Loading @@ -2493,6 +2524,135 @@ out: return sret; } static void tracing_pipe_buf_release(struct pipe_inode_info *pipe, struct pipe_buffer *buf) { __free_page(buf->page); } static void tracing_spd_release_pipe(struct splice_pipe_desc *spd, unsigned int idx) { __free_page(spd->pages[idx]); } static struct pipe_buf_operations tracing_pipe_buf_ops = { .can_merge = 0, .map = generic_pipe_buf_map, .unmap = generic_pipe_buf_unmap, .confirm = generic_pipe_buf_confirm, .release = tracing_pipe_buf_release, .steal = generic_pipe_buf_steal, .get = generic_pipe_buf_get, }; static size_t tracing_fill_pipe_page(struct page *pages, size_t rem, struct trace_iterator *iter) { size_t count; int ret; /* Seq buffer is page-sized, exactly what we need. */ for (;;) { count = iter->seq.len; ret = print_trace_line(iter); count = iter->seq.len - count; if (rem < count) { rem = 0; iter->seq.len -= count; break; } if (ret == TRACE_TYPE_PARTIAL_LINE) { iter->seq.len -= count; break; } trace_consume(iter); rem -= count; if (!find_next_entry_inc(iter)) { rem = 0; iter->ent = NULL; break; } } return rem; } static ssize_t tracing_splice_read_pipe(struct file *filp, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags) { struct page *pages[PIPE_BUFFERS]; struct partial_page partial[PIPE_BUFFERS]; struct trace_iterator *iter = filp->private_data; struct splice_pipe_desc spd = { .pages = pages, .partial = partial, .nr_pages = 0, /* This gets updated below. */ .flags = flags, .ops = &tracing_pipe_buf_ops, .spd_release = tracing_spd_release_pipe, }; ssize_t ret; size_t rem; unsigned int i; mutex_lock(&trace_types_lock); if (iter->trace->splice_read) { ret = iter->trace->splice_read(iter, filp, ppos, pipe, len, flags); if (ret) goto out_err; } ret = tracing_wait_pipe(filp); if (ret <= 0) goto out_err; if (!iter->ent && !find_next_entry_inc(iter)) { ret = -EFAULT; goto out_err; } /* Fill as many pages as possible. */ for (i = 0, rem = len; i < PIPE_BUFFERS && rem; i++) { pages[i] = alloc_page(GFP_KERNEL); if (!pages[i]) break; rem = tracing_fill_pipe_page(pages[i], rem, iter); /* Copy the data into the page, so we can start over. */ ret = trace_seq_to_buffer(&iter->seq, page_address(pages[i]), iter->seq.len); if (ret < 0) { __free_page(pages[i]); break; } partial[i].offset = 0; partial[i].len = iter->seq.len; trace_seq_reset(&iter->seq); } mutex_unlock(&trace_types_lock); spd.nr_pages = i; return splice_to_pipe(pipe, &spd); out_err: mutex_unlock(&trace_types_lock); return ret; } static ssize_t tracing_entries_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos) Loading Loading @@ -2656,6 +2816,7 @@ static struct file_operations tracing_pipe_fops = { .open = tracing_open_pipe, .poll = tracing_poll_pipe, .read = tracing_read_pipe, .splice_read = tracing_splice_read_pipe, .release = tracing_release_pipe, }; Loading
kernel/trace/trace.h +6 −0 Original line number Diff line number Diff line Loading @@ -353,6 +353,12 @@ struct tracer { ssize_t (*read)(struct trace_iterator *iter, struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos); ssize_t (*splice_read)(struct trace_iterator *iter, struct file *filp, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); #ifdef CONFIG_FTRACE_STARTUP_TEST int (*selftest)(struct tracer *trace, struct trace_array *tr); Loading