From 3a161d99c43ce74c76aecff309be4c3ba455e823 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 25 Jun 2014 15:54:42 -0400 Subject: 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. Link: http://lkml.kernel.org/r/20141104160221.864997179@goodmis.org Link: http://lkml.kernel.org/r/20141114011412.170377300@goodmis.org Tested-by: Jiri Kosina Acked-by: Jiri Kosina Reviewed-by: Petr Mladek Signed-off-by: Steven Rostedt --- include/linux/seq_buf.h | 81 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/trace_seq.h | 12 +++---- 2 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 include/linux/seq_buf.h (limited to 'include') diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h new file mode 100644 index 0000000..4f7a96a --- /dev/null +++ b/include/linux/seq_buf.h @@ -0,0 +1,81 @@ +#ifndef _LINUX_SEQ_BUF_H +#define _LINUX_SEQ_BUF_H + +#include + +/* + * 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) +{ + if (seq_buf_has_overflowed(s)) + return 0; + + 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 */ diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h index db8a732..85d3710 100644 --- a/include/linux/trace_seq.h +++ b/include/linux/trace_seq.h @@ -1,7 +1,7 @@ #ifndef _LINUX_TRACE_SEQ_H #define _LINUX_TRACE_SEQ_H -#include +#include #include @@ -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; } /** @@ -49,7 +47,7 @@ trace_seq_buffer_ptr(struct trace_seq *s) */ static inline bool trace_seq_has_overflowed(struct trace_seq *s) { - return s->full || s->len > PAGE_SIZE - 1; + return s->full || seq_buf_has_overflowed(&s->seq); } /* -- cgit v1.1 From dd23180aacf4b27d48f40b27249f1e58c8df03be Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 29 Oct 2014 13:48:37 -0400 Subject: 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. Link: http://lkml.kernel.org/r/20141104160222.048795666@goodmis.org Link: http://lkml.kernel.org/r/20141114011412.338523371@goodmis.org Tested-by: Jiri Kosina Acked-by: Jiri Kosina Reviewed-by: Petr Mladek Signed-off-by: Steven Rostedt --- include/linux/seq_buf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h index 4f7a96a..3877068 100644 --- a/include/linux/seq_buf.h +++ b/include/linux/seq_buf.h @@ -73,7 +73,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); -- cgit v1.1 From 9a7777935c34b9192e28ef3d232a4b6b5414a657 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 29 Oct 2014 13:59:58 -0400 Subject: tracing: Convert seq_buf fields to be like seq_file fields In facilitating the conversion of seq_file to use seq_buf, have the seq_buf fields match the types used by seq_file. Link: http://lkml.kernel.org/r/20141104160222.195301024@goodmis.org Tested-by: Jiri Kosina Acked-by: Jiri Kosina Reviewed-by: Petr Mladek Signed-off-by: Steven Rostedt --- include/linux/seq_buf.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h index 3877068..d14dc90 100644 --- a/include/linux/seq_buf.h +++ b/include/linux/seq_buf.h @@ -16,10 +16,10 @@ * @readpos: The next position to read in the 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 -- cgit v1.1 From 0736c033a81547b1cdc5120fc8dd60e26a00fd28 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 29 Oct 2014 14:17:52 -0400 Subject: tracing: Add a seq_buf_clear() helper and clear len and readpos in init 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. Link: http://lkml.kernel.org/r/20141104160222.352309995@goodmis.org Tested-by: Jiri Kosina Acked-by: Jiri Kosina Reviewed-by: Petr Mladek Signed-off-by: Steven Rostedt --- include/linux/seq_buf.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h index d14dc90..5d91262 100644 --- a/include/linux/seq_buf.h +++ b/include/linux/seq_buf.h @@ -22,13 +22,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); } /* -- cgit v1.1 From eeab98154dc0b49afd398afdd71c464a8af5911f Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Thu, 6 Nov 2014 16:38:28 -0500 Subject: seq_buf: Create seq_buf_used() to find out how much was written Add a helper function seq_buf_used() that replaces the SEQ_BUF_USED() private macro to let callers have a method to know how much of the seq_buf was written to. Link: http://lkml.kernel.org/r/20141114011412.170377300@goodmis.org Link: http://lkml.kernel.org/r/20141114011413.321654244@goodmis.org Reviewed-by: Petr Mladek Signed-off-by: Steven Rostedt --- include/linux/seq_buf.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include') diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h index 5d91262..93718e5 100644 --- a/include/linux/seq_buf.h +++ b/include/linux/seq_buf.h @@ -64,6 +64,12 @@ seq_buf_buffer_left(struct seq_buf *s) return (s->size - 1) - s->len; } +/* How much buffer was written? */ +static inline unsigned int seq_buf_used(struct seq_buf *s) +{ + return min(s->len, s->size); +} + extern __printf(2, 3) int seq_buf_printf(struct seq_buf *s, const char *fmt, ...); extern __printf(2, 0) -- cgit v1.1 From 5ac48378414dccca735897c4d7f4e19987c8977c Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Fri, 14 Nov 2014 15:49:41 -0500 Subject: tracing: Use trace_seq_used() and seq_buf_used() instead of len As the seq_buf->len will soon be +1 size when there's an overflow, we must use trace_seq_used() or seq_buf_used() methods to get the real length. This will prevent buffer overflow issues if just the len of the seq_buf descriptor is used to copy memory. Link: http://lkml.kernel.org/r/20141114121911.09ba3d38@gandalf.local.home Reported-by: Petr Mladek Signed-off-by: Steven Rostedt --- include/linux/trace_seq.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h index 85d3710..cfaf5a1 100644 --- a/include/linux/trace_seq.h +++ b/include/linux/trace_seq.h @@ -24,6 +24,24 @@ trace_seq_init(struct trace_seq *s) } /** + * trace_seq_used - amount of actual data written to buffer + * @s: trace sequence descriptor + * + * Returns the amount of data written to the buffer. + * + * IMPORTANT! + * + * Use this instead of @s->seq.len if you need to pass the amount + * of data from the buffer to another buffer (userspace, or what not). + * The @s->seq.len on overflow is bigger than the buffer size and + * using it can cause access to undefined memory. + */ +static inline int trace_seq_used(struct trace_seq *s) +{ + return seq_buf_used(&s->seq); +} + +/** * trace_seq_buffer_ptr - return pointer to next location in buffer * @s: trace sequence descriptor * @@ -35,7 +53,7 @@ trace_seq_init(struct trace_seq *s) static inline unsigned char * trace_seq_buffer_ptr(struct trace_seq *s) { - return s->buffer + s->seq.len; + return s->buffer + seq_buf_used(&s->seq); } /** -- cgit v1.1 From 8cd709ae7658a7fd7f6630699e3229188c2591e4 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 29 Oct 2014 15:26:09 -0400 Subject: 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. Link: http://lkml.kernel.org/r/20141104160222.502133196@goodmis.org Link: http://lkml.kernel.org/r/20141114011412.811957882@goodmis.org Tested-by: Jiri Kosina Acked-by: Jiri Kosina Reviewed-by: Petr Mladek Signed-off-by: Steven Rostedt --- include/linux/seq_buf.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h index 93718e5..0800a24 100644 --- a/include/linux/seq_buf.h +++ b/include/linux/seq_buf.h @@ -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; } /* @@ -61,7 +61,7 @@ seq_buf_buffer_left(struct seq_buf *s) if (seq_buf_has_overflowed(s)) return 0; - return (s->size - 1) - s->len; + return s->size - s->len; } /* How much buffer was written? */ -- cgit v1.1 From 01cb06a4c229908d239149017049fdd1fca1dd51 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Wed, 29 Oct 2014 17:30:50 -0400 Subject: 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 the seq_file: seq_path() function, and will help to be able to consolidate the functions between seq_file and trace_seq. Link: http://lkml.kernel.org/r/20141104160222.644881406@goodmis.org Link: http://lkml.kernel.org/r/20141114011412.977571447@goodmis.org Tested-by: Jiri Kosina Acked-by: Jiri Kosina Reviewed-by: Petr Mladek Signed-off-by: Steven Rostedt --- include/linux/seq_buf.h | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'include') diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h index 0800a24..12c6428 100644 --- a/include/linux/seq_buf.h +++ b/include/linux/seq_buf.h @@ -70,6 +70,47 @@ static inline unsigned int seq_buf_used(struct seq_buf *s) return min(s->len, s->size); } +/** + * 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) +{ + WARN_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 { + /* num must be negative on overflow */ + BUG_ON(s->len + num > s->size); + s->len += num; + } +} + extern __printf(2, 3) int seq_buf_printf(struct seq_buf *s, const char *fmt, ...); extern __printf(2, 0) -- cgit v1.1 From 2448913ed2aa7a7424d9b9ca79861d13c746a3f1 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Mon, 3 Nov 2014 18:53:50 -0500 Subject: seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF 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. Link: http://lkml.kernel.org/r/20141104160222.969013383@goodmis.org Tested-by: Jiri Kosina Acked-by: Jiri Kosina Reviewed-by: Petr Mladek Signed-off-by: Steven Rostedt --- include/linux/seq_buf.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h index 12c6428..9aafe0e 100644 --- a/include/linux/seq_buf.h +++ b/include/linux/seq_buf.h @@ -115,8 +115,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); @@ -130,4 +128,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 */ -- cgit v1.1 From afdc34a3d3b823a12a93b822ee1efb566f884032 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Thu, 19 Jun 2014 17:33:31 -0400 Subject: printk: Add per_cpu printk func to allow printk to be diverted 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(). Link: http://lkml.kernel.org/p/20140619213952.209176403@goodmis.org Tested-by: Jiri Kosina Acked-by: Jiri Kosina Acked-by: Paul E. McKenney Reviewed-by: Petr Mladek Signed-off-by: Steven Rostedt --- include/linux/percpu.h | 3 +++ include/linux/printk.h | 2 ++ 2 files changed, 5 insertions(+) (limited to 'include') diff --git a/include/linux/percpu.h b/include/linux/percpu.h index a3aa63e..ba2e85a 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h @@ -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 */ diff --git a/include/linux/printk.h b/include/linux/printk.h index d78125f..3bbd979 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -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, ...); -- cgit v1.1 From 04b74b27c2941e5d62120f6fee3a0a9388a30613 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Fri, 21 Nov 2014 09:16:58 -0500 Subject: printk/percpu: Define printk_func when printk is not defined To avoid include hell, the per_cpu variable printk_func was declared in percpu.h. But it is only defined if printk is defined. As users of printk may also use the printk_func variable, it needs to be defined even if CONFIG_PRINTK is not. Also add a printk.h include in percpu.h just to be safe. Link: http://lkml.kernel.org/r/20141121183215.01ba539c@canb.auug.org.au Reported-by: Stephen Rothwell Signed-off-by: Steven Rostedt --- include/linux/percpu.h | 1 + include/linux/printk.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/percpu.h b/include/linux/percpu.h index ba2e85a..caebf2a 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include diff --git a/include/linux/printk.h b/include/linux/printk.h index 3bbd979..c69be9e 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -124,6 +124,8 @@ static inline __printf(1, 2) __cold void early_printk(const char *s, ...) { } #endif +typedef int(*printk_func_t)(const char *fmt, va_list args); + #ifdef CONFIG_PRINTK asmlinkage __printf(5, 0) int vprintk_emit(int facility, int level, @@ -162,8 +164,6 @@ 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, ...); -- cgit v1.1