seq-buf/x86/printk: Print all stacks from NMI safely
Subsystems (7)
Steven Rostedt
maintainerv3 cover seq-buf/x86/printk: Print all stacks from NMI safely
This is version 3:
This is my proposal to print the NMI stack traces from an RCU stall safely, as well as from a sysrq-l.
Here's the gist of it.
o Add a new layer to trace_seq called seq_buf, that the trace seq uses. The seq_buf is more generic, and does not supply its own buffer. The buffer must be supplied when initializing the seq_buf. Note, these patches may be going into 3.19. There's some places in the tracing code that I wanted to use a different size buffer but still needed trace_seq to have a pre-allocated buffer. Having this new layer will help me out.
I also based this on seq_file, and ideally, I want to merge the code between seq_file.c and trace_seq.c, as they are very similar. I already have a working set of patches that do this, but will get seq_buf merged first.
o Update the seq_buf code to be more like seq_file.
o Move the seq_buf out of the tracing code. It's useful for other purposes too. Like writing from an NMI context, and for seq_file.
o Add a per_cpu "printk_func" that printk calls. By default it calls vprintk_def() which does what it has always done. This allows us to override what printk() calls normally on a per cpu basis.
o Have the NMI handler that dumps the stack trace just change the printk_func to call a NMI safe printk function that writes to a per cpu seq_buf. When all NMI handlers chimed in, the original caller prints out the seq_buf buffers for each CPU from a printk safe context.
Changes since V2:
- Mostly it was modifying seq_buf to be based on seq_file as there were some questions to the way seq_buf should work. Note, there's also a set of patches that are getting ready to remove the return value of the seq_printf() and friends to be void, so the seq_buf_printf() and friends return values can be ignored, because they will be void as well. but for now, they just match what seq_file does.
Changes since V1:
- Note, I based this off of my 3.17 queue that already updated trace_seq with a lot of comments from Andrew Morton. His comments have already been incorporated into the trace_seq.c file. This patch set is on top of those.
- Added a change that is in my 3.17 queue that cleans up open coded calculations of the trace_seq buffer to get the current location of the buffer.
- Biggest change is the added seq_buf. I'm keeping trace_seq doing the stop everything once it fills up. But seq_buf will act more like other utilities, as it will return what I would have written, and fills up the buffer as much as it can. It sets an overflow flag to test to see if there wasn't enough buffer space.
- I updated the last patch to use the seq_buf instead of the trace_seq by using its own struct nmi_seq_buf that allocates the buffer used. I also made some updates from previous reviews like not stripping the log level from the NMI printks and just using it in the final output as well as adding more comments and fixing the "return true" on a void function.
Thoughts?
-- Steve
Steven Rostedt (Red Hat) (12):
x86/kvm/tracing: Use helper function trace_seq_buffer_ptr() RAS/tracing: Use trace_seq_buffer_ptr() helper instead of open coded
tracing: Create seq_buf layer in trace_seq
tracing: Convert seq_buf_path() to be like seq_path()
tracing: Convert seq_buf fields to be like seq_file fields
tracing: Add a seq_buf_clear() helper and clear len and readpos in init
tracing: Have seq_buf use full buffer
tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions
seq_buf: Move the seq_buf code to lib/
seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
printk: Add per_cpu printk func to allow printk to be diverted x86/nmi: Perform a safe NMI stack trace on all CPUs
----
arch/x86/kernel/apic/hw_nmi.c | 90 ++++++++- arch/x86/kvm/mmutrace.h | 4 +- drivers/firmware/efi/cper.c | 2 +- include/linux/percpu.h | 3 + include/linux/printk.h | 2 + include/linux/seq_buf.h | 120 ++++++++++++ include/linux/trace_seq.h | 10 +- kernel/printk/printk.c | 38 +++- kernel/trace/trace.c | 39 ++-- kernel/trace/trace_events.c | 6 +- kernel/trace/trace_functions_graph.c | 6 +- kernel/trace/trace_seq.c | 184 +++++++++---------- lib/Makefile | 2 +- lib/seq_buf.c | 344 +++++++++++++++++++++++++++++++++++ 14 files changed, 707 insertions(+), 143 deletions(-)
Steven Rostedt
maintainerRFC PATCH v3 1/12 x86/kvm/tracing: Use helper function trace_seq_buffer_ptr()
From: "Steven Rostedt (Red Hat)" <[email protected]>
To allow for the restructiong of the trace_seq code, we need users of it to use the helper functions instead of accessing the internals of the trace_seq structure itself.
--- arch/x86/kvm/mmutrace.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/kvm/mmutrace.h +2 -2
@@ -22,7 +22,7 @@ __entry->unsync = sp->unsync;#define KVM_MMU_PAGE_PRINTK () ({ \ - const u32 saved_len = p->len; \ + const char *saved_ptr = trace_seq_buffer_ptr(p); \ static const char *access_str[] = { \ "---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux" \ }; \
@@ -41,7 +41,7 @@ role.nxe ?"" :"!" , \ __entry->root_count, \ __entry->unsync ? "unsync" : "sync", 0); \ - p->buffer + saved_len; \ + saved_ptr; \ })#define kvm_mmu_trace_pferr_flags \
Signature · 1 line
2.1.1
Re: [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr()
Quoted 29 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
To allow for the restructiong of the
trace_seqcode, we need users of it to use the helper functions instead of accessing the internals of thetrace_seqstructure itself.Cc Mark Rustad <[email protected]>Cc Jeff Kirsher <[email protected]>Cc Paolo Bonzini <[email protected]>Signed-off-by Steven Rostedt <[email protected]>--- arch/x86/kvm/mmutrace.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)arch/x86/kvm/mmutrace.h +1
-1@@ -22,7 +22,7 @@ __entry->unsync = sp->unsync;#define KVM_MMU_PAGE_PRINTK () ({ \ - const u32 saved_len = p->len; \ + const char *saved_ptr = trace_seq_buffer_ptr(p); \ static const char *access_str[] = { \ "---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux" \ }; \
arch/x86/kvm/mmutrace.h
Quoted 9 lines
arch/x86/kvm/mmutrace.h +1
-2@@ -41,7 +41,7 @@ role.nxe ?"" :"!" , \ __entry->root_count, \ __entry->unsync ? "unsync" : "sync", 0); \ - p->buffer + saved_len; \ + saved_ptr; \ })#define kvm_mmu_trace_pferr_flags \ -- 2.1.1
Re: [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr()
In reply to Steven RostedtQuoted 19 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
To allow for the restructiong of the
trace_seqcode, we need users of it to use the helper functions instead of accessing the internals of thetrace_seqstructure itself.Cc Mark Rustad <[email protected]>Cc Jeff Kirsher <[email protected]>Cc Paolo Bonzini <[email protected]>Signed-off-by Steven Rostedt <[email protected]>---
arch/x86/kvm/mmutrace.h| 4 ++--1 file changed, 2 insertions(+), 2 deletions(-)arch/x86/kvm/mmutrace.h +0
-0
arch/x86/kvm/mmutrace.h line 25
Quoted 5 lines
arch/x86/kvm/mmutrace.h +1
-1@@ -22,7 +22,7 @@ __entry->unsync = sp->unsync;#define KVM_MMU_PAGE_PRINTK () ({ \ - const u32 saved_len = p->len; \ + const char *saved_ptr = trace_seq_buffer_ptr(p); \
I think the above should not be a const char *, because the location pointed to is surely being changed. It should either be a char * or a char * const.
Quoted 14 lines
arch/x86/kvm/mmutrace.h +1
-1static const char *access_str[] = { \"---" ,"--x" ,"w--" ,"w-x" ,"-u-" ,"-ux" ,"wu-" ,"wux" \ }; \@@ -41,7 +41,7 @@ role.nxe ?"" :"!" , \ __entry->root_count, \ __entry->unsync ? "unsync" : "sync", 0); \ - p->buffer + saved_len; \ + saved_ptr; \ })#define kvm_mmu_trace_pferr_flags \Signature · 1 line
2.1.1
Signature · 1 line
Mark Rustad, Networking Division, Intel Corporation
Steven Rostedt
maintainerRe: [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr()
Quoted 23 lines · Mark D
Quoted 21 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
To allow for the restructiong of the
trace_seqcode, we need users of it to use the helper functions instead of accessing the internals of thetrace_seqstructure itself.Cc Mark Rustad <[email protected]>Cc Jeff Kirsher <[email protected]>Cc Paolo Bonzini <[email protected]>Signed-off-by Steven Rostedt <[email protected]>---
arch/x86/kvm/mmutrace.h| 4 ++--1 file changed, 2 insertions(+), 2 deletions(-)arch/x86/kvm/mmutrace.h +0
-0@@ -22,7 +22,7 @@ __entry->unsync = sp->unsync;
Quoted 5 lines
arch/x86/kvm/mmutrace.h line 25
Quoted 3 lines
arch/x86/kvm/mmutrace.h +1
-1#define KVM_MMU_PAGE_PRINTK () ({ \ - const u32 saved_len = p->len; \ + const char *saved_ptr = trace_seq_buffer_ptr(p); \I think the above should not be a const char *, because the location pointed to is surely being changed. It should either be a char * or a char * const.
Ah right. It should be 'char * const'.
Thanks, I'll update it.
-- Steve
Quoted 16 lines
Quoted 15 lines
arch/x86/kvm/mmutrace.h +1
-1static const char *access_str[] = { \"---" ,"--x" ,"w--" ,"w-x" ,"-u-" ,"-ux" ,"wu-" ,"wux" \ }; \@@ -41,7 +41,7 @@ role.nxe ?"" :"!" , \ __entry->root_count, \ __entry->unsync ? "unsync" : "sync", 0); \ - p->buffer + saved_len; \ + saved_ptr; \ })#define kvm_mmu_trace_pferr_flags \Signature · 1 line
2.1.1
Steven Rostedt
maintainerRe: [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr()
Quoted 26 lines · On Tue, 4 Nov 2014 14:09:54 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 23 lines · Mark D
Quoted 21 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
To allow for the restructiong of the
trace_seqcode, we need users of it to use the helper functions instead of accessing the internals of thetrace_seqstructure itself.Cc Mark Rustad <[email protected]>Cc Jeff Kirsher <[email protected]>Cc Paolo Bonzini <[email protected]>Signed-off-by Steven Rostedt <[email protected]>---
arch/x86/kvm/mmutrace.h| 4 ++--1 file changed, 2 insertions(+), 2 deletions(-)arch/x86/kvm/mmutrace.h +0
-0@@ -22,7 +22,7 @@ __entry->unsync = sp->unsync;
Quoted 8 lines
Quoted 5 lines
arch/x86/kvm/mmutrace.h line 25
Quoted 3 lines
arch/x86/kvm/mmutrace.h +1
-1#define KVM_MMU_PAGE_PRINTK () ({ \ - const u32 saved_len = p->len; \ + const char *saved_ptr = trace_seq_buffer_ptr(p); \I think the above should not be a const char *, because the location pointed to is surely being changed. It should either be a char * or a char * const.
Ah right. It should be 'char * const'.
Actually, I take that back. The contents of saved_ptr should not be modified.
It may seem strange, but the update is done via the trace_seq_printf(). Then that content is return back to the user. The user should definitely *not* modify the contents of saved_ptr.
This patch is good as is. It should not be a char *, or char * const.
-- Steve
Quoted 18 lines
Quoted 17 lines
Quoted 16 lines
arch/x86/kvm/mmutrace.h +1
-1static const char *access_str[] = { \"---" ,"--x" ,"w--" ,"w-x" ,"-u-" ,"-ux" ,"wu-" ,"wux" \ }; \@@ -41,7 +41,7 @@ role.nxe ?"" :"!" , \ __entry->root_count, \ __entry->unsync ? "unsync" : "sync", 0); \ - p->buffer + saved_len; \ + saved_ptr; \ })#define kvm_mmu_trace_pferr_flags \Signature · 1 line
2.1.1
Rustad, Mark D
Acked-byRe: [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr()
Quoted 35 lines · Steven Rostedt
Quoted 32 lines · On Tue, 4 Nov 2014 14:09:54 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 28 lines · Mark D
Quoted 19 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
To allow for the restructiong of the
trace_seqcode, we need users of it to use the helper functions instead of accessing the internals of thetrace_seqstructure itself.Cc Mark Rustad <[email protected]>Cc Jeff Kirsher <[email protected]>Cc Paolo Bonzini <[email protected]>Signed-off-by Steven Rostedt <[email protected]>---
arch/x86/kvm/mmutrace.h| 4 ++--1 file changed, 2 insertions(+), 2 deletions(-)arch/x86/kvm/mmutrace.h +0
-0arch/x86/kvm/mmutrace.h line 25
Quoted 5 lines
arch/x86/kvm/mmutrace.h +1
-1@@ -22,7 +22,7 @@ __entry->unsync = sp->unsync;#define KVM_MMU_PAGE_PRINTK () ({ \ - const u32 saved_len = p->len; \ + const char *saved_ptr = trace_seq_buffer_ptr(p); \I think the above should not be a const char *, because the location pointed to is surely being changed. It should either be a char * or a char * const.
Quoted 5 lines
Quoted 2 lines
Ah right. It should be 'char * const'.
Actually, I take that back. The contents of
saved_ptrshould not be modified.
At least not by the caller of the macro. The subsequent call to trace_seq_printf will be changing the contents at that address, but not through use of that pointer.
Quoted 3 lines
It may seem strange, but the update is done via the
trace_seq_printf(). Then that content is return back to the user. The user should definitely *not* modify the contents ofsaved_ptr.
Agreed.
Quoted 1 line
This patch is good as is. It should not be a char *, or char * const.
Yes. I did further checking and agree. Although that memory will be written, it isn't written through that pointer and it is the best type as a return value.
Quoted 22 lines
-- Steve
Quoted 18 lines
Quoted 17 lines
Quoted 16 lines
arch/x86/kvm/mmutrace.h +1
-1static const char *access_str[] = { \"---" ,"--x" ,"w--" ,"w-x" ,"-u-" ,"-ux" ,"wu-" ,"wux" \ }; \@@ -41,7 +41,7 @@ role.nxe ?"" :"!" , \ __entry->root_count, \ __entry->unsync ? "unsync" : "sync", 0); \ - p->buffer + saved_len; \ + saved_ptr; \ })#define kvm_mmu_trace_pferr_flags \Signature · 1 line
2.1.1
Signature · 1 line
Mark Rustad, Networking Division, Intel Corporation
Re: [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr()
In reply to Steven RostedtQuoted 10 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
To allow for the restructiong of the
trace_seqcode, we need users of it to use the helper functions instead of accessing the internals of thetrace_seqstructure itself.Cc Mark Rustad <[email protected]>Cc Jeff Kirsher <[email protected]>Cc Paolo Bonzini <[email protected]>Signed-off-by Steven Rostedt <[email protected]>
Best Regards,
Petr
Quoted 30 lines
--- arch/x86/kvm/mmutrace.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)arch/x86/kvm/mmutrace.h +2
-2@@ -22,7 +22,7 @@ __entry->unsync = sp->unsync;#define KVM_MMU_PAGE_PRINTK () ({ \ - const u32 saved_len = p->len; \ + const char *saved_ptr = trace_seq_buffer_ptr(p); \ static const char *access_str[] = { \ "---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux" \ }; \@@ -41,7 +41,7 @@ role.nxe ?"" :"!" , \ __entry->root_count, \ __entry->unsync ? "unsync" : "sync", 0); \ - p->buffer + saved_len; \ + saved_ptr; \ })#define kvm_mmu_trace_pferr_flags \Signature · 1 line
2.1.1
Steven Rostedt
maintainerRFC PATCH v3 2/12 RAS/tracing: Use trace_seq_buffer_ptr() helper instead of open coded
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
Use the helper function trace_seq_buffer_ptr() to get the current location of the next buffer write of a trace_seq object, instead of open coding it.
This facilitates the conversion of trace_seq to use seq_buf.
--- drivers/firmware/efi/cper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/firmware/efi/cper.c +1 -1
@@ -294,7 +294,7 @@ void cper_mem_err_pack(const struct cper_sec_mem_err *mem,const char *cper_mem_err_unpack (struct trace_seq *p,struct cper_mem_err_compact *cmem) { -const char *ret = p->buffer + p->len; +const char *ret =trace_seq_buffer_ptr (p);if (cper_mem_err_location (cmem, rcd_decode_str))trace_seq_printf (p,"%s" , rcd_decode_str);
Signature · 1 line
2.1.1
Re: [RFC][PATCH 02/12 v3] RAS/tracing: Use trace_seq_buffer_ptr() helper instead of open coded
Quoted 6 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
Use the helper function
trace_seq_buffer_ptr()to get the current location of the next buffer write of atrace_seqobject, instead of open coding it.
Quoted 6 lines
This facilitates the conversion of
trace_seqto useseq_buf.Cc Chen Gong <[email protected]>Cc Borislav Petkov <[email protected]>Cc Tony Luck <[email protected]>Signed-off-by Steven Rostedt <[email protected]>
Signature · 5 lines
Regards/Gruss,
Boris.
Sent from a fat crate under my desk. Formatting is fine.
--Re: [RFC][PATCH 02/12 v3] RAS/tracing: Use trace_seq_buffer_ptr() helper instead of open coded
In reply to Steven RostedtQuoted 6 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
Use the helper function
trace_seq_buffer_ptr()to get the current location of the next buffer write of atrace_seqobject, instead of open coding it.
Quoted 6 lines
This facilitates the conversion of
trace_seqto useseq_buf.Cc Chen Gong <[email protected]>Cc Borislav Petkov <[email protected]>Cc Tony Luck <[email protected]>Signed-off-by Steven Rostedt <[email protected]>
Best Regards,
Petr
Steven Rostedt
maintainerRFC PATCH v3 3/12 tracing: Create seq_buf layer in trace_seq
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
Create a seq_buf layer that trace_seq sits on. The seq_buf will not be limited to page size. This will allow other usages of seq_buf instead of a hard set PAGE_SIZE one that trace_seq has.
--- include/linux/seq_buf.h | 72 ++++++++ include/linux/trace_seq.h | 10 +- kernel/trace/Makefile | 1 + kernel/trace/seq_buf.c | 341 +++++++++++++++++++++++++++++++++++ kernel/trace/trace.c | 39 ++-- kernel/trace/trace_events.c | 6 +- kernel/trace/trace_functions_graph.c | 6 +- kernel/trace/trace_seq.c | 184 +++++++++---------- 8 files changed, 534 insertions(+), 125 deletions(-) create mode 100644 include/linux/seq_buf.h create mode 100644 kernel/trace/seq_buf.c
include/linux/seq_buf.h new file +72 -0
@@ -0,0 +1,72 @@ +#ifndef _LINUX_SEQ_BUF_H +#define _LINUX_SEQ_BUF_H + +#include <linux/fs.h> + +#include <asm/page.h> + +/* +* Trace sequences are used to allow a function to call several other functions +* to create a string of data to use. +*/ + +/** +* seq_buf - seq buffer structure +* @buffer: pointer to the buffer +* @size: size of the buffer +* @len: the amount of data inside the buffer +* @readpos: The next position to read in the buffer. +* @overflow: Set if more bytes should have been written to buffer +*/ +struct seq_buf { +unsigned char *buffer; +unsigned int size; +unsigned int len; +unsigned int readpos; +}; + +static inline void +seq_buf_init (struct seq_buf *s,unsigned char *buf,unsigned int size) +{ + s->buffer = buf; + s->size = size; + s->len =0 ; + s->readpos =0 ; +} + +/* +* seq_buf have a buffer that might overflow. When this happens +* the len and size are set to be equal. +*/ +static inline bool +seq_buf_has_overflowed (struct seq_buf *s) +{ +return s->len == s->size; +} + +static inline void +seq_buf_set_overflow (struct seq_buf *s) +{ + s->len = s->size; +} + +extern __printf(2, 3) +int seq_buf_printf(struct seq_buf *s, const char *fmt, ...); +extern __printf(2, 0) +int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args); +extern int +seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary); +extern int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s); +extern int seq_buf_to_user(struct seq_buf *s, char __user *ubuf, + int cnt); +extern int seq_buf_puts(struct seq_buf *s, const char *str); +extern int seq_buf_putc(struct seq_buf *s, unsigned char c); +extern int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len); +extern int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, + unsigned int len); +extern int seq_buf_path(struct seq_buf *s, const struct path *path); + +extern int seq_buf_bitmask(struct seq_buf *s, const unsigned long *maskp, + int nmaskbits); + +#endif /* _LINUX_SEQ_BUF_H */
include/linux/trace_seq.h +4 -6
@@ -1,7 +1,7 @@#ifndef _LINUX_TRACE_SEQ_H#define _LINUX_TRACE_SEQ_H -#include <linux/fs.h> +#include <linux/seq_buf.h> #include <asm/page.h>
@@ -12,16 +12,14 @@struct trace_seq {unsigned char buffer[PAGE_SIZE ]; -unsigned int len; -unsigned int readpos; +struct seq_buf seq;int full; };static inline void trace_seq_init (struct trace_seq *s) { - s->len =0 ; - s->readpos =0 ; +seq_buf_init (&s->seq, s->buffer,PAGE_SIZE ); s->full =0 ; }
@@ -37,7 +35,7 @@ trace_seq_init(struct trace_seq *s)static inline unsigned char *trace_seq_buffer_ptr (struct trace_seq *s) { -return s->buffer + s->len; +return s->buffer + s->seq.len; }/*
kernel/trace/Makefile +1 -0
@@ -29,6 +29,7 @@ obj-$(CONFIG_RING_BUFFER_BENCHMARK) += ring_buffer_benchmark.o obj-$(CONFIG_TRACING) += trace.o obj-$(CONFIG_TRACING) += trace_output.o obj-$(CONFIG_TRACING) += trace_seq.o +obj-$(CONFIG_TRACING) += seq_buf.o obj-$(CONFIG_TRACING) += trace_stat.o obj-$(CONFIG_TRACING) += trace_printk.o obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o
kernel/trace/seq_buf.c new file +341 -0
341 lines not on this page · raw message
kernel/trace/trace.c +21 -18
@@ -938,19 +938,20 @@ out:return ret; } +/* TODO add a seq_buf_to_buffer() */ static ssize_t trace_seq_to_buffer (struct trace_seq *s,void *buf,size_t cnt) {int len; -if (s->len <= s->readpos) +if (s->seq.len <= s->seq.readpos)return -EBUSY ; - len = s->len - s->readpos; + len = s->seq.len - s->seq.readpos;if (cnt > len) cnt = len; -memcpy (buf, s->buffer + s->readpos, cnt); +memcpy (buf, s->buffer + s->seq.readpos, cnt); - s->readpos += cnt; + s->seq.readpos += cnt;return cnt; }
@@ -4313,6 +4314,8 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp) goto out; } +trace_seq_init (&iter->seq); +/* * We make a copy of the current tracer to avoid concurrent * changes on it while we are reading.
@@ -4509,18 +4512,18 @@ waitagain:trace_access_lock (iter->cpu_file);while (trace_find_next_entry_inc (iter) !=NULL ) {enum print_line_t ret; -int len = iter->seq.len; +int len = iter->seq.seq.len; ret =print_trace_line (iter);if (ret ==TRACE_TYPE_PARTIAL_LINE ) {/* don't print partial lines */ - iter->seq.len = len; + iter->seq.seq.len = len;break ; }if (ret !=TRACE_TYPE_NO_CONSUME )trace_consume (iter); -if (iter->seq.len >= cnt) +if (iter->seq.seq.len >= cnt)break ;/*
@@ -4536,7 +4539,7 @@ waitagain:/* Now copy what we have to the user */ sret =trace_seq_to_user (&iter->seq, ubuf, cnt); -if (iter->seq.readpos >= iter->seq.len) +if (iter->seq.seq.readpos >= iter->seq.seq.len)trace_seq_init (&iter->seq);/*
@@ -4574,16 +4577,16 @@ tracing_fill_pipe_page(size_t rem, struct trace_iterator *iter)/* Seq buffer is page-sized, exactly what we need. */ for (;;) { - count = iter->seq.len; + count = iter->seq.seq.len; ret =print_trace_line (iter); - count = iter->seq.len - count; + count = iter->seq.seq.len - count;if (rem < count) { rem =0 ; - iter->seq.len -= count; + iter->seq.seq.len -= count;break ; }if (ret ==TRACE_TYPE_PARTIAL_LINE ) { - iter->seq.len -= count; + iter->seq.seq.len -= count;break ; }
@@ -4664,13 +4667,13 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,/* Copy the data into the page, so we can start over. */ ret =trace_seq_to_buffer (&iter->seq,page_address (spd.pages[i]), - iter->seq.len); + iter->seq.seq.len);if (ret <0 ) {__free_page (spd.pages[i]);break ; } spd.partial[i].offset =0 ; - spd.partial[i].len = iter->seq.len; + spd.partial[i].len = iter->seq.seq.len;trace_seq_init (&iter->seq); }
@@ -5671,7 +5674,7 @@ tracing_stats_read(struct file *filp, char __user *ubuf, cnt =ring_buffer_read_events_cpu (trace_buf->buffer, cpu);trace_seq_printf (s,"read events: %ld\n" , cnt); - count =simple_read_from_buffer (ubuf, count, ppos, s->buffer, s->len); + count =simple_read_from_buffer (ubuf, count, ppos, s->buffer, s->seq.len);kfree (s);
@@ -6634,11 +6637,11 @@ void trace_printk_seq(struct trace_seq *s) {/* Probably should print a warning here. */ -if (s->len >=TRACE_MAX_PRINT ) - s->len =TRACE_MAX_PRINT ; +if (s->seq.len >=TRACE_MAX_PRINT ) + s->seq.len =TRACE_MAX_PRINT ;/* should be zero ended, but we are paranoid. */ - s->buffer[s->len] =0 ; + s->buffer[s->seq.len] =0 ;printk (KERN_TRACE "%s" , s->buffer);
kernel/trace/trace_events.c +3 -3
@@ -1044,7 +1044,7 @@ event_filter_read(struct file *filp, char __user *ubuf, size_t cnt,mutex_unlock (&event_mutex);if (file) - r =simple_read_from_buffer (ubuf, cnt, ppos, s->buffer, s->len); + r =simple_read_from_buffer (ubuf, cnt, ppos, s->buffer, s->seq.len);kfree (s);
@@ -1210,7 +1210,7 @@ subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt,trace_seq_init (s);print_subsystem_event_filter (system, s); - r =simple_read_from_buffer (ubuf, cnt, ppos, s->buffer, s->len); + r =simple_read_from_buffer (ubuf, cnt, ppos, s->buffer, s->seq.len);kfree (s);
@@ -1265,7 +1265,7 @@ show_header(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)trace_seq_init (s);func (s); - r =simple_read_from_buffer (ubuf, cnt, ppos, s->buffer, s->len); + r =simple_read_from_buffer (ubuf, cnt, ppos, s->buffer, s->seq.len);kfree (s);
kernel/trace/trace_functions_graph.c +3 -3
@@ -1291,9 +1291,9 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent, }/* Strip ending newline */ -if (s->buffer[s->len -1 ] =='\n' ) { - s->buffer[s->len -1 ] ='\0' ; - s->len--; +if (s->buffer[s->seq.len -1 ] =='\n' ) { + s->buffer[s->seq.len -1 ] ='\0' ; + s->seq.len--; } ret =trace_seq_puts (s," */\n" );
kernel/trace/trace_seq.c +89 -95
330 lines not on this page · raw message
Signature · 1 line
2.1.1
Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
Quoted 35 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
Create a
seq_buflayer thattrace_seqsits on. Theseq_bufwill not be limited to page size. This will allow other usages ofseq_bufinstead of a hard setPAGE_SIZEone thattrace_seqhas.Signed-off-by Steven Rostedt <[email protected]>--- include/linux/seq_buf.h | 72 ++++++++ include/linux/trace_seq.h | 10 +- kernel/trace/Makefile | 1 + kernel/trace/seq_buf.c | 341 +++++++++++++++++++++++++++++++++++ kernel/trace/trace.c | 39 ++-- kernel/trace/trace_events.c | 6 +- kernel/trace/trace_functions_graph.c | 6 +- kernel/trace/trace_seq.c | 184 +++++++++---------- 8 files changed, 534 insertions(+), 125 deletions(-) create mode 100644 include/linux/seq_buf.h create mode 100644 kernel/trace/seq_buf.cinclude/linux/seq_buf.h new file +9
-0@@ -0,0 +1,72 @@ +#ifndef _LINUX_SEQ_BUF_H +#define _LINUX_SEQ_BUF_H + +#include <linux/fs.h> + +#include <asm/page.h> + +/* +* Trace sequences are used to allow a function to call several other functions
include/linux/seq_buf.h line 19
Quoted 10 lines
include/linux/seq_buf.h new file +10
-0+* to create a string of data to use. +*/ + +/** +* seq_buf - seq buffer structure +* @buffer: pointer to the buffer +* @size: size of the buffer +* @len: the amount of data inside the buffer +* @readpos: The next position to read in the buffer. +* @overflow: Set if more bytes should have been written to buffer
There is no @overflow flag in the end.
Also I would add an explanation of the overall logic. If I get it correctly from the code, it is:
/*
* The last byte of the buffer is used to detect an overflow in some
* operations. Therefore, the buffer offers (@size - 1) bytes for valid
* data.
*/
Quoted 8 lines
include/linux/seq_buf.h new file +8
-0+*/ +struct seq_buf { +unsigned char *buffer; +unsigned int size; +unsigned int len; +unsigned int readpos; +}; +
[...]
Quoted 10 lines
kernel/trace/seq_buf.c new file +4
-0@@ -0,0 +1,341 @@ +/* +* seq_buf.c +* +* Copyright (C) 2014 Red Hat Inc, Steven Rostedt <[email protected]>
kernel/trace/seq_buf.c line 14
Quoted 10 lines
kernel/trace/seq_buf.c new file +10
-0+* +* The seq_buf is a handy tool that allows you to pass a descriptor around +* to a buffer that other functions can write to. It is similar to the +* seq_file functionality but has some differences. +* +* To use it, the seq_buf must be initialized with seq_buf_init(). +* This will set up the counters within the descriptor. You can call +* seq_buf_init() more than once to reset the seq_buf to start +* from scratch. +*
^ trailing whitespace :-)
kernel/trace/seq_buf.c line 20
Quoted 6 lines
kernel/trace/seq_buf.c new file +6
-0+*/ +#include <linux/uaccess.h> +#include <linux/seq_file.h> +#include <linux/seq_buf.h> + +/* How much buffer is left on the seq_buf? */
I would write the following to explain the -1:
/* How much buffer is left for valid data */
kernel/trace/seq_buf.c line 21
Quoted 1 line
kernel/trace/seq_buf.c new file +1
-0+#define SEQ_BUF_LEFT (s) (((s)->size - 1) - (s)->len)
Hmm, it might overflow when the buffer has overflown (s->len == s->size) or when the buffer is not initialized (s->size == 0). Note that the result should be unsigned int.
I can't find any cool solution as a macro at the moment. It might be better to define an inline function for this.
kernel/trace/seq_buf.c line 23
Quoted 1 line
kernel/trace/seq_buf.c new file +1
-0+/* How much buffer is written? */
I would write the following to explain the -1:
/* How much buffer is written with valid data */
Quoted 1 line
kernel/trace/seq_buf.c new file +1
-0+#define SEQ_BUF_USED (s) min((s)->len, (s)->size - 1)
[...]
kernel/trace/seq_buf.c line 96
Quoted 10 lines
kernel/trace/seq_buf.c new file +10
-0+ +/** +* seq_buf_bitmask - write a bitmask array in its ASCII representation +* @s: seq_buf descriptor +* @maskp: points to an array of unsigned longs that represent a bitmask +* @nmaskbits: The number of bits that are valid in @maskp +* +* Writes a ASCII representation of a bitmask string into @s. +* +* Returns the number of bytes written.
The text should be:
* Returns zero on success, -1 on overflow.
kernel/trace/seq_buf.c line 107
Quoted 12 lines
+ */
kernel/trace/seq_buf.c new file +10
-0+int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp, +int nmaskbits) +{ +unsigned int len =SEQ_BUF_LEFT (s); +int ret; + +WARN_ON (s->size ==0 ); + +if (s->len < s->size) { + ret =bitmap_scnprintf (s->buffer, len, maskp, nmaskbits);
It writes to the beginning of the buffer. It should be
ret = bitmap_scnprintf(s->buffer + s->len, len, maskp, nmaskbits);
kernel/trace/seq_buf.c
Quoted 1 line
kernel/trace/seq_buf.c new file +1
-0+if (s->len + ret < s->size) {
This will always happen because bitmap_scnprintf() is limited by SEQ_BUF_LEFT(s) and it currently returns the remaining size - len - 1.
You might want to use "s->size - s->len" instead of SEQ_BUF_LEFT(s).
Quoted 23 lines
kernel/trace/seq_buf.c new file +23
-0+ s->len += ret; +return 0 ; + } + } +seq_buf_set_overflow (s); +return -1 ; +} + +/** +* seq_buf_bprintf - Write the printf string from binary arguments +* @s: seq_buf descriptor +* @fmt: The format string for the @binary arguments +* @binary: The binary arguments for @fmt. +* +* When recording in a fast path, a printf may be recorded with just +* saving the format and the arguments as they were passed to the +* function, instead of wasting cycles converting the arguments into +* ASCII characters. Instead, the arguments are saved in a 32 bit +* word array that is defined by the format string constraints. +* +* This function will take the format and the binary array and finish +* the conversion into the ASCII string within the buffer. +*
kernel/trace/seq_buf.c line 141
Quoted 10 lines
kernel/trace/seq_buf.c new file +10
-0+* Returns zero on success, -1 on overflow. +*/ +int seq_buf_bprintf (struct seq_buf *s,const char *fmt,const u32 *binary) +{ +unsigned int len =SEQ_BUF_LEFT (s); +int ret; + +WARN_ON (s->size ==0 ); + +if (s->len < s->size) {
Always true. It is the same problem as in seq_buf_bitmask().
Quoted 20 lines
kernel/trace/seq_buf.c new file +20
-0+ ret =bstr_printf (s->buffer + s->len, len, fmt, binary); +if (s->len + ret < s->size) { + s->len += ret; +return 0 ; + } + } +seq_buf_set_overflow (s); +return -1 ; +} + +/** +* seq_buf_puts - sequence printing of simple string +* @s: seq_buf descriptor +* @str: simple string to record +* +* Copy a simple string into the sequence buffer. +* +* Returns zero on success, -1 on overflow +*/ +int seq_buf_puts (struct seq_buf *s,const char *str)
kernel/trace/seq_buf.c line 171
Quoted 10 lines
kernel/trace/seq_buf.c new file +10
-0+{ +unsigned int len =strlen (str); + +WARN_ON (s->size ==0 ); + +if (s->len + len < s->size) { +memcpy (s->buffer + s->len, str, len); + s->len += len; +return 0 ; + }
We might want to copy the maximum possible number of bytes. It will then behave the same as the other functions.
Quoted 4 lines
kernel/trace/seq_buf.c new file +4
-0+seq_buf_set_overflow (s); +return -1 ; +} +
[...]
Quoted 12 lines
kernel/trace/seq_buf.c new file +12
-0+ +/** +* seq_buf_putmem - write raw data into the sequenc buffer +* @s: seq_buf descriptor +* @mem: The raw memory to copy into the buffer +* @len: The length of the raw memory to copy (in bytes) +* +* There may be cases where raw memory needs to be written into the +* buffer and a strcpy() would not work. Using this function allows +* for such cases. +* +* Returns zero on success, -1 on overflow
kernel/trace/seq_buf.c line 217
Quoted 10 lines
kernel/trace/seq_buf.c new file +10
-0+*/ +int seq_buf_putmem (struct seq_buf *s,const void *mem,unsigned int len) +{ +WARN_ON (s->size ==0 ); + +if (s->len + len < s->size) { +memcpy (s->buffer + s->len, mem, len); + s->len += len; +return 0 ; + }
Same as seq_buf_puts(). Do we want to always copy the possible number of bytes?
Quoted 38 lines
kernel/trace/seq_buf.c new file +38
-0+seq_buf_set_overflow (s); +return -1 ; +} + +#define MAX_MEMHEX_BYTES 8U +#define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1) + +/** +* seq_buf_putmem_hex - write raw memory into the buffer in ASCII hex +* @s: seq_buf descriptor +* @mem: The raw memory to write its hex ASCII representation of +* @len: The length of the raw memory to copy (in bytes) +* +* This is similar to seq_buf_putmem() except instead of just copying the +* raw memory into the buffer it writes its ASCII representation of it +* in hex characters. +* +* Returns zero on success, -1 on overflow +*/ +int seq_buf_putmem_hex (struct seq_buf *s,const void *mem, +unsigned int len) +{ +unsigned char hex[HEX_CHARS ]; +const unsigned char *data = mem; +unsigned int start_len; +int i, j; + +WARN_ON (s->size ==0 ); + +while (len) { + start_len =min (len,HEX_CHARS -1 ); +#ifdef __BIG_ENDIAN +for (i =0 , j =0 ; i < start_len; i++) { +#else +for (i = start_len-1 , j =0 ; i >=0 ; i--) { +#endif + hex[j++] =hex_asc_hi (data[i]); + hex[j++] =hex_asc_lo (data[i]);
kernel/trace/seq_buf.c line 265
Quoted 10 lines
kernel/trace/seq_buf.c new file +10
-0+ } +if (WARN_ON_ONCE (j ==0 || j/2 > len)) +break ; + +/* j increments twice per loop */ + len -= j /2 ; + hex[j++] =' ' ; + +seq_buf_putmem (s, hex, j); +if (seq_buf_has_overflowed (s))
We might want to use the seq_buf_putmem() return value here.
Quoted 5 lines
kernel/trace/seq_buf.c new file +5
-0+return -1 ; + } +return 0 ; +} +
[...]
Quoted 8 lines
kernel/trace/seq_buf.c new file +8
-0+ +/** +* seq_buf_to_user - copy the squence buffer to user space +* @s: seq_buf descriptor +* @ubuf: The userspace memory location to copy to +* @cnt: The amount to copy +* +* Copies the sequence buffer into the userspace memory pointed to
kernel/trace/seq_buf.c line 315
Quoted 10 lines
kernel/trace/seq_buf.c new file +10
-0+* by @ubuf. It starts from the last read position (@s->readpos) +* and writes up to @cnt characters or till it reaches the end of +* the content in the buffer (@s->len), which ever comes first. +* +* On success, it returns a positive number of the number of bytes +* it copied. +* +* On failure it returns -EBUSY if all of the content in the +* sequence has been already read, which includes nothing in the +* sequenc (@s->len == @s->readpos).
sequenc -> sequence
Quoted 26 lines
+ *
+ * Returns-EFAULTif the copy to userspace fails.
+ */kernel/trace/seq_buf.c new file +23
-0+int seq_buf_to_user (struct seq_buf *s,char __user *ubuf,int cnt) +{ +int len; +int ret; + +if (!cnt) +return 0 ; + +if (s->len <= s->readpos) +return -EBUSY ; + + len = s->len - s->readpos; +if (cnt > len) + cnt = len; + ret =copy_to_user (ubuf, s->buffer + s->readpos, cnt); +if (ret == cnt) +return -EFAULT ; + + cnt -= ret; + + s->readpos += cnt; +return cnt; +}
[...]
kernel/trace/trace_seq.c line 30
Quoted 10 lines
kernel/trace/trace_seq.c +1
-1@@ -27,10 +27,19 @@#include <linux/trace_seq.h> /* How much buffer is left on the trace_seq? */ -#define TRACE_SEQ_BUF_LEFT (s) ((PAGE_SIZE - 1) - (s)->len) +#define TRACE_SEQ_BUF_LEFT (s) ((PAGE_SIZE - 1) - (s)->seq.len)
This might overflow when s->len == PAGE_SIZE. I think that it newer happenes because we always check s->full before. The question is if we really want to depend on this.
Quoted 42 lines
kernel/trace/trace_seq.c +15
-6/* How much buffer is written? */ -#define TRACE_SEQ_BUF_USED (s) min((s)->len, (unsigned int)(PAGE_SIZE - 1)) +#define TRACE_SEQ_BUF_USED (s) min((s)->seq.len, (unsigned int)(PAGE_SIZE - 1)) + +/* +* trace_seq should work with being initialized with 0s. +*/ +static inline void __trace_seq_init (struct trace_seq *s) +{ +if (unlikely (!s->seq.size)) +trace_seq_init (s); +}/** * trace_print_seq - move the contents of trace_seq into a seq_file @@ -43,10 +52,11 @@*/ int trace_print_seq (struct seq_file *m,struct trace_seq *s) { -unsigned int len =TRACE_SEQ_BUF_USED (s);int ret; - ret =seq_write (m, s->buffer, len); +__trace_seq_init (s); + + ret =seq_buf_print_seq (m, &s->seq);/* * Only reset this buffer if we successfully wrote to the @@ -77,25 +87,25 @@ int trace_print_seq(struct seq_file *m, struct trace_seq *s)*/ int trace_seq_printf (struct trace_seq *s,const char *fmt, ...) { -unsigned int len =TRACE_SEQ_BUF_LEFT (s); +unsigned int save_len = s->seq.len;va_list ap; -int ret; -if (s->full || !len) +if (s->full)return 0 ;
kernel/trace/trace_seq.c int trace_print_seq(struct seq_file *m, struct trace_seq *s) · line 103
Quoted 10 lines
kernel/trace/trace_seq.c +4
-2+__trace_seq_init (s); +va_start (ap, fmt); - ret =vsnprintf (s->buffer + s->len, len, fmt, ap); +seq_buf_vprintf (&s->seq, fmt, ap);va_end (ap);/* If we can't write it all, don't bother writing anything */ -if (ret >= len) { +if (unlikely (seq_buf_has_overflowed (&s->seq))) {
We might check the return value from seq_buf_vprintf() here.
We could do similar thing also in the other functions. We even already store the ret value in some of them.
Best Regards,
Petr
Steven Rostedt
maintainerRe: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
Quoted 40 lines · On Wed, 5 Nov 2014 15:22:22 +0100 Petr Mladek <[email protected]> wrote:
Quoted 39 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
Create a
seq_buflayer thattrace_seqsits on. Theseq_bufwill not be limited to page size. This will allow other usages ofseq_bufinstead of a hard setPAGE_SIZEone thattrace_seqhas.Signed-off-by Steven Rostedt <[email protected]>--- include/linux/seq_buf.h | 72 ++++++++ include/linux/trace_seq.h | 10 +- kernel/trace/Makefile | 1 + kernel/trace/seq_buf.c | 341 +++++++++++++++++++++++++++++++++++ kernel/trace/trace.c | 39 ++-- kernel/trace/trace_events.c | 6 +- kernel/trace/trace_functions_graph.c | 6 +- kernel/trace/trace_seq.c | 184 +++++++++---------- 8 files changed, 534 insertions(+), 125 deletions(-) create mode 100644 include/linux/seq_buf.h create mode 100644 kernel/trace/seq_buf.cinclude/linux/seq_buf.h new file +13
-0@@ -0,0 +1,72 @@ +#ifndef _LINUX_SEQ_BUF_H +#define _LINUX_SEQ_BUF_H + +#include <linux/fs.h> + +#include <asm/page.h> + +/* +* Trace sequences are used to allow a function to call several other functions +* to create a string of data to use. +*/ + +/**
Quoted 9 lines
include/linux/seq_buf.h line 19
Quoted 6 lines
include/linux/seq_buf.h new file +6
-0+* seq_buf - seq buffer structure +* @buffer: pointer to the buffer +* @size: size of the buffer +* @len: the amount of data inside the buffer +* @readpos: The next position to read in the buffer. +* @overflow: Set if more bytes should have been written to buffer There is no @overflow flag in the end.
Crap, that was left over from a previos version.
Quoted 7 lines
Also I would add an explanation of the overall logic. If I get it correctly from the code, it is:
/*
* The last byte of the buffer is used to detect an overflow in some
* operations. Therefore, the buffer offers (@size - 1) bytes for valid
* data.
Well, this will change in the future. And it is commented with the seq_buf_has_overflowed() function. I don't want to comment about it with the structure.
Quoted 27 lines
*/
Quoted 8 lines
include/linux/seq_buf.h new file +8
-0+*/ +struct seq_buf { +unsigned char *buffer; +unsigned int size; +unsigned int len; +unsigned int readpos; +}; +[...]
Quoted 14 lines
kernel/trace/seq_buf.c new file +8
-0@@ -0,0 +1,341 @@ +/* +* seq_buf.c +* +* Copyright (C) 2014 Red Hat Inc, Steven Rostedt <[email protected]> +* +* The seq_buf is a handy tool that allows you to pass a descriptor around +* to a buffer that other functions can write to. It is similar to the +* seq_file functionality but has some differences.
Quoted 8 lines
kernel/trace/seq_buf.c line 14
Quoted 6 lines
kernel/trace/seq_buf.c new file +6
-0+* +* To use it, the seq_buf must be initialized with seq_buf_init(). +* This will set up the counters within the descriptor. You can call +* seq_buf_init() more than once to reset the seq_buf to start +* from scratch. +* ^ trailing whitespace :-)
I had that fixed in my latest version. But I'm nuking the extra line anyway.
Quoted 9 lines
kernel/trace/seq_buf.c line 20
Quoted 7 lines
kernel/trace/seq_buf.c new file +6
-0+*/ +#include <linux/uaccess.h> +#include <linux/seq_file.h> +#include <linux/seq_buf.h> + +/* How much buffer is left on the seq_buf? */ I would write the following to explain the -1:
Later patches gets rid of the -1. It's -1 because seq_file is -1 as well.
Quoted 8 lines
/* How much buffer is left for valid data */
kernel/trace/seq_buf.c line 21
Quoted 1 line
kernel/trace/seq_buf.c new file +1
-0+#define SEQ_BUF_LEFT (s) (((s)->size - 1) - (s)->len)Hmm, it might overflow when the buffer has overflown (
s->len==s->size) or when the buffer is not initialized (s->size== 0). Note that the result should be unsigned int.
The two places that use it is "unsigned int" so that should not be a problem.
Quoted 11 lines
I can't find any cool solution as a macro at the moment. It might be better to define an inline function for this.
kernel/trace/seq_buf.c line 23
Quoted 1 line
kernel/trace/seq_buf.c new file +1
-0+/* How much buffer is written? */ I would write the following to explain the -1:
/* How much buffer is written with valid data */
Again, this gets changed in later patches. I don't want to expand too much time commenting what I want to remove ;-)
I did it this way to match seq_file, and I have patches to change seq_file to have overflow be len > size too.
Quoted 17 lines
Quoted 1 line
kernel/trace/seq_buf.c new file +1
-0+#define SEQ_BUF_USED (s) min((s)->len, (s)->size - 1)[...]
kernel/trace/seq_buf.c line 96
Quoted 10 lines
kernel/trace/seq_buf.c new file +10
-0+ +/** +* seq_buf_bitmask - write a bitmask array in its ASCII representation +* @s: seq_buf descriptor +* @maskp: points to an array of unsigned longs that represent a bitmask +* @nmaskbits: The number of bits that are valid in @maskp +* +* Writes a ASCII representation of a bitmask string into @s. +* +* Returns the number of bytes written. The text should be:
Quoted 1 line
* Returns zero on success, -1 on overflow.
Darn, I thought I caught all the updates of the return value.
Will fix.
Quoted 16 lines
kernel/trace/seq_buf.c line 107
Quoted 13 lines
+ */
kernel/trace/seq_buf.c new file +10
-0+int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp, +int nmaskbits) +{ +unsigned int len =SEQ_BUF_LEFT (s); +int ret; + +WARN_ON (s->size ==0 ); + +if (s->len < s->size) { + ret =bitmap_scnprintf (s->buffer, len, maskp, nmaskbits);It writes to the beginning of the buffer. It should be
Quoted 3 lines
ret = bitmap_scnprintf(s->buffer + s->len, len, maskp, nmaskbits);
Yep thanks. Luckily its only user didn't care.
Will fix.
Quoted 5 lines
kernel/trace/seq_buf.c
Quoted 2 lines
kernel/trace/seq_buf.c new file +1
-0+if (s->len + ret < s->size) {This will always happen because
bitmap_scnprintf()is limited bySEQ_BUF_LEFT(s)and it currently returns the remaining size - len - 1.
Hmm, that's correct, as bitmap_scnprintf() returns the amount written instead of the amount that it would write like snprintf() would.
Quoted 2 lines
You might want to use "
s->size-s->len" instead ofSEQ_BUF_LEFT(s).
That wont help when we make overflow len > size.
Probably should see if ret == the amount of bits required for the bitmask.
Quoted 29 lines
Quoted 29 lines
kernel/trace/seq_buf.c new file +27
-0+ s->len += ret; +return 0 ; + } + } +seq_buf_set_overflow (s); +return -1 ; +} + +/** +* seq_buf_bprintf - Write the printf string from binary arguments +* @s: seq_buf descriptor +* @fmt: The format string for the @binary arguments +* @binary: The binary arguments for @fmt. +* +* When recording in a fast path, a printf may be recorded with just +* saving the format and the arguments as they were passed to the +* function, instead of wasting cycles converting the arguments into +* ASCII characters. Instead, the arguments are saved in a 32 bit +* word array that is defined by the format string constraints. +* +* This function will take the format and the binary array and finish +* the conversion into the ASCII string within the buffer. +* +* Returns zero on success, -1 on overflow. +*/ +int seq_buf_bprintf (struct seq_buf *s,const char *fmt,const u32 *binary) +{
Quoted 8 lines
kernel/trace/seq_buf.c line 106
Quoted 6 lines
kernel/trace/seq_buf.c new file +6
-0+unsigned int len =SEQ_BUF_LEFT (s); +int ret; + +WARN_ON (s->size ==0 ); + +if (s->len < s->size) {Always true. It is the same problem as in
seq_buf_bitmask().
No this is not the same. This will not be true if we have overflowed.
Quoted 3 lines
kernel/trace/seq_buf.c line 143
Quoted 3 lines
kernel/trace/seq_buf.c new file +2
-0+ ret =bstr_printf (s->buffer + s->len, len, fmt, binary); +if (s->len + ret < s->size) {
This is the "if" you are thinking of with seq_buf_bitmask(). But unlike bitmap_scnprintf(), bstr_printf() returns the number of characters that would be written. Not the number that were. This condition does make sense.
Quoted 23 lines
Quoted 23 lines
kernel/trace/seq_buf.c new file +23
-0+ s->len += ret; +return 0 ; + } + } +seq_buf_set_overflow (s); +return -1 ; +} + +/** +* seq_buf_puts - sequence printing of simple string +* @s: seq_buf descriptor +* @str: simple string to record +* +* Copy a simple string into the sequence buffer. +* +* Returns zero on success, -1 on overflow +*/ +int seq_buf_puts (struct seq_buf *s,const char *str) +{ +unsigned int len =strlen (str); + +WARN_ON (s->size ==0 ); +
Quoted 8 lines
kernel/trace/seq_buf.c line 171
Quoted 5 lines
kernel/trace/seq_buf.c new file +5
-0+if (s->len + len < s->size) { +memcpy (s->buffer + s->len, str, len); + s->len += len; +return 0 ; + }We might want to copy the maximum possible number of bytes. It will then behave the same as the other functions.
I'm converting all this to be like seq_file in the other patches.
Quoted 25 lines
Quoted 5 lines
kernel/trace/seq_buf.c new file +4
-0+seq_buf_set_overflow (s); +return -1 ; +} +[...]
Quoted 17 lines
kernel/trace/seq_buf.c new file +17
-0+ +/** +* seq_buf_putmem - write raw data into the sequenc buffer +* @s: seq_buf descriptor +* @mem: The raw memory to copy into the buffer +* @len: The length of the raw memory to copy (in bytes) +* +* There may be cases where raw memory needs to be written into the +* buffer and a strcpy() would not work. Using this function allows +* for such cases. +* +* Returns zero on success, -1 on overflow +*/ +int seq_buf_putmem (struct seq_buf *s,const void *mem,unsigned int len) +{ +WARN_ON (s->size ==0 ); +
Quoted 8 lines
kernel/trace/seq_buf.c line 217
Quoted 5 lines
kernel/trace/seq_buf.c new file +5
-0+if (s->len + len < s->size) { +memcpy (s->buffer + s->len, mem, len); + s->len += len; +return 0 ; + }Same as
seq_buf_puts(). Do we want to always copy the possible number of bytes?
Again, this will be made to be like seq_file.
Quoted 43 lines
Quoted 43 lines
kernel/trace/seq_buf.c new file +42
-0+seq_buf_set_overflow (s); +return -1 ; +} + +#define MAX_MEMHEX_BYTES 8U +#define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1) + +/** +* seq_buf_putmem_hex - write raw memory into the buffer in ASCII hex +* @s: seq_buf descriptor +* @mem: The raw memory to write its hex ASCII representation of +* @len: The length of the raw memory to copy (in bytes) +* +* This is similar to seq_buf_putmem() except instead of just copying the +* raw memory into the buffer it writes its ASCII representation of it +* in hex characters. +* +* Returns zero on success, -1 on overflow +*/ +int seq_buf_putmem_hex (struct seq_buf *s,const void *mem, +unsigned int len) +{ +unsigned char hex[HEX_CHARS ]; +const unsigned char *data = mem; +unsigned int start_len; +int i, j; + +WARN_ON (s->size ==0 ); + +while (len) { + start_len =min (len,HEX_CHARS -1 ); +#ifdef __BIG_ENDIAN +for (i =0 , j =0 ; i < start_len; i++) { +#else +for (i = start_len-1 , j =0 ; i >=0 ; i--) { +#endif + hex[j++] =hex_asc_hi (data[i]); + hex[j++] =hex_asc_lo (data[i]); + } +if (WARN_ON_ONCE (j ==0 || j/2 > len)) +break ; +
Quoted 8 lines
kernel/trace/seq_buf.c line 265
Quoted 6 lines
kernel/trace/seq_buf.c new file +6
-0+/* j increments twice per loop */ + len -= j /2 ; + hex[j++] =' ' ; + +seq_buf_putmem (s, hex, j); +if (seq_buf_has_overflowed (s))We might want to use the
seq_buf_putmem()return value here.
We could do that.
Quoted 21 lines
Quoted 6 lines
kernel/trace/seq_buf.c new file +5
-0+return -1 ; + } +return 0 ; +} +[...]
Quoted 12 lines
kernel/trace/seq_buf.c new file +12
-0+ +/** +* seq_buf_to_user - copy the squence buffer to user space +* @s: seq_buf descriptor +* @ubuf: The userspace memory location to copy to +* @cnt: The amount to copy +* +* Copies the sequence buffer into the userspace memory pointed to +* by @ubuf. It starts from the last read position (@s->readpos) +* and writes up to @cnt characters or till it reaches the end of +* the content in the buffer (@s->len), which ever comes first. +*
Quoted 8 lines
Quoted 6 lines
+ * On success, it returns a positive number of the number of bytes
+ * it copied.
+ *
+ * On failure it returns-EBUSYif all of the content in the
+ * sequence has been already read, which includes nothing in the
+ * sequenc (@s->len == @s->readpos).sequenc -> sequence
Thanks.
Quoted 37 lines
Quoted 27 lines
+ *
+ * Returns-EFAULTif the copy to userspace fails.
+ */kernel/trace/seq_buf.c new file +23
-0+int seq_buf_to_user (struct seq_buf *s,char __user *ubuf,int cnt) +{ +int len; +int ret; + +if (!cnt) +return 0 ; + +if (s->len <= s->readpos) +return -EBUSY ; + + len = s->len - s->readpos; +if (cnt > len) + cnt = len; + ret =copy_to_user (ubuf, s->buffer + s->readpos, cnt); +if (ret == cnt) +return -EFAULT ; + + cnt -= ret; + + s->readpos += cnt; +return cnt; +}[...]
Quoted 7 lines
kernel/trace/trace_seq.c +0
-0@@ -27,10 +27,19 @@#include <linux/trace_seq.h>
Quoted 7 lines
kernel/trace/trace_seq.c line 30
Quoted 3 lines
kernel/trace/trace_seq.c +1
-1/* How much buffer is left on the trace_seq? */ -#define TRACE_SEQ_BUF_LEFT (s) ((PAGE_SIZE - 1) - (s)->len) +#define TRACE_SEQ_BUF_LEFT (s) ((PAGE_SIZE - 1) - (s)->seq.len)This might overflow when
s->len==PAGE_SIZE. I think that it newer happenes because we always checks->fullbefore. The question is if we really want to depend on this.
Yeah, we should make this check seq_buf itself. Maybe make a static inline function that is in seq_buf.h.
Quoted 50 lines
Quoted 50 lines
kernel/trace/trace_seq.c +18
-7/* How much buffer is written? */ -#define TRACE_SEQ_BUF_USED (s) min((s)->len, (unsigned int)(PAGE_SIZE - 1)) +#define TRACE_SEQ_BUF_USED (s) min((s)->seq.len, (unsigned int)(PAGE_SIZE - 1)) + +/* +* trace_seq should work with being initialized with 0s. +*/ +static inline void __trace_seq_init (struct trace_seq *s) +{ +if (unlikely (!s->seq.size)) +trace_seq_init (s); +}/** * trace_print_seq - move the contents of trace_seq into a seq_file @@ -43,10 +52,11 @@*/ int trace_print_seq (struct seq_file *m,struct trace_seq *s) { -unsigned int len =TRACE_SEQ_BUF_USED (s);int ret; - ret =seq_write (m, s->buffer, len); +__trace_seq_init (s); + + ret =seq_buf_print_seq (m, &s->seq);/* * Only reset this buffer if we successfully wrote to the @@ -77,25 +87,25 @@ int trace_print_seq(struct seq_file *m, struct trace_seq *s)*/ int trace_seq_printf (struct trace_seq *s,const char *fmt, ...) { -unsigned int len =TRACE_SEQ_BUF_LEFT (s); +unsigned int save_len = s->seq.len;va_list ap; -int ret; -if (s->full || !len) +if (s->full)return 0 ; +__trace_seq_init (s); +va_start (ap, fmt); - ret =vsnprintf (s->buffer + s->len, len, fmt, ap); +seq_buf_vprintf (&s->seq, fmt, ap);va_end (ap);
Quoted 5 lines
kernel/trace/trace_seq.c int trace_print_seq(struct seq_file *m, struct trace_seq *s) · line 103
Quoted 3 lines
kernel/trace/trace_seq.c +1
-1/* If we can't write it all, don't bother writing anything */ -if (ret >= len) { +if (unlikely (seq_buf_has_overflowed (&s->seq))) {We might check the return value from
seq_buf_vprintf()here.
No, we are working to get rid of the return values for the seq_*() functions (with a few exceptions). One now must check if the buffer has overflowed, and not the return value of the seq_*() functions themselves.
There's already patches out to convert the seq_file calls as well.
-- Steve
Quoted 6 lines
We could do similar thing also in the other functions. We even already store the ret value in some of them.
Best Regards,
Petr
Steven Rostedt
maintainerRe: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
Quoted 35 lines · On Wed, 5 Nov 2014 13:41:47 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 16 lines
kernel/trace/seq_buf.c line 107
Quoted 13 lines
+ */
kernel/trace/seq_buf.c new file +10
-0+int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp, +int nmaskbits) +{ +unsigned int len =SEQ_BUF_LEFT (s); +int ret; + +WARN_ON (s->size ==0 ); + +if (s->len < s->size) { + ret =bitmap_scnprintf (s->buffer, len, maskp, nmaskbits);It writes to the beginning of the buffer. It should be
Quoted 3 lines
ret = bitmap_scnprintf(s->buffer + s->len, len, maskp, nmaskbits);Yep thanks. Luckily its only user didn't care.
Will fix.
Quoted 5 lines
Review
Quoted 2 lines
(quoted diff) +1
-0+ if (s->len + ret < s->size) {This will always happen because
bitmap_scnprintf()is limited bySEQ_BUF_LEFT(s)and it currently returns the remaining size - len - 1.Hmm, that's correct, as
bitmap_scnprintf()returns the amount written instead of the amount that it would write likesnprintf()would.Quoted 1 line
Quoted 6 lines
Quoted 1 line
You might want to use "
s->size-s->len" instead ofSEQ_BUF_LEFT(s).That wont help when we make overflow len > size.
Probably should see if ret == the amount of bits required for the bitmask.
Here's the new version:
int seq_buf_bitmask(struct seq_buf *s, const unsigned long *maskp,
int nmaskbits)
{
unsigned int len = seq_buf_buffer_left(s);
int size;
int ret;
WARN_ON(s->size == 0);
if (s->len < s->size) {
/*
* Calculate to see if we have enough room to fit
* @nmaskbits as a string
*/
size = (nmaskbits + 3) / 4;
/* Add the commas that are used for groups of 8 hex digits */
size += size / 8;
if (len >= size) {
ret = bitmap_scnprintf(s->buffer, len, maskp, nmaskbits);
WARN_ON_ONCE(s->len + ret >= s->size);
s->len += ret;
return 0;
}
}
seq_buf_set_overflow(s);
return -1;
}Quoted 57 lines
Quoted 48 lines
Quoted 48 lines
kernel/trace/seq_buf.c new file +42
-0+ s->len += ret; +return 0 ; + } + } +seq_buf_set_overflow (s); +return -1 ; +} +/** +* seq_buf_putmem_hex - write raw memory into the buffer in ASCII hex +* @s: seq_buf descriptor +* @mem: The raw memory to write its hex ASCII representation of +* @len: The length of the raw memory to copy (in bytes) +* +* This is similar to seq_buf_putmem() except instead of just copying the +* raw memory into the buffer it writes its ASCII representation of it +* in hex characters. +* +* Returns zero on success, -1 on overflow +*/ +int seq_buf_putmem_hex (struct seq_buf *s,const void *mem, +unsigned int len) +{ +unsigned char hex[HEX_CHARS ]; +const unsigned char *data = mem; +unsigned int start_len; +int i, j; + +WARN_ON (s->size ==0 ); + +while (len) { + start_len =min (len,HEX_CHARS -1 ); +#ifdef __BIG_ENDIAN +for (i =0 , j =0 ; i < start_len; i++) { +#else +for (i = start_len-1 , j =0 ; i >=0 ; i--) { +#endif + hex[j++] =hex_asc_hi (data[i]); + hex[j++] =hex_asc_lo (data[i]); + } +if (WARN_ON_ONCE (j ==0 || j/2 > len)) +break ; +Quoted 8 lines
kernel/trace/seq_buf.c line 265
Quoted 6 lines
kernel/trace/seq_buf.c new file +6
-0+/* j increments twice per loop */ + len -= j /2 ; + hex[j++] =' ' ; + +seq_buf_putmem (s, hex, j); +if (seq_buf_has_overflowed (s))We might want to use the
seq_buf_putmem()return value here.
Quoted 1 line
We could do that.
Actually, no we can't. As I stated before, the return values of most of the seq_*() functions (for seq_file and seq_buf) will be turning into void functions.
I'm avoiding checking return values here.
-- Steve
Quoted 8 lines
Quoted 8 lines
Quoted 7 lines
kernel/trace/seq_buf.c new file +5
-0+return -1 ; + } +return 0 ; +} +
Steven Rostedt
maintainerRe: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
Quoted 38 lines · On Wed, 5 Nov 2014 15:00:07 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 35 lines · On Wed, 5 Nov 2014 13:41:47 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 16 lines
kernel/trace/seq_buf.c line 107
Quoted 13 lines
+ */
kernel/trace/seq_buf.c new file +10
-0+int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp, +int nmaskbits) +{ +unsigned int len =SEQ_BUF_LEFT (s); +int ret; + +WARN_ON (s->size ==0 ); + +if (s->len < s->size) { + ret =bitmap_scnprintf (s->buffer, len, maskp, nmaskbits);It writes to the beginning of the buffer. It should be
Quoted 3 lines
ret = bitmap_scnprintf(s->buffer + s->len, len, maskp, nmaskbits);Yep thanks. Luckily its only user didn't care.
Will fix.
Quoted 5 lines
Review
Quoted 2 lines
(quoted diff) +1
-0+ if (s->len + ret < s->size) {This will always happen because
bitmap_scnprintf()is limited bySEQ_BUF_LEFT(s)and it currently returns the remaining size - len - 1.Hmm, that's correct, as
bitmap_scnprintf()returns the amount written instead of the amount that it would write likesnprintf()would.Quoted 1 line
Quoted 9 lines
Quoted 6 lines
Quoted 1 line
You might want to use "
s->size-s->len" instead ofSEQ_BUF_LEFT(s).That wont help when we make overflow len > size.
Probably should see if ret == the amount of bits required for the bitmask.
Here's the new version:
Take 2:
int seq_buf_bitmask(struct seq_buf *s, const unsigned long *maskp,
int nmaskbits)
{
unsigned int len = seq_buf_buffer_left(s);
int ret;
WARN_ON(s->size == 0);
if (s->len < s->size) {
ret = bitmap_scnprintf(s->buffer, len, maskp, nmaskbits);
/*
* Note, because bitmap_scnprintf() only returns the
* number of bytes written and not the number that
* would be written, we use the last byte of the buffer
* to let us know if we overflowed. There's a small
* chance that the bitmap could have fit exactly inside
* the buffer, but it's not that critical if that does
* happen.
*/
if (s->len + ret < s->size) {
s->len += ret;
return 0;
}
}
seq_buf_set_overflow(s);
return -1;
}-- Steve
Steven Rostedt
maintainerRe: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
Quoted 51 lines · On Wed, 5 Nov 2014 16:17:20 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 38 lines · On Wed, 5 Nov 2014 15:00:07 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 35 lines · On Wed, 5 Nov 2014 13:41:47 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 16 lines
kernel/trace/seq_buf.c line 107
Quoted 13 lines
+ */
kernel/trace/seq_buf.c new file +10
-0+int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp, +int nmaskbits) +{ +unsigned int len =SEQ_BUF_LEFT (s); +int ret; + +WARN_ON (s->size ==0 ); + +if (s->len < s->size) { + ret =bitmap_scnprintf (s->buffer, len, maskp, nmaskbits);It writes to the beginning of the buffer. It should be
Quoted 3 lines
ret = bitmap_scnprintf(s->buffer + s->len, len, maskp, nmaskbits);Yep thanks. Luckily its only user didn't care.
Will fix.
Quoted 5 lines
Review
Quoted 2 lines
(quoted diff) +1
-0+ if (s->len + ret < s->size) {This will always happen because
bitmap_scnprintf()is limited bySEQ_BUF_LEFT(s)and it currently returns the remaining size - len - 1.Hmm, that's correct, as
bitmap_scnprintf()returns the amount written instead of the amount that it would write likesnprintf()would.Quoted 1 line
Quoted 9 lines
Quoted 6 lines
Quoted 1 line
You might want to use "
s->size-s->len" instead ofSEQ_BUF_LEFT(s).That wont help when we make overflow len > size.
Probably should see if ret == the amount of bits required for the bitmask.
Here's the new version:
Quoted 6 lines
Take 2:
int seq_buf_bitmask(struct
seq_buf*s, const unsigned long *maskp,
int nmaskbits){ unsigned int len = seq_buf_buffer_left(s);
Bah, I need to make this: len = s->size - s->len.
As this would work for both cases of what a overflowed buffer is.
-- Steve
Quoted 25 lines
int ret; WARN_ON(s->size == 0); if (s->len < s->size) { ret = bitmap_scnprintf(s->buffer, len, maskp, nmaskbits); /* * Note, because bitmap_scnprintf() only returns the * number of bytes written and not the number that * would be written, we use the last byte of the buffer * to let us know if we overflowed. There's a small * chance that the bitmap could have fit exactly inside * the buffer, but it's not that critical if that does * happen. */ if (s->len + ret < s->size) { s->len += ret; return 0; } } seq_buf_set_overflow(s); return -1; }-- Steve
Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
Quoted 56 lines · Steven Rostedt
Quoted 53 lines · On Wed, 5 Nov 2014 16:17:20 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 38 lines · On Wed, 5 Nov 2014 15:00:07 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 35 lines · On Wed, 5 Nov 2014 13:41:47 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 16 lines
kernel/trace/seq_buf.c line 107
Quoted 13 lines
+ */
kernel/trace/seq_buf.c new file +10
-0+int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp, +int nmaskbits) +{ +unsigned int len =SEQ_BUF_LEFT (s); +int ret; + +WARN_ON (s->size ==0 ); + +if (s->len < s->size) { + ret =bitmap_scnprintf (s->buffer, len, maskp, nmaskbits);It writes to the beginning of the buffer. It should be
Quoted 3 lines
ret = bitmap_scnprintf(s->buffer + s->len, len, maskp, nmaskbits);Yep thanks. Luckily its only user didn't care.
Will fix.
Quoted 5 lines
Review
Quoted 2 lines
(quoted diff) +1
-0+ if (s->len + ret < s->size) {This will always happen because
bitmap_scnprintf()is limited bySEQ_BUF_LEFT(s)and it currently returns the remaining size - len - 1.Hmm, that's correct, as
bitmap_scnprintf()returns the amount written instead of the amount that it would write likesnprintf()would.Quoted 1 line
Quoted 9 lines
Quoted 6 lines
Quoted 1 line
You might want to use "
s->size-s->len" instead ofSEQ_BUF_LEFT(s).That wont help when we make overflow len > size.
Probably should see if ret == the amount of bits required for the bitmask.
Here's the new version:
Take 2:
Quoted 8 lines
Quoted 4 lines
int seq_buf_bitmask(struct
seq_buf*s, const unsigned long *maskp,
int nmaskbits){ unsigned int len = seq_buf_buffer_left(s);Bah, I need to make this: len =
s->size-s->len.As this would work for both cases of what a overflowed buffer is.
Hmm, this would produce -1 (UNIT_MAX) when the overflow is (s->len = s->size + 1). I would keep seq_buf_buffer_left(s);
Quoted 5 lines
Quoted 5 lines
int ret; WARN_ON(s->size == 0); if (s->len < s->size) {
It does not make sense to try if there is only one byte left. I would do:
if (len > 1)
together with the change below.
Quoted 10 lines
Quoted 10 lines
ret =
bitmap_scnprintf(s->buffer, len, maskp, nmaskbits); /*
* Note, becausebitmap_scnprintf()only returns the
* number of bytes written and not the number that
* would be written, we use the last byte of the buffer
* to let us know if we overflowed. There's a small
* chance that the bitmap could have fit exactly inside
* the buffer, but it's not that critical if that does
* happen.
*/
This is great explanation. You might want to move it above the "if (len > 1)" if you agree with it.
Quoted 1 line
Quoted 1 line
if (s->len + ret < s->size) {
This should work with both variants of the overflow if "len" is really the space left.
if (ret < len)
I mean that we fail if we wrote the buffer until the last possible byte.
Quoted 7 lines
Quoted 7 lines
s->len += ret; return 0; } } seq_buf_set_overflow(s); return -1; }
Best Regards,
Petr
Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
I'm not going to waist bandwidth reposting the entire series. Here's a new version of this patch. I'm getting ready to pull it into my next queue.
-- Steve
Quoted 1 line
From
11674c8df0580a03a2517e3a8e4705c47c663564Mon Sep 17 00:00:00 2001
From: "Steven Rostedt (Red Hat)" <[email protected]>
Date: Wed, 25 Jun 2014 15:54:42 -0400
Subject: [PATCH] tracing: Create seq_buf layer in trace_seq
Create a seq_buf layer that trace_seq sits on. The seq_buf will not be limited to page size. This will allow other usages of seq_buf instead of a hard set PAGE_SIZE one that trace_seq has.
--- include/linux/seq_buf.h | 78 ++++++++ include/linux/trace_seq.h | 10 +- kernel/trace/Makefile | 1 + kernel/trace/seq_buf.c | 341 +++++++++++++++++++++++++++++++++++ kernel/trace/trace.c | 39 ++-- kernel/trace/trace_events.c | 6 +- kernel/trace/trace_functions_graph.c | 6 +- kernel/trace/trace_seq.c | 184 +++++++++---------- 8 files changed, 540 insertions(+), 125 deletions(-) create mode 100644 include/linux/seq_buf.h create mode 100644 kernel/trace/seq_buf.c
include/linux/seq_buf.h new file +78 -0
@@ -0,0 +1,78 @@ +#ifndef _LINUX_SEQ_BUF_H +#define _LINUX_SEQ_BUF_H + +#include <linux/fs.h> + +/* +* Trace sequences are used to allow a function to call several other functions +* to create a string of data to use. +*/ + +/** +* seq_buf - seq buffer structure +* @buffer: pointer to the buffer +* @size: size of the buffer +* @len: the amount of data inside the buffer +* @readpos: The next position to read in the buffer. +*/ +struct seq_buf { +unsigned char *buffer; +unsigned int size; +unsigned int len; +unsigned int readpos; +}; + +static inline void +seq_buf_init (struct seq_buf *s,unsigned char *buf,unsigned int size) +{ + s->buffer = buf; + s->size = size; + s->len =0 ; + s->readpos =0 ; +} + +/* +* seq_buf have a buffer that might overflow. When this happens +* the len and size are set to be equal. +*/ +static inline bool +seq_buf_has_overflowed (struct seq_buf *s) +{ +return s->len == s->size; +} + +static inline void +seq_buf_set_overflow (struct seq_buf *s) +{ + s->len = s->size; +} + +/* +* How much buffer is left on the seq_buf? +*/ +static inline unsigned int +seq_buf_buffer_left (struct seq_buf *s) +{ +return (s->size -1 ) - s->len; +} + +extern __printf(2, 3) +int seq_buf_printf(struct seq_buf *s, const char *fmt, ...); +extern __printf(2, 0) +int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args); +extern int +seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary); +extern int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s); +extern int seq_buf_to_user(struct seq_buf *s, char __user *ubuf, + int cnt); +extern int seq_buf_puts(struct seq_buf *s, const char *str); +extern int seq_buf_putc(struct seq_buf *s, unsigned char c); +extern int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len); +extern int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, + unsigned int len); +extern int seq_buf_path(struct seq_buf *s, const struct path *path); + +extern int seq_buf_bitmask(struct seq_buf *s, const unsigned long *maskp, + int nmaskbits); + +#endif /* _LINUX_SEQ_BUF_H */
include/linux/trace_seq.h +4 -6
@@ -1,7 +1,7 @@#ifndef _LINUX_TRACE_SEQ_H#define _LINUX_TRACE_SEQ_H -#include <linux/fs.h> +#include <linux/seq_buf.h> #include <asm/page.h>
@@ -12,16 +12,14 @@struct trace_seq {unsigned char buffer[PAGE_SIZE ]; -unsigned int len; -unsigned int readpos; +struct seq_buf seq;int full; };static inline void trace_seq_init (struct trace_seq *s) { - s->len =0 ; - s->readpos =0 ; +seq_buf_init (&s->seq, s->buffer,PAGE_SIZE ); s->full =0 ; }
@@ -37,7 +35,7 @@ trace_seq_init(struct trace_seq *s)static inline unsigned char *trace_seq_buffer_ptr (struct trace_seq *s) { -return s->buffer + s->len; +return s->buffer + s->seq.len; }/*
kernel/trace/Makefile +1 -0
@@ -29,6 +29,7 @@ obj-$(CONFIG_RING_BUFFER_BENCHMARK) += ring_buffer_benchmark.o obj-$(CONFIG_TRACING) += trace.o obj-$(CONFIG_TRACING) += trace_output.o obj-$(CONFIG_TRACING) += trace_seq.o +obj-$(CONFIG_TRACING) += seq_buf.o obj-$(CONFIG_TRACING) += trace_stat.o obj-$(CONFIG_TRACING) += trace_printk.o obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o
kernel/trace/seq_buf.c new file +341 -0
341 lines not on this page · raw message
kernel/trace/trace.c +21 -18
@@ -938,19 +938,20 @@ out:return ret; } +/* TODO add a seq_buf_to_buffer() */ static ssize_t trace_seq_to_buffer (struct trace_seq *s,void *buf,size_t cnt) {int len; -if (s->len <= s->readpos) +if (s->seq.len <= s->seq.readpos)return -EBUSY ; - len = s->len - s->readpos; + len = s->seq.len - s->seq.readpos;if (cnt > len) cnt = len; -memcpy (buf, s->buffer + s->readpos, cnt); +memcpy (buf, s->buffer + s->seq.readpos, cnt); - s->readpos += cnt; + s->seq.readpos += cnt;return cnt; }
@@ -4313,6 +4314,8 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp) goto out; } +trace_seq_init (&iter->seq); +/* * We make a copy of the current tracer to avoid concurrent * changes on it while we are reading.
@@ -4509,18 +4512,18 @@ waitagain:trace_access_lock (iter->cpu_file);while (trace_find_next_entry_inc (iter) !=NULL ) {enum print_line_t ret; -int len = iter->seq.len; +int len = iter->seq.seq.len; ret =print_trace_line (iter);if (ret ==TRACE_TYPE_PARTIAL_LINE ) {/* don't print partial lines */ - iter->seq.len = len; + iter->seq.seq.len = len;break ; }if (ret !=TRACE_TYPE_NO_CONSUME )trace_consume (iter); -if (iter->seq.len >= cnt) +if (iter->seq.seq.len >= cnt)break ;/*
@@ -4536,7 +4539,7 @@ waitagain:/* Now copy what we have to the user */ sret =trace_seq_to_user (&iter->seq, ubuf, cnt); -if (iter->seq.readpos >= iter->seq.len) +if (iter->seq.seq.readpos >= iter->seq.seq.len)trace_seq_init (&iter->seq);/*
@@ -4574,16 +4577,16 @@ tracing_fill_pipe_page(size_t rem, struct trace_iterator *iter)/* Seq buffer is page-sized, exactly what we need. */ for (;;) { - count = iter->seq.len; + count = iter->seq.seq.len; ret =print_trace_line (iter); - count = iter->seq.len - count; + count = iter->seq.seq.len - count;if (rem < count) { rem =0 ; - iter->seq.len -= count; + iter->seq.seq.len -= count;break ; }if (ret ==TRACE_TYPE_PARTIAL_LINE ) { - iter->seq.len -= count; + iter->seq.seq.len -= count;break ; }
@@ -4664,13 +4667,13 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,/* Copy the data into the page, so we can start over. */ ret =trace_seq_to_buffer (&iter->seq,page_address (spd.pages[i]), - iter->seq.len); + iter->seq.seq.len);if (ret <0 ) {__free_page (spd.pages[i]);break ; } spd.partial[i].offset =0 ; - spd.partial[i].len = iter->seq.len; + spd.partial[i].len = iter->seq.seq.len;trace_seq_init (&iter->seq); }
@@ -5671,7 +5674,7 @@ tracing_stats_read(struct file *filp, char __user *ubuf, cnt =ring_buffer_read_events_cpu (trace_buf->buffer, cpu);trace_seq_printf (s,"read events: %ld\n" , cnt); - count =simple_read_from_buffer (ubuf, count, ppos, s->buffer, s->len); + count =simple_read_from_buffer (ubuf, count, ppos, s->buffer, s->seq.len);kfree (s);
@@ -6634,11 +6637,11 @@ void trace_printk_seq(struct trace_seq *s) {/* Probably should print a warning here. */ -if (s->len >=TRACE_MAX_PRINT ) - s->len =TRACE_MAX_PRINT ; +if (s->seq.len >=TRACE_MAX_PRINT ) + s->seq.len =TRACE_MAX_PRINT ;/* should be zero ended, but we are paranoid. */ - s->buffer[s->len] =0 ; + s->buffer[s->seq.len] =0 ;printk (KERN_TRACE "%s" , s->buffer);
kernel/trace/trace_events.c +3 -3
@@ -1044,7 +1044,7 @@ event_filter_read(struct file *filp, char __user *ubuf, size_t cnt,mutex_unlock (&event_mutex);if (file) - r =simple_read_from_buffer (ubuf, cnt, ppos, s->buffer, s->len); + r =simple_read_from_buffer (ubuf, cnt, ppos, s->buffer, s->seq.len);kfree (s);
@@ -1210,7 +1210,7 @@ subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt,trace_seq_init (s);print_subsystem_event_filter (system, s); - r =simple_read_from_buffer (ubuf, cnt, ppos, s->buffer, s->len); + r =simple_read_from_buffer (ubuf, cnt, ppos, s->buffer, s->seq.len);kfree (s);
@@ -1265,7 +1265,7 @@ show_header(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)trace_seq_init (s);func (s); - r =simple_read_from_buffer (ubuf, cnt, ppos, s->buffer, s->len); + r =simple_read_from_buffer (ubuf, cnt, ppos, s->buffer, s->seq.len);kfree (s);
kernel/trace/trace_functions_graph.c +3 -3
@@ -1291,9 +1291,9 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent, }/* Strip ending newline */ -if (s->buffer[s->len -1 ] =='\n' ) { - s->buffer[s->len -1 ] ='\0' ; - s->len--; +if (s->buffer[s->seq.len -1 ] =='\n' ) { + s->buffer[s->seq.len -1 ] ='\0' ; + s->seq.len--; } ret =trace_seq_puts (s," */\n" );
kernel/trace/trace_seq.c +89 -95
330 lines not on this page · raw message
Signature · 1 line
2.1.1
Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
Quoted 3 lines · Steven Rostedt
I'm not going to waist bandwidth reposting the entire series. Here's a new version of this patch. I'm getting ready to pull it into my next queue.
All this seems sensible enough though I think it'd be nicer if all the touch-ups were compressed into a single patch.
and some trivia:
Quoted 5 lines
Create a
seq_buflayer thattrace_seqsits on. Theseq_bufwill not be limited to page size. This will allow other usages ofseq_bufinstead of a hard setPAGE_SIZEone thattrace_seqhas.
[]
include/linux/seq_buf.h
Quoted 1 line
include/linux/seq_buf.h +0
-0
[]
Quoted 8 lines
include/linux/seq_buf.h +8
-0+extern __printf(2, 3) +int seq_buf_printf(struct seq_buf *s, const char *fmt, ...); +extern __printf(2, 0) +int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args); +extern int +seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary); +extern int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s); +extern int seq_buf_to_user(struct seq_buf *s, char __user *ubuf,
include/linux/seq_buf.h line 76
Quoted 10 lines
include/linux/seq_buf.h +10
-0+ int cnt); +extern int seq_buf_puts (struct seq_buf *s,const char *str); +extern int seq_buf_putc (struct seq_buf *s,unsigned char c); +extern int seq_buf_putmem (struct seq_buf *s,const void *mem,unsigned int len); +extern int seq_buf_putmem_hex (struct seq_buf *s,const void *mem, +unsigned int len); +extern int seq_buf_path (struct seq_buf *s,const struct path *path); + +extern int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp, +int nmaskbits);
Maybe remove the extern bits from the function definitions? And maybe the unsigned int len/cnt could be size_t
include/linux/trace_seq.h
Quoted 1 line
include/linux/trace_seq.h +0
-0
[]
Quoted 6 lines
include/linux/trace_seq.h +0
-2@@ -12,16 +12,14 @@struct trace_seq {unsigned char buffer[PAGE_SIZE ]; -unsigned int len; -unsigned int readpos;
include/linux/trace_seq.h line 22
Quoted 10 lines
include/linux/trace_seq.h +2
-2+struct seq_buf seq;int full; };static inline void trace_seq_init (struct trace_seq *s) { - s->len =0 ; - s->readpos =0 ; +seq_buf_init (&s->seq, s->buffer,PAGE_SIZE );
Maybe the PAGE_SIZE uses could be ARRAY_SIZE(s->buffer)
kernel/trace/trace_seq.c
Quoted 1 line
kernel/trace/trace_seq.c +0
-0
[]
kernel/trace/trace_seq.c line 33
Quoted 3 lines
/* How much buffer is written? */
kernel/trace/trace_seq.c +1
-1-#define TRACE_SEQ_BUF_USED (s) min((s)->len, (unsigned int)(PAGE_SIZE - 1)) +#define TRACE_SEQ_BUF_USED (s) min((s)->seq.len, (unsigned int)(PAGE_SIZE - 1))
min_t?
maybe this should be FIELD_SIZEOF(struct trace_seq, buffer) - 1
Steven Rostedt
maintainerRe: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
Quoted 20 lines · On Fri, 07 Nov 2014 10:59:27 -0800 Joe Perches <[email protected]> wrote:
Quoted 5 lines
Create a
seq_buflayer thattrace_seqsits on. Theseq_bufwill not be limited to page size. This will allow other usages ofseq_bufinstead of a hard setPAGE_SIZEone thattrace_seqhas.[]
include/linux/seq_buf.h
Quoted 1 line
include/linux/seq_buf.h +0
-0[]
Quoted 12 lines
include/linux/seq_buf.h +12
-0+extern __printf(2, 3) +int seq_buf_printf(struct seq_buf *s, const char *fmt, ...); +extern __printf(2, 0) +int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args); +extern int +seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary); +extern int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s); +extern int seq_buf_to_user(struct seq_buf *s, char __user *ubuf, + int cnt); +extern int seq_buf_puts(struct seq_buf *s, const char *str); +extern int seq_buf_putc(struct seq_buf *s, unsigned char c); +extern int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len);
Quoted 8 lines
include/linux/seq_buf.h line 76
Quoted 6 lines
include/linux/seq_buf.h +6
-0+extern int seq_buf_putmem_hex (struct seq_buf *s,const void *mem, +unsigned int len); +extern int seq_buf_path (struct seq_buf *s,const struct path *path); + +extern int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp, +int nmaskbits);Maybe remove the extern bits from the function definitions?
Yeah, probably should have done that. Not sure why I kept them. Cut and paste?
Quoted 1 line
And maybe the unsigned int len/cnt could be
size_t
The struct does get changed later to match seq_file.
Quoted 22 lines
include/linux/trace_seq.h
Quoted 2 lines
include/linux/trace_seq.h +0
-0[]
Quoted 6 lines
include/linux/trace_seq.h +0
-2@@ -12,16 +12,14 @@struct trace_seq {unsigned char buffer[PAGE_SIZE ]; -unsigned int len; -unsigned int readpos;include/linux/trace_seq.h line 22
Quoted 10 lines
include/linux/trace_seq.h +2
-2+struct seq_buf seq;int full; };static inline void trace_seq_init (struct trace_seq *s) { - s->len =0 ; - s->readpos =0 ; +seq_buf_init (&s->seq, s->buffer,PAGE_SIZE );Maybe the
PAGE_SIZEuses could beARRAY_SIZE(s->buffer)
Quoted 8 lines
kernel/trace/trace_seq.c
Quoted 1 line
kernel/trace/trace_seq.c +0
-0[]
kernel/trace/trace_seq.c line 33
Quoted 3 lines
/* How much buffer is written? */
kernel/trace/trace_seq.c +1
-1-#define TRACE_SEQ_BUF_USED (s) min((s)->len, (unsigned int)(PAGE_SIZE - 1)) +#define TRACE_SEQ_BUF_USED (s) min((s)->seq.len, (unsigned int)(PAGE_SIZE - 1))
min_t?
maybe this should beFIELD_SIZEOF(struct trace_seq, buffer)- 1
These can be done at a later time. This patch set is focusing on creation of seq_buf, not cleaning up trace_seq.
-- Steve
Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
In reply to Steven RostedtQuoted 86 lines · Steven Rostedt
I'm not going to waist bandwidth reposting the entire series. Here's a new version of this patch. I'm getting ready to pull it into my next queue.
-- Steve
From
11674c8df0580a03a2517e3a8e4705c47c663564Mon Sep 17 00:00:00 2001
From: "Steven Rostedt (Red Hat)" <[email protected]>
Date: Wed, 25 Jun 2014 15:54:42 -0400
Subject: [PATCH] tracing: Createseq_buflayer intrace_seqCreate a
seq_buflayer thattrace_seqsits on. Theseq_bufwill not be limited to page size. This will allow other usages ofseq_bufinstead of a hard setPAGE_SIZEone thattrace_seqhas.Tested-by Jiri Kosina <[email protected]>Acked-by Jiri Kosina <[email protected]>Signed-off-by Steven Rostedt <[email protected]>--- include/linux/seq_buf.h | 78 ++++++++ include/linux/trace_seq.h | 10 +- kernel/trace/Makefile | 1 + kernel/trace/seq_buf.c | 341 +++++++++++++++++++++++++++++++++++ kernel/trace/trace.c | 39 ++-- kernel/trace/trace_events.c | 6 +- kernel/trace/trace_functions_graph.c | 6 +- kernel/trace/trace_seq.c | 184 +++++++++---------- 8 files changed, 540 insertions(+), 125 deletions(-) create mode 100644 include/linux/seq_buf.h create mode 100644 kernel/trace/seq_buf.cinclude/linux/seq_buf.h new file +46
-0@@ -0,0 +1,78 @@ +#ifndef _LINUX_SEQ_BUF_H +#define _LINUX_SEQ_BUF_H + +#include <linux/fs.h> + +/* +* Trace sequences are used to allow a function to call several other functions +* to create a string of data to use. +*/ + +/** +* seq_buf - seq buffer structure +* @buffer: pointer to the buffer +* @size: size of the buffer +* @len: the amount of data inside the buffer +* @readpos: The next position to read in the buffer. +*/ +struct seq_buf { +unsigned char *buffer; +unsigned int size; +unsigned int len; +unsigned int readpos; +}; + +static inline void +seq_buf_init (struct seq_buf *s,unsigned char *buf,unsigned int size) +{ + s->buffer = buf; + s->size = size; + s->len =0 ; + s->readpos =0 ; +} + +/* +* seq_buf have a buffer that might overflow. When this happens +* the len and size are set to be equal. +*/ +static inline bool +seq_buf_has_overflowed (struct seq_buf *s) +{ +return s->len == s->size; +} + +static inline void +seq_buf_set_overflow (struct seq_buf *s) +{
include/linux/seq_buf.h line 56
Quoted 10 lines
include/linux/seq_buf.h new file +10
-0+ s->len = s->size; +} + +/* +* How much buffer is left on the seq_buf? +*/ +static inline unsigned int +seq_buf_buffer_left (struct seq_buf *s) +{ +return (s->size -1 ) - s->len;
This should be
if (seq_buf_has_overflowed(s) return 0; return (s->size - 1) - s->len;
otherwise, it would return UNIT_MAX for the overflown state. If I am not mistaken.
[...]
Quoted 5 lines
kernel/trace/seq_buf.c new file +0
-0
[...]
Quoted 15 lines
kernel/trace/seq_buf.c new file +15
-0+ +/** +* seq_buf_bitmask - write a bitmask array in its ASCII representation +* @s: seq_buf descriptor +* @maskp: points to an array of unsigned longs that represent a bitmask +* @nmaskbits: The number of bits that are valid in @maskp +* +* Writes a ASCII representation of a bitmask string into @s. +* +* Returns zero on success, -1 on overflow. +*/ +int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp, +int nmaskbits) +{ +unsigned int len =seq_buf_buffer_left (s);
kernel/trace/seq_buf.c line 107
Quoted 10 lines
kernel/trace/seq_buf.c new file +10
-0+int ret; + +WARN_ON (s->size ==0 ); + +/* +* The last byte of the buffer is used to determine if we +* overflowed or not. +*/ +if (len >1 ) { + ret =bitmap_scnprintf (s->buffer, len, maskp, nmaskbits);
It should be:
ret = bitmap_scnprintf(s->buffer + s->len, len, maskp, nmaskbits);
otherwise, we would write to the beginning to the buffer.
Quoted 9 lines
kernel/trace/seq_buf.c new file +9
-0+if (ret < len) { + s->len += ret; +return 0 ; + } + } +seq_buf_set_overflow (s); +return -1 ; +} +
[...]
Quoted 4 lines
kernel/trace/trace_seq.c +0
-0
[...]
Quoted 6 lines
kernel/trace/trace_seq.c +1
-1@@ -144,23 +160,24 @@ EXPORT_SYMBOL_GPL(trace_seq_bitmask);*/ int trace_seq_vprintf (struct trace_seq *s,const char *fmt,va_list args) { -unsigned int len =TRACE_SEQ_BUF_LEFT (s); +unsigned int save_len = s->seq.len;
kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_bitmask); · line 171
Quoted 10 lines
kernel/trace/trace_seq.c +4
-2int ret; -if (s->full || !len) +if (s->full)return 0 ; - ret =vsnprintf (s->buffer + s->len, len, fmt, args); +__trace_seq_init (s); + + ret =seq_buf_vprintf (&s->seq, fmt, args);
Note that this returns 0 on success => we do not need to store it
kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_bitmask); · line 180
Quoted 12 lines
kernel/trace/trace_seq.c +3
-4/* If we can't write it all, don't bother writing anything */ -if (ret >= len) { +if (unlikely (seq_buf_has_overflowed (&s->seq))) { + s->seq.len = save_len; s->full =1 ;return 0 ; } - s->len += ret; - -return len; +return ret;
Instead, we have to do something like:
return s->seq.len - save_len;
Quoted 9 lines
kernel/trace/trace_seq.c +1
-1}EXPORT_SYMBOL_GPL (trace_seq_vprintf);@@ -183,23 +200,24 @@ EXPORT_SYMBOL_GPL(trace_seq_vprintf);*/ int trace_seq_bprintf (struct trace_seq *s,const char *fmt,const u32 *binary) { -unsigned int len =TRACE_SEQ_BUF_LEFT (s); +unsigned int save_len = s->seq.len;
kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_vprintf); · line 211
Quoted 10 lines
kernel/trace/trace_seq.c +4
-2int ret; -if (s->full || !len) +if (s->full)return 0 ; - ret =bstr_printf (s->buffer + s->len, len, fmt, binary); +__trace_seq_init (s); + + ret =seq_buf_bprintf (&s->seq, fmt, binary);
Same here, it returns 0 on success => no need to store.
kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_bitmask); · line 180
Quoted 12 lines
kernel/trace/trace_seq.c +3
-4/* If we can't write it all, don't bother writing anything */ -if (ret >= len) { +if (unlikely (seq_buf_has_overflowed (&s->seq))) { + s->seq.len = save_len; s->full =1 ;return 0 ; } - s->len += ret; - -return len; +return ret;
and
return s->seq.len - save_len;
Quoted 3 lines
kernel/trace/trace_seq.c +0
-0}EXPORT_SYMBOL_GPL (trace_seq_bprintf);
[...]
Quoted 36 lines
/**
*trace_seq_putmem_hex- write raw memory into the buffer in ASCII hex
* @s: trace sequence descriptorkernel/trace/trace_seq.c +2
-23@@ -309,35 +328,30 @@ EXPORT_SYMBOL_GPL(trace_seq_putmem);int trace_seq_putmem_hex (struct trace_seq *s,const void *mem,unsigned int len) { -unsigned char hex[HEX_CHARS ]; -const unsigned char *data = mem; -unsigned int start_len; -int i, j; -int cnt =0 ; +unsigned int save_len = s->seq.len; +int ret;if (s->full)return 0 ; -while (len) { - start_len =min (len,HEX_CHARS -1 ); -#ifdef __BIG_ENDIAN -for (i =0 , j =0 ; i < start_len; i++) { -#else -for (i = start_len-1 , j =0 ; i >=0 ; i--) { -#endif - hex[j++] =hex_asc_hi (data[i]); - hex[j++] =hex_asc_lo (data[i]); - } -if (WARN_ON_ONCE (j ==0 || j/2 > len)) -break ; - -/* j increments twice per loop */ - len -= j /2 ; - hex[j++] =' ' ; - - cnt +=trace_seq_putmem (s, hex, j);
kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_putmem); · line 346
Quoted 10 lines
kernel/trace/trace_seq.c +10
-0+__trace_seq_init (s); + +/* Each byte is represented by two chars */ +if (len *2 >TRACE_SEQ_BUF_LEFT (s)) { + s->full =1 ; +return 0 ; + } + +/* The added spaces can still cause an overflow */ + ret =seq_buf_putmem_hex (&s->seq, mem, len);
and here, it returns zero on success
kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_putmem); · line 354
Quoted 9 lines
kernel/trace/trace_seq.c +7
-1+ +if (unlikely (seq_buf_has_overflowed (&s->seq))) { + s->seq.len = save_len; + s->full =1 ; +return 0 ; } -return cnt; + +return ret;
Therefore we need something like:
return s->seq.len - save_len;
Quoted 22 lines
kernel/trace/trace_seq.c +4
-2}EXPORT_SYMBOL_GPL (trace_seq_putmem_hex);@@ -355,30 +369,28 @@ EXPORT_SYMBOL_GPL(trace_seq_putmem_hex);*/ int trace_seq_path (struct trace_seq *s,const struct path *path) { -unsigned char *p; +unsigned int save_len = s->seq.len; +int ret;if (s->full)return 0 ; +__trace_seq_init (s); +if (TRACE_SEQ_BUF_LEFT (s) <1 ) { s->full =1 ;return 0 ; } - p =d_path (path, s->buffer + s->len,PAGE_SIZE - s->len);
kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_putmem_hex); · line 385
Quoted 10 lines
kernel/trace/trace_seq.c +1
-9-if (!IS_ERR (p)) { - p =mangle_path (s->buffer + s->len, p,"\n" ); -if (p) { - s->len = p - s->buffer; -return 1 ; - } - }else { - s->buffer[s->len++] ='?' ; -return 1 ; + ret =seq_buf_path (&s->seq, path);
This returns zero on sucess.
kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_putmem_hex); · line 393
Quoted 9 lines
kernel/trace/trace_seq.c +5
-2+if (unlikely (seq_buf_has_overflowed (&s->seq))) { + s->seq.len = save_len; + s->full =1 ; +return 0 ; } - s->full =1 ; -return 0 ; +return ret;
and we want to return 1 on success =>
return 1;
kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_putmem_hex); · line 395
Quoted 2 lines
kernel/trace/trace_seq.c +0
-0}EXPORT_SYMBOL_GPL (trace_seq_path);
Best Regards,
Petr
PS: I have to leave for a bit now. I hope that I will be able to look at the other patches later today.
Steven Rostedt
maintainerRe: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
Quoted 10 lines · On Mon, 10 Nov 2014 14:53:30 +0100 Petr Mladek <[email protected]> wrote:
include/linux/seq_buf.h line 56
Quoted 7 lines
include/linux/seq_buf.h new file +7
-0+/* +* How much buffer is left on the seq_buf? +*/ +static inline unsigned int +seq_buf_buffer_left (struct seq_buf *s) +{ +return (s->size -1 ) - s->len;This should be
Quoted 6 lines
if (seq_buf_has_overflowed(s) return 0; return (s->size - 1) - s->len;otherwise, it would return
UNIT_MAXfor the overflown state. If I am not mistaken.
I guess I could add that. Probably the safer bet. Or document it that this is undefined if buffer has overflowed. I have to check how my use cases worked.
Probably best to add the overflow check anyway.
Quoted 39 lines
[...]
Quoted 5 lines
kernel/trace/seq_buf.c new file +0
-0[...]
Quoted 15 lines
kernel/trace/seq_buf.c new file +15
-0+ +/** +* seq_buf_bitmask - write a bitmask array in its ASCII representation +* @s: seq_buf descriptor +* @maskp: points to an array of unsigned longs that represent a bitmask +* @nmaskbits: The number of bits that are valid in @maskp +* +* Writes a ASCII representation of a bitmask string into @s. +* +* Returns zero on success, -1 on overflow. +*/ +int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp, +int nmaskbits) +{ +unsigned int len =seq_buf_buffer_left (s);kernel/trace/seq_buf.c line 107
Quoted 10 lines
kernel/trace/seq_buf.c new file +10
-0+int ret; + +WARN_ON (s->size ==0 ); + +/* +* The last byte of the buffer is used to determine if we +* overflowed or not. +*/ +if (len >1 ) { + ret =bitmap_scnprintf (s->buffer, len, maskp, nmaskbits);It should be:
Quoted 4 lines
ret = bitmap_scnprintf(s->buffer + s->len, len, maskp, nmaskbits);otherwise, we would write to the beginning to the buffer.
You are correct. But I'll make that a separate patch. This is just keeping the bug that was in the original code.
Quoted 47 lines
Quoted 10 lines
kernel/trace/seq_buf.c new file +9
-0+if (ret < len) { + s->len += ret; +return 0 ; + } + } +seq_buf_set_overflow (s); +return -1 ; +} +[...]
Quoted 4 lines
kernel/trace/trace_seq.c +0
-0[...]
Quoted 6 lines
kernel/trace/trace_seq.c +1
-1@@ -144,23 +160,24 @@ EXPORT_SYMBOL_GPL(trace_seq_bitmask);*/ int trace_seq_vprintf (struct trace_seq *s,const char *fmt,va_list args) { -unsigned int len =TRACE_SEQ_BUF_LEFT (s); +unsigned int save_len = s->seq.len;kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_bitmask); · line 171
Quoted 10 lines
kernel/trace/trace_seq.c +4
-2int ret; -if (s->full || !len) +if (s->full)return 0 ; - ret =vsnprintf (s->buffer + s->len, len, fmt, args); +__trace_seq_init (s); + + ret =seq_buf_vprintf (&s->seq, fmt, args);Note that this returns 0 on success => we do not need to store it
Quoted 8 lines
kernel/trace/trace_seq.c +2
-1/* If we can't write it all, don't bother writing anything */ -if (ret >= len) { +if (unlikely (seq_buf_has_overflowed (&s->seq))) { + s->seq.len = save_len; s->full =1 ;return 0 ; }
Quoted 8 lines
kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_bitmask); · line 180
Quoted 4 lines
kernel/trace/trace_seq.c +1
-3- s->len += ret; - -return len; +return ret;Instead, we have to do something like:
return s->seq.len - save_len;
Actually, I need to make the trace_seq_*() functions return the same as the seq_buf_*() functions.
I'll update this for now, but it's gotta change later. Probably why I wasn't so careful about it.
Quoted 31 lines
Quoted 10 lines
kernel/trace/trace_seq.c +1
-1}EXPORT_SYMBOL_GPL (trace_seq_vprintf);@@ -183,23 +200,24 @@ EXPORT_SYMBOL_GPL(trace_seq_vprintf);*/ int trace_seq_bprintf (struct trace_seq *s,const char *fmt,const u32 *binary) { -unsigned int len =TRACE_SEQ_BUF_LEFT (s); +unsigned int save_len = s->seq.len;kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_vprintf); · line 211
Quoted 10 lines
kernel/trace/trace_seq.c +4
-2int ret; -if (s->full || !len) +if (s->full)return 0 ; - ret =bstr_printf (s->buffer + s->len, len, fmt, binary); +__trace_seq_init (s); + + ret =seq_buf_bprintf (&s->seq, fmt, binary);Same here, it returns 0 on success => no need to store.
Quoted 8 lines
kernel/trace/trace_seq.c +2
-1/* If we can't write it all, don't bother writing anything */ -if (ret >= len) { +if (unlikely (seq_buf_has_overflowed (&s->seq))) { + s->seq.len = save_len; s->full =1 ;return 0 ; }
Quoted 6 lines
kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_bitmask); · line 180
Quoted 4 lines
kernel/trace/trace_seq.c +1
-3- s->len += ret; - -return len; +return ret;and
same thing.
Quoted 70 lines
return s->seq.len - save_len;Quoted 3 lines
kernel/trace/trace_seq.c +0
-0}EXPORT_SYMBOL_GPL (trace_seq_bprintf);[...]
Quoted 36 lines
/**
*trace_seq_putmem_hex- write raw memory into the buffer in ASCII hex
* @s: trace sequence descriptorkernel/trace/trace_seq.c +2
-23@@ -309,35 +328,30 @@ EXPORT_SYMBOL_GPL(trace_seq_putmem);int trace_seq_putmem_hex (struct trace_seq *s,const void *mem,unsigned int len) { -unsigned char hex[HEX_CHARS ]; -const unsigned char *data = mem; -unsigned int start_len; -int i, j; -int cnt =0 ; +unsigned int save_len = s->seq.len; +int ret;if (s->full)return 0 ; -while (len) { - start_len =min (len,HEX_CHARS -1 ); -#ifdef __BIG_ENDIAN -for (i =0 , j =0 ; i < start_len; i++) { -#else -for (i = start_len-1 , j =0 ; i >=0 ; i--) { -#endif - hex[j++] =hex_asc_hi (data[i]); - hex[j++] =hex_asc_lo (data[i]); - } -if (WARN_ON_ONCE (j ==0 || j/2 > len)) -break ; - -/* j increments twice per loop */ - len -= j /2 ; - hex[j++] =' ' ; - - cnt +=trace_seq_putmem (s, hex, j);kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_putmem); · line 346
Quoted 10 lines
kernel/trace/trace_seq.c +10
-0+__trace_seq_init (s); + +/* Each byte is represented by two chars */ +if (len *2 >TRACE_SEQ_BUF_LEFT (s)) { + s->full =1 ; +return 0 ; + } + +/* The added spaces can still cause an overflow */ + ret =seq_buf_putmem_hex (&s->seq, mem, len);and here, it returns zero on success
kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_putmem); · line 354
Quoted 9 lines
kernel/trace/trace_seq.c +7
-1+ +if (unlikely (seq_buf_has_overflowed (&s->seq))) { + s->seq.len = save_len; + s->full =1 ; +return 0 ; } -return cnt; + +return ret;Therefore we need something like:
Quoted 2 lines
return s->seq.len - save_len;
Hmm, I may make the trace_seq_*() functions not return length written first, before pulling out the seq_buf_*() code. That is, make the trace_seq_*() behave more like what the seq_buf_*() code does first, before pulling out the seq_buf_*() code.
Quoted 52 lines
Quoted 22 lines
kernel/trace/trace_seq.c +4
-2}EXPORT_SYMBOL_GPL (trace_seq_putmem_hex);@@ -355,30 +369,28 @@ EXPORT_SYMBOL_GPL(trace_seq_putmem_hex);*/ int trace_seq_path (struct trace_seq *s,const struct path *path) { -unsigned char *p; +unsigned int save_len = s->seq.len; +int ret;if (s->full)return 0 ; +__trace_seq_init (s); +if (TRACE_SEQ_BUF_LEFT (s) <1 ) { s->full =1 ;return 0 ; } - p =d_path (path, s->buffer + s->len,PAGE_SIZE - s->len);kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_putmem_hex); · line 385
Quoted 10 lines
kernel/trace/trace_seq.c +1
-9-if (!IS_ERR (p)) { - p =mangle_path (s->buffer + s->len, p,"\n" ); -if (p) { - s->len = p - s->buffer; -return 1 ; - } - }else { - s->buffer[s->len++] ='?' ; -return 1 ; + ret =seq_buf_path (&s->seq, path);This returns zero on sucess.
kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_putmem_hex); · line 393
Quoted 9 lines
kernel/trace/trace_seq.c +5
-2+if (unlikely (seq_buf_has_overflowed (&s->seq))) { + s->seq.len = save_len; + s->full =1 ; +return 0 ; } - s->full =1 ; -return 0 ; +return ret;and we want to return 1 on success =>
return 1;kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_putmem_hex); · line 395
Quoted 2 lines
kernel/trace/trace_seq.c +0
-0}EXPORT_SYMBOL_GPL (trace_seq_path);
Quoted 6 lines
Best Regards,
PetrPS: I have to leave for a bit now. I hope that I will be able to look at the other patches later today.
Thanks for the review. Most of this will be fixed by doing the change to the return value of the trace_seq_*() code first. I think I'll do that.
-- Steve
Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
Quoted 17 lines · Steven Rostedt
Quoted 14 lines · On Mon, 10 Nov 2014 14:53:30 +0100 Petr Mladek <[email protected]> wrote:
include/linux/seq_buf.h line 56
Quoted 7 lines
include/linux/seq_buf.h new file +7
-0+/* +* How much buffer is left on the seq_buf? +*/ +static inline unsigned int +seq_buf_buffer_left (struct seq_buf *s) +{ +return (s->size -1 ) - s->len;This should be
if (seq_buf_has_overflowed(s) return 0; return (s->size - 1) - s->len;
Quoted 8 lines
Quoted 2 lines
otherwise, it would return
UNIT_MAXfor the overflown state. If I am not mistaken.I guess I could add that. Probably the safer bet. Or document it that this is undefined if buffer has overflowed. I have to check how my use cases worked.
Probably best to add the overflow check anyway.
I vote for it :-)
Quoted 38 lines
Quoted 38 lines
[...]
Quoted 5 lines
kernel/trace/seq_buf.c new file +0
-0[...]
Quoted 15 lines
kernel/trace/seq_buf.c new file +15
-0+ +/** +* seq_buf_bitmask - write a bitmask array in its ASCII representation +* @s: seq_buf descriptor +* @maskp: points to an array of unsigned longs that represent a bitmask +* @nmaskbits: The number of bits that are valid in @maskp +* +* Writes a ASCII representation of a bitmask string into @s. +* +* Returns zero on success, -1 on overflow. +*/ +int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp, +int nmaskbits) +{ +unsigned int len =seq_buf_buffer_left (s);kernel/trace/seq_buf.c line 107
Quoted 10 lines
kernel/trace/seq_buf.c new file +10
-0+int ret; + +WARN_ON (s->size ==0 ); + +/* +* The last byte of the buffer is used to determine if we +* overflowed or not. +*/ +if (len >1 ) { + ret =bitmap_scnprintf (s->buffer, len, maskp, nmaskbits);It should be:
Quoted 7 lines
Quoted 4 lines
ret = bitmap_scnprintf(s->buffer + s->len, len, maskp, nmaskbits);otherwise, we would write to the beginning to the buffer.
You are correct. But I'll make that a separate patch. This is just keeping the bug that was in the original code.
Fair enough.
Quoted 59 lines
Quoted 47 lines
Quoted 10 lines
kernel/trace/seq_buf.c new file +9
-0+if (ret < len) { + s->len += ret; +return 0 ; + } + } +seq_buf_set_overflow (s); +return -1 ; +} +[...]
Quoted 4 lines
kernel/trace/trace_seq.c +0
-0[...]
Quoted 6 lines
kernel/trace/trace_seq.c +1
-1@@ -144,23 +160,24 @@ EXPORT_SYMBOL_GPL(trace_seq_bitmask);*/ int trace_seq_vprintf (struct trace_seq *s,const char *fmt,va_list args) { -unsigned int len =TRACE_SEQ_BUF_LEFT (s); +unsigned int save_len = s->seq.len;kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_bitmask); · line 171
Quoted 10 lines
kernel/trace/trace_seq.c +4
-2int ret; -if (s->full || !len) +if (s->full)return 0 ; - ret =vsnprintf (s->buffer + s->len, len, fmt, args); +__trace_seq_init (s); + + ret =seq_buf_vprintf (&s->seq, fmt, args);Note that this returns 0 on success => we do not need to store it
Quoted 8 lines
kernel/trace/trace_seq.c +2
-1/* If we can't write it all, don't bother writing anything */ -if (ret >= len) { +if (unlikely (seq_buf_has_overflowed (&s->seq))) { + s->seq.len = save_len; s->full =1 ;return 0 ; }Quoted 8 lines
kernel/trace/trace_seq.c EXPORT_SYMBOL_GPL(trace_seq_bitmask); · line 180
Quoted 4 lines
kernel/trace/trace_seq.c +1
-3- s->len += ret; - -return len; +return ret;Instead, we have to do something like:
return s->seq.len - save_len;Actually, I need to make the trace_seq_*() functions return the same as the seq_buf_*() functions.
Quoted 7 lines
I'll update this for now, but it's gotta change later. Probably why I wasn't so careful about it.
Hmm, I may make the trace_seq_*() functions not return length written first, before pulling out the seq_buf_*() code. That is, make the trace_seq_*() behave more like what the seq_buf_*() code does first, before pulling out the seq_buf_*() code.
Sounds like the best solution if it does not cause too many changes in the trace_seq() callers.
Best Regards,
Petr
Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
In reply to Steven RostedtQuoted 8 lines · Steven Rostedt
Quoted 5 lines · On Wed, 5 Nov 2014 15:22:22 +0100 Petr Mladek <[email protected]> wrote:
Quoted 1 line · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
Also I would add an explanation of the overall logic. If I get it correctly from the code, it is:
Quoted 8 lines
Quoted 4 lines
/*
* The last byte of the buffer is used to detect an overflow in some
* operations. Therefore, the buffer offers (@size - 1) bytes for valid
* data.Well, this will change in the future. And it is commented with the
seq_buf_has_overflowed()function. I don't want to comment about it with the structure.
Fair enough.
Quoted 11 lines
Quoted 8 lines
kernel/trace/seq_buf.c line 20
Quoted 6 lines
+ */
kernel/trace/seq_buf.c new file +5
-0+#include <linux/uaccess.h> +#include <linux/seq_file.h> +#include <linux/seq_buf.h> + +/* How much buffer is left on the seq_buf? */ I would write the following to explain the -1:
Later patches gets rid of the -1. It's -1 because
seq_fileis -1 as well.
Yup. Let's leave it as is.
Quoted 11 lines
Quoted 8 lines
/* How much buffer is left for valid data */
Quoted 1 line
+#define
SEQ_BUF_LEFT(s)(((s)->size - 1) - (s)->len)Hmm, it might overflow when the buffer has overflown (
s->len==s->size) or when the buffer is not initialized (s->size== 0). Note that the result should be unsigned int.The two places that use it is "unsigned int" so that should not be a problem.
It might overflow. If ("size == len"), the result will be -1 which is UINT_MAX.
Well, this should not happen if callers check the overflow before any use. Also we are going to remove the -1 in the followup patches. I am fine with it after all.
Quoted 25 lines
Quoted 16 lines
Quoted 16 lines
kernel/trace/seq_buf.c new file +16
-0+ +/** +* seq_buf_puts - sequence printing of simple string +* @s: seq_buf descriptor +* @str: simple string to record +* +* Copy a simple string into the sequence buffer. +* +* Returns zero on success, -1 on overflow +*/ +int seq_buf_puts (struct seq_buf *s,const char *str) +{ +unsigned int len =strlen (str); + +WARN_ON (s->size ==0 ); +Quoted 8 lines
kernel/trace/seq_buf.c line 171
Quoted 5 lines
kernel/trace/seq_buf.c new file +5
-0+if (s->len + len < s->size) { +memcpy (s->buffer + s->len, str, len); + s->len += len; +return 0 ; + }We might want to copy the maximum possible number of bytes. It will then behave the same as the other functions.
Quoted 1 line
I'm converting all this to be like
seq_filein the other patches.
Fair enough.
Quoted 46 lines
Quoted 38 lines
Quoted 28 lines
+ *
+ * Returns-EFAULTif the copy to userspace fails.
+ */kernel/trace/seq_buf.c new file +23
-0+int seq_buf_to_user (struct seq_buf *s,char __user *ubuf,int cnt) +{ +int len; +int ret; + +if (!cnt) +return 0 ; + +if (s->len <= s->readpos) +return -EBUSY ; + + len = s->len - s->readpos; +if (cnt > len) + cnt = len; + ret =copy_to_user (ubuf, s->buffer + s->readpos, cnt); +if (ret == cnt) +return -EFAULT ; + + cnt -= ret; + + s->readpos += cnt; +return cnt; +}[...]
Quoted 7 lines
kernel/trace/trace_seq.c +0
-0@@ -27,10 +27,19 @@#include <linux/trace_seq.h> Quoted 7 lines
kernel/trace/trace_seq.c line 30
Quoted 3 lines
kernel/trace/trace_seq.c +1
-1/* How much buffer is left on the trace_seq? */ -#define TRACE_SEQ_BUF_LEFT (s) ((PAGE_SIZE - 1) - (s)->len) +#define TRACE_SEQ_BUF_LEFT (s) ((PAGE_SIZE - 1) - (s)->seq.len)This might overflow when
s->len==PAGE_SIZE. I think that it newer happenes because we always checks->fullbefore. The question is if we really want to depend on this.
Quoted 2 lines
Yeah, we should make this check
seq_bufitself. Maybe make a static inline function that is inseq_buf.h.
The inline function in seq_buf.h looks like a good idea.
Quoted 56 lines
Quoted 50 lines
Quoted 50 lines
kernel/trace/trace_seq.c +18
-7/* How much buffer is written? */ -#define TRACE_SEQ_BUF_USED (s) min((s)->len, (unsigned int)(PAGE_SIZE - 1)) +#define TRACE_SEQ_BUF_USED (s) min((s)->seq.len, (unsigned int)(PAGE_SIZE - 1)) + +/* +* trace_seq should work with being initialized with 0s. +*/ +static inline void __trace_seq_init (struct trace_seq *s) +{ +if (unlikely (!s->seq.size)) +trace_seq_init (s); +}/** * trace_print_seq - move the contents of trace_seq into a seq_file @@ -43,10 +52,11 @@*/ int trace_print_seq (struct seq_file *m,struct trace_seq *s) { -unsigned int len =TRACE_SEQ_BUF_USED (s);int ret; - ret =seq_write (m, s->buffer, len); +__trace_seq_init (s); + + ret =seq_buf_print_seq (m, &s->seq);/* * Only reset this buffer if we successfully wrote to the @@ -77,25 +87,25 @@ int trace_print_seq(struct seq_file *m, struct trace_seq *s)*/ int trace_seq_printf (struct trace_seq *s,const char *fmt, ...) { -unsigned int len =TRACE_SEQ_BUF_LEFT (s); +unsigned int save_len = s->seq.len;va_list ap; -int ret; -if (s->full || !len) +if (s->full)return 0 ; +__trace_seq_init (s); +va_start (ap, fmt); - ret =vsnprintf (s->buffer + s->len, len, fmt, ap); +seq_buf_vprintf (&s->seq, fmt, ap);va_end (ap);Quoted 5 lines
kernel/trace/trace_seq.c int trace_print_seq(struct seq_file *m, struct trace_seq *s) · line 103
Quoted 3 lines
kernel/trace/trace_seq.c +1
-1/* If we can't write it all, don't bother writing anything */ -if (ret >= len) { +if (unlikely (seq_buf_has_overflowed (&s->seq))) {We might check the return value from
seq_buf_vprintf()here.
Quoted 4 lines
No, we are working to get rid of the return values for the seq_*() functions (with a few exceptions). One now must check if the buffer has overflowed, and not the return value of the seq_*() functions themselves.
I see.
Quoted 1 line
There's already patches out to convert the
seq_filecalls as well.
Good to know.
Best Regards,
Petr
Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
In reply to Steven RostedtQuoted 26 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
Create a
seq_buflayer thattrace_seqsits on. Theseq_bufwill not be limited to page size. This will allow other usages ofseq_bufinstead of a hard setPAGE_SIZEone thattrace_seqhas.Signed-off-by Steven Rostedt <[email protected]>--- include/linux/seq_buf.h | 72 ++++++++ include/linux/trace_seq.h | 10 +- kernel/trace/Makefile | 1 + kernel/trace/seq_buf.c | 341 +++++++++++++++++++++++++++++++++++ kernel/trace/trace.c | 39 ++-- kernel/trace/trace_events.c | 6 +- kernel/trace/trace_functions_graph.c | 6 +- kernel/trace/trace_seq.c | 184 +++++++++---------- 8 files changed, 534 insertions(+), 125 deletions(-) create mode 100644 include/linux/seq_buf.h create mode 100644 kernel/trace/seq_buf.cinclude/linux/seq_buf.h new file +0
-0
include/linux/seq_buf.h line 6
Quoted 6 lines
include/linux/seq_buf.h new file +6
-0@@ -0,0 +1,72 @@ +#ifndef _LINUX_SEQ_BUF_H +#define _LINUX_SEQ_BUF_H + +#include <linux/fs.h> + +#include <asm/page.h>
One more small thing. We do not need this include because seq_buf does not use the PAGE_SIZE.
Best Regards,
Petr
Steven Rostedt
maintainerRe: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
Quoted 5 lines · On Wed, 5 Nov 2014 15:26:20 +0100 Petr Mladek <[email protected]> wrote:
Quoted 5 lines
index 000000000000..97872154d51c
include/linux/seq_buf.h new file +1
-0@@ -0,0 +1,72 @@ +#ifndef _LINUX_SEQ_BUF_H
Quoted 8 lines
include/linux/seq_buf.h line 6
Quoted 5 lines
include/linux/seq_buf.h new file +5
-0+#define _LINUX_SEQ_BUF_H + +#include <linux/fs.h> + +#include <asm/page.h> One more small thing. We do not need this include because
seq_bufdoes not use thePAGE_SIZE.
Good catch.
I'll remove it.
-- Steve
Steven Rostedt
maintainerRFC PATCH v3 4/12 tracing: Convert seq_buf_path() to be like seq_path()
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
Rewrite seq_buf_path() like it is done in seq_path() and allow it to accept any escape character instead of just "\n".
Making seq_buf_path() like seq_path() will help prevent problems when converting seq_file to use the seq_buf logic.
--- include/linux/seq_buf.h | 2 +- kernel/trace/seq_buf.c | 30 ++++++++++++++++-------------- kernel/trace/trace_seq.c | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-)
include/linux/seq_buf.h +1 -1
@@ -64,7 +64,7 @@ extern int seq_buf_putc(struct seq_buf *s, unsigned char c);extern int seq_buf_putmem (struct seq_buf *s,const void *mem,unsigned int len);extern int seq_buf_putmem_hex (struct seq_buf *s,const void *mem,unsigned int len); -extern int seq_buf_path (struct seq_buf *s,const struct path *path); +extern int seq_buf_path (struct seq_buf *s,const struct path *path,const char *esc);extern int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp,int nmaskbits);
kernel/trace/seq_buf.c +16 -14
@@ -272,28 +272,30 @@ int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,* seq_buf_path - copy a path into the sequence buffer * @s: seq_buf descriptor * @path: path to write into the sequence buffer. +* @esc: set of characters to escape in the output * * Write a path name into the sequence buffer. * * Returns zero on success, -1 on overflow */ -int seq_buf_path (struct seq_buf *s,const struct path *path) +int seq_buf_path (struct seq_buf *s,const struct path *path,const char *esc) { -unsigned int len =SEQ_BUF_LEFT (s); -unsigned char *p; - -WARN_ON (s->size ==0 ); - - p =d_path (path, s->buffer + s->len, len); -if (!IS_ERR (p)) { - p =mangle_path (s->buffer + s->len, p,"\n" ); -if (p) { - s->len = p - s->buffer; -return 0 ; +char *buf = s->buffer + s->len; +size_t size =SEQ_BUF_LEFT (s); +int res =-1 ; + +if (size) { +char *p =d_path (path, buf, size); +if (!IS_ERR (p)) { +char *end =mangle_path (buf, p, esc); +if (end) + res = end - buf; } } -seq_buf_set_overflow (s); -return -1 ; +if (res >0 ) + s->len += res; + +return res; }/**
kernel/trace/trace_seq.c +1 -1
@@ -382,7 +382,7 @@ int trace_seq_path(struct trace_seq *s, const struct path *path)return 0 ; } - ret =seq_buf_path (&s->seq, path); + ret =seq_buf_path (&s->seq, path,"\n" );if (unlikely (seq_buf_has_overflowed (&s->seq))) { s->seq.len = save_len;
Signature · 1 line
2.1.1
Re: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
Quoted 40 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
Rewrite
seq_buf_path()like it is done inseq_path()and allow it to accept any escape character instead of just "\n".Making
seq_buf_path()likeseq_path()will help prevent problems when convertingseq_fileto use theseq_buflogic.Signed-off-by Steven Rostedt <[email protected]>--- include/linux/seq_buf.h | 2 +- kernel/trace/seq_buf.c | 30 ++++++++++++++++-------------- kernel/trace/trace_seq.c | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-)include/linux/seq_buf.h +1
-1@@ -64,7 +64,7 @@ extern int seq_buf_putc(struct seq_buf *s, unsigned char c);extern int seq_buf_putmem (struct seq_buf *s,const void *mem,unsigned int len);extern int seq_buf_putmem_hex (struct seq_buf *s,const void *mem,unsigned int len); -extern int seq_buf_path (struct seq_buf *s,const struct path *path); +extern int seq_buf_path (struct seq_buf *s,const struct path *path,const char *esc);extern int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp,int nmaskbits);kernel/trace/seq_buf.c +1
-0@@ -272,28 +272,30 @@ int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,* seq_buf_path - copy a path into the sequence buffer * @s: seq_buf descriptor * @path: path to write into the sequence buffer. +* @esc: set of characters to escape in the output * * Write a path name into the sequence buffer. *
kernel/trace/seq_buf.c int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, · line 286
Quoted 10 lines
kernel/trace/seq_buf.c +1
-5* Returns zero on success, -1 on overflow */ -int seq_buf_path (struct seq_buf *s,const struct path *path) +int seq_buf_path (struct seq_buf *s,const struct path *path,const char *esc) { -unsigned int len =SEQ_BUF_LEFT (s); -unsigned char *p; - -WARN_ON (s->size ==0 );
I would keep this check.
kernel/trace/seq_buf.c int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, · line 284
Quoted 8 lines
kernel/trace/seq_buf.c +2
-6- p =d_path (path, s->buffer + s->len, len); -if (!IS_ERR (p)) { - p =mangle_path (s->buffer + s->len, p,"\n" ); -if (p) { - s->len = p - s->buffer; -return 0 ; +char *buf = s->buffer + s->len; +size_t size =SEQ_BUF_LEFT (s);
I would use the variable name "len" to make it consistent with the other fucntions in seq_buf.c.
kernel/trace/seq_buf.c int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, · line 295
Quoted 11 lines
kernel/trace/seq_buf.c +8
-1+int res =-1 ; + +if (size) { +char *p =d_path (path, buf, size); +if (!IS_ERR (p)) { +char *end =mangle_path (buf, p, esc); +if (end) + res = end - buf; } } -seq_buf_set_overflow (s);
We still should set overflow on failure.
kernel/trace/seq_buf.c int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, · line 298
Quoted 5 lines
kernel/trace/seq_buf.c +4
-1-return -1 ; +if (res >0 ) + s->len += res; + +return res;
It returns -1 on failure and the number of written characters on success. This is incompatible with the other seq_buf functions and with the comment above this function. Also it changes the return value from trace_seq_path().
I do not mind about the used scheme but I think that we should make it consistent.
Best Regards,
Petr
Steven Rostedt
maintainerRe: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
Quoted 10 lines · On Wed, 5 Nov 2014 15:45:53 +0100 Petr Mladek <[email protected]> wrote:
kernel/trace/seq_buf.c int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, · line 285
Quoted 8 lines
*/
kernel/trace/seq_buf.c +1
-5-int seq_buf_path (struct seq_buf *s,const struct path *path) +int seq_buf_path (struct seq_buf *s,const struct path *path,const char *esc) { -unsigned int len =SEQ_BUF_LEFT (s); -unsigned char *p; - -WARN_ON (s->size ==0 );I would keep this check.
Yeah, I could.
Quoted 12 lines
kernel/trace/seq_buf.c int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, · line 284
Quoted 9 lines
kernel/trace/seq_buf.c +2
-6- p =d_path (path, s->buffer + s->len, len); -if (!IS_ERR (p)) { - p =mangle_path (s->buffer + s->len, p,"\n" ); -if (p) { - s->len = p - s->buffer; -return 0 ; +char *buf = s->buffer + s->len; +size_t size =SEQ_BUF_LEFT (s);I would use the variable name "len" to make it consistent with the other fucntions in
seq_buf.c.
Note, seq_path() is a different beast than the other seq_*() functions (this will be keeping a return code). And the inconsistency is in seq_file.c as well. I'm not saying we shouldn't keep it consistent. But as this patch is to make seq_buf like seq_file, I'll keep the inconsistencies the same too.
We can always do a clean up later.
Quoted 14 lines
kernel/trace/seq_buf.c int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, · line 295
Quoted 12 lines
kernel/trace/seq_buf.c +8
-1+int res =-1 ; + +if (size) { +char *p =d_path (path, buf, size); +if (!IS_ERR (p)) { +char *end =mangle_path (buf, p, esc); +if (end) + res = end - buf; } } -seq_buf_set_overflow (s);We still should set overflow on failure.
Again, this is different in seq_file too. I'm leaving it as is.
Quoted 12 lines
kernel/trace/seq_buf.c int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, · line 298
Quoted 6 lines
kernel/trace/seq_buf.c +4
-1-return -1 ; +if (res >0 ) + s->len += res; + +return res;It returns -1 on failure and the number of written characters on success. This is incompatible with the other
seq_buffunctions and with the comment above this function. Also it changes the return value fromtrace_seq_path().
Quoted 3 lines
I do not mind about the used scheme but I think that we should make it consistent.
As seq_file has had this inconsistency for a long time, and this code is to try to merge the code between trace_seq and seq_file, I'm going to follow seq_file as that has been around much longer than trace_seq.
-- Steve
Re: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
Quoted 15 lines · Steven Rostedt
Quoted 10 lines · On Wed, 5 Nov 2014 15:45:53 +0100 Petr Mladek <[email protected]> wrote:
kernel/trace/seq_buf.c int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, · line 285
Quoted 8 lines
*/
kernel/trace/seq_buf.c +1
-5-int seq_buf_path (struct seq_buf *s,const struct path *path) +int seq_buf_path (struct seq_buf *s,const struct path *path,const char *esc) { -unsigned int len =SEQ_BUF_LEFT (s); -unsigned char *p; - -WARN_ON (s->size ==0 );I would keep this check.
Quoted 1 line
Yeah, I could.
great :-)
Quoted 13 lines
Quoted 12 lines
kernel/trace/seq_buf.c int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, · line 284
Quoted 9 lines
kernel/trace/seq_buf.c +2
-6- p =d_path (path, s->buffer + s->len, len); -if (!IS_ERR (p)) { - p =mangle_path (s->buffer + s->len, p,"\n" ); -if (p) { - s->len = p - s->buffer; -return 0 ; +char *buf = s->buffer + s->len; +size_t size =SEQ_BUF_LEFT (s);I would use the variable name "len" to make it consistent with the other fucntions in
seq_buf.c.
Quoted 5 lines
Note,
seq_path()is a different beast than the other seq_*() functions (this will be keeping a return code). And the inconsistency is inseq_file.cas well. I'm not saying we shouldn't keep it consistent. But as this patch is to makeseq_buflikeseq_file, I'll keep the inconsistencies the same too.
Ah, I have missed this.
Quoted 1 line
We can always do a clean up later.
Fair enough. The result of this patch set (safe printing of backtraces from all CPUs) is more important than this clean up.
[...]
Quoted 12 lines
Quoted 12 lines
kernel/trace/seq_buf.c int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, · line 298
Quoted 6 lines
kernel/trace/seq_buf.c +4
-1-return -1 ; +if (res >0 ) + s->len += res; + +return res;It returns -1 on failure and the number of written characters on success. This is incompatible with the other
seq_buffunctions and with the comment above this function. Also it changes the return value fromtrace_seq_path().
Quoted 7 lines
Quoted 3 lines
I do not mind about the used scheme but I think that we should make it consistent.
As
seq_filehas had this inconsistency for a long time, and this code is to try to merge the code betweentrace_seqandseq_file, I'm going to followseq_fileas that has been around much longer thantrace_seq.
I see. Well, we still need to fix trace_seq_path() or its callers. For example, seq_print_user_ip() checks trace_seq_path() return value and expects 0 on failure.
Best Regards,
Petr
Steven Rostedt
maintainerRe: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
Quoted 3 lines · On Thu, 6 Nov 2014 15:18:22 +0100 Petr Mladek <[email protected]> wrote:
I see. Well, we still need to fix
trace_seq_path()or its callers. For example,seq_print_user_ip()checkstrace_seq_path()return value and expects 0 on failure.
Crap, thanks for pointing that out. Luckily, there's only one user, and it's not used much. It's the user backtrace and that only prints if a file is found, and this would only cause the offset not to be printed.
-- Steve
Re: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
In reply to Steven RostedtQuoted 33 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
Rewrite
seq_buf_path()like it is done inseq_path()and allow it to accept any escape character instead of just "\n".Making
seq_buf_path()likeseq_path()will help prevent problems when convertingseq_fileto use theseq_buflogic.Signed-off-by Steven Rostedt <[email protected]>--- include/linux/seq_buf.h | 2 +- kernel/trace/seq_buf.c | 30 ++++++++++++++++-------------- kernel/trace/trace_seq.c | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-)include/linux/seq_buf.h +1
-1@@ -64,7 +64,7 @@ extern int seq_buf_putc(struct seq_buf *s, unsigned char c);extern int seq_buf_putmem (struct seq_buf *s,const void *mem,unsigned int len);extern int seq_buf_putmem_hex (struct seq_buf *s,const void *mem,unsigned int len); -extern int seq_buf_path (struct seq_buf *s,const struct path *path); +extern int seq_buf_path (struct seq_buf *s,const struct path *path,const char *esc);extern int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp,int nmaskbits);kernel/trace/seq_buf.c +0
-0
kernel/trace/seq_buf.c int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, · line 279
Quoted 8 lines
kernel/trace/seq_buf.c +1
-0@@ -272,28 +272,30 @@ int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,* seq_buf_path - copy a path into the sequence buffer * @s: seq_buf descriptor * @path: path to write into the sequence buffer. +* @esc: set of characters to escape in the output * * Write a path name into the sequence buffer. * * Returns zero on success, -1 on overflow
Ah, I have missed this. We should also update this comment to reflect the change. I would also add a note that it is because of compatibility with seq_path(). So, something like:
* Return the number of written bytes on success, -1 on overflow *
* The behavior is consistent with seq_path()
Quoted 4 lines
kernel/trace/seq_buf.c +1
-1*/ -int seq_buf_path (struct seq_buf *s,const struct path *path) +int seq_buf_path (struct seq_buf *s,const struct path *path,const char *esc) {
[...]
Quoted 4 lines
kernel/trace/seq_buf.c +4
-0+if (size) { +char *p =d_path (path, buf, size); +if (!IS_ERR (p)) { +char *end =mangle_path (buf, p, esc);
kernel/trace/seq_buf.c int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, · line 298
Quoted 10 lines
kernel/trace/seq_buf.c +6
-2+if (end) + res = end - buf; } } -seq_buf_set_overflow (s); -return -1 ; +if (res >0 ) + s->len += res; + +return res;
Best Regards,
Petr
Re: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
I made a few touch ups on this patch.
-- Steve
Quoted 1 line
From
309e8ce4cc1605d3038b16b8e43219a2867f47b1Mon Sep 17 00:00:00 2001
From: "Steven Rostedt (Red Hat)" <[email protected]>
Date: Wed, 29 Oct 2014 13:48:37 -0400
Subject: [PATCH] tracing: Convert seq_buf_path() to be like seq_path()
Rewrite seq_buf_path() like it is done in seq_path() and allow it to accept any escape character instead of just "\n".
Making seq_buf_path() like seq_path() will help prevent problems when converting seq_file to use the seq_buf logic.
--- include/linux/seq_buf.h | 2 +- kernel/trace/seq_buf.c | 26 +++++++++++++++----------- kernel/trace/trace_seq.c | 4 ++-- 3 files changed, 18 insertions(+), 14 deletions(-)
include/linux/seq_buf.h +1 -1
@@ -70,7 +70,7 @@ extern int seq_buf_putc(struct seq_buf *s, unsigned char c);extern int seq_buf_putmem (struct seq_buf *s,const void *mem,unsigned int len);extern int seq_buf_putmem_hex (struct seq_buf *s,const void *mem,unsigned int len); -extern int seq_buf_path (struct seq_buf *s,const struct path *path); +extern int seq_buf_path (struct seq_buf *s,const struct path *path,const char *esc);extern int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp,int nmaskbits);
kernel/trace/seq_buf.c +15 -11
@@ -272,28 +272,32 @@ int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,* seq_buf_path - copy a path into the sequence buffer * @s: seq_buf descriptor * @path: path to write into the sequence buffer. +* @esc: set of characters to escape in the output * * Write a path name into the sequence buffer. * * Returns zero on success, -1 on overflow */ -int seq_buf_path (struct seq_buf *s,const struct path *path) +int seq_buf_path (struct seq_buf *s,const struct path *path,const char *esc) { -unsigned int len =seq_buf_buffer_left (s); -unsigned char *p; +char *buf = s->buffer + s->len; +size_t size =seq_buf_buffer_left (s); +int res =-1 ;WARN_ON (s->size ==0 ); - p =d_path (path, s->buffer + s->len, len); -if (!IS_ERR (p)) { - p =mangle_path (s->buffer + s->len, p,"\n" ); -if (p) { - s->len = p - s->buffer; -return 0 ; +if (size) { +char *p =d_path (path, buf, size); +if (!IS_ERR (p)) { +char *end =mangle_path (buf, p, esc); +if (end) + res = end - buf; } } -seq_buf_set_overflow (s); -return -1 ; +if (res >0 ) + s->len += res; + +return res; }/**
kernel/trace/trace_seq.c +2 -2
@@ -382,7 +382,7 @@ int trace_seq_path(struct trace_seq *s, const struct path *path)return 0 ; } - ret =seq_buf_path (&s->seq, path); + ret =seq_buf_path (&s->seq, path,"\n" );if (unlikely (seq_buf_has_overflowed (&s->seq))) { s->seq.len = save_len;
@@ -390,7 +390,7 @@ int trace_seq_path(struct trace_seq *s, const struct path *path)return 0 ; } -return ret; +return 1 ; }EXPORT_SYMBOL_GPL (trace_seq_path);
Signature · 1 line
2.1.1
Petr Mladek
Reviewed-byRe: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
Quoted 45 lines · Steven Rostedt
I made a few touch ups on this patch.
-- Steve
From
309e8ce4cc1605d3038b16b8e43219a2867f47b1Mon Sep 17 00:00:00 2001
From: "Steven Rostedt (Red Hat)" <[email protected]>
Date: Wed, 29 Oct 2014 13:48:37 -0400
Subject: [PATCH] tracing: Convertseq_buf_path()to be likeseq_path()Rewrite
seq_buf_path()like it is done inseq_path()and allow it to accept any escape character instead of just "\n".Making
seq_buf_path()likeseq_path()will help prevent problems when convertingseq_fileto use theseq_buflogic.Tested-by Jiri Kosina <[email protected]>Acked-by Jiri Kosina <[email protected]>Signed-off-by Steven Rostedt <[email protected]>--- include/linux/seq_buf.h | 2 +- kernel/trace/seq_buf.c | 26 +++++++++++++++----------- kernel/trace/trace_seq.c | 4 ++-- 3 files changed, 18 insertions(+), 14 deletions(-)include/linux/seq_buf.h +1
-1@@ -70,7 +70,7 @@ extern int seq_buf_putc(struct seq_buf *s, unsigned char c);extern int seq_buf_putmem (struct seq_buf *s,const void *mem,unsigned int len);extern int seq_buf_putmem_hex (struct seq_buf *s,const void *mem,unsigned int len); -extern int seq_buf_path (struct seq_buf *s,const struct path *path); +extern int seq_buf_path (struct seq_buf *s,const struct path *path,const char *esc);extern int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp,int nmaskbits);kernel/trace/seq_buf.c +0
-0
kernel/trace/seq_buf.c int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, · line 279
Quoted 8 lines
kernel/trace/seq_buf.c +1
-0@@ -272,28 +272,32 @@ int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,* seq_buf_path - copy a path into the sequence buffer * @s: seq_buf descriptor * @path: path to write into the sequence buffer. +* @esc: set of characters to escape in the output * * Write a path name into the sequence buffer. * * Returns zero on success, -1 on overflow
This should be
* Returns the number of written bytes on success, -1 on overflow
This is just a minor issue. I believe the you would fix it. Feel free to add:
Best Regards,
Petr
Quoted 59 lines
kernel/trace/seq_buf.c +14
-11-int seq_buf_path (struct seq_buf *s,const struct path *path) +int seq_buf_path (struct seq_buf *s,const struct path *path,const char *esc) { -unsigned int len =seq_buf_buffer_left (s); -unsigned char *p; +char *buf = s->buffer + s->len; +size_t size =seq_buf_buffer_left (s); +int res =-1 ;WARN_ON (s->size ==0 ); - p =d_path (path, s->buffer + s->len, len); -if (!IS_ERR (p)) { - p =mangle_path (s->buffer + s->len, p,"\n" ); -if (p) { - s->len = p - s->buffer; -return 0 ; +if (size) { +char *p =d_path (path, buf, size); +if (!IS_ERR (p)) { +char *end =mangle_path (buf, p, esc); +if (end) + res = end - buf; } } -seq_buf_set_overflow (s); -return -1 ; +if (res >0 ) + s->len += res; + +return res; }/** kernel/trace/trace_seq.c +2
-2@@ -382,7 +382,7 @@ int trace_seq_path(struct trace_seq *s, const struct path *path)return 0 ; } - ret =seq_buf_path (&s->seq, path); + ret =seq_buf_path (&s->seq, path,"\n" );if (unlikely (seq_buf_has_overflowed (&s->seq))) { s->seq.len = save_len;@@ -390,7 +390,7 @@ int trace_seq_path(struct trace_seq *s, const struct path *path)return 0 ; } -return ret; +return 1 ; }EXPORT_SYMBOL_GPL (trace_seq_path);Signature · 1 line
2.1.1
Steven Rostedt
maintainerRe: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
Quoted 57 lines · On Mon, 10 Nov 2014 15:03:25 +0100 Petr Mladek <[email protected]> wrote:
Quoted 45 lines · Steven Rostedt
I made a few touch ups on this patch.
-- Steve
From
309e8ce4cc1605d3038b16b8e43219a2867f47b1Mon Sep 17 00:00:00 2001
From: "Steven Rostedt (Red Hat)" <[email protected]>
Date: Wed, 29 Oct 2014 13:48:37 -0400
Subject: [PATCH] tracing: Convertseq_buf_path()to be likeseq_path()Rewrite
seq_buf_path()like it is done inseq_path()and allow it to accept any escape character instead of just "\n".Making
seq_buf_path()likeseq_path()will help prevent problems when convertingseq_fileto use theseq_buflogic.Tested-by Jiri Kosina <[email protected]>Acked-by Jiri Kosina <[email protected]>Signed-off-by Steven Rostedt <[email protected]>--- include/linux/seq_buf.h | 2 +- kernel/trace/seq_buf.c | 26 +++++++++++++++----------- kernel/trace/trace_seq.c | 4 ++-- 3 files changed, 18 insertions(+), 14 deletions(-)include/linux/seq_buf.h +1
-1@@ -70,7 +70,7 @@ extern int seq_buf_putc(struct seq_buf *s, unsigned char c);extern int seq_buf_putmem (struct seq_buf *s,const void *mem,unsigned int len);extern int seq_buf_putmem_hex (struct seq_buf *s,const void *mem,unsigned int len); -extern int seq_buf_path (struct seq_buf *s,const struct path *path); +extern int seq_buf_path (struct seq_buf *s,const struct path *path,const char *esc);extern int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp,int nmaskbits);kernel/trace/seq_buf.c +0
-0kernel/trace/seq_buf.c int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, · line 279
Quoted 8 lines
kernel/trace/seq_buf.c +1
-0@@ -272,28 +272,32 @@ int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,* seq_buf_path - copy a path into the sequence buffer * @s: seq_buf descriptor * @path: path to write into the sequence buffer. +* @esc: set of characters to escape in the output * * Write a path name into the sequence buffer. * * Returns zero on success, -1 on overflow This should be
Quoted 1 line
* Returns the number of written bytes on success, -1 on overflow
Yep.
Quoted 5 lines
This is just a minor issue. I believe the you would fix it. Feel free to add:
Reviewed-by Petr Mladek <[email protected]>
Thanks,
-- Steve
Steven Rostedt
maintainerRFC PATCH v3 5/12 tracing: Convert seq_buf fields to be like seq_file fields
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
In facilitating the conversion of seq_file to use seq_buf, have the seq_buf fields match the types used by seq_file.
--- include/linux/seq_buf.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
include/linux/seq_buf.h +4 -4
@@ -19,10 +19,10 @@* @overflow: Set if more bytes should have been written to buffer */ struct seq_buf { -unsigned char *buffer; -unsigned int size; -unsigned int len; -unsigned int readpos; +char *buffer; +size_t size; +size_t len; +loff_t readpos; }; static inline void
Signature · 1 line
2.1.1
Re: [RFC][PATCH 05/12 v3] tracing: Convert seq_buf fields to be like seq_file fields
Quoted 15 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
In facilitating the conversion of
seq_fileto useseq_buf, have theseq_buffields match the types used byseq_file.Signed-off-by Steven Rostedt <[email protected]>--- include/linux/seq_buf.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)include/linux/seq_buf.h +0
-0
include/linux/seq_buf.h line 22
Quoted 8 lines
include/linux/seq_buf.h +1
-4@@ -19,10 +19,10 @@* @overflow: Set if more bytes should have been written to buffer */ struct seq_buf { -unsigned char *buffer; -unsigned int size; -unsigned int len; -unsigned int readpos; +char *buffer;
It would make sense to use "char" from the beginning. In fact, it is already used on many locations in seq_buf.c. Or we might want to get rid of "unsigned char" in seq_buf.c here as well.
include/linux/seq_buf.h line 25
Quoted 3 lines
include/linux/seq_buf.h +3
-0+size_t size; +size_t len; +loff_t readpos;
I have just noticed that the variable is called "read_pos" in seq_file. Are you going to sync the name later?
Also I am a bit curious that "readpos" use another type than "len" and "size". Well, this is not in the scope of this patchset. I am fine with keeping "loff_t" at this point.
Best Regards,
Petr
Steven Rostedt
maintainerRe: [RFC][PATCH 05/12 v3] tracing: Convert seq_buf fields to be like seq_file fields
Quoted 20 lines · On Wed, 5 Nov 2014 16:57:11 +0100 Petr Mladek <[email protected]> wrote:
Quoted 19 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
In facilitating the conversion of
seq_fileto useseq_buf, have theseq_buffields match the types used byseq_file.Signed-off-by Steven Rostedt <[email protected]>--- include/linux/seq_buf.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)include/linux/seq_buf.h +0
-1@@ -19,10 +19,10 @@* @overflow: Set if more bytes should have been written to buffer */ struct seq_buf { -unsigned char *buffer;
Quoted 8 lines
include/linux/seq_buf.h line 22
Quoted 4 lines
include/linux/seq_buf.h +1
-3-unsigned int size; -unsigned int len; -unsigned int readpos; +char *buffer;It would make sense to use "char" from the beginning. In fact, it is already used on many locations in
seq_buf.c. Or we might want to get rid of "unsigned char" inseq_buf.chere as well.
I could, but I'm being lazy ;-) No reason to change the patch series for something as small as this. It doesn't break bisect.
Quoted 7 lines
include/linux/seq_buf.h line 25
Quoted 4 lines
include/linux/seq_buf.h +3
-0+size_t size; +size_t len; +loff_t readpos;I have just noticed that the variable is called "
read_pos" inseq_file. Are you going to sync the name later?
Yeah, I purposely kept them different to find the two when needed.
Quoted 4 lines
Also I am a bit curious that "readpos" use another type than "len" and "size". Well, this is not in the scope of this patchset. I am fine with keeping "
loff_t" at this point.
Again, seq_file has been around for a long time with these types. But as you said, it's out of scope for this patch series. I'm just trying to keep with what's been the norm here.
-- Steve
Petr Mladek
Reviewed-byRe: [RFC][PATCH 05/12 v3] tracing: Convert seq_buf fields to be like seq_file fields
Quoted 36 lines · Steven Rostedt
Quoted 20 lines · On Wed, 5 Nov 2014 16:57:11 +0100 Petr Mladek <[email protected]> wrote:
Quoted 19 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
In facilitating the conversion of
seq_fileto useseq_buf, have theseq_buffields match the types used byseq_file.Signed-off-by Steven Rostedt <[email protected]>--- include/linux/seq_buf.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)include/linux/seq_buf.h +0
-1@@ -19,10 +19,10 @@* @overflow: Set if more bytes should have been written to buffer */ struct seq_buf { -unsigned char *buffer;Quoted 8 lines
include/linux/seq_buf.h line 22
Quoted 4 lines
include/linux/seq_buf.h +1
-3-unsigned int size; -unsigned int len; -unsigned int readpos; +char *buffer;It would make sense to use "char" from the beginning. In fact, it is already used on many locations in
seq_buf.c. Or we might want to get rid of "unsigned char" inseq_buf.chere as well.I could, but I'm being lazy ;-) No reason to change the patch series for something as small as this. It doesn't break bisect.
Quoted 1 line
Quoted 8 lines
Quoted 6 lines
include/linux/seq_buf.h line 25
Quoted 3 lines
include/linux/seq_buf.h +3
-0+size_t size; +size_t len; +loff_t readpos;I have just noticed that the variable is called "
read_pos" inseq_file. Are you going to sync the name later?Yeah, I purposely kept them different to find the two when needed.
I see. And if I get it right, you want to use "seq_buf" in "file_seq", so there will be only one variable and no confusion in the end.
Quoted 8 lines
Quoted 4 lines
Also I am a bit curious that "readpos" use another type than "len" and "size". Well, this is not in the scope of this patchset. I am fine with keeping "
loff_t" at this point.Again,
seq_filehas been around for a long time with these types. But as you said, it's out of scope for this patch series. I'm just trying to keep with what's been the norm here.
Fair enough. I am fine with the explanation.
Best Regards,
Petr
Steven Rostedt
maintainerRFC PATCH v3 6/12 tracing: Add a seq_buf_clear() helper and clear len and readpos in init
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
Add a helper function seq_buf_clear() that resets the len and readpos fields of a seq_buf. Currently it is only used in the seq_buf_init() but will be used later when updating the seq_file code.
--- include/linux/seq_buf.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
include/linux/seq_buf.h +7 -2
@@ -25,13 +25,18 @@ struct seq_buf {loff_t readpos; }; +static inline void seq_buf_clear (struct seq_buf *s) +{ + s->len =0 ; + s->readpos =0 ; +} +static inline void seq_buf_init (struct seq_buf *s,unsigned char *buf,unsigned int size) { s->buffer = buf; s->size = size; - s->len =0 ; - s->readpos =0 ; +seq_buf_clear (s); }/*
Signature · 1 line
2.1.1
Re: [RFC][PATCH 06/12 v3] tracing: Add a seq_buf_clear() helper and clear len and readpos in init
Quoted 7 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
Add a helper function
seq_buf_clear()that resets the len and readpos fields of aseq_buf. Currently it is only used in theseq_buf_init()but will be used later when updating theseq_filecode.Signed-off-by Steven Rostedt <[email protected]>
Best Regards,
Petr
Steven Rostedt
maintainerRFC PATCH v3 7/12 tracing: Have seq_buf use full buffer
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
Currently seq_buf is full when all but one byte of the buffer is filled. Change it so that the seq_buf is full when all of the buffer is filled.
Some of the functions would fill the buffer completely and report everything was fine. This was inconsistent with the max of size - 1. Changing this to be max of size makes all functions consistent.
--- include/linux/seq_buf.h | 4 ++-- kernel/trace/seq_buf.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-)
include/linux/seq_buf.h +2 -2
@@ -46,13 +46,13 @@ seq_buf_init(struct seq_buf *s, unsigned char *buf, unsigned int size)static inline bool seq_buf_has_overflowed (struct seq_buf *s) { -return s->len == s->size; +return s->len > s->size; }static inline void seq_buf_set_overflow (struct seq_buf *s) { - s->len = s->size; + s->len = s->size +1 ; } extern __printf(2, 3)
kernel/trace/seq_buf.c +9 -9
@@ -11,17 +11,17 @@* This will set up the counters within the descriptor. You can call * seq_buf_init() more than once to reset the seq_buf to start * from scratch. -* +* */ #include <linux/uaccess.h> #include <linux/seq_file.h> #include <linux/seq_buf.h> /* How much buffer is left on the seq_buf? */ -#define SEQ_BUF_LEFT (s) (((s)->size - 1) - (s)->len) +#define SEQ_BUF_LEFT (s) ((s)->size - (s)->len)/* How much buffer is written? */ -#define SEQ_BUF_USED (s) min((s)->len, (s)->size - 1) +#define SEQ_BUF_USED (s) min((s)->len, (s)->size)/** * seq_buf_print_seq - move the contents of seq_buf into a seq_file
@@ -55,7 +55,7 @@ int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)if (s->len < s->size) { len =vsnprintf (s->buffer + s->len, s->size - s->len, fmt, args); -if (s->len + len < s->size) { +if (s->len + len <= s->size) { s->len += len;return 0 ; }
@@ -105,7 +105,7 @@ int seq_buf_bitmask(struct seq_buf *s, const unsigned long *maskp,if (s->len < s->size) { ret =bitmap_scnprintf (s->buffer, len, maskp, nmaskbits); -if (s->len + ret < s->size) { +if (s->len + ret <= s->size) { s->len += ret;return 0 ; }
@@ -140,7 +140,7 @@ int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary)if (s->len < s->size) { ret =bstr_printf (s->buffer + s->len, len, fmt, binary); -if (s->len + ret < s->size) { +if (s->len + ret <= s->size) { s->len += ret;return 0 ; }
@@ -164,7 +164,7 @@ int seq_buf_puts(struct seq_buf *s, const char *str)WARN_ON (s->size ==0 ); -if (s->len + len < s->size) { +if (s->len + len <= s->size) {memcpy (s->buffer + s->len, str, len); s->len += len;return 0 ;
@@ -186,7 +186,7 @@ int seq_buf_putc(struct seq_buf *s, unsigned char c) {WARN_ON (s->size ==0 ); -if (s->len +1 < s->size) { +if (s->len +1 <= s->size) { s->buffer[s->len++] = c;return 0 ; }
@@ -210,7 +210,7 @@ int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len) {WARN_ON (s->size ==0 ); -if (s->len + len < s->size) { +if (s->len + len <= s->size) {memcpy (s->buffer + s->len, mem, len); s->len += len;return 0 ;
Signature · 1 line
2.1.1
Re: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
Quoted 62 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
Currently
seq_bufis full when all but one byte of the buffer is filled. Change it so that theseq_bufis full when all of the buffer is filled.Some of the functions would fill the buffer completely and report everything was fine. This was inconsistent with the max of size - 1. Changing this to be max of size makes all functions consistent.
Signed-off-by Steven Rostedt <[email protected]>--- include/linux/seq_buf.h | 4 ++-- kernel/trace/seq_buf.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-)include/linux/seq_buf.h +2
-2@@ -46,13 +46,13 @@ seq_buf_init(struct seq_buf *s, unsigned char *buf, unsigned int size)static inline bool seq_buf_has_overflowed (struct seq_buf *s) { -return s->len == s->size; +return s->len > s->size; }static inline void seq_buf_set_overflow (struct seq_buf *s) { - s->len = s->size; + s->len = s->size +1 ; } extern __printf(2, 3)kernel/trace/seq_buf.c +3
-3@@ -11,17 +11,17 @@* This will set up the counters within the descriptor. You can call * seq_buf_init() more than once to reset the seq_buf to start * from scratch. -* +* */ #include <linux/uaccess.h> #include <linux/seq_file.h> #include <linux/seq_buf.h> /* How much buffer is left on the seq_buf? */ -#define SEQ_BUF_LEFT (s) (((s)->size - 1) - (s)->len) +#define SEQ_BUF_LEFT (s) ((s)->size - (s)->len)/* How much buffer is written? */ -#define SEQ_BUF_USED (s) min((s)->len, (s)->size - 1) +#define SEQ_BUF_USED (s) min((s)->len, (s)->size)/** * seq_buf_print_seq - move the contents of seq_buf into a seq_file
kernel/trace/seq_buf.c int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args) · line 58
Quoted 5 lines
kernel/trace/seq_buf.c +1
-1@@ -55,7 +55,7 @@ int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)if (s->len < s->size) { len =vsnprintf (s->buffer + s->len, s->size - s->len, fmt, args); -if (s->len + len < s->size) { +if (s->len + len <= s->size) {
This is always true because we limit vsnprintf() to write (s->size - s->len) bytes. Similar problem is also in the other parts of this patch.
I wonder if we want this change at all. It means that we are not able to detect overflow in some functions. It is pity because the users might want to increase the buffer size and try again if the print was incomplete.
I think that we need to leave the one byte for the overflow detection if we want to detect it properly.
Best Regards,
Petr
Quoted 12 lines
kernel/trace/seq_buf.c +1
-1s->len += len;return 0 ; }@@ -105,7 +105,7 @@ int seq_buf_bitmask(struct seq_buf *s, const unsigned long *maskp,if (s->len < s->size) { ret =bitmap_scnprintf (s->buffer, len, maskp, nmaskbits); -if (s->len + ret < s->size) { +if (s->len + ret <= s->size) { s->len += ret;return 0 ; }
Steven Rostedt
maintainerRe: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
Quoted 4 lines · On Wed, 5 Nov 2014 17:31:50 +0100 Petr Mladek <[email protected]> wrote:
Quoted 4 lines
/**
*seq_buf_print_seq- move the contents ofseq_bufinto aseq_file(quoted diff) +0
-0@@ -55,7 +55,7 @@ int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)
Quoted 8 lines
kernel/trace/seq_buf.c int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args) · line 58
Quoted 4 lines
kernel/trace/seq_buf.c +1
-1if (s->len < s->size) { len =vsnprintf (s->buffer + s->len, s->size - s->len, fmt, args); -if (s->len + len < s->size) { +if (s->len + len <= s->size) {This is always true because we limit
vsnprintf()to write (s->size-s->len) bytes. Similar problem is also in the other parts of this patch.
No, len is the length of bytes that should have been written, not the amount that has been written.
Quoted 5 lines
I wonder if we want this change at all. It means that we are not able to detect overflow in some functions. It is pity because the users might want to increase the buffer size and try again if the print was incomplete.
What do you mean we can't detect overflow? That's what seq_buf_has_overflowed() does.
Quoted 3 lines
I think that we need to leave the one byte for the overflow detection if we want to detect it properly.
I don't.
-- Steve
Steven Rostedt
maintainerRe: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
Quoted 9 lines · On Wed, 5 Nov 2014 15:21:30 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 5 lines
I wonder if we want this change at all. It means that we are not able to detect overflow in some functions. It is pity because the users might want to increase the buffer size and try again if the print was incomplete.
What do you mean we can't detect overflow? That's what
seq_buf_has_overflowed()does.
Although I'm looking at the seq_file versions of the bitmap code, which does only return the len of what was written and not what would have been written, and it does have this issue.
I hate to go back to the -1 of the size of buffer as that causes inconsistencies within the functions themselves, as proved with the seq_file code.
What I might do as just have the bitmap calls not be allowed to fill the buffer and keep the logic the same. That is, if the bitmap calls fill the rest of the length, assume we overflowed, otherwise we are fine.
I'm going to change seq_buf to do that instead of my new update with the bitmask code.
-- Steve
Re: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
Quoted 13 lines · Steven Rostedt
Quoted 9 lines · On Wed, 5 Nov 2014 15:21:30 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 5 lines
I wonder if we want this change at all. It means that we are not able to detect overflow in some functions. It is pity because the users might want to increase the buffer size and try again if the print was incomplete.
What do you mean we can't detect overflow? That's what
seq_buf_has_overflowed()does.
Quoted 7 lines
Although I'm looking at the
seq_fileversions of the bitmap code, which does only return the len of what was written and not what would have been written, and it does have this issue.I hate to go back to the -1 of the size of buffer as that causes inconsistencies within the functions themselves, as proved with the
seq_filecode.
Yeah, the -1 and the unused byte is strange and it would be great to avoid it.
On the other hand, I am slightly afraid of the "len = size + 1" that signalizes the buffer overflow. It might be prone for creating security bugs. If people forget to check seq_buf_has_overflowed() before reading or if there is a race, they might read outside of the buffer.
Quoted 7 lines
What I might do as just have the bitmap calls not be allowed to fill the buffer and keep the logic the same. That is, if the bitmap calls fill the rest of the length, assume we overflowed, otherwise we are fine.
I'm going to change
seq_bufto do that instead of my new update with the bitmask code.
I like the idea of having the exception only in the bitmap code and filling the whole buffer in other cases.
I am now in doubts about the overflow state. A solution would be to add an "overflow" flag to struct seq_bug. I agree that it is ugly but it looks more secure then "len = size + 1".
Well, I do not have that strong opinion about it. What do you think?
Best Regards,
Petr
Steven Rostedt
maintainerRe: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
Quoted 8 lines · On Thu, 6 Nov 2014 16:31:07 +0100 Petr Mladek <[email protected]> wrote:
I like the idea of having the exception only in the bitmap code and filling the whole buffer in other cases.
I am now in doubts about the overflow state. A solution would be to add an "overflow" flag to struct
seq_bug. I agree that it is ugly but it looks more secure then "len = size + 1".Well, I do not have that strong opinion about it. What do you think?
Ideally, I want struct seq_buf defined only within seq_buf.c, and all users must access the buffer via function methods.
We would need to remove all the inline calls, which will have a small affect on performance. But most seq_buf code is for output of text, where this overhead would be a nit to the total cost of operations.
That would get rid of all users that think it's safe to access s->buffer + s->len.
-- Steve
Re: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
Quoted 16 lines · Steven Rostedt
Quoted 8 lines · On Thu, 6 Nov 2014 16:31:07 +0100 Petr Mladek <[email protected]> wrote:
I like the idea of having the exception only in the bitmap code and filling the whole buffer in other cases.
I am now in doubts about the overflow state. A solution would be to add an "overflow" flag to struct
seq_bug. I agree that it is ugly but it looks more secure then "len = size + 1".Well, I do not have that strong opinion about it. What do you think?
Ideally, I want struct
seq_bufdefined only withinseq_buf.c, and all users must access the buffer via function methods.
Quoted 6 lines
We would need to remove all the inline calls, which will have a small affect on performance. But most
seq_bufcode is for output of text, where this overhead would be a nit to the total cost of operations.That would get rid of all users that think it's safe to access
s->buffer+s->len.
Sounds like a good plan.
Best Regards,
Petr
Re: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
Some more touch ups.
-- Steve
Quoted 1 line
From
7e724556c21178a9890b31ff57f69761b41f435aMon Sep 17 00:00:00 2001
From: "Steven Rostedt (Red Hat)" <[email protected]>
Date: Wed, 29 Oct 2014 15:26:09 -0400
Subject: [PATCH] tracing: Have seq_buf use full buffer
Currently seq_buf is full when all but one byte of the buffer is filled. Change it so that the seq_buf is full when all of the buffer is filled.
Some of the functions would fill the buffer completely and report everything was fine. This was inconsistent with the max of size - 1. Changing this to be max of size makes all functions consistent.
--- include/linux/seq_buf.h | 6 +++--- kernel/trace/seq_buf.c | 19 +++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-)
include/linux/seq_buf.h +3 -3
@@ -43,13 +43,13 @@ seq_buf_init(struct seq_buf *s, unsigned char *buf, unsigned int size)static inline bool seq_buf_has_overflowed (struct seq_buf *s) { -return s->len == s->size; +return s->len > s->size; }static inline void seq_buf_set_overflow (struct seq_buf *s) { - s->len = s->size; + s->len = s->size +1 ; }/*
@@ -58,7 +58,7 @@ seq_buf_set_overflow(struct seq_buf *s)static inline unsigned int seq_buf_buffer_left (struct seq_buf *s) { -return (s->size -1 ) - s->len; +return s->size - s->len; } extern __printf(2, 3)
kernel/trace/seq_buf.c +11 -8
@@ -17,7 +17,7 @@#include <linux/seq_buf.h> /* How much buffer is written? */ -#define SEQ_BUF_USED (s) min((s)->len, (s)->size - 1) +#define SEQ_BUF_USED (s) min((s)->len, (s)->size)/** * seq_buf_print_seq - move the contents of seq_buf into a seq_file
@@ -51,7 +51,7 @@ int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)if (s->len < s->size) { len =vsnprintf (s->buffer + s->len, s->size - s->len, fmt, args); -if (s->len + len < s->size) { +if (s->len + len <= s->size) { s->len += len;return 0 ; }
@@ -100,8 +100,11 @@ int seq_buf_bitmask(struct seq_buf *s, const unsigned long *maskp,WARN_ON (s->size ==0 );/* -* The last byte of the buffer is used to determine if we -* overflowed or not. +* Note, because bitmap_scnprintf() only returns the number of bytes +* written and not the number that would be written, we use the last +* byte of the buffer to let us know if we overflowed. There's a small +* chance that the bitmap could have fit exactly inside the buffer, but +* it's not that critical if that does happen. */ if (len >1 ) { ret =bitmap_scnprintf (s->buffer, len, maskp, nmaskbits);
@@ -140,7 +143,7 @@ int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary)if (s->len < s->size) { ret =bstr_printf (s->buffer + s->len, len, fmt, binary); -if (s->len + ret < s->size) { +if (s->len + ret <= s->size) { s->len += ret;return 0 ; }
@@ -164,7 +167,7 @@ int seq_buf_puts(struct seq_buf *s, const char *str)WARN_ON (s->size ==0 ); -if (s->len + len < s->size) { +if (s->len + len <= s->size) {memcpy (s->buffer + s->len, str, len); s->len += len;return 0 ;
@@ -186,7 +189,7 @@ int seq_buf_putc(struct seq_buf *s, unsigned char c) {WARN_ON (s->size ==0 ); -if (s->len +1 < s->size) { +if (s->len +1 <= s->size) { s->buffer[s->len++] = c;return 0 ; }
@@ -210,7 +213,7 @@ int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len) {WARN_ON (s->size ==0 ); -if (s->len + len < s->size) { +if (s->len + len <= s->size) {memcpy (s->buffer + s->len, mem, len); s->len += len;return 0 ;
Signature · 1 line
2.1.1
Petr Mladek
Reviewed-byRe: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
Quoted 18 lines · Steven Rostedt
Some more touch ups.
-- Steve
From
7e724556c21178a9890b31ff57f69761b41f435aMon Sep 17 00:00:00 2001
From: "Steven Rostedt (Red Hat)" <[email protected]>
Date: Wed, 29 Oct 2014 15:26:09 -0400
Subject: [PATCH] tracing: Haveseq_bufuse full bufferCurrently
seq_bufis full when all but one byte of the buffer is filled. Change it so that theseq_bufis full when all of the buffer is filled.Some of the functions would fill the buffer completely and report everything was fine. This was inconsistent with the max of size - 1. Changing this to be max of size makes all functions consistent.
Quoted 5 lines
Tested-by Jiri Kosina <[email protected]>Acked-by Jiri Kosina <[email protected]>Signed-off-by Steven Rostedt <[email protected]>
This patch might need a refresh if you add the extra buffer overflow check into seq_buf_set_overflow() in the 3rd patch. Anyway, changes in this patch looks good.
I am happy with all the changes in the patchset. Thanks a lot for driving it forward.
Best Regards,
Petr
Re: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
In reply to Steven RostedtQuoted 17 lines · Steven Rostedt
Quoted 4 lines · On Wed, 5 Nov 2014 17:31:50 +0100 Petr Mladek <[email protected]> wrote:
Quoted 4 lines
/**
*seq_buf_print_seq- move the contents ofseq_bufinto aseq_file(quoted diff) +0
-0@@ -55,7 +55,7 @@ int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)Quoted 8 lines
kernel/trace/seq_buf.c int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args) · line 58
Quoted 4 lines
kernel/trace/seq_buf.c +1
-1if (s->len < s->size) { len =vsnprintf (s->buffer + s->len, s->size - s->len, fmt, args); -if (s->len + len < s->size) { +if (s->len + len <= s->size) {This is always true because we limit
vsnprintf()to write (s->size-s->len) bytes. Similar problem is also in the other parts of this patch.
Quoted 2 lines
No, len is the length of bytes that should have been written, not the amount that has been written.
That is cool! I did not know that there was also this variant of the printf() functions. I am still learning.
Best Regards,
Petr
Steven Rostedt
maintainerRFC PATCH v3 8/12 tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
Add two helper functions; seq_buf_get_buf() and seq_buf_commit() that are used by seq_buf_path(). This makes the code similar to theseq_file: seq_path() function, and will help to be able to consolidate the functions between seq_file and trace_seq.
--- include/linux/seq_buf.h | 40 ++++++++++++++++++++++++++++++++++++++++ kernel/trace/seq_buf.c | 7 +++---- 2 files changed, 43 insertions(+), 4 deletions(-)
include/linux/seq_buf.h +40 -0
@@ -55,6 +55,46 @@ seq_buf_set_overflow(struct seq_buf *s) s->len = s->size +1 ; } +/** +* seq_buf_get_buf - get buffer to write arbitrary data to +* @s: the seq_buf handle +* @bufp: the beginning of the buffer is stored here +* +* Return the number of bytes available in the buffer, or zero if +* there's no space. +*/ +static inline size_t seq_buf_get_buf (struct seq_buf *s,char **bufp) +{ +BUG_ON (s->len > s->size +1 ); + +if (s->len < s->size) { + *bufp = s->buffer + s->len; +return s->size - s->len; + } + + *bufp =NULL ; +return 0 ; +} + +/** +* seq_buf_commit - commit data to the buffer +* @s: the seq_buf handle +* @num: the number of bytes to commit +* +* Commit @num bytes of data written to a buffer previously acquired +* by seq_buf_get. To signal an error condition, or that the data +* didn't fit in the available space, pass a negative @num value. +*/ +static inline void seq_buf_commit (struct seq_buf *s,int num) +{ +if (num <0 ) { + s->len = s->size; + }else { +BUG_ON (s->len + num > s->size +1 ); + s->len += num; + } +} + extern __printf(2, 3) int seq_buf_printf(struct seq_buf *s, const char *fmt, ...); extern __printf(2, 0)
kernel/trace/seq_buf.c +3 -4
@@ -280,8 +280,8 @@ int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,*/ int seq_buf_path (struct seq_buf *s,const struct path *path,const char *esc) { -char *buf = s->buffer + s->len; -size_t size =SEQ_BUF_LEFT (s); +char *buf; +size_t size =seq_buf_get_buf (s, &buf);int res =-1 ;if (size) {
@@ -292,8 +292,7 @@ int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc) res = end - buf; } } -if (res >0 ) - s->len += res; +seq_buf_commit (s, res);return res; }
Signature · 1 line
2.1.1
Re: [RFC][PATCH 08/12 v3] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions
Quoted 43 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
Add two helper functions;
seq_buf_get_buf()andseq_buf_commit()that are used byseq_buf_path(). This makes the code similar to theseq_file:seq_path()function, and will help to be able to consolidate the functions betweenseq_fileandtrace_seq.Signed-off-by Steven Rostedt <[email protected]>--- include/linux/seq_buf.h | 40 ++++++++++++++++++++++++++++++++++++++++ kernel/trace/seq_buf.c | 7 +++---- 2 files changed, 43 insertions(+), 4 deletions(-)include/linux/seq_buf.h +22
-0@@ -55,6 +55,46 @@ seq_buf_set_overflow(struct seq_buf *s) s->len = s->size +1 ; } +/** +* seq_buf_get_buf - get buffer to write arbitrary data to +* @s: the seq_buf handle +* @bufp: the beginning of the buffer is stored here +* +* Return the number of bytes available in the buffer, or zero if +* there's no space. +*/ +static inline size_t seq_buf_get_buf (struct seq_buf *s,char **bufp) +{ +BUG_ON (s->len > s->size +1 ); +if (s->len < s->size) { + *bufp = s->buffer + s->len; +return s->size - s->len; + } + *bufp =NULL ; +return 0 ; +} + +/** +* seq_buf_commit - commit data to the buffer +* @s: the seq_buf handle
include/linux/seq_buf.h seq_buf_set_overflow(struct seq_buf *s) · line 89
Quoted 10 lines
include/linux/seq_buf.h +10
-0+* @num: the number of bytes to commit +* +* Commit @num bytes of data written to a buffer previously acquired +* by seq_buf_get. To signal an error condition, or that the data +* didn't fit in the available space, pass a negative @num value. +*/ +static inline void seq_buf_commit (struct seq_buf *s,int num) +{ +if (num <0 ) { + s->len = s->size;
I guess that you want to get the buffer into an overflow state. If yes, it should be:
s->len = s->size + 1;
or even better
seq_buf_set_overflow(s);
Note that this whole patch depends on the decision about the 7th patch ("tracing: Have seq_buf use full buffer").
It might make sense to move the SEQ_BUF_LEFT, SEQ_BUF_USED macros to this header and use them in these two function. Or move the functions to seq_file.c.
Best Regards,
Petr
Steven Rostedt
maintainerRe: [RFC][PATCH 08/12 v3] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions
Quoted 18 lines · On Wed, 5 Nov 2014 17:51:25 +0100 Petr Mladek <[email protected]> wrote:
Quoted 4 lines
include/linux/seq_buf.h +4
-0+ +/** +* seq_buf_commit - commit data to the buffer +* @s: the seq_buf handle include/linux/seq_buf.h seq_buf_set_overflow(struct seq_buf *s) · line 91
Quoted 10 lines
include/linux/seq_buf.h +10
-0+* @num: the number of bytes to commit +* +* Commit @num bytes of data written to a buffer previously acquired +* by seq_buf_get. To signal an error condition, or that the data +* didn't fit in the available space, pass a negative @num value. +*/ +static inline void seq_buf_commit (struct seq_buf *s,int num) +{ +if (num <0 ) { + s->len = s->size;I guess that you want to get the buffer into an overflow state. If yes, it should be:
Quoted 5 lines
s->len = s->size + 1;or even better
seq_buf_set_overflow(s);
Yeah, I agree with using the seq_buf_set_overflow().
Quoted 4 lines
Note that this whole patch depends on the decision about the 7th patch ("tracing: Have
seq_bufuse full buffer").
Which I have decided to do.
Quoted 5 lines
It might make sense to move the
SEQ_BUF_LEFT,SEQ_BUF_USEDmacros to this header and use them in these two function. Or move the functions toseq_file.c.
I moved SEQ_BUF_LEFT as a static inline seq_buf_buffer_left() and have used it in trace_seq.c in the TRACE_SEQ_BUF_LEFT macro.
-- Steve
Re: [RFC][PATCH 08/12 v3] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions
In reply to Petr MladekMore updates. Hmm, maybe I should have posted the full series ;-)
-- Steve
Quoted 1 line
From
41a3f3f5e772ca26ef4441a0312d3f108693d7dcMon Sep 17 00:00:00 2001
From: "Steven Rostedt (Red Hat)" <[email protected]>
Date: Wed, 29 Oct 2014 17:30:50 -0400
Subject: [PATCH] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper
functions
Add two helper functions; seq_buf_get_buf() and seq_buf_commit() that are used by seq_buf_path(). This makes the code similar to theseq_file: seq_path() function, and will help to be able to consolidate the functions between seq_file and trace_seq.
--- include/linux/seq_buf.h | 40 ++++++++++++++++++++++++++++++++++++++++ kernel/trace/seq_buf.c | 7 +++---- 2 files changed, 43 insertions(+), 4 deletions(-)
include/linux/seq_buf.h +40 -0
@@ -61,6 +61,46 @@ seq_buf_buffer_left(struct seq_buf *s)return s->size - s->len; } +/** +* seq_buf_get_buf - get buffer to write arbitrary data to +* @s: the seq_buf handle +* @bufp: the beginning of the buffer is stored here +* +* Return the number of bytes available in the buffer, or zero if +* there's no space. +*/ +static inline size_t seq_buf_get_buf (struct seq_buf *s,char **bufp) +{ +BUG_ON (s->len > s->size +1 ); + +if (s->len < s->size) { + *bufp = s->buffer + s->len; +return s->size - s->len; + } + + *bufp =NULL ; +return 0 ; +} + +/** +* seq_buf_commit - commit data to the buffer +* @s: the seq_buf handle +* @num: the number of bytes to commit +* +* Commit @num bytes of data written to a buffer previously acquired +* by seq_buf_get. To signal an error condition, or that the data +* didn't fit in the available space, pass a negative @num value. +*/ +static inline void seq_buf_commit (struct seq_buf *s,int num) +{ +if (num <0 ) { +seq_buf_set_overflow (s); + }else { +BUG_ON (s->len + num > s->size +1 ); + s->len += num; + } +} + extern __printf(2, 3) int seq_buf_printf(struct seq_buf *s, const char *fmt, ...); extern __printf(2, 0)
kernel/trace/seq_buf.c +3 -4
@@ -283,8 +283,8 @@ int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,*/ int seq_buf_path (struct seq_buf *s,const struct path *path,const char *esc) { -char *buf = s->buffer + s->len; -size_t size =seq_buf_buffer_left (s); +char *buf; +size_t size =seq_buf_get_buf (s, &buf);int res =-1 ;WARN_ON (s->size ==0 );
@@ -297,8 +297,7 @@ int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc) res = end - buf; } } -if (res >0 ) - s->len += res; +seq_buf_commit (s, res);return res; }
Signature · 1 line
2.1.1
Petr Mladek
Reviewed-byRe: [RFC][PATCH 08/12 v3] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions
Quoted 15 lines · Steven Rostedt
More updates. Hmm, maybe I should have posted the full series ;-)
-- Steve
From
41a3f3f5e772ca26ef4441a0312d3f108693d7dcMon Sep 17 00:00:00 2001
From: "Steven Rostedt (Red Hat)" <[email protected]>
Date: Wed, 29 Oct 2014 17:30:50 -0400
Subject: [PATCH] tracing: Addseq_buf_get_buf()andseq_buf_commit()helper
functionsAdd two helper functions;
seq_buf_get_buf()andseq_buf_commit()that are used byseq_buf_path(). This makes the code similar to theseq_file:seq_path()function, and will help to be able to consolidate the functions betweenseq_fileandtrace_seq.
Quoted 5 lines
Tested-by Jiri Kosina <[email protected]>Acked-by Jiri Kosina <[email protected]>Signed-off-by Steven Rostedt <[email protected]>
Well, I am curious about the BUG_ONs, see below.
Quoted 14 lines
--- include/linux/seq_buf.h | 40 ++++++++++++++++++++++++++++++++++++++++ kernel/trace/seq_buf.c | 7 +++---- 2 files changed, 43 insertions(+), 4 deletions(-)include/linux/seq_buf.h +1
-0@@ -61,6 +61,46 @@ seq_buf_buffer_left(struct seq_buf *s)return s->size - s->len; } +/**
include/linux/seq_buf.h seq_buf_buffer_left(struct seq_buf *s) · line 74
Quoted 10 lines
include/linux/seq_buf.h +10
-0+* seq_buf_get_buf - get buffer to write arbitrary data to +* @s: the seq_buf handle +* @bufp: the beginning of the buffer is stored here +* +* Return the number of bytes available in the buffer, or zero if +* there's no space. +*/ +static inline size_t seq_buf_get_buf (struct seq_buf *s,char **bufp) +{ +BUG_ON (s->len > s->size +1 );
I just wonder if the BUG_ON() is appropriate here. There is used WARN_ON() for the other similar checks.
On one hand. This function will be used by a code that manipulates the buffer its own way. Therefore the BUG() would help to debug potential problems.
On the other hand, this function is used just to get the buffer. Therefore the BUG() might come too late. The buffer was broken somewhere else.
Quoted 15 lines
include/linux/seq_buf.h +15
-0+ +if (s->len < s->size) { + *bufp = s->buffer + s->len; +return s->size - s->len; + } + + *bufp =NULL ; +return 0 ; +} + +/** +* seq_buf_commit - commit data to the buffer +* @s: the seq_buf handle +* @num: the number of bytes to commit +*
include/linux/seq_buf.h seq_buf_buffer_left(struct seq_buf *s) · line 99
Quoted 10 lines
include/linux/seq_buf.h +10
-0+* Commit @num bytes of data written to a buffer previously acquired +* by seq_buf_get. To signal an error condition, or that the data +* didn't fit in the available space, pass a negative @num value. +*/ +static inline void seq_buf_commit (struct seq_buf *s,int num) +{ +if (num <0 ) { +seq_buf_set_overflow (s); + }else { +BUG_ON (s->len + num > s->size +1 );
I agree that the BUG_ON makes sense here. If someone passed too big "num", she probably also wrote too many bytes and the memory is corrupted at this point.
include/linux/seq_buf.h seq_buf_buffer_left(struct seq_buf *s) · line 103
Quoted 4 lines
include/linux/seq_buf.h +4
-0+ s->len += num; + } +} +
Best Regards,
Petr
Steven Rostedt
maintainerRe: [RFC][PATCH 08/12 v3] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions
Quoted 39 lines · On Mon, 10 Nov 2014 19:33:29 +0100 Petr Mladek <[email protected]> wrote:
Quoted 15 lines · Steven Rostedt
More updates. Hmm, maybe I should have posted the full series ;-)
-- Steve
From
41a3f3f5e772ca26ef4441a0312d3f108693d7dcMon Sep 17 00:00:00 2001
From: "Steven Rostedt (Red Hat)" <[email protected]>
Date: Wed, 29 Oct 2014 17:30:50 -0400
Subject: [PATCH] tracing: Addseq_buf_get_buf()andseq_buf_commit()helper
functionsAdd two helper functions;
seq_buf_get_buf()andseq_buf_commit()that are used byseq_buf_path(). This makes the code similar to theseq_file:seq_path()function, and will help to be able to consolidate the functions betweenseq_fileandtrace_seq.Quoted 5 lines
Tested-by Jiri Kosina <[email protected]>Acked-by Jiri Kosina <[email protected]>Signed-off-by Steven Rostedt <[email protected]>Reviewed-by Petr Mladek <[email protected]>Well, I am curious about the
BUG_ONs, see below.Quoted 13 lines
--- include/linux/seq_buf.h | 40 ++++++++++++++++++++++++++++++++++++++++ kernel/trace/seq_buf.c | 7 +++---- 2 files changed, 43 insertions(+), 4 deletions(-)include/linux/seq_buf.h +0
-0@@ -61,6 +61,46 @@ seq_buf_buffer_left(struct seq_buf *s)return s->size - s->len; }
Quoted 14 lines
include/linux/seq_buf.h seq_buf_buffer_left(struct seq_buf *s) · line 74
Quoted 11 lines
include/linux/seq_buf.h +11
-0+/** +* seq_buf_get_buf - get buffer to write arbitrary data to +* @s: the seq_buf handle +* @bufp: the beginning of the buffer is stored here +* +* Return the number of bytes available in the buffer, or zero if +* there's no space. +*/ +static inline size_t seq_buf_get_buf (struct seq_buf *s,char **bufp) +{ +BUG_ON (s->len > s->size +1 );I just wonder if the
BUG_ON()is appropriate here. There is usedWARN_ON()for the other similar checks.
That should be a WARN_ON(). Thanks.
It's probably a BUG_ON as that was code that was used internally for earlier iterations, and the BUG_ON() was for me to see it quickly. Could have also been that previous versions could access memory that it should not.
But as it's intended to be used by others, it should be a warning instead of a bug.
Quoted 30 lines
On one hand. This function will be used by a code that manipulates the buffer its own way. Therefore the
BUG()would help to debug potential problems.On the other hand, this function is used just to get the buffer. Therefore the
BUG()might come too late. The buffer was broken somewhere else.Quoted 21 lines
include/linux/seq_buf.h +21
-0+ +if (s->len < s->size) { + *bufp = s->buffer + s->len; +return s->size - s->len; + } + + *bufp =NULL ; +return 0 ; +} + +/** +* seq_buf_commit - commit data to the buffer +* @s: the seq_buf handle +* @num: the number of bytes to commit +* +* Commit @num bytes of data written to a buffer previously acquired +* by seq_buf_get. To signal an error condition, or that the data +* didn't fit in the available space, pass a negative @num value. +*/ +static inline void seq_buf_commit (struct seq_buf *s,int num) +{
Quoted 8 lines
include/linux/seq_buf.h seq_buf_buffer_left(struct seq_buf *s) · line 99
Quoted 4 lines
include/linux/seq_buf.h +4
-0+if (num <0 ) { +seq_buf_set_overflow (s); + }else { +BUG_ON (s->len + num > s->size +1 );I agree that the
BUG_ONmakes sense here. If someone passed too big "num", she probably also wrote too many bytes and the memory is corrupted at this point.
Yeah, this one is worse than the other one and should bug to prevent memory corruption.
Thanks for reviewing this,
-- Steve
Quoted 8 lines
include/linux/seq_buf.h seq_buf_buffer_left(struct seq_buf *s) · line 103
Quoted 5 lines
include/linux/seq_buf.h +4
-0+ s->len += num; + } +} +Best Regards,
Petr
Steven Rostedt
maintainerRFC PATCH v3 9/12 seq_buf: Move the seq_buf code to lib/
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
The seq_buf functions are rather useful outside of tracing. Instead of having it be dependent on CONFIG_TRACING, move the code into lib/ and allow other users to have access to it even when tracing is not configured.
The seq_buf utility is similar to the seq_file utility, but instead of writing sending data back up to userland, it writes it into a buffer defined at seq_buf_init(). This allows us to send a descriptor around that writes printf() formatted strings into it that can be retrieved later.
It is currently used by the tracing facility for such things like trace events to convert its binary saved data in the ring buffer into an ASCII human readable context to be displayed in /sys/kernel/debug/trace.
It can also be used for doing NMI prints safely from NMI context into the seq_buf and retrieved later and dumped to printk() safely. Doing printk() from an NMI context is dangerous because an NMI can preempt a current printk() and deadlock on it.
--- kernel/trace/Makefile | 1 - kernel/trace/seq_buf.c | 342 ------------------------------------------------- lib/Makefile | 2 +- lib/seq_buf.c | 342 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 343 insertions(+), 344 deletions(-) delete mode 100644 kernel/trace/seq_buf.c create mode 100644 lib/seq_buf.c
kernel/trace/Makefile +0 -1
@@ -29,7 +29,6 @@ obj-$(CONFIG_RING_BUFFER_BENCHMARK) += ring_buffer_benchmark.o obj-$(CONFIG_TRACING) += trace.o obj-$(CONFIG_TRACING) += trace_output.o obj-$(CONFIG_TRACING) += trace_seq.o -obj-$(CONFIG_TRACING) += seq_buf.o obj-$(CONFIG_TRACING) += trace_stat.o obj-$(CONFIG_TRACING) += trace_printk.o obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o
kernel/trace/seq_buf.c deleted +0 -342
342 lines not on this page · raw message
lib/Makefile +1 -1
@@ -13,7 +13,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \ proportions.o flex_proportions.o ratelimit.o show_mem.o \ is_single_threaded.o plist.o decompress.o kobject_uevent.o \ - earlycpio.o + earlycpio.o seq_buf.o obj-$(CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS) += usercopy.o lib-$(CONFIG_MMU) += ioremap.o
lib/seq_buf.c new file +342 -0
342 lines not on this page · raw message
Signature · 1 line
2.1.1
Re: [RFC][PATCH 09/12 v3] seq_buf: Move the seq_buf code to lib/
Quoted 17 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
The
seq_buffunctions are rather useful outside of tracing. Instead of having it be dependent onCONFIG_TRACING, move the code intolib/and allow other users to have access to it even when tracing is not configured.The
seq_bufutility is similar to theseq_fileutility, but instead of writing sending data back up to userland, it writes it into a buffer defined atseq_buf_init(). This allows us to send a descriptor around that writesprintf()formatted strings into it that can be retrieved later.It is currently used by the tracing facility for such things like trace events to convert its binary saved data in the ring buffer into an ASCII human readable context to be displayed in
/sys/kernel/debug/trace.
Quoted 8 lines
It can also be used for doing NMI prints safely from NMI context into the
seq_bufand retrieved later and dumped toprintk()safely. Doingprintk()from an NMI context is dangerous because an NMI can preempt a currentprintk()and deadlock on it.Signed-off-by Steven Rostedt <[email protected]>
This patch might needed an update when there are changes in the previous patches. But it is a simple file move that makes perfect sense, so:
Best Regards,
Petr
Steven Rostedt
maintainerRe: [RFC][PATCH 09/12 v3] seq_buf: Move the seq_buf code to lib/
Quoted 3 lines · On Wed, 5 Nov 2014 17:57:26 +0100 Petr Mladek <[email protected]> wrote:
This patch might needed an update when there are changes in the previous patches. But it is a simple file move that makes perfect sense, so:
I love git rebase. It knows that this change was a simple file move and even if you change the file that is moving, it wont have any conflicts during the rebase.
Quoted 2 lines
Reviewed-by Petr Mladek <[email protected]>
Thanks,
-- Steve
Steven Rostedt
maintainerRFC PATCH v3 10/12 seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
The function bstr_printf() from lib/vsprnintf.c is only available if CONFIG_BINARY_PRINTF is defined. This is due to the only user currently being the tracing infrastructure, which needs to select this config when tracing is configured. Until there is another user of the binary printf formats, this will continue to be the case.
Since seq_buf.c is now lives in lib/ and is compiled even without tracing, it must encompass its use of bstr_printf() which is used by seq_buf_printf(). This too is only used by the tracing infrastructure and is still encapsulated by the CONFIG_BINARY_PRINTF.
--- include/linux/seq_buf.h | 7 +++++-- lib/seq_buf.c | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-)
include/linux/seq_buf.h +5 -2
@@ -99,8 +99,6 @@ extern __printf(2, 3)int seq_buf_printf (struct seq_buf *s,const char *fmt, ...); extern __printf(2, 0) int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args); -extern int -seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary); extern int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s); extern int seq_buf_to_user(struct seq_buf *s, char __user *ubuf, int cnt);
@@ -114,4 +112,9 @@ extern int seq_buf_path(struct seq_buf *s, const struct path *path, const char *extern int seq_buf_bitmask (struct seq_buf *s,const unsigned long *maskp,int nmaskbits); +#ifdef CONFIG_BINARY_PRINTF +extern int +seq_buf_bprintf (struct seq_buf *s,const char *fmt,const u32 *binary); +#endif +#endif /* _LINUX_SEQ_BUF_H */
lib/seq_buf.c +2 -0
@@ -114,6 +114,7 @@ int seq_buf_bitmask(struct seq_buf *s, const unsigned long *maskp,return -1 ; } +#ifdef CONFIG_BINARY_PRINTF /** * seq_buf_bprintf - Write the printf string from binary arguments * @s: seq_buf descriptor
@@ -148,6 +149,7 @@ int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary)seq_buf_set_overflow (s); return -1; } +#endif /* CONFIG_BINARY_PRINTF */ /** * seq_buf_puts - sequence printing of simple string
Signature · 1 line
2.1.1
Re: [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
Quoted 8 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
The function
bstr_printf()fromlib/vsprnintf.cis only available ifCONFIG_BINARY_PRINTFis defined. This is due to the only user currently being the tracing infrastructure, which needs to select this config when tracing is configured. Until there is another user of the binary printf formats, this will continue to be the case.
Quoted 6 lines
Since
seq_buf.cis now lives inlib/and is compiled even without tracing, it must encompass its use ofbstr_printf()which is used byseq_buf_printf(). This too is only used by the tracing infrastructure and is still encapsulated by theCONFIG_BINARY_PRINTF.Signed-off-by Steven Rostedt <[email protected]>
Please switch the order and do this change before moving to lib/. IMHO, the current order would break bisecting when tracing is disabled.
Otherwise, the change looks good in itself, so:
Best Regards,
Petr
Steven Rostedt
maintainerRe: [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
Quoted 14 lines · On Wed, 5 Nov 2014 18:06:05 +0100 Petr Mladek <[email protected]> wrote:
Quoted 13 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
The function
bstr_printf()fromlib/vsprnintf.cis only available ifCONFIG_BINARY_PRINTFis defined. This is due to the only user currently being the tracing infrastructure, which needs to select this config when tracing is configured. Until there is another user of the binary printf formats, this will continue to be the case.Since
seq_buf.cis now lives inlib/and is compiled even without tracing, it must encompass its use ofbstr_printf()which is used byseq_buf_printf(). This too is only used by the tracing infrastructure and is still encapsulated by theCONFIG_BINARY_PRINTF.
Quoted 5 lines
Quoted 1 line
Signed-off-by Steven Rostedt <[email protected]>Please switch the order and do this change before moving to
lib/. IMHO, the current order would break bisecting when tracing is disabled.
I agree. I was being lazy and when my test broke, I added the update to test again. But to move this change to before the move, I need to monkey with the patch file.
I'll move it before the move regardless.
Quoted 4 lines
Otherwise, the change looks good in itself, so:
Reviewed-by Petr Mladek <[email protected]>
Thanks,
-- Steve
Steven Rostedt
maintainerRe: [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
Quoted 23 lines · On Wed, 5 Nov 2014 15:33:55 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 14 lines · On Wed, 5 Nov 2014 18:06:05 +0100 Petr Mladek <[email protected]> wrote:
Quoted 13 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
The function
bstr_printf()fromlib/vsprnintf.cis only available ifCONFIG_BINARY_PRINTFis defined. This is due to the only user currently being the tracing infrastructure, which needs to select this config when tracing is configured. Until there is another user of the binary printf formats, this will continue to be the case.Since
seq_buf.cis now lives inlib/and is compiled even without tracing, it must encompass its use ofbstr_printf()which is used byseq_buf_printf(). This too is only used by the tracing infrastructure and is still encapsulated by theCONFIG_BINARY_PRINTF.Quoted 5 lines
Quoted 1 line
Signed-off-by Steven Rostedt <[email protected]>Please switch the order and do this change before moving to
lib/. IMHO, the current order would break bisecting when tracing is disabled.
Quoted 6 lines
I agree. I was being lazy and when my test broke, I added the update to test again. But to move this change to before the move, I need to monkey with the patch file.
I'll move it before the move regardless.
OK, 'git rebase' is SUPER AWESOME!!!
I just did a git rebase, moved this change to before the file move, and git somehow knew that the change was for the old file, and updated it without any modification from me. The rebase simply succeeded!
I checked, the change still changed seq_buf.c, but in the old kernel/trace directory.
-- Steve
Re: [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
Quoted 33 lines · Steven Rostedt
Quoted 23 lines · On Wed, 5 Nov 2014 15:33:55 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 14 lines · On Wed, 5 Nov 2014 18:06:05 +0100 Petr Mladek <[email protected]> wrote:
Quoted 13 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
The function
bstr_printf()fromlib/vsprnintf.cis only available ifCONFIG_BINARY_PRINTFis defined. This is due to the only user currently being the tracing infrastructure, which needs to select this config when tracing is configured. Until there is another user of the binary printf formats, this will continue to be the case.Since
seq_buf.cis now lives inlib/and is compiled even without tracing, it must encompass its use ofbstr_printf()which is used byseq_buf_printf(). This too is only used by the tracing infrastructure and is still encapsulated by theCONFIG_BINARY_PRINTF.Quoted 5 lines
Quoted 1 line
Signed-off-by Steven Rostedt <[email protected]>Please switch the order and do this change before moving to
lib/. IMHO, the current order would break bisecting when tracing is disabled.Quoted 6 lines
I agree. I was being lazy and when my test broke, I added the update to test again. But to move this change to before the move, I need to monkey with the patch file.
I'll move it before the move regardless.
Quoted 8 lines
OK, 'git rebase' is SUPER AWESOME!!!
I just did a git rebase, moved this change to before the file move, and git somehow knew that the change was for the old file, and updated it without any modification from me. The rebase simply succeeded!
I checked, the change still changed
seq_buf.c, but in the old kernel/trace directory.
That is really awesome! Dreams become reality.
Best Regards,
Petr
Re: [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
Quoted 5 lines · Petr Mladek
On Wed 2014-11-05 15:42:03, Steven Rostedt wrote:
...Quoted 3 lines
OK, 'git rebase' is SUPER AWESOME!!!
Quoted 8 lines
Quoted 6 lines
I just did a git rebase, moved this change to before the file move, and git somehow knew that the change was for the old file, and updated it without any modification from me. The rebase simply succeeded!
I checked, the change still changed
seq_buf.c, but in the old kernel/trace directory.That is really awesome! Dreams become reality.
It is rare to hear somebody talks about Git without having "sucks" in the same sentence ;-)
Steven Rostedt
maintainerRe: [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
Quoted 11 lines · On Fri, 07 Nov 2014 12:36:05 -0800 Junio C Hamano <[email protected]> wrote:
Quoted 9 lines · Petr Mladek
On Wed 2014-11-05 15:42:03, Steven Rostedt wrote:
...Quoted 7 lines
OK, 'git rebase' is SUPER AWESOME!!!
I just did a git rebase, moved this change to before the file move, and git somehow knew that the change was for the old file, and updated it without any modification from me. The rebase simply succeeded!
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
I checked, the change still changed
seq_buf.c, but in the old kernel/trace directory.That is really awesome! Dreams become reality.
It is rare to hear somebody talks about Git without having "sucks" in the same sentence ;-)
Yes, that's why I Cc'd you. I figured you would want to hear it.
-- Steve
Re: [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
In reply to Junio C HamanoQuoted 11 lines · Junio C Hamano
Quoted 9 lines · Petr Mladek
On Wed 2014-11-05 15:42:03, Steven Rostedt wrote:
...Quoted 7 lines
OK, 'git rebase' is SUPER AWESOME!!!
I just did a git rebase, moved this change to before the file move, and git somehow knew that the change was for the old file, and updated it without any modification from me. The rebase simply succeeded!
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
I checked, the change still changed
seq_buf.c, but in the old kernel/trace directory.That is really awesome! Dreams become reality.
It is rare to hear somebody talks about Git without having "sucks" in the same sentence ;-)
This might be an effect of bugzilla and other bugreport tools. One gets the feeling that there are only people strugling with the software. In fact, there is usually much bigger group of happy users. They just keep the happines inside until something goes wrong :-)
I am happy git user (most of the time :-)
Best Regards,
Petr
Steven Rostedt
maintainerRFC PATCH v3 11/12 printk: Add per_cpu printk func to allow printk to be diverted
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
Being able to divert printk to call another function besides the normal logging is useful for such things like NMI handling. If some functions are to be called from NMI that does printk() it is possible to lock up the box if the nmi handler triggers when another printk is happening.
One example of this use is to perform a stack trace on all CPUs via NMI. But if the NMI is to do the printk() it can cause the system to lock up. By allowing the printk to be diverted to another function that can safely record the printk output and then print it when it in a safe context then NMIs will be safe to call these functions like show_regs().
--- include/linux/percpu.h | 3 +++ include/linux/printk.h | 2 ++ kernel/printk/printk.c | 38 +++++++++++++++++++++++++++++--------- 3 files changed, 34 insertions(+), 9 deletions(-)
include/linux/percpu.h +3 -0
@@ -134,4 +134,7 @@ extern phys_addr_t per_cpu_ptr_to_phys(void *addr); (typeof(type) __percpu *)__alloc_percpu(sizeof(type), \ __alignof__(type )) +/* To avoid include hell, as printk can not declare this, we declare it here */ +DECLARE_PER_CPU (printk_func_t, printk_func); +#endif /* __LINUX_PERCPU_H */
include/linux/printk.h +2 -0
@@ -162,6 +162,8 @@ extern int kptr_restrict;extern void wake_up_klogd (void ); +typedef int (*printk_func_t )(const char *fmt,va_list args); +void log_buf_kexec_setup (void );void __init setup_log_buf (int early);void dump_stack_set_arch_desc (const char *fmt, ...);
kernel/printk/printk.c +29 -9
@@ -1807,6 +1807,30 @@ asmlinkage int printk_emit(int facility, int level, }EXPORT_SYMBOL (printk_emit); +int vprintk_default (const char *fmt,va_list args) +{ +int r; + +#ifdef CONFIG_KGDB_KDB +if (unlikely (kdb_trap_printk)) { + r =vkdb_printf (fmt, args); +return r; + } +#endif + r =vprintk_emit (0 ,-1 ,NULL ,0 , fmt, args); + +return r; +} +EXPORT_SYMBOL_GPL (vprintk_default); + +/* +* This allows printk to be diverted to another function per cpu. +* This is useful for calling printk functions from within NMI +* without worrying about race conditions that can lock up the +* box. +*/ +DEFINE_PER_CPU (printk_func_t, printk_func) = vprintk_default; +/** * printk - print a kernel message * @fmt: format string
@@ -1830,19 +1854,15 @@ EXPORT_SYMBOL(printk_emit);*/ asmlinkage __visible int printk(const char *fmt, ...) { +printk_func_t vprintk_func;va_list args;int r; -#ifdef CONFIG_KGDB_KDB -if (unlikely (kdb_trap_printk)) { -va_start (args, fmt); - r =vkdb_printf (fmt, args); -va_end (args); -return r; - } -#endif va_start (args, fmt); - r =vprintk_emit (0 ,-1 ,NULL ,0 , fmt, args); +preempt_disable (); + vprintk_func =this_cpu_read (printk_func); + r =vprintk_func (fmt, args); +preempt_enable ();va_end (args);return r;
Signature · 1 line
2.1.1
Re: [RFC][PATCH 11/12 v3] printk: Add per_cpu printk func to allow printk to be diverted
Quoted 13 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
Being able to divert printk to call another function besides the normal logging is useful for such things like NMI handling. If some functions are to be called from NMI that does
printk()it is possible to lock up the box if the nmi handler triggers when another printk is happening.One example of this use is to perform a stack trace on all CPUs via NMI. But if the NMI is to do the
printk()it can cause the system to lock up. By allowing the printk to be diverted to another function that can safely record the printk output and then print it when it in a safe context then NMIs will be safe to call these functions likeshow_regs().
Quoted 4 lines
Acked-by Paul E. McKenney <[email protected]>Signed-off-by Steven Rostedt <[email protected]>
Looks fine to me.
Best Regards,
Petr
Steven Rostedt
maintainerRFC PATCH v3 12/12 x86/nmi: Perform a safe NMI stack trace on all CPUs
In reply to Steven RostedtFrom: "Steven Rostedt (Red Hat)" <[email protected]>
When trigger_all_cpu_backtrace() is called on x86, it will trigger an NMI on each CPU and call show_regs(). But this can lead to a hard lock up if the NMI comes in on another printk().
In order to avoid this, when the NMI triggers, it switches the printk routine for that CPU to call a NMI safe printk function that records the printk in a per_cpu seq_buf descriptor. After all NMIs have finished recording its data, the trace_seqs are printed in a safe context.
--- arch/x86/kernel/apic/hw_nmi.c | 90 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 5 deletions(-)
arch/x86/kernel/apic/hw_nmi.c +85 -5
@@ -18,6 +18,7 @@#include <linux/nmi.h> #include <linux/module.h> #include <linux/delay.h> +#include <linux/seq_buf.h> #ifdef CONFIG_HARDLOCKUP_DETECTOR u64 hw_nmi_get_sample_period (int watchdog_thresh)
@@ -29,14 +30,35 @@ u64 hw_nmi_get_sample_period(int watchdog_thresh)#ifdef arch_trigger_all_cpu_backtrace/* For reliability, we're prepared to waste bits here. */ static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly; +static cpumask_var_t printtrace_mask; + +#define NMI_BUF_SIZE 4096 + +struct nmi_seq_buf { +unsigned char buffer[NMI_BUF_SIZE ]; +struct seq_buf seq; +}; + +/* Safe printing in NMI context */ +static DEFINE_PER_CPU(struct nmi_seq_buf, nmi_print_seq);/* "in progress" flag of arch_trigger_all_cpu_backtrace */ static unsigned long backtrace_flag; +static void print_seq_line (struct nmi_seq_buf *s,int last,int pos) +{ +const char *buf = s->buffer + last; + +printk ("%.*s" , (pos - last) +1 , buf); +} +void arch_trigger_all_cpu_backtrace (bool include_self) { +struct nmi_seq_buf *s; +int len; +int cpu;int i; -int cpu =get_cpu (); +int this_cpu =get_cpu ();if (test_and_set_bit (0 , &backtrace_flag)) {/*
@@ -49,7 +71,17 @@ void arch_trigger_all_cpu_backtrace(bool include_self)cpumask_copy (to_cpumask (backtrace_mask), cpu_online_mask);if (!include_self) -cpumask_clear_cpu (cpu,to_cpumask (backtrace_mask)); +cpumask_clear_cpu (this_cpu,to_cpumask (backtrace_mask)); + +cpumask_copy (printtrace_mask,to_cpumask (backtrace_mask)); +/* +* Set up per_cpu seq_buf buffers that the NMIs running on the other +* CPUs will write to. +*/ +for_each_cpu (cpu,to_cpumask (backtrace_mask)) { + s = &per_cpu (nmi_print_seq, cpu); +seq_buf_init (&s->seq, s->buffer,NMI_BUF_SIZE ); + }if (!cpumask_empty (to_cpumask (backtrace_mask))) { pr_info("sending NMI to %s CPUs:\n",
@@ -65,11 +97,57 @@ void arch_trigger_all_cpu_backtrace(bool include_self)touch_softlockup_watchdog (); } +/* +* Now that all the NMIs have triggered, we can dump out their +* back traces safely to the console. +*/ +for_each_cpu (cpu, printtrace_mask) { +int last_i =0 ; + + s = &per_cpu (nmi_print_seq, cpu); + len = s->seq.len; +if (!len) +continue ; + +/* Print line by line. */ +for (i =0 ; i < len; i++) { +if (s->buffer[i] =='\n' ) { +print_seq_line (s, last_i, i); + last_i = i +1 ; + } + } +if (last_i < i -1 ) { +print_seq_line (s, last_i, i); +pr_cont ("\n" ); + } + } +clear_bit (0 , &backtrace_flag);smp_mb__after_atomic ();put_cpu (); } +/* +* It is not safe to call printk() directly from NMI handlers. +* It may be fine if the NMI detected a lock up and we have no choice +* but to do so, but doing a NMI on all other CPUs to get a back trace +* can be done with a sysrq-l. We don't want that to lock up, which +* can happen if the NMI interrupts a printk in progress. +* +* Instead, we redirect the vprintk() to this nmi_vprintk() that writes +* the content into a per cpu seq_buf buffer. Then when the NMIs are +* all done, we can safely dump the contents of the seq_buf to a printk() +* from a non NMI context. +*/ +static int nmi_vprintk (const char *fmt,va_list args) +{ +struct nmi_seq_buf *s =this_cpu_ptr (&nmi_print_seq); +unsigned int len = s->seq.len; + +seq_buf_vprintf (&s->seq, fmt, args); +return s->seq.len - len; +} +static int arch_trigger_all_cpu_backtrace_handler (unsigned int cmd,struct pt_regs *regs) {
@@ -78,12 +156,14 @@ arch_trigger_all_cpu_backtrace_handler(unsigned int cmd, struct pt_regs *regs) cpu =smp_processor_id ();if (cpumask_test_cpu (cpu,to_cpumask (backtrace_mask))) { -static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED; +printk_func_t printk_func_save =this_cpu_read (printk_func); -arch_spin_lock (&lock); +/* Replace printk to write into the NMI seq */ +this_cpu_write (printk_func, nmi_vprintk);printk (KERN_WARNING "NMI backtrace for cpu %d\n" , cpu);show_regs (regs); -arch_spin_unlock (&lock); +this_cpu_write (printk_func, printk_func_save); +cpumask_clear_cpu (cpu,to_cpumask (backtrace_mask));return NMI_HANDLED ; }
Signature · 1 line
2.1.1
Re: [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs
Quoted 11 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
When
trigger_all_cpu_backtrace()is called on x86, it will trigger an NMI on each CPU and callshow_regs(). But this can lead to a hard lock up if the NMI comes in on anotherprintk().In order to avoid this, when the NMI triggers, it switches the printk routine for that CPU to call a NMI safe printk function that records the printk in a
per_cpuseq_bufdescriptor. After all NMIs have finished recording its data, thetrace_seqsare printed in a safe context.
Quoted 4 lines
Acked-by Paul E. McKenney <[email protected]>Signed-off-by Steven Rostedt <[email protected]>
I've been running the whole machinery that used to trigger very quickly the complete hardlock of the machine (*) for the whole evening/night, and it's still running flawlessly.
Plus, as I said previously, I agree with the whole idea (given the general nastiness of the problem and given the fact this simply has to be fixed without pointless delays).
I.e FWIW
for the whole series.
(*) heavy printk() workload (**) + sysrq-l in parallel (**) iptables logging every incoming packet + flood ping from another
machine
Thanks,
Signature · 2 lines
Jiri Kosina SUSE Labs
Steven Rostedt
maintainerRe: [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs
Quoted 4 lines · On Wed, 5 Nov 2014 00:05:12 +0100 (CET) Jiri Kosina <[email protected]> wrote:
Quoted 2 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
Quoted 8 lines
Quoted 8 lines
When
trigger_all_cpu_backtrace()is called on x86, it will trigger an NMI on each CPU and callshow_regs(). But this can lead to a hard lock up if the NMI comes in on anotherprintk().In order to avoid this, when the NMI triggers, it switches the printk routine for that CPU to call a NMI safe printk function that records the printk in a
per_cpuseq_bufdescriptor. After all NMIs have finished recording its data, thetrace_seqsare printed in a safe context.
Hmm, I need to update the change log to say seq_bufs instead of trace_seqs.
Quoted 14 lines
Quoted 5 lines
Acked-by Paul E. McKenney <[email protected]>Signed-off-by Steven Rostedt <[email protected]>I've been running the whole machinery that used to trigger very quickly the complete hardlock of the machine (*) for the whole evening/night, and it's still running flawlessly.
Plus, as I said previously, I agree with the whole idea (given the general nastiness of the problem and given the fact this simply has to be fixed without pointless delays).
Quoted 6 lines
I.e FWIW
Tested-by Jiri Kosina <[email protected]>Acked-by Jiri Kosina <[email protected]>for the whole series.
Thanks! I'll update the commits.
-- Steve
Quoted 7 lines
(*) heavy
printk()workload (**) + sysrq-l in parallel (**) iptables logging every incoming packet + flood ping from another
machineThanks,
Re: [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs
In reply to Steven RostedtQuoted 41 lines · Steven Rostedt
From: "Steven Rostedt (Red Hat)" <[email protected]>
When
trigger_all_cpu_backtrace()is called on x86, it will trigger an NMI on each CPU and callshow_regs(). But this can lead to a hard lock up if the NMI comes in on anotherprintk().In order to avoid this, when the NMI triggers, it switches the printk routine for that CPU to call a NMI safe printk function that records the printk in a
per_cpuseq_bufdescriptor. After all NMIs have finished recording its data, thetrace_seqsare printed in a safe context.Acked-by Paul E. McKenney <[email protected]>Signed-off-by Steven Rostedt <[email protected]>--- arch/x86/kernel/apic/hw_nmi.c | 90 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 5 deletions(-)arch/x86/kernel/apic/hw_nmi.c +7
-0@@ -18,6 +18,7 @@#include <linux/nmi.h> #include <linux/module.h> #include <linux/delay.h> +#include <linux/seq_buf.h> #ifdef CONFIG_HARDLOCKUP_DETECTOR u64 hw_nmi_get_sample_period (int watchdog_thresh)@@ -29,14 +30,35 @@ u64 hw_nmi_get_sample_period(int watchdog_thresh) #ifdef arch_trigger_all_cpu_backtrace /* For reliability, we're prepared to waste bits here. */ static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly; +static cpumask_var_t printtrace_mask; + +#define NMI_BUF_SIZE 4096 + +struct nmi_seq_buf { + unsigned char buffer[NMI_BUF_SIZE];
arch/x86/kernel/apic/hw_nmi.c u64 hw_nmi_get_sample_period(int watchdog_thresh) · line 48
Quoted 10 lines
arch/x86/kernel/apic/hw_nmi.c +6
-0+struct seq_buf seq; +}; + +/* Safe printing in NMI context */ +static DEFINE_PER_CPU(struct nmi_seq_buf, nmi_print_seq);/* "in progress" flag of arch_trigger_all_cpu_backtrace */ static unsigned long backtrace_flag; +static void print_seq_line (struct nmi_seq_buf *s,int last,int pos)
I would rename the arguments:
"last -> first" "pos -> last"
or maybe better would be to pass first positon and len.
Quoted 46 lines
arch/x86/kernel/apic/hw_nmi.c +26
-2+{ +const char *buf = s->buffer + last; + +printk ("%.*s" , (pos - last) +1 , buf); +} +{ +const char *buf = s->buffer + last; + +printk ("%.*s" , (pos - last) +1 , buf); +} +void arch_trigger_all_cpu_backtrace (bool include_self) { +struct nmi_seq_buf *s; +int len; +int cpu;int i; -int cpu =get_cpu (); +int this_cpu =get_cpu ();if (test_and_set_bit (0 , &backtrace_flag)) {/* @@ -49,7 +71,17 @@ void arch_trigger_all_cpu_backtrace(bool include_self)cpumask_copy (to_cpumask (backtrace_mask), cpu_online_mask);if (!include_self) -cpumask_clear_cpu (cpu,to_cpumask (backtrace_mask)); +cpumask_clear_cpu (this_cpu,to_cpumask (backtrace_mask)); + +cpumask_copy (printtrace_mask,to_cpumask (backtrace_mask)); +/* +* Set up per_cpu seq_buf buffers that the NMIs running on the other +* CPUs will write to. +*/ +for_each_cpu (cpu,to_cpumask (backtrace_mask)) { + s = &per_cpu (nmi_print_seq, cpu); +seq_buf_init (&s->seq, s->buffer,NMI_BUF_SIZE ); + }if (!cpumask_empty (to_cpumask (backtrace_mask))) { pr_info("sending NMI to %s CPUs:\n",@@ -65,11 +97,57 @@ void arch_trigger_all_cpu_backtrace(bool include_self)touch_softlockup_watchdog (); }
arch/x86/kernel/apic/hw_nmi.c void arch_trigger_all_cpu_backtrace(bool include_self) · line 108
Quoted 10 lines
arch/x86/kernel/apic/hw_nmi.c +9
-0+/* +* Now that all the NMIs have triggered, we can dump out their +* back traces safely to the console. +*/ +for_each_cpu (cpu, printtrace_mask) { +int last_i =0 ; + + s = &per_cpu (nmi_print_seq, cpu); + len = s->seq.len;
If there is an seq_buf overflow, the len might be size + 1, so we need to do:
len = min(s->seq.len, s->size);
Well, we should create a function for this in seq_buf.h. Alternatively, we might reconsider the overflow state, use len == size and extra "overflow" flag in the seq_buf struct.
arch/x86/kernel/apic/hw_nmi.c void arch_trigger_all_cpu_backtrace(bool include_self)
Quoted 12 lines
arch/x86/kernel/apic/hw_nmi.c +11
-0+if (!len) +continue ; + +/* Print line by line. */ +for (i =0 ; i < len; i++) { +if (s->buffer[i] =='\n' ) { +print_seq_line (s, last_i, i); + last_i = i +1 ; + } + } +if (last_i < i -1 ) {
IMHO, this should be:
if (last_i < i)
because last_i = i + 1. Otherwise, we would ignore state when there is one character after a new line. For example, imagine the following:
buffer = "a\nb"; len = 3;
it will end with:
last_i = 2; i = 3;
and we still need to print the "b".
arch/x86/kernel/apic/hw_nmi.c void arch_trigger_all_cpu_backtrace(bool include_self) · line 121
Quoted 1 line
arch/x86/kernel/apic/hw_nmi.c +1
-0+print_seq_line (s, last_i, i);
If I get it correctly, (i == len) here and "printk_seq_line" print_seq_line() prints the characters including "pos" value. So, we should call:
print_seq_line(s, last_i, i - 1)
arch/x86/kernel/apic/hw_nmi.c void arch_trigger_all_cpu_backtrace(bool include_self) · line 124
Quoted 4 lines
arch/x86/kernel/apic/hw_nmi.c +4
-0+pr_cont ("\n" ); + } + } +
I hope that I have got it correctly. It is getting late here and I feel tired to see the off-by-one problems clearly ;-)
Best Regards,
Petr
Steven Rostedt
maintainerRe: [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs
Quoted 11 lines · On Thu, 6 Nov 2014 19:41:55 +0100 Petr Mladek <[email protected]> wrote:
Quoted 4 lines
/* "in progress" flag of
arch_trigger_all_cpu_backtrace*/ static unsigned longbacktrace_flag;+static void
print_seq_line(struct nmi_seq_buf *s, int last, int pos)I would rename the arguments:
"last -> first" "pos -> last"or maybe better would be to pass first positon and len.
I switched it to "start" and "end" to not be confused by the last_i that is being passed in.
Quoted 53 lines
Quoted 10 lines
arch/x86/kernel/apic/hw_nmi.c +5
-0+{ +const char *buf = s->buffer + last; + +printk ("%.*s" , (pos - last) +1 , buf); +}arch/x86/kernel/apic/hw_nmi.c void arch_trigger_all_cpu_backtrace(bool include_self) · line 108
Quoted 10 lines
arch/x86/kernel/apic/hw_nmi.c +9
-0+/* +* Now that all the NMIs have triggered, we can dump out their +* back traces safely to the console. +*/ +for_each_cpu (cpu, printtrace_mask) { +int last_i =0 ; + + s = &per_cpu (nmi_print_seq, cpu); + len = s->seq.len;If there is an
seq_bufoverflow, the len might be size + 1, so we need to do:len = min(s->seq.len, s->size);Well, we should create a function for this in
seq_buf.h. Alternatively, we might reconsider the overflow state, use len == size and extra "overflow" flag in theseq_bufstruct.arch/x86/kernel/apic/hw_nmi.c void arch_trigger_all_cpu_backtrace(bool include_self)
Quoted 12 lines
arch/x86/kernel/apic/hw_nmi.c +11
-0+if (!len) +continue ; + +/* Print line by line. */ +for (i =0 ; i < len; i++) { +if (s->buffer[i] =='\n' ) { +print_seq_line (s, last_i, i); + last_i = i +1 ; + } + } +if (last_i < i -1 ) {IMHO, this should be:
if (last_i < i)because
last_i= i + 1. Otherwise, we would ignore state when there is one character after a new line. For example, imagine the following:buffer = "a\nb"; len = 3;
Quoted 6 lines
it will end with:
last_i = 2; i = 3;and we still need to print the "b".
Well, we really don't *need* to ;-)
But for correctness sake, I agree, it should be last_i < i.
Quoted 8 lines
Review
Quoted 2 lines
(quoted diff) +1
-0+ print_seq_line(s, last_i, i);If I get it correctly, (i == len) here and "
printk_seq_line"print_seq_line()prints the characters including "pos" value. So, we should call:print_seq_line(s, last_i, i - 1)
Right that was wrong. Actually, I think the best answer would be:
print_seq_line(s, last_i, len - 1);
This removes the variable 'i'. Probably should add a comment here too that reminds the reviewer that print_seq_line() prints up to and including the last index.
Note, my current code also has:
len = seq_buf_used(&s->seq);
where we don't need to worry about the semantics of seq_buf internals.
-- Steve
Quoted 6 lines
Quoted 5 lines
arch/x86/kernel/apic/hw_nmi.c +4
-0+pr_cont ("\n" ); + } + } +
Re: [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs
Quoted 10 lines · Steven Rostedt
Quoted 7 lines · On Thu, 6 Nov 2014 19:41:55 +0100 Petr Mladek <[email protected]> wrote:
Quoted 4 lines
/* "in progress" flag of
arch_trigger_all_cpu_backtrace*/ static unsigned longbacktrace_flag;+static void
print_seq_line(struct nmi_seq_buf *s, int last, int pos)I would rename the arguments:
Quoted 7 lines
Quoted 4 lines
"last -> first" "pos -> last"or maybe better would be to pass first positon and len.
I switched it to "start" and "end" to not be confused by the
last_ithat is being passed in.
I like it.
Quoted 55 lines
Quoted 55 lines
Quoted 10 lines
arch/x86/kernel/apic/hw_nmi.c +5
-0+{ +const char *buf = s->buffer + last; + +printk ("%.*s" , (pos - last) +1 , buf); +}arch/x86/kernel/apic/hw_nmi.c void arch_trigger_all_cpu_backtrace(bool include_self) · line 108
Quoted 10 lines
arch/x86/kernel/apic/hw_nmi.c +9
-0+/* +* Now that all the NMIs have triggered, we can dump out their +* back traces safely to the console. +*/ +for_each_cpu (cpu, printtrace_mask) { +int last_i =0 ; + + s = &per_cpu (nmi_print_seq, cpu); + len = s->seq.len;If there is an
seq_bufoverflow, the len might be size + 1, so we need to do:len = min(s->seq.len, s->size);Well, we should create a function for this in
seq_buf.h. Alternatively, we might reconsider the overflow state, use len == size and extra "overflow" flag in theseq_bufstruct.arch/x86/kernel/apic/hw_nmi.c void arch_trigger_all_cpu_backtrace(bool include_self)
Quoted 12 lines
arch/x86/kernel/apic/hw_nmi.c +11
-0+if (!len) +continue ; + +/* Print line by line. */ +for (i =0 ; i < len; i++) { +if (s->buffer[i] =='\n' ) { +print_seq_line (s, last_i, i); + last_i = i +1 ; + } + } +if (last_i < i -1 ) {IMHO, this should be:
if (last_i < i)because
last_i= i + 1. Otherwise, we would ignore state when there is one character after a new line. For example, imagine the following:buffer = "a\nb"; len = 3;it will end with:
Quoted 8 lines
Quoted 4 lines
last_i = 2; i = 3;and we still need to print the "b".
Well, we really don't *need* to ;-)
But for correctness sake, I agree, it should be
last_i< i.
I agree that one more character does not make much difference but it might save someones day :-)
Quoted 7 lines
Quoted 7 lines
Review
Quoted 2 lines
(quoted diff) +1
-0+ print_seq_line(s, last_i, i);If I get it correctly, (i == len) here and "
printk_seq_line"print_seq_line()prints the characters including "pos" value. So, we should call:
Quoted 5 lines
Quoted 1 line
print_seq_line(s, last_i, i - 1)Right that was wrong. Actually, I think the best answer would be:
print_seq_line(s, last_i, len - 1);
Yup
Quoted 3 lines
This removes the variable 'i'. Probably should add a comment here too that reminds the reviewer that
print_seq_line()prints up to and including the last index.
Yes, the comment is worth having.
Quoted 5 lines
Note, my current code also has:
len = seq_buf_used(&s->seq);where we don't need to worry about the semantics of
seq_bufinternals.
Perfect
Thanks a lot for working on it. Please, resend this patch once you are happy with it.
Best Regards,
Petr