linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC][PATCH 00/12 v3] seq-buf/x86/printk: Print all stacks from NMI safely
@ 2014-11-04 15:52 Steven Rostedt
  2014-11-04 15:52 ` [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr() Steven Rostedt
                   ` (11 more replies)
  0 siblings, 12 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 15:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Jiri Kosina, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner

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(-)

^ permalink raw reply	[flat|nested] 77+ messages in thread

* [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr()
  2014-11-04 15:52 [RFC][PATCH 00/12 v3] seq-buf/x86/printk: Print all stacks from NMI safely Steven Rostedt
@ 2014-11-04 15:52 ` Steven Rostedt
  2014-11-04 16:27   ` Paolo Bonzini
                     ` (2 more replies)
  2014-11-04 15:52 ` [RFC][PATCH 02/12 v3] RAS/tracing: Use trace_seq_buffer_ptr() helper instead of open coded Steven Rostedt
                   ` (10 subsequent siblings)
  11 siblings, 3 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 15:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Jiri Kosina, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner, Mark Rustad, Jeff Kirsher,
	Paolo Bonzini

[-- Attachment #1: 0001-x86-kvm-tracing-Use-helper-function-trace_seq_buffer.patch --]
[-- Type: text/plain, Size: 1227 bytes --]

From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>

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.

Cc: Mark Rustad <mark.d.rustad@intel.com>
Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 arch/x86/kvm/mmutrace.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h
index 5aaf35641768..ce463a9cc8fb 100644
--- a/arch/x86/kvm/mmutrace.h
+++ b/arch/x86/kvm/mmutrace.h
@@ -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       \
-- 
2.1.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC][PATCH 02/12 v3] RAS/tracing: Use trace_seq_buffer_ptr() helper instead of open coded
  2014-11-04 15:52 [RFC][PATCH 00/12 v3] seq-buf/x86/printk: Print all stacks from NMI safely Steven Rostedt
  2014-11-04 15:52 ` [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr() Steven Rostedt
@ 2014-11-04 15:52 ` Steven Rostedt
  2014-11-04 19:59   ` Borislav Petkov
  2014-11-05 10:29   ` Petr Mladek
  2014-11-04 15:52 ` [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq Steven Rostedt
                   ` (9 subsequent siblings)
  11 siblings, 2 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 15:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Jiri Kosina, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner, Chen Gong, Borislav Petkov,
	Tony Luck

[-- Attachment #1: 0002-RAS-tracing-Use-trace_seq_buffer_ptr-helper-instead-.patch --]
[-- Type: text/plain, Size: 1071 bytes --]

From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>

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.

Cc: Chen Gong <gong.chen@linux.intel.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Tony Luck <tony.luck@intel.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 drivers/firmware/efi/cper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
index 5b53d6183b6b..4fd9961d552e 100644
--- a/drivers/firmware/efi/cper.c
+++ b/drivers/firmware/efi/cper.c
@@ -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);
-- 
2.1.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-04 15:52 [RFC][PATCH 00/12 v3] seq-buf/x86/printk: Print all stacks from NMI safely Steven Rostedt
  2014-11-04 15:52 ` [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr() Steven Rostedt
  2014-11-04 15:52 ` [RFC][PATCH 02/12 v3] RAS/tracing: Use trace_seq_buffer_ptr() helper instead of open coded Steven Rostedt
@ 2014-11-04 15:52 ` Steven Rostedt
  2014-11-05 14:22   ` Petr Mladek
  2014-11-05 14:26   ` Petr Mladek
  2014-11-04 15:52 ` [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path() Steven Rostedt
                   ` (8 subsequent siblings)
  11 siblings, 2 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 15:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Jiri Kosina, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner

[-- Attachment #1: 0003-tracing-Create-seq_buf-layer-in-trace_seq.patch --]
[-- Type: text/plain, Size: 26112 bytes --]

From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>

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.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 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

diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
new file mode 100644
index 000000000000..97872154d51c
--- /dev/null
+++ b/include/linux/seq_buf.h
@@ -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 */
diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h
index ea6c9dea79e3..27c98fd76503 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 <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;
 }
 
 /*
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 67d6369ddf83..edc98c72a634 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -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
diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
new file mode 100644
index 000000000000..2bf582753902
--- /dev/null
+++ b/kernel/trace/seq_buf.c
@@ -0,0 +1,341 @@
+/*
+ * seq_buf.c
+ *
+ * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * 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.
+ * 
+ */
+#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)
+
+/* How much buffer is written? */
+#define SEQ_BUF_USED(s) min((s)->len, (s)->size - 1)
+
+/**
+ * seq_buf_print_seq - move the contents of seq_buf into a seq_file
+ * @m: the seq_file descriptor that is the destination
+ * @s: the seq_buf descriptor that is the source.
+ *
+ * Returns zero on success, non zero otherwise
+ */
+int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s)
+{
+	unsigned int len = SEQ_BUF_USED(s);
+
+	return seq_write(m, s->buffer, len);
+}
+
+/**
+ * seq_buf_vprintf - sequence printing of information.
+ * @s: seq_buf descriptor
+ * @fmt: printf format string
+ * @args: va_list of arguments from a printf() type function
+ *
+ * Writes a vnprintf() format into the sequencce buffer.
+ *
+ * Returns zero on success, -1 on overflow.
+ */
+int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)
+{
+	int len;
+
+	WARN_ON(s->size == 0);
+
+	if (s->len < s->size) {
+		len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args);
+		if (s->len + len < s->size) {
+			s->len += len;
+			return 0;
+		}
+	}
+	seq_buf_set_overflow(s);
+	return -1;
+}
+
+/**
+ * seq_buf_printf - sequence printing of information
+ * @s: seq_buf descriptor
+ * @fmt: printf format string
+ *
+ * Writes a printf() format into the sequence buffer.
+ *
+ * Returns zero on success, -1 on overflow.
+ */
+int seq_buf_printf(struct seq_buf *s, const char *fmt, ...)
+{
+	va_list ap;
+	int ret;
+
+	va_start(ap, fmt);
+	ret = seq_buf_vprintf(s, fmt, ap);
+	va_end(ap);
+
+	return ret;
+}
+
+/**
+ * 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.
+ */
+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);
+		if (s->len + ret < s->size) {
+			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)
+{
+	unsigned int len = SEQ_BUF_LEFT(s);
+	int ret;
+
+	WARN_ON(s->size == 0);
+
+	if (s->len < s->size) {
+		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)
+{
+	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;
+	}
+	seq_buf_set_overflow(s);
+	return -1;
+}
+
+/**
+ * seq_buf_putc - sequence printing of simple character
+ * @s: seq_buf descriptor
+ * @c: simple character to record
+ *
+ * Copy a single character into the sequence buffer.
+ *
+ * Returns zero on success, -1 on overflow
+ */
+int seq_buf_putc(struct seq_buf *s, unsigned char c)
+{
+	WARN_ON(s->size == 0);
+
+	if (s->len + 1 < s->size) {
+		s->buffer[s->len++] = c;
+		return 0;
+	}
+	seq_buf_set_overflow(s);
+	return -1;
+}
+
+/**
+ * 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);
+
+	if (s->len + len < s->size) {
+		memcpy(s->buffer + s->len, mem, len);
+		s->len += len;
+		return 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;
+
+		/* j increments twice per loop */
+		len -= j / 2;
+		hex[j++] = ' ';
+
+		seq_buf_putmem(s, hex, j);
+		if (seq_buf_has_overflowed(s))
+			return -1;
+	}
+	return 0;
+}
+
+/**
+ * seq_buf_path - copy a path into the sequence buffer
+ * @s: seq_buf descriptor
+ * @path: path to write into the sequence buffer.
+ *
+ * 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)
+{
+	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;
+		}
+	}
+	seq_buf_set_overflow(s);
+	return -1;
+}
+
+/**
+ * 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.
+ *
+ * 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).
+ *
+ * Returns -EFAULT if the copy to userspace fails.
+ */
+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;
+}
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 8a528392b1f4..0c46168e938e 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -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);
 
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 0cc51edde3a8..33525bf6cbf5 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -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);
 
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index f0a0c982cde3..488273458bfd 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -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");
diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
index 1f24ed99dca2..960ccfb2f50c 100644
--- a/kernel/trace/trace_seq.c
+++ b/kernel/trace/trace_seq.c
@@ -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)
 
 /* 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);
 
 	/* 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 1;
 }
 EXPORT_SYMBOL_GPL(trace_seq_printf);
@@ -116,14 +126,20 @@ EXPORT_SYMBOL_GPL(trace_seq_printf);
 int trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp,
 		      int nmaskbits)
 {
-	unsigned int len = TRACE_SEQ_BUF_LEFT(s);
-	int ret;
+	unsigned int save_len = s->seq.len;
 
-	if (s->full || !len)
+	if (s->full)
 		return 0;
 
-	ret = bitmap_scnprintf(s->buffer, len, maskp, nmaskbits);
-	s->len += ret;
+	__trace_seq_init(s);
+
+	seq_buf_bitmask(&s->seq, maskp, nmaskbits);
+
+	if (unlikely(seq_buf_has_overflowed(&s->seq))) {
+		s->seq.len = save_len;
+		s->full = 1;
+		return 0;
+	}
 
 	return 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;
 	int 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);
 
 	/* 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;
 }
 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;
 	int 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);
 
 	/* 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;
 }
 EXPORT_SYMBOL_GPL(trace_seq_bprintf);
 
@@ -222,13 +240,14 @@ int trace_seq_puts(struct trace_seq *s, const char *str)
 	if (s->full)
 		return 0;
 
+	__trace_seq_init(s);
+
 	if (len > TRACE_SEQ_BUF_LEFT(s)) {
 		s->full = 1;
 		return 0;
 	}
 
-	memcpy(s->buffer + s->len, str, len);
-	s->len += len;
+	seq_buf_putmem(&s->seq, str, len);
 
 	return len;
 }
@@ -251,12 +270,14 @@ int trace_seq_putc(struct trace_seq *s, unsigned char c)
 	if (s->full)
 		return 0;
 
+	__trace_seq_init(s);
+
 	if (TRACE_SEQ_BUF_LEFT(s) < 1) {
 		s->full = 1;
 		return 0;
 	}
 
-	s->buffer[s->len++] = c;
+	seq_buf_putc(&s->seq, c);
 
 	return 1;
 }
@@ -279,21 +300,19 @@ int trace_seq_putmem(struct trace_seq *s, const void *mem, unsigned int len)
 	if (s->full)
 		return 0;
 
+	__trace_seq_init(s);
+
 	if (len > TRACE_SEQ_BUF_LEFT(s)) {
 		s->full = 1;
 		return 0;
 	}
 
-	memcpy(s->buffer + s->len, mem, len);
-	s->len += len;
+	seq_buf_putmem(&s->seq, mem, len);
 
 	return len;
 }
 EXPORT_SYMBOL_GPL(trace_seq_putmem);
 
-#define MAX_MEMHEX_BYTES	8U
-#define HEX_CHARS		(MAX_MEMHEX_BYTES*2 + 1)
-
 /**
  * trace_seq_putmem_hex - write raw memory into the buffer in ASCII hex
  * @s: trace sequence descriptor
@@ -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);
+	__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);
+
+	if (unlikely(seq_buf_has_overflowed(&s->seq))) {
+		s->seq.len = save_len;
+		s->full = 1;
+		return 0;
 	}
-	return cnt;
+
+	return ret;
 }
 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);
-	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);
+
+	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;
 }
 EXPORT_SYMBOL_GPL(trace_seq_path);
 
@@ -404,25 +416,7 @@ EXPORT_SYMBOL_GPL(trace_seq_path);
  */
 int trace_seq_to_user(struct trace_seq *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;
+	__trace_seq_init(s);
+	return seq_buf_to_user(&s->seq, ubuf, cnt);
 }
 EXPORT_SYMBOL_GPL(trace_seq_to_user);
-- 
2.1.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
  2014-11-04 15:52 [RFC][PATCH 00/12 v3] seq-buf/x86/printk: Print all stacks from NMI safely Steven Rostedt
                   ` (2 preceding siblings ...)
  2014-11-04 15:52 ` [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq Steven Rostedt
@ 2014-11-04 15:52 ` Steven Rostedt
  2014-11-05 14:45   ` Petr Mladek
  2014-11-06 15:01   ` Petr Mladek
  2014-11-04 15:52 ` [RFC][PATCH 05/12 v3] tracing: Convert seq_buf fields to be like seq_file fields Steven Rostedt
                   ` (7 subsequent siblings)
  11 siblings, 2 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 15:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Jiri Kosina, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner

[-- Attachment #1: 0004-tracing-Convert-seq_buf_path-to-be-like-seq_path.patch --]
[-- Type: text/plain, Size: 2924 bytes --]

From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>

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.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 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(-)

diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
index 97872154d51c..6d1c57d6073f 100644
--- a/include/linux/seq_buf.h
+++ b/include/linux/seq_buf.h
@@ -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);
diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
index 2bf582753902..243123b12d16 100644
--- a/kernel/trace/seq_buf.c
+++ b/kernel/trace/seq_buf.c
@@ -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;
 }
 
 /**
diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
index 960ccfb2f50c..6599577cea15 100644
--- a/kernel/trace/trace_seq.c
+++ b/kernel/trace/trace_seq.c
@@ -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;
-- 
2.1.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC][PATCH 05/12 v3] tracing: Convert seq_buf fields to be like seq_file fields
  2014-11-04 15:52 [RFC][PATCH 00/12 v3] seq-buf/x86/printk: Print all stacks from NMI safely Steven Rostedt
                   ` (3 preceding siblings ...)
  2014-11-04 15:52 ` [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path() Steven Rostedt
@ 2014-11-04 15:52 ` Steven Rostedt
  2014-11-05 15:57   ` Petr Mladek
  2014-11-04 15:52 ` [RFC][PATCH 06/12 v3] tracing: Add a seq_buf_clear() helper and clear len and readpos in init Steven Rostedt
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 15:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Jiri Kosina, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner

[-- Attachment #1: 0005-tracing-Convert-seq_buf-fields-to-be-like-seq_file-f.patch --]
[-- Type: text/plain, Size: 795 bytes --]

From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>

In facilitating the conversion of seq_file to use seq_buf,
have the seq_buf fields match the types used by seq_file.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 include/linux/seq_buf.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
index 6d1c57d6073f..a4d114e6f740 100644
--- a/include/linux/seq_buf.h
+++ b/include/linux/seq_buf.h
@@ -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
-- 
2.1.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC][PATCH 06/12 v3] tracing: Add a seq_buf_clear() helper and clear len and readpos in init
  2014-11-04 15:52 [RFC][PATCH 00/12 v3] seq-buf/x86/printk: Print all stacks from NMI safely Steven Rostedt
                   ` (4 preceding siblings ...)
  2014-11-04 15:52 ` [RFC][PATCH 05/12 v3] tracing: Convert seq_buf fields to be like seq_file fields Steven Rostedt
@ 2014-11-04 15:52 ` Steven Rostedt
  2014-11-05 16:00   ` Petr Mladek
  2014-11-04 15:52 ` [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer Steven Rostedt
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 15:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Jiri Kosina, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner

[-- Attachment #1: 0006-tracing-Add-a-seq_buf_clear-helper-and-clear-len-and.patch --]
[-- Type: text/plain, Size: 921 bytes --]

From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>

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.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 include/linux/seq_buf.h | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
index a4d114e6f740..064a8604ad33 100644
--- a/include/linux/seq_buf.h
+++ b/include/linux/seq_buf.h
@@ -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);
 }
 
 /*
-- 
2.1.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
  2014-11-04 15:52 [RFC][PATCH 00/12 v3] seq-buf/x86/printk: Print all stacks from NMI safely Steven Rostedt
                   ` (5 preceding siblings ...)
  2014-11-04 15:52 ` [RFC][PATCH 06/12 v3] tracing: Add a seq_buf_clear() helper and clear len and readpos in init Steven Rostedt
@ 2014-11-04 15:52 ` Steven Rostedt
  2014-11-05 16:31   ` Petr Mladek
  2014-11-04 15:52 ` [RFC][PATCH 08/12 v3] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions Steven Rostedt
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 15:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Jiri Kosina, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner

[-- Attachment #1: 0007-tracing-Have-seq_buf-use-full-buffer.patch --]
[-- Type: text/plain, Size: 3488 bytes --]

From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>

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.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 include/linux/seq_buf.h |  4 ++--
 kernel/trace/seq_buf.c  | 18 +++++++++---------
 2 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
index 064a8604ad33..3cd25038cb5e 100644
--- a/include/linux/seq_buf.h
+++ b/include/linux/seq_buf.h
@@ -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)
diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
index 243123b12d16..06fd1833e692 100644
--- a/kernel/trace/seq_buf.c
+++ b/kernel/trace/seq_buf.c
@@ -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;
-- 
2.1.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC][PATCH 08/12 v3] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions
  2014-11-04 15:52 [RFC][PATCH 00/12 v3] seq-buf/x86/printk: Print all stacks from NMI safely Steven Rostedt
                   ` (6 preceding siblings ...)
  2014-11-04 15:52 ` [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer Steven Rostedt
@ 2014-11-04 15:52 ` Steven Rostedt
  2014-11-05 16:51   ` Petr Mladek
  2014-11-04 15:52 ` [RFC][PATCH 09/12 v3] seq_buf: Move the seq_buf code to lib/ Steven Rostedt
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 15:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Jiri Kosina, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner

[-- Attachment #1: 0008-tracing-Add-seq_buf_get_buf-and-seq_buf_commit-helpe.patch --]
[-- Type: text/plain, Size: 2570 bytes --]

From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>

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.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 include/linux/seq_buf.h | 40 ++++++++++++++++++++++++++++++++++++++++
 kernel/trace/seq_buf.c  |  7 +++----
 2 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
index 3cd25038cb5e..10c17c61c7a4 100644
--- a/include/linux/seq_buf.h
+++ b/include/linux/seq_buf.h
@@ -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)
diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
index 06fd1833e692..d118d0d6c956 100644
--- a/kernel/trace/seq_buf.c
+++ b/kernel/trace/seq_buf.c
@@ -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;
 }
-- 
2.1.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC][PATCH 09/12 v3] seq_buf: Move the seq_buf code to lib/
  2014-11-04 15:52 [RFC][PATCH 00/12 v3] seq-buf/x86/printk: Print all stacks from NMI safely Steven Rostedt
                   ` (7 preceding siblings ...)
  2014-11-04 15:52 ` [RFC][PATCH 08/12 v3] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions Steven Rostedt
@ 2014-11-04 15:52 ` Steven Rostedt
  2014-11-05 16:57   ` Petr Mladek
  2014-11-04 15:52 ` [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF Steven Rostedt
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 15:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Jiri Kosina, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner

[-- Attachment #1: 0009-seq_buf-Move-the-seq_buf-code-to-lib.patch --]
[-- Type: text/plain, Size: 20319 bytes --]

From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>

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.

Link: http://lkml.kernel.org/p/20140619213952.058255809@goodmis.org

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 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

diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index edc98c72a634..67d6369ddf83 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -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
diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
deleted file mode 100644
index d118d0d6c956..000000000000
--- a/kernel/trace/seq_buf.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * seq_buf.c
- *
- * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
- *
- * 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.
- *
- */
-#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 - (s)->len)
-
-/* How much buffer is written? */
-#define SEQ_BUF_USED(s) min((s)->len, (s)->size)
-
-/**
- * seq_buf_print_seq - move the contents of seq_buf into a seq_file
- * @m: the seq_file descriptor that is the destination
- * @s: the seq_buf descriptor that is the source.
- *
- * Returns zero on success, non zero otherwise
- */
-int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s)
-{
-	unsigned int len = SEQ_BUF_USED(s);
-
-	return seq_write(m, s->buffer, len);
-}
-
-/**
- * seq_buf_vprintf - sequence printing of information.
- * @s: seq_buf descriptor
- * @fmt: printf format string
- * @args: va_list of arguments from a printf() type function
- *
- * Writes a vnprintf() format into the sequencce buffer.
- *
- * Returns zero on success, -1 on overflow.
- */
-int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)
-{
-	int len;
-
-	WARN_ON(s->size == 0);
-
-	if (s->len < s->size) {
-		len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args);
-		if (s->len + len <= s->size) {
-			s->len += len;
-			return 0;
-		}
-	}
-	seq_buf_set_overflow(s);
-	return -1;
-}
-
-/**
- * seq_buf_printf - sequence printing of information
- * @s: seq_buf descriptor
- * @fmt: printf format string
- *
- * Writes a printf() format into the sequence buffer.
- *
- * Returns zero on success, -1 on overflow.
- */
-int seq_buf_printf(struct seq_buf *s, const char *fmt, ...)
-{
-	va_list ap;
-	int ret;
-
-	va_start(ap, fmt);
-	ret = seq_buf_vprintf(s, fmt, ap);
-	va_end(ap);
-
-	return ret;
-}
-
-/**
- * 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.
- */
-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);
-		if (s->len + ret <= s->size) {
-			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)
-{
-	unsigned int len = SEQ_BUF_LEFT(s);
-	int ret;
-
-	WARN_ON(s->size == 0);
-
-	if (s->len < s->size) {
-		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)
-{
-	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;
-	}
-	seq_buf_set_overflow(s);
-	return -1;
-}
-
-/**
- * seq_buf_putc - sequence printing of simple character
- * @s: seq_buf descriptor
- * @c: simple character to record
- *
- * Copy a single character into the sequence buffer.
- *
- * Returns zero on success, -1 on overflow
- */
-int seq_buf_putc(struct seq_buf *s, unsigned char c)
-{
-	WARN_ON(s->size == 0);
-
-	if (s->len + 1 <= s->size) {
-		s->buffer[s->len++] = c;
-		return 0;
-	}
-	seq_buf_set_overflow(s);
-	return -1;
-}
-
-/**
- * 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);
-
-	if (s->len + len <= s->size) {
-		memcpy(s->buffer + s->len, mem, len);
-		s->len += len;
-		return 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;
-
-		/* j increments twice per loop */
-		len -= j / 2;
-		hex[j++] = ' ';
-
-		seq_buf_putmem(s, hex, j);
-		if (seq_buf_has_overflowed(s))
-			return -1;
-	}
-	return 0;
-}
-
-/**
- * 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, const char *esc)
-{
-	char *buf;
-	size_t size = seq_buf_get_buf(s, &buf);
-	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_commit(s, res);
-
-	return res;
-}
-
-/**
- * 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.
- *
- * 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).
- *
- * Returns -EFAULT if the copy to userspace fails.
- */
-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;
-}
diff --git a/lib/Makefile b/lib/Makefile
index 7512dc978f18..a1aa1e81ed36 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -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
diff --git a/lib/seq_buf.c b/lib/seq_buf.c
new file mode 100644
index 000000000000..d118d0d6c956
--- /dev/null
+++ b/lib/seq_buf.c
@@ -0,0 +1,342 @@
+/*
+ * seq_buf.c
+ *
+ * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * 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.
+ *
+ */
+#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 - (s)->len)
+
+/* How much buffer is written? */
+#define SEQ_BUF_USED(s) min((s)->len, (s)->size)
+
+/**
+ * seq_buf_print_seq - move the contents of seq_buf into a seq_file
+ * @m: the seq_file descriptor that is the destination
+ * @s: the seq_buf descriptor that is the source.
+ *
+ * Returns zero on success, non zero otherwise
+ */
+int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s)
+{
+	unsigned int len = SEQ_BUF_USED(s);
+
+	return seq_write(m, s->buffer, len);
+}
+
+/**
+ * seq_buf_vprintf - sequence printing of information.
+ * @s: seq_buf descriptor
+ * @fmt: printf format string
+ * @args: va_list of arguments from a printf() type function
+ *
+ * Writes a vnprintf() format into the sequencce buffer.
+ *
+ * Returns zero on success, -1 on overflow.
+ */
+int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)
+{
+	int len;
+
+	WARN_ON(s->size == 0);
+
+	if (s->len < s->size) {
+		len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args);
+		if (s->len + len <= s->size) {
+			s->len += len;
+			return 0;
+		}
+	}
+	seq_buf_set_overflow(s);
+	return -1;
+}
+
+/**
+ * seq_buf_printf - sequence printing of information
+ * @s: seq_buf descriptor
+ * @fmt: printf format string
+ *
+ * Writes a printf() format into the sequence buffer.
+ *
+ * Returns zero on success, -1 on overflow.
+ */
+int seq_buf_printf(struct seq_buf *s, const char *fmt, ...)
+{
+	va_list ap;
+	int ret;
+
+	va_start(ap, fmt);
+	ret = seq_buf_vprintf(s, fmt, ap);
+	va_end(ap);
+
+	return ret;
+}
+
+/**
+ * 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.
+ */
+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);
+		if (s->len + ret <= s->size) {
+			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)
+{
+	unsigned int len = SEQ_BUF_LEFT(s);
+	int ret;
+
+	WARN_ON(s->size == 0);
+
+	if (s->len < s->size) {
+		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)
+{
+	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;
+	}
+	seq_buf_set_overflow(s);
+	return -1;
+}
+
+/**
+ * seq_buf_putc - sequence printing of simple character
+ * @s: seq_buf descriptor
+ * @c: simple character to record
+ *
+ * Copy a single character into the sequence buffer.
+ *
+ * Returns zero on success, -1 on overflow
+ */
+int seq_buf_putc(struct seq_buf *s, unsigned char c)
+{
+	WARN_ON(s->size == 0);
+
+	if (s->len + 1 <= s->size) {
+		s->buffer[s->len++] = c;
+		return 0;
+	}
+	seq_buf_set_overflow(s);
+	return -1;
+}
+
+/**
+ * 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);
+
+	if (s->len + len <= s->size) {
+		memcpy(s->buffer + s->len, mem, len);
+		s->len += len;
+		return 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;
+
+		/* j increments twice per loop */
+		len -= j / 2;
+		hex[j++] = ' ';
+
+		seq_buf_putmem(s, hex, j);
+		if (seq_buf_has_overflowed(s))
+			return -1;
+	}
+	return 0;
+}
+
+/**
+ * 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, const char *esc)
+{
+	char *buf;
+	size_t size = seq_buf_get_buf(s, &buf);
+	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_commit(s, res);
+
+	return res;
+}
+
+/**
+ * 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.
+ *
+ * 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).
+ *
+ * Returns -EFAULT if the copy to userspace fails.
+ */
+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;
+}
-- 
2.1.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
  2014-11-04 15:52 [RFC][PATCH 00/12 v3] seq-buf/x86/printk: Print all stacks from NMI safely Steven Rostedt
                   ` (8 preceding siblings ...)
  2014-11-04 15:52 ` [RFC][PATCH 09/12 v3] seq_buf: Move the seq_buf code to lib/ Steven Rostedt
@ 2014-11-04 15:52 ` Steven Rostedt
  2014-11-05 17:06   ` Petr Mladek
  2014-11-04 15:52 ` [RFC][PATCH 11/12 v3] printk: Add per_cpu printk func to allow printk to be diverted Steven Rostedt
  2014-11-04 15:52 ` [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs Steven Rostedt
  11 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 15:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Jiri Kosina, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner

[-- Attachment #1: 0010-seq-buf-Make-seq_buf_bprintf-conditional-on-CONFIG_B.patch --]
[-- Type: text/plain, Size: 2381 bytes --]

From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>

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.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 include/linux/seq_buf.h | 7 +++++--
 lib/seq_buf.c           | 2 ++
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
index 10c17c61c7a4..b6291e2de99d 100644
--- a/include/linux/seq_buf.h
+++ b/include/linux/seq_buf.h
@@ -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 */
diff --git a/lib/seq_buf.c b/lib/seq_buf.c
index d118d0d6c956..ad09f8e6f2a6 100644
--- a/lib/seq_buf.c
+++ b/lib/seq_buf.c
@@ -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
-- 
2.1.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC][PATCH 11/12 v3] printk: Add per_cpu printk func to allow printk to be diverted
  2014-11-04 15:52 [RFC][PATCH 00/12 v3] seq-buf/x86/printk: Print all stacks from NMI safely Steven Rostedt
                   ` (9 preceding siblings ...)
  2014-11-04 15:52 ` [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF Steven Rostedt
@ 2014-11-04 15:52 ` Steven Rostedt
  2014-11-06 16:56   ` Petr Mladek
  2014-11-04 15:52 ` [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs Steven Rostedt
  11 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 15:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Jiri Kosina, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner, Paul E. McKenney

[-- Attachment #1: 0011-printk-Add-per_cpu-printk-func-to-allow-printk-to-be.patch --]
[-- Type: text/plain, Size: 3424 bytes --]

From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>

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

Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 include/linux/percpu.h |  3 +++
 include/linux/printk.h |  2 ++
 kernel/printk/printk.c | 38 +++++++++++++++++++++++++++++---------
 3 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index a3aa63e47637..ba2e85a0ff5b 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 d78125f73ac4..3bbd979d32fb 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, ...);
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index ced2b84b1cb7..f7b723f98cb9 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -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;
-- 
2.1.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs
  2014-11-04 15:52 [RFC][PATCH 00/12 v3] seq-buf/x86/printk: Print all stacks from NMI safely Steven Rostedt
                   ` (10 preceding siblings ...)
  2014-11-04 15:52 ` [RFC][PATCH 11/12 v3] printk: Add per_cpu printk func to allow printk to be diverted Steven Rostedt
@ 2014-11-04 15:52 ` Steven Rostedt
  2014-11-04 23:05   ` Jiri Kosina
  2014-11-06 18:41   ` Petr Mladek
  11 siblings, 2 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 15:52 UTC (permalink / raw)
  To: linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Jiri Kosina, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner, Paul E. McKenney

[-- Attachment #1: 0012-x86-nmi-Perform-a-safe-NMI-stack-trace-on-all-CPUs.patch --]
[-- Type: text/plain, Size: 5177 bytes --]

From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>

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.

Link: http://lkml.kernel.org/p/20140619213952.360076309@goodmis.org

Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 arch/x86/kernel/apic/hw_nmi.c | 90 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 85 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c
index 6a1e71bde323..6e7bb0bc6fcd 100644
--- a/arch/x86/kernel/apic/hw_nmi.c
+++ b/arch/x86/kernel/apic/hw_nmi.c
@@ -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;
 	}
-- 
2.1.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr()
  2014-11-04 15:52 ` [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr() Steven Rostedt
@ 2014-11-04 16:27   ` Paolo Bonzini
  2014-11-04 17:17   ` Rustad, Mark D
  2014-11-05 10:28   ` Petr Mladek
  2 siblings, 0 replies; 77+ messages in thread
From: Paolo Bonzini @ 2014-11-04 16:27 UTC (permalink / raw)
  To: Steven Rostedt, linux-kernel
  Cc: Ingo Molnar, Andrew Morton, Jiri Kosina, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner, Mark Rustad, Jeff Kirsher

On 04/11/2014 16:52, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Cc: Mark Rustad <mark.d.rustad@intel.com>
> Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
>  arch/x86/kvm/mmutrace.h | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h
> index 5aaf35641768..ce463a9cc8fb 100644
> --- a/arch/x86/kvm/mmutrace.h
> +++ b/arch/x86/kvm/mmutrace.h
> @@ -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       \
> -- 2.1.1
> 

Acked-by: Paolo Bonzini <pbonzini@redhat.com>

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr()
  2014-11-04 15:52 ` [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr() Steven Rostedt
  2014-11-04 16:27   ` Paolo Bonzini
@ 2014-11-04 17:17   ` Rustad, Mark D
  2014-11-04 19:09     ` Steven Rostedt
  2014-11-05 10:28   ` Petr Mladek
  2 siblings, 1 reply; 77+ messages in thread
From: Rustad, Mark D @ 2014-11-04 17:17 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	Petr Mladek, H. Peter Anvin, Thomas Gleixner, Kirsher, Jeffrey T,
	Paolo Bonzini

[-- Attachment #1: Type: text/plain, Size: 1620 bytes --]

On Nov 4, 2014, at 7:52 AM, Steven Rostedt <rostedt@goodmis.org> wrote:

> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Cc: Mark Rustad <mark.d.rustad@intel.com>
> Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
> arch/x86/kvm/mmutrace.h | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h
> index 5aaf35641768..ce463a9cc8fb 100644
> --- a/arch/x86/kvm/mmutrace.h
> +++ b/arch/x86/kvm/mmutrace.h
> @@ -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.

> 	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       \
> -- 
> 2.1.1

-- 
Mark Rustad, Networking Division, Intel Corporation


[-- Attachment #2: Message signed with OpenPGP using GPGMail --]
[-- Type: application/pgp-signature, Size: 841 bytes --]

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr()
  2014-11-04 17:17   ` Rustad, Mark D
@ 2014-11-04 19:09     ` Steven Rostedt
  2014-11-04 19:35       ` Steven Rostedt
  0 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 19:09 UTC (permalink / raw)
  To: Rustad, Mark D
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	Petr Mladek, H. Peter Anvin, Thomas Gleixner, Kirsher, Jeffrey T,
	Paolo Bonzini

On Tue, 4 Nov 2014 17:17:08 +0000
"Rustad, Mark D" <mark.d.rustad@intel.com> wrote:

> On Nov 4, 2014, at 7:52 AM, Steven Rostedt <rostedt@goodmis.org> wrote:
> 
> > From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> > 
> > 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.
> > 
> > Cc: Mark Rustad <mark.d.rustad@intel.com>
> > Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> > Cc: Paolo Bonzini <pbonzini@redhat.com>
> > Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> > ---
> > arch/x86/kvm/mmutrace.h | 4 ++--
> > 1 file changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h
> > index 5aaf35641768..ce463a9cc8fb 100644
> > --- a/arch/x86/kvm/mmutrace.h
> > +++ b/arch/x86/kvm/mmutrace.h
> > @@ -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.

Ah right. It should be 'char * const'.

Thanks, I'll update it.

-- Steve

> 
> > 	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       \
> > -- 
> > 2.1.1
> 


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr()
  2014-11-04 19:09     ` Steven Rostedt
@ 2014-11-04 19:35       ` Steven Rostedt
  2014-11-04 20:09         ` Rustad, Mark D
  0 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 19:35 UTC (permalink / raw)
  To: Rustad, Mark D
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	Petr Mladek, H. Peter Anvin, Thomas Gleixner, Kirsher, Jeffrey T,
	Paolo Bonzini

On Tue, 4 Nov 2014 14:09:54 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Tue, 4 Nov 2014 17:17:08 +0000
> "Rustad, Mark D" <mark.d.rustad@intel.com> wrote:
> 
> > On Nov 4, 2014, at 7:52 AM, Steven Rostedt <rostedt@goodmis.org> wrote:
> > 
> > > From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> > > 
> > > 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.
> > > 
> > > Cc: Mark Rustad <mark.d.rustad@intel.com>
> > > Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> > > Cc: Paolo Bonzini <pbonzini@redhat.com>
> > > Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> > > ---
> > > arch/x86/kvm/mmutrace.h | 4 ++--
> > > 1 file changed, 2 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h
> > > index 5aaf35641768..ce463a9cc8fb 100644
> > > --- a/arch/x86/kvm/mmutrace.h
> > > +++ b/arch/x86/kvm/mmutrace.h
> > > @@ -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.
> 
> 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


> 
> > 
> > > 	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       \
> > > -- 
> > > 2.1.1
> > 
> 


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 02/12 v3] RAS/tracing: Use trace_seq_buffer_ptr() helper instead of open coded
  2014-11-04 15:52 ` [RFC][PATCH 02/12 v3] RAS/tracing: Use trace_seq_buffer_ptr() helper instead of open coded Steven Rostedt
@ 2014-11-04 19:59   ` Borislav Petkov
  2014-11-05 10:29   ` Petr Mladek
  1 sibling, 0 replies; 77+ messages in thread
From: Borislav Petkov @ 2014-11-04 19:59 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	Petr Mladek, H. Peter Anvin, Thomas Gleixner, Chen Gong,
	Borislav Petkov, Tony Luck

On Tue, Nov 04, 2014 at 10:52:39AM -0500, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Cc: Chen Gong <gong.chen@linux.intel.com>
> Cc: Borislav Petkov <bp@suse.de>
> Cc: Tony Luck <tony.luck@intel.com>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

Acked-by: Borislav Petkov <bp@suse.de>

-- 
Regards/Gruss,
    Boris.

Sent from a fat crate under my desk. Formatting is fine.
--

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr()
  2014-11-04 19:35       ` Steven Rostedt
@ 2014-11-04 20:09         ` Rustad, Mark D
  0 siblings, 0 replies; 77+ messages in thread
From: Rustad, Mark D @ 2014-11-04 20:09 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	Petr Mladek, H. Peter Anvin, Thomas Gleixner, Kirsher, Jeffrey T,
	Paolo Bonzini

[-- Attachment #1: Type: text/plain, Size: 2860 bytes --]

On Nov 4, 2014, at 11:35 AM, Steven Rostedt <rostedt@goodmis.org> wrote:

> On Tue, 4 Nov 2014 14:09:54 -0500
> Steven Rostedt <rostedt@goodmis.org> wrote:
> 
>> On Tue, 4 Nov 2014 17:17:08 +0000
>> "Rustad, Mark D" <mark.d.rustad@intel.com> wrote:
>> 
>>> On Nov 4, 2014, at 7:52 AM, Steven Rostedt <rostedt@goodmis.org> wrote:
>>> 
>>>> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
>>>> 
>>>> 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.
>>>> 
>>>> Cc: Mark Rustad <mark.d.rustad@intel.com>
>>>> Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
>>>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>>>> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
>>>> ---
>>>> arch/x86/kvm/mmutrace.h | 4 ++--
>>>> 1 file changed, 2 insertions(+), 2 deletions(-)
>>>> 
>>>> diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h
>>>> index 5aaf35641768..ce463a9cc8fb 100644
>>>> --- a/arch/x86/kvm/mmutrace.h
>>>> +++ b/arch/x86/kvm/mmutrace.h
>>>> @@ -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.
>> 
>> Ah right. It should be 'char * const'.
>> 
> 
> Actually, I take that back. The contents of saved_ptr should 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.

> 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.

Agreed.

> 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.

> -- Steve
> 
> 
>> 
>>> 
>>>> 	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       \
>>>> -- 
>>>> 2.1.1
>>> 
>> 
> 

Acked-by: Mark Rustad <mark.d.rustad@intel.com>

-- 
Mark Rustad, Networking Division, Intel Corporation


[-- Attachment #2: Message signed with OpenPGP using GPGMail --]
[-- Type: application/pgp-signature, Size: 841 bytes --]

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs
  2014-11-04 15:52 ` [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs Steven Rostedt
@ 2014-11-04 23:05   ` Jiri Kosina
  2014-11-04 23:41     ` Steven Rostedt
  2014-11-06 18:41   ` Petr Mladek
  1 sibling, 1 reply; 77+ messages in thread
From: Jiri Kosina @ 2014-11-04 23:05 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner, Paul E. McKenney

On Tue, 4 Nov 2014, Steven Rostedt wrote:

> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Link: http://lkml.kernel.org/p/20140619213952.360076309@goodmis.org
> 
> Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

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

	Tested-by: Jiri Kosina <jkosina@suse.cz>
	Acked-by: Jiri Kosina <jkosina@suse.cz>

for the whole series.

(*) heavy printk() workload (**) + sysrq-l in parallel
(**) iptables logging every incoming packet + flood ping from another 
     machine

Thanks,

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs
  2014-11-04 23:05   ` Jiri Kosina
@ 2014-11-04 23:41     ` Steven Rostedt
  0 siblings, 0 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-04 23:41 UTC (permalink / raw)
  To: Jiri Kosina
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Petr Mladek,
	H. Peter Anvin, Thomas Gleixner, Paul E. McKenney

On Wed, 5 Nov 2014 00:05:12 +0100 (CET)
Jiri Kosina <jkosina@suse.cz> wrote:

> On Tue, 4 Nov 2014, Steven Rostedt wrote:
> 
> > From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> > 
> > 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.

Hmm, I need to update the change log to say seq_bufs instead of
trace_seqs.

> > 
> > Link: http://lkml.kernel.org/p/20140619213952.360076309@goodmis.org
> > 
> > Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> > Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> 
> 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
> 
> 	Tested-by: Jiri Kosina <jkosina@suse.cz>
> 	Acked-by: Jiri Kosina <jkosina@suse.cz>
> 
> for the whole series.

Thanks! I'll update the commits.

-- Steve

> 
> (*) heavy printk() workload (**) + sysrq-l in parallel
> (**) iptables logging every incoming packet + flood ping from another 
>      machine
> 
> Thanks,
> 


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr()
  2014-11-04 15:52 ` [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr() Steven Rostedt
  2014-11-04 16:27   ` Paolo Bonzini
  2014-11-04 17:17   ` Rustad, Mark D
@ 2014-11-05 10:28   ` Petr Mladek
  2 siblings, 0 replies; 77+ messages in thread
From: Petr Mladek @ 2014-11-05 10:28 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner, Mark Rustad, Jeff Kirsher,
	Paolo Bonzini

On Tue 2014-11-04 10:52:38, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Cc: Mark Rustad <mark.d.rustad@intel.com>
> Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

Reviewed-by: Petr Mladek <pmladek@suse.cz>

Best Regards,
Petr

> ---
>  arch/x86/kvm/mmutrace.h | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h
> index 5aaf35641768..ce463a9cc8fb 100644
> --- a/arch/x86/kvm/mmutrace.h
> +++ b/arch/x86/kvm/mmutrace.h
> @@ -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       \
> -- 
> 2.1.1
> 
> 

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 02/12 v3] RAS/tracing: Use trace_seq_buffer_ptr() helper instead of open coded
  2014-11-04 15:52 ` [RFC][PATCH 02/12 v3] RAS/tracing: Use trace_seq_buffer_ptr() helper instead of open coded Steven Rostedt
  2014-11-04 19:59   ` Borislav Petkov
@ 2014-11-05 10:29   ` Petr Mladek
  1 sibling, 0 replies; 77+ messages in thread
From: Petr Mladek @ 2014-11-05 10:29 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner, Chen Gong, Borislav Petkov,
	Tony Luck

On Tue 2014-11-04 10:52:39, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Cc: Chen Gong <gong.chen@linux.intel.com>
> Cc: Borislav Petkov <bp@suse.de>
> Cc: Tony Luck <tony.luck@intel.com>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

Reviewed-by: Petr Mladek <pmladek@suse.cz>

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-04 15:52 ` [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq Steven Rostedt
@ 2014-11-05 14:22   ` Petr Mladek
  2014-11-05 18:41     ` Steven Rostedt
  2014-11-05 14:26   ` Petr Mladek
  1 sibling, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-05 14:22 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Tue 2014-11-04 10:52:40, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
>  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
> 
> diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> new file mode 100644
> index 000000000000..97872154d51c
> --- /dev/null
> +++ b/include/linux/seq_buf.h
> @@ -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

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.
 */

> + */
> +struct seq_buf {
> +	unsigned char		*buffer;
> +	unsigned int		size;
> +	unsigned int		len;
> +	unsigned int		readpos;
> +};
> +

[...]

> diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
> new file mode 100644
> index 000000000000..2bf582753902
> --- /dev/null
> +++ b/kernel/trace/seq_buf.c
> @@ -0,0 +1,341 @@
> +/*
> + * seq_buf.c
> + *
> + * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
> + *
> + * 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 :-)

> + */
> +#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 */

> +#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.


> +/* How much buffer is written? */

I would write the following to explain the -1:

/* How much buffer is written with valid data */

> +#define SEQ_BUF_USED(s) min((s)->len, (s)->size - 1)

[...]

> +
> +/**
> + * 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.

> + */
> +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);


> +		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).


> +			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)
> +{
> +	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().

> +		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)
> +{
> +	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.

> +	seq_buf_set_overflow(s);
> +	return -1;
> +}
> +

[...]

> +
> +/**
> + * 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);
> +
> +	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?

> +	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;
> +
> +		/* 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.

> +			return -1;
> +	}
> +	return 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.
> + *
> + * 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

> + *
> + * Returns -EFAULT if the copy to userspace fails.
> + */
> +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;
> +}

[...]

> diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
> index 1f24ed99dca2..960ccfb2f50c 100644
> --- a/kernel/trace/trace_seq.c
> +++ b/kernel/trace/trace_seq.c
> @@ -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.

>  /* 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);
>  
>  	/* 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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-04 15:52 ` [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq Steven Rostedt
  2014-11-05 14:22   ` Petr Mladek
@ 2014-11-05 14:26   ` Petr Mladek
  2014-11-05 18:42     ` Steven Rostedt
  1 sibling, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-05 14:26 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Tue 2014-11-04 10:52:40, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
>  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
> 
> diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> new file mode 100644
> index 000000000000..97872154d51c
> --- /dev/null
> +++ b/include/linux/seq_buf.h
> @@ -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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
  2014-11-04 15:52 ` [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path() Steven Rostedt
@ 2014-11-05 14:45   ` Petr Mladek
  2014-11-05 20:10     ` Steven Rostedt
  2014-11-06 15:01   ` Petr Mladek
  1 sibling, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-05 14:45 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Tue 2014-11-04 10:52:41, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
>  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(-)
> 
> diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> index 97872154d51c..6d1c57d6073f 100644
> --- a/include/linux/seq_buf.h
> +++ b/include/linux/seq_buf.h
> @@ -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);
> diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
> index 2bf582753902..243123b12d16 100644
> --- a/kernel/trace/seq_buf.c
> +++ b/kernel/trace/seq_buf.c
> @@ -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);

I would keep this check.

> -	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.

> +	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.

> -	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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 05/12 v3] tracing: Convert seq_buf fields to be like seq_file fields
  2014-11-04 15:52 ` [RFC][PATCH 05/12 v3] tracing: Convert seq_buf fields to be like seq_file fields Steven Rostedt
@ 2014-11-05 15:57   ` Petr Mladek
  2014-11-05 20:14     ` Steven Rostedt
  0 siblings, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-05 15:57 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Tue 2014-11-04 10:52:42, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> In facilitating the conversion of seq_file to use seq_buf,
> have the seq_buf fields match the types used by seq_file.
> 
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
>  include/linux/seq_buf.h | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> index 6d1c57d6073f..a4d114e6f740 100644
> --- a/include/linux/seq_buf.h
> +++ b/include/linux/seq_buf.h
> @@ -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.

> +	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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 06/12 v3] tracing: Add a seq_buf_clear() helper and clear len and readpos in init
  2014-11-04 15:52 ` [RFC][PATCH 06/12 v3] tracing: Add a seq_buf_clear() helper and clear len and readpos in init Steven Rostedt
@ 2014-11-05 16:00   ` Petr Mladek
  0 siblings, 0 replies; 77+ messages in thread
From: Petr Mladek @ 2014-11-05 16:00 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Tue 2014-11-04 10:52:43, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

Reviewed-by: Petr Mladek <pmladek@suse.cz>

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
  2014-11-04 15:52 ` [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer Steven Rostedt
@ 2014-11-05 16:31   ` Petr Mladek
  2014-11-05 20:21     ` Steven Rostedt
  0 siblings, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-05 16:31 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Tue 2014-11-04 10:52:44, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
>  include/linux/seq_buf.h |  4 ++--
>  kernel/trace/seq_buf.c  | 18 +++++++++---------
>  2 files changed, 11 insertions(+), 11 deletions(-)
> 
> diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> index 064a8604ad33..3cd25038cb5e 100644
> --- a/include/linux/seq_buf.h
> +++ b/include/linux/seq_buf.h
> @@ -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)
> diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
> index 243123b12d16..06fd1833e692 100644
> --- a/kernel/trace/seq_buf.c
> +++ b/kernel/trace/seq_buf.c
> @@ -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) {

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

>  			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;
>  		}

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 08/12 v3] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions
  2014-11-04 15:52 ` [RFC][PATCH 08/12 v3] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions Steven Rostedt
@ 2014-11-05 16:51   ` Petr Mladek
  2014-11-05 20:26     ` Steven Rostedt
  2014-11-07 18:39     ` Steven Rostedt
  0 siblings, 2 replies; 77+ messages in thread
From: Petr Mladek @ 2014-11-05 16:51 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Tue 2014-11-04 10:52:45, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
>  include/linux/seq_buf.h | 40 ++++++++++++++++++++++++++++++++++++++++
>  kernel/trace/seq_buf.c  |  7 +++----
>  2 files changed, 43 insertions(+), 4 deletions(-)
> 
> diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> index 3cd25038cb5e..10c17c61c7a4 100644
> --- a/include/linux/seq_buf.h
> +++ b/include/linux/seq_buf.h
> @@ -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;

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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 09/12 v3] seq_buf: Move the seq_buf code to lib/
  2014-11-04 15:52 ` [RFC][PATCH 09/12 v3] seq_buf: Move the seq_buf code to lib/ Steven Rostedt
@ 2014-11-05 16:57   ` Petr Mladek
  2014-11-05 20:32     ` Steven Rostedt
  0 siblings, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-05 16:57 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Tue 2014-11-04 10:52:46, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Link: http://lkml.kernel.org/p/20140619213952.058255809@goodmis.org
> 
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

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:

Reviewed-by: Petr Mladek <pmladek@suse.cz>

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
  2014-11-04 15:52 ` [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF Steven Rostedt
@ 2014-11-05 17:06   ` Petr Mladek
  2014-11-05 20:33     ` Steven Rostedt
  0 siblings, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-05 17:06 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Tue 2014-11-04 10:52:47, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

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:

Reviewed-by: Petr Mladek <pmladek@suse.cz>

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-05 14:22   ` Petr Mladek
@ 2014-11-05 18:41     ` Steven Rostedt
  2014-11-05 20:00       ` Steven Rostedt
  2014-11-06 16:13       ` Petr Mladek
  0 siblings, 2 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-05 18:41 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed, 5 Nov 2014 15:22:22 +0100
Petr Mladek <pmladek@suse.cz> wrote:

> On Tue 2014-11-04 10:52:40, Steven Rostedt wrote:
> > From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> > 
> > 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.
> > 
> > Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> > ---
> >  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
> > 
> > diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> > new file mode 100644
> > index 000000000000..97872154d51c
> > --- /dev/null
> > +++ b/include/linux/seq_buf.h
> > @@ -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
> 
> There is no @overflow flag in the end.
> 

Crap, that was left over from a previos version.

> 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.


>  */
> 
> > + */
> > +struct seq_buf {
> > +	unsigned char		*buffer;
> > +	unsigned int		size;
> > +	unsigned int		len;
> > +	unsigned int		readpos;
> > +};
> > +
> 
> [...]
> 
> > diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
> > new file mode 100644
> > index 000000000000..2bf582753902
> > --- /dev/null
> > +++ b/kernel/trace/seq_buf.c
> > @@ -0,0 +1,341 @@
> > +/*
> > + * seq_buf.c
> > + *
> > + * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
> > + *
> > + * 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 :-)

I had that fixed in my latest version. But I'm nuking the extra line
anyway.

> 
> > + */
> > +#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.

> 
> /* How much buffer is left for valid data */
> 
> > +#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.

> 
> I can't find any cool solution as a macro at the moment. It might be
> better to define an inline function for this.
> 
> 
> > +/* 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.


> > +#define SEQ_BUF_USED(s) min((s)->len, (s)->size - 1)
> 
> [...]
> 
> > +
> > +/**
> > + * 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.

Darn, I thought I caught all the updates of the return value.

Will fix.

> 
> > + */
> > +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);
>

Yep thanks. Luckily its only user didn't care.

Will fix.
 
> 
> > +		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.

Hmm, that's correct, as bitmap_scnprintf() returns the amount written
instead of the amount that it would write like snprintf() would.


> 
> You might want to use "s->size - s->len" instead of SEQ_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.

> 
> 
> > +			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)
> > +{
> > +	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.

> 
> > +		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.


> > +			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);
> > +
> > +	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.


> 
> > +	seq_buf_set_overflow(s);
> > +	return -1;
> > +}
> > +
> 
> [...]
> 
> > +
> > +/**
> > + * 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);
> > +
> > +	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.

> 
> > +	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;
> > +
> > +		/* 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.

> 
> > +			return -1;
> > +	}
> > +	return 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.
> > + *
> > + * 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

Thanks.

> 
> > + *
> > + * Returns -EFAULT if the copy to userspace fails.
> > + */
> > +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;
> > +}
> 
> [...]
> 
> > diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
> > index 1f24ed99dca2..960ccfb2f50c 100644
> > --- a/kernel/trace/trace_seq.c
> > +++ b/kernel/trace/trace_seq.c
> > @@ -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.

Yeah, we should make this check seq_buf itself. Maybe make a static
inline function that is in seq_buf.h.


> 
> >  /* 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);
> >  
> >  	/* 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


> 
> We could do similar thing also in the other functions. We even
> already store the ret value in some of them.
> 
> Best Regards,
> Petr


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-05 14:26   ` Petr Mladek
@ 2014-11-05 18:42     ` Steven Rostedt
  0 siblings, 0 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-05 18:42 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed, 5 Nov 2014 15:26:20 +0100
Petr Mladek <pmladek@suse.cz> wrote:


> > index 000000000000..97872154d51c
> > --- /dev/null
> > +++ b/include/linux/seq_buf.h
> > @@ -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.

Good catch.

I'll remove it.

-- Steve


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-05 18:41     ` Steven Rostedt
@ 2014-11-05 20:00       ` Steven Rostedt
  2014-11-05 21:17         ` Steven Rostedt
  2014-11-06 16:13       ` Petr Mladek
  1 sibling, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-05 20:00 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed, 5 Nov 2014 13:41:47 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:

> > 
> > > + */
> > > +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);
> >
> 
> Yep thanks. Luckily its only user didn't care.
> 
> Will fix.
>  
> > 
> > > +		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.
> 
> Hmm, that's correct, as bitmap_scnprintf() returns the amount written
> instead of the amount that it would write like snprintf() would.
> 
> 
> > 
> > You might want to use "s->size - s->len" instead of SEQ_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;
}


> 
> > 
> > 
> > > +			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;
> > > +
> > > +		/* 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.

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

> 
> > 
> > > +			return -1;
> > > +	}
> > > +	return 0;
> > > +}
> > > +
> > 


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
  2014-11-05 14:45   ` Petr Mladek
@ 2014-11-05 20:10     ` Steven Rostedt
  2014-11-06 14:18       ` Petr Mladek
  0 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-05 20:10 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed, 5 Nov 2014 15:45:53 +0100
Petr Mladek <pmladek@suse.cz> wrote:


> >   */
> > -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.

> 
> > -	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.


> 
> > +	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.

> 
> > -	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.
> 

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


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 05/12 v3] tracing: Convert seq_buf fields to be like seq_file fields
  2014-11-05 15:57   ` Petr Mladek
@ 2014-11-05 20:14     ` Steven Rostedt
  2014-11-06 14:24       ` Petr Mladek
  0 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-05 20:14 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed, 5 Nov 2014 16:57:11 +0100
Petr Mladek <pmladek@suse.cz> wrote:

> On Tue 2014-11-04 10:52:42, Steven Rostedt wrote:
> > From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> > 
> > In facilitating the conversion of seq_file to use seq_buf,
> > have the seq_buf fields match the types used by seq_file.
> > 
> > Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> > ---
> >  include/linux/seq_buf.h | 8 ++++----
> >  1 file changed, 4 insertions(+), 4 deletions(-)
> > 
> > diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> > index 6d1c57d6073f..a4d114e6f740 100644
> > --- a/include/linux/seq_buf.h
> > +++ b/include/linux/seq_buf.h
> > @@ -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.

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.

> 
> > +	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?

Yeah, I purposely kept them different to find the two when needed.

> 
> 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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
  2014-11-05 16:31   ` Petr Mladek
@ 2014-11-05 20:21     ` Steven Rostedt
  2014-11-05 21:06       ` Steven Rostedt
  2014-11-06 15:13       ` Petr Mladek
  0 siblings, 2 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-05 20:21 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed, 5 Nov 2014 17:31:50 +0100
Petr Mladek <pmladek@suse.cz> wrote:


> >  /**
> >   * 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) {
> 
> 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.

> 
> 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.

> 
> 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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 08/12 v3] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions
  2014-11-05 16:51   ` Petr Mladek
@ 2014-11-05 20:26     ` Steven Rostedt
  2014-11-07 18:39     ` Steven Rostedt
  1 sibling, 0 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-05 20:26 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed, 5 Nov 2014 17:51:25 +0100
Petr Mladek <pmladek@suse.cz> wrote:


> > +
> > +/**
> > + * 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;
> 
> 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);

Yeah, I agree with using the seq_buf_set_overflow().

> 
> 
> Note that this whole patch depends on the decision about the 7th patch
> ("tracing: Have seq_buf use full buffer").

Which I have decided to do.

> 
> 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.
> 

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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 09/12 v3] seq_buf: Move the seq_buf code to lib/
  2014-11-05 16:57   ` Petr Mladek
@ 2014-11-05 20:32     ` Steven Rostedt
  0 siblings, 0 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-05 20:32 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed, 5 Nov 2014 17:57:26 +0100
Petr Mladek <pmladek@suse.cz> 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.

> 
> Reviewed-by: Petr Mladek <pmladek@suse.cz>

Thanks,

-- Steve


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
  2014-11-05 17:06   ` Petr Mladek
@ 2014-11-05 20:33     ` Steven Rostedt
  2014-11-05 20:42       ` Steven Rostedt
  0 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-05 20:33 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed, 5 Nov 2014 18:06:05 +0100
Petr Mladek <pmladek@suse.cz> wrote:

> On Tue 2014-11-04 10:52:47, Steven Rostedt wrote:
> > From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> > 
> > 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.
> > 
> > Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> 
> 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.

> 
> Otherwise, the change looks good in itself, so:
> 
> Reviewed-by: Petr Mladek <pmladek@suse.cz>

Thanks,

-- Steve


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
  2014-11-05 20:33     ` Steven Rostedt
@ 2014-11-05 20:42       ` Steven Rostedt
  2014-11-06 14:39         ` Petr Mladek
  0 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-05 20:42 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner, Junio C Hamano

On Wed, 5 Nov 2014 15:33:55 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Wed, 5 Nov 2014 18:06:05 +0100
> Petr Mladek <pmladek@suse.cz> wrote:
> 
> > On Tue 2014-11-04 10:52:47, Steven Rostedt wrote:
> > > From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> > > 
> > > 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.
> > > 
> > > Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> > 
> > 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.
> 

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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
  2014-11-05 20:21     ` Steven Rostedt
@ 2014-11-05 21:06       ` Steven Rostedt
  2014-11-06 15:31         ` Petr Mladek
  2014-11-06 15:13       ` Petr Mladek
  1 sibling, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-05 21:06 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed, 5 Nov 2014 15:21:30 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:
 
> > 
> > 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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-05 20:00       ` Steven Rostedt
@ 2014-11-05 21:17         ` Steven Rostedt
  2014-11-05 21:21           ` Steven Rostedt
  0 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-05 21:17 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed, 5 Nov 2014 15:00:07 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Wed, 5 Nov 2014 13:41:47 -0500
> Steven Rostedt <rostedt@goodmis.org> wrote:
> 
> > > 
> > > > + */
> > > > +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);
> > >
> > 
> > Yep thanks. Luckily its only user didn't care.
> > 
> > Will fix.
> >  
> > > 
> > > > +		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.
> > 
> > Hmm, that's correct, as bitmap_scnprintf() returns the amount written
> > instead of the amount that it would write like snprintf() would.
> > 
> > 
> > > 
> > > You might want to use "s->size - s->len" instead of SEQ_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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-05 21:17         ` Steven Rostedt
@ 2014-11-05 21:21           ` Steven Rostedt
  2014-11-06 16:33             ` Petr Mladek
  0 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-05 21:21 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed, 5 Nov 2014 16:17:20 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Wed, 5 Nov 2014 15:00:07 -0500
> Steven Rostedt <rostedt@goodmis.org> wrote:
> 
> > On Wed, 5 Nov 2014 13:41:47 -0500
> > Steven Rostedt <rostedt@goodmis.org> wrote:
> > 
> > > > 
> > > > > + */
> > > > > +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);
> > > >
> > > 
> > > Yep thanks. Luckily its only user didn't care.
> > > 
> > > Will fix.
> > >  
> > > > 
> > > > > +		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.
> > > 
> > > Hmm, that's correct, as bitmap_scnprintf() returns the amount written
> > > instead of the amount that it would write like snprintf() would.
> > > 
> > > 
> > > > 
> > > > You might want to use "s->size - s->len" instead of SEQ_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);

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

> 	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


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
  2014-11-05 20:10     ` Steven Rostedt
@ 2014-11-06 14:18       ` Petr Mladek
  2014-11-06 21:09         ` Steven Rostedt
  0 siblings, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-06 14:18 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed 2014-11-05 15:10:53, Steven Rostedt wrote:
> On Wed, 5 Nov 2014 15:45:53 +0100
> Petr Mladek <pmladek@suse.cz> wrote:
> 
> 
> > >   */
> > > -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.

great :-)

> > 
> > > -	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.

Ah, I have missed this.

> 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.

[...]

> > 
> > > -	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.
> > 
> 
> 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.

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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 05/12 v3] tracing: Convert seq_buf fields to be like seq_file fields
  2014-11-05 20:14     ` Steven Rostedt
@ 2014-11-06 14:24       ` Petr Mladek
  0 siblings, 0 replies; 77+ messages in thread
From: Petr Mladek @ 2014-11-06 14:24 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed 2014-11-05 15:14:46, Steven Rostedt wrote:
> On Wed, 5 Nov 2014 16:57:11 +0100
> Petr Mladek <pmladek@suse.cz> wrote:
> 
> > On Tue 2014-11-04 10:52:42, Steven Rostedt wrote:
> > > From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> > > 
> > > In facilitating the conversion of seq_file to use seq_buf,
> > > have the seq_buf fields match the types used by seq_file.
> > > 
> > > Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> > > ---
> > >  include/linux/seq_buf.h | 8 ++++----
> > >  1 file changed, 4 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> > > index 6d1c57d6073f..a4d114e6f740 100644
> > > --- a/include/linux/seq_buf.h
> > > +++ b/include/linux/seq_buf.h
> > > @@ -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.
> 
> 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.
> 
> > 
> > > +	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?
> 
> 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.

> >
> > 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.

Fair enough. I am fine with the explanation.

Reviewed-by: Petr Mladek <pmladek@suse.cz>

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
  2014-11-05 20:42       ` Steven Rostedt
@ 2014-11-06 14:39         ` Petr Mladek
  2014-11-07 20:36           ` Junio C Hamano
  0 siblings, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-06 14:39 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner, Junio C Hamano

On Wed 2014-11-05 15:42:03, Steven Rostedt wrote:
> On Wed, 5 Nov 2014 15:33:55 -0500
> Steven Rostedt <rostedt@goodmis.org> wrote:
> 
> > On Wed, 5 Nov 2014 18:06:05 +0100
> > Petr Mladek <pmladek@suse.cz> wrote:
> > 
> > > On Tue 2014-11-04 10:52:47, Steven Rostedt wrote:
> > > > From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> > > > 
> > > > 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.
> > > > 
> > > > Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> > > 
> > > 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.
> > 
> 
> 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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
  2014-11-04 15:52 ` [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path() Steven Rostedt
  2014-11-05 14:45   ` Petr Mladek
@ 2014-11-06 15:01   ` Petr Mladek
  2014-11-07 18:34     ` Steven Rostedt
  1 sibling, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-06 15:01 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Tue 2014-11-04 10:52:41, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
>  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(-)
> 
> diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> index 97872154d51c..6d1c57d6073f 100644
> --- a/include/linux/seq_buf.h
> +++ b/include/linux/seq_buf.h
> @@ -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);
> diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
> index 2bf582753902..243123b12d16 100644
> --- a/kernel/trace/seq_buf.c
> +++ b/kernel/trace/seq_buf.c
> @@ -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()

>   */
> -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)
>  {
[...]
> +	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;

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
  2014-11-05 20:21     ` Steven Rostedt
  2014-11-05 21:06       ` Steven Rostedt
@ 2014-11-06 15:13       ` Petr Mladek
  1 sibling, 0 replies; 77+ messages in thread
From: Petr Mladek @ 2014-11-06 15:13 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed 2014-11-05 15:21:30, Steven Rostedt wrote:
> On Wed, 5 Nov 2014 17:31:50 +0100
> Petr Mladek <pmladek@suse.cz> wrote:
> 
> 
> > >  /**
> > >   * 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) {
> > 
> > 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.

That is cool! I did not know that there was also this variant of the
printf() functions. I am still learning.

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
  2014-11-05 21:06       ` Steven Rostedt
@ 2014-11-06 15:31         ` Petr Mladek
  2014-11-06 19:24           ` Steven Rostedt
  0 siblings, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-06 15:31 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed 2014-11-05 16:06:18, Steven Rostedt wrote:
> On Wed, 5 Nov 2014 15:21:30 -0500
> Steven Rostedt <rostedt@goodmis.org> wrote:
>  
> > > 
> > > 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.

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.


> 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.

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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-05 18:41     ` Steven Rostedt
  2014-11-05 20:00       ` Steven Rostedt
@ 2014-11-06 16:13       ` Petr Mladek
  1 sibling, 0 replies; 77+ messages in thread
From: Petr Mladek @ 2014-11-06 16:13 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed 2014-11-05 13:41:47, Steven Rostedt wrote:
> On Wed, 5 Nov 2014 15:22:22 +0100
> Petr Mladek <pmladek@suse.cz> wrote:
> 
> > On Tue 2014-11-04 10:52:40, Steven Rostedt wrote:
> > > From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> > 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.

Fair enough.

> > > + */
> > > +#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.

Yup. Let's leave it as is.
 
> > 
> > /* How much buffer is left for valid data */
> > 
> > > +#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.

> > > +
> > > +/**
> > > + * 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);
> > > +
> > > +	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.

Fair enough.

> 
> > 
> > > + *
> > > + * Returns -EFAULT if the copy to userspace fails.
> > > + */
> > > +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;
> > > +}
> > 
> > [...]
> > 
> > > diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
> > > index 1f24ed99dca2..960ccfb2f50c 100644
> > > --- a/kernel/trace/trace_seq.c
> > > +++ b/kernel/trace/trace_seq.c
> > > @@ -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.
> 
> Yeah, we should make this check seq_buf itself. Maybe make a static
> inline function that is in seq_buf.h.

The inline function in seq_buf.h looks like a good idea.

> > 
> > >  /* 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);
> > >  
> > >  	/* 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.

I see.
 
> There's already patches out to convert the seq_file calls as well.

Good to know.

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-05 21:21           ` Steven Rostedt
@ 2014-11-06 16:33             ` Petr Mladek
  2014-11-07 18:30               ` Steven Rostedt
  0 siblings, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-06 16:33 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Wed 2014-11-05 16:21:46, Steven Rostedt wrote:
> On Wed, 5 Nov 2014 16:17:20 -0500
> Steven Rostedt <rostedt@goodmis.org> wrote:
> 
> > On Wed, 5 Nov 2014 15:00:07 -0500
> > Steven Rostedt <rostedt@goodmis.org> wrote:
> > 
> > > On Wed, 5 Nov 2014 13:41:47 -0500
> > > Steven Rostedt <rostedt@goodmis.org> wrote:
> > > 
> > > > > 
> > > > > > + */
> > > > > > +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);
> > > > >
> > > > 
> > > > Yep thanks. Luckily its only user didn't care.
> > > > 
> > > > Will fix.
> > > >  
> > > > > 
> > > > > > +		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.
> > > > 
> > > > Hmm, that's correct, as bitmap_scnprintf() returns the amount written
> > > > instead of the amount that it would write like snprintf() would.
> > > > 
> > > > 
> > > > > 
> > > > > You might want to use "s->size - s->len" instead of SEQ_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);
> 
> 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);


> > 	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.

> > 		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.
> > 		 */

This is great explanation. You might want to move it above the
"if (len > 1)" if you agree with it.

> > 		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.

> > 			s->len += ret;
> > 			return 0;
> > 		}
> > 	}
> > 	seq_buf_set_overflow(s);
> > 	return -1;
> > }


Best Regards,
Petr

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 11/12 v3] printk: Add per_cpu printk func to allow printk to be diverted
  2014-11-04 15:52 ` [RFC][PATCH 11/12 v3] printk: Add per_cpu printk func to allow printk to be diverted Steven Rostedt
@ 2014-11-06 16:56   ` Petr Mladek
  0 siblings, 0 replies; 77+ messages in thread
From: Petr Mladek @ 2014-11-06 16:56 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner, Paul E. McKenney

On Tue 2014-11-04 10:52:48, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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
> 
> Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

Looks fine to me.

Reviewed-by: Petr Mladek <pmladek@suse.cz>

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs
  2014-11-04 15:52 ` [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs Steven Rostedt
  2014-11-04 23:05   ` Jiri Kosina
@ 2014-11-06 18:41   ` Petr Mladek
  2014-11-07 18:56     ` Steven Rostedt
  1 sibling, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-06 18:41 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner, Paul E. McKenney

On Tue 2014-11-04 10:52:49, Steven Rostedt wrote:
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 
> 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.
> 
> Link: http://lkml.kernel.org/p/20140619213952.360076309@goodmis.org
> 
> Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
>  arch/x86/kernel/apic/hw_nmi.c | 90 ++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 85 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c
> index 6a1e71bde323..6e7bb0bc6fcd 100644
> --- a/arch/x86/kernel/apic/hw_nmi.c
> +++ b/arch/x86/kernel/apic/hw_nmi.c
> @@ -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)

I would rename the arguments:

	"last -> first"
	"pos -> last"

or maybe better would be to pass first positon and len.

> +{
> +	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();
>  	}
>  
> +	/*
> +	 * 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.


> +		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".

> +			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)

> +			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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
  2014-11-06 15:31         ` Petr Mladek
@ 2014-11-06 19:24           ` Steven Rostedt
  2014-11-07  9:11             ` Petr Mladek
  0 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-06 19:24 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Thu, 6 Nov 2014 16:31:07 +0100
Petr Mladek <pmladek@suse.cz> 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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
  2014-11-06 14:18       ` Petr Mladek
@ 2014-11-06 21:09         ` Steven Rostedt
  0 siblings, 0 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-06 21:09 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Thu, 6 Nov 2014 15:18:22 +0100
Petr Mladek <pmladek@suse.cz> wrote:


> 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.

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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
  2014-11-06 19:24           ` Steven Rostedt
@ 2014-11-07  9:11             ` Petr Mladek
  2014-11-07 18:37               ` Steven Rostedt
  0 siblings, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-07  9:11 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Thu 2014-11-06 14:24:02, Steven Rostedt wrote:
> On Thu, 6 Nov 2014 16:31:07 +0100
> Petr Mladek <pmladek@suse.cz> 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.

Sounds like a good plan.

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-06 16:33             ` Petr Mladek
@ 2014-11-07 18:30               ` Steven Rostedt
  2014-11-07 18:59                 ` Joe Perches
  2014-11-10 13:53                 ` Petr Mladek
  0 siblings, 2 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-07 18:30 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner


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 11674c8df0580a03a2517e3a8e4705c47c663564 Mon Sep 17 00:00:00 2001
From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
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.

Link: http://lkml.kernel.org/r/20141104160221.864997179@goodmis.org

Tested-by: Jiri Kosina <jkosina@suse.cz>
Acked-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 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

diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
new file mode 100644
index 000000000000..64bf5a43411e
--- /dev/null
+++ b/include/linux/seq_buf.h
@@ -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 */
diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h
index ea6c9dea79e3..27c98fd76503 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 <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;
 }
 
 /*
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 67d6369ddf83..edc98c72a634 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -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
diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
new file mode 100644
index 000000000000..88738b200bf3
--- /dev/null
+++ b/kernel/trace/seq_buf.c
@@ -0,0 +1,341 @@
+/*
+ * seq_buf.c
+ *
+ * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * 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.
+ */
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+#include <linux/seq_buf.h>
+
+/* How much buffer is written? */
+#define SEQ_BUF_USED(s) min((s)->len, (s)->size - 1)
+
+/**
+ * seq_buf_print_seq - move the contents of seq_buf into a seq_file
+ * @m: the seq_file descriptor that is the destination
+ * @s: the seq_buf descriptor that is the source.
+ *
+ * Returns zero on success, non zero otherwise
+ */
+int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s)
+{
+	unsigned int len = SEQ_BUF_USED(s);
+
+	return seq_write(m, s->buffer, len);
+}
+
+/**
+ * seq_buf_vprintf - sequence printing of information.
+ * @s: seq_buf descriptor
+ * @fmt: printf format string
+ * @args: va_list of arguments from a printf() type function
+ *
+ * Writes a vnprintf() format into the sequencce buffer.
+ *
+ * Returns zero on success, -1 on overflow.
+ */
+int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)
+{
+	int len;
+
+	WARN_ON(s->size == 0);
+
+	if (s->len < s->size) {
+		len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args);
+		if (s->len + len < s->size) {
+			s->len += len;
+			return 0;
+		}
+	}
+	seq_buf_set_overflow(s);
+	return -1;
+}
+
+/**
+ * seq_buf_printf - sequence printing of information
+ * @s: seq_buf descriptor
+ * @fmt: printf format string
+ *
+ * Writes a printf() format into the sequence buffer.
+ *
+ * Returns zero on success, -1 on overflow.
+ */
+int seq_buf_printf(struct seq_buf *s, const char *fmt, ...)
+{
+	va_list ap;
+	int ret;
+
+	va_start(ap, fmt);
+	ret = seq_buf_vprintf(s, fmt, ap);
+	va_end(ap);
+
+	return ret;
+}
+
+/**
+ * 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);
+	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);
+		if (ret < len) {
+			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)
+{
+	unsigned int len = seq_buf_buffer_left(s);
+	int ret;
+
+	WARN_ON(s->size == 0);
+
+	if (s->len < s->size) {
+		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)
+{
+	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;
+	}
+	seq_buf_set_overflow(s);
+	return -1;
+}
+
+/**
+ * seq_buf_putc - sequence printing of simple character
+ * @s: seq_buf descriptor
+ * @c: simple character to record
+ *
+ * Copy a single character into the sequence buffer.
+ *
+ * Returns zero on success, -1 on overflow
+ */
+int seq_buf_putc(struct seq_buf *s, unsigned char c)
+{
+	WARN_ON(s->size == 0);
+
+	if (s->len + 1 < s->size) {
+		s->buffer[s->len++] = c;
+		return 0;
+	}
+	seq_buf_set_overflow(s);
+	return -1;
+}
+
+/**
+ * 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);
+
+	if (s->len + len < s->size) {
+		memcpy(s->buffer + s->len, mem, len);
+		s->len += len;
+		return 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;
+
+		/* j increments twice per loop */
+		len -= j / 2;
+		hex[j++] = ' ';
+
+		seq_buf_putmem(s, hex, j);
+		if (seq_buf_has_overflowed(s))
+			return -1;
+	}
+	return 0;
+}
+
+/**
+ * seq_buf_path - copy a path into the sequence buffer
+ * @s: seq_buf descriptor
+ * @path: path to write into the sequence buffer.
+ *
+ * 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)
+{
+	unsigned int len = seq_buf_buffer_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;
+		}
+	}
+	seq_buf_set_overflow(s);
+	return -1;
+}
+
+/**
+ * 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.
+ *
+ * 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
+ * sequence (@s->len == @s->readpos).
+ *
+ * Returns -EFAULT if the copy to userspace fails.
+ */
+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;
+}
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 8a528392b1f4..0c46168e938e 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -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);
 
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 0cc51edde3a8..33525bf6cbf5 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -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);
 
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index f0a0c982cde3..488273458bfd 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -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");
diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
index 1f24ed99dca2..3ad8738aea19 100644
--- a/kernel/trace/trace_seq.c
+++ b/kernel/trace/trace_seq.c
@@ -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) seq_buf_buffer_left(&(s)->seq)
 
 /* 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);
 
 	/* 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 1;
 }
 EXPORT_SYMBOL_GPL(trace_seq_printf);
@@ -116,14 +126,20 @@ EXPORT_SYMBOL_GPL(trace_seq_printf);
 int trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp,
 		      int nmaskbits)
 {
-	unsigned int len = TRACE_SEQ_BUF_LEFT(s);
-	int ret;
+	unsigned int save_len = s->seq.len;
 
-	if (s->full || !len)
+	if (s->full)
 		return 0;
 
-	ret = bitmap_scnprintf(s->buffer, len, maskp, nmaskbits);
-	s->len += ret;
+	__trace_seq_init(s);
+
+	seq_buf_bitmask(&s->seq, maskp, nmaskbits);
+
+	if (unlikely(seq_buf_has_overflowed(&s->seq))) {
+		s->seq.len = save_len;
+		s->full = 1;
+		return 0;
+	}
 
 	return 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;
 	int 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);
 
 	/* 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;
 }
 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;
 	int 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);
 
 	/* 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;
 }
 EXPORT_SYMBOL_GPL(trace_seq_bprintf);
 
@@ -222,13 +240,14 @@ int trace_seq_puts(struct trace_seq *s, const char *str)
 	if (s->full)
 		return 0;
 
+	__trace_seq_init(s);
+
 	if (len > TRACE_SEQ_BUF_LEFT(s)) {
 		s->full = 1;
 		return 0;
 	}
 
-	memcpy(s->buffer + s->len, str, len);
-	s->len += len;
+	seq_buf_putmem(&s->seq, str, len);
 
 	return len;
 }
@@ -251,12 +270,14 @@ int trace_seq_putc(struct trace_seq *s, unsigned char c)
 	if (s->full)
 		return 0;
 
+	__trace_seq_init(s);
+
 	if (TRACE_SEQ_BUF_LEFT(s) < 1) {
 		s->full = 1;
 		return 0;
 	}
 
-	s->buffer[s->len++] = c;
+	seq_buf_putc(&s->seq, c);
 
 	return 1;
 }
@@ -279,21 +300,19 @@ int trace_seq_putmem(struct trace_seq *s, const void *mem, unsigned int len)
 	if (s->full)
 		return 0;
 
+	__trace_seq_init(s);
+
 	if (len > TRACE_SEQ_BUF_LEFT(s)) {
 		s->full = 1;
 		return 0;
 	}
 
-	memcpy(s->buffer + s->len, mem, len);
-	s->len += len;
+	seq_buf_putmem(&s->seq, mem, len);
 
 	return len;
 }
 EXPORT_SYMBOL_GPL(trace_seq_putmem);
 
-#define MAX_MEMHEX_BYTES	8U
-#define HEX_CHARS		(MAX_MEMHEX_BYTES*2 + 1)
-
 /**
  * trace_seq_putmem_hex - write raw memory into the buffer in ASCII hex
  * @s: trace sequence descriptor
@@ -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);
+	__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);
+
+	if (unlikely(seq_buf_has_overflowed(&s->seq))) {
+		s->seq.len = save_len;
+		s->full = 1;
+		return 0;
 	}
-	return cnt;
+
+	return ret;
 }
 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);
-	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);
+
+	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;
 }
 EXPORT_SYMBOL_GPL(trace_seq_path);
 
@@ -404,25 +416,7 @@ EXPORT_SYMBOL_GPL(trace_seq_path);
  */
 int trace_seq_to_user(struct trace_seq *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;
+	__trace_seq_init(s);
+	return seq_buf_to_user(&s->seq, ubuf, cnt);
 }
 EXPORT_SYMBOL_GPL(trace_seq_to_user);
-- 
2.1.1


^ permalink raw reply related	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
  2014-11-06 15:01   ` Petr Mladek
@ 2014-11-07 18:34     ` Steven Rostedt
  2014-11-10 14:03       ` Petr Mladek
  0 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-07 18:34 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner


I made a few touch ups on this patch.

-- Steve

>From 309e8ce4cc1605d3038b16b8e43219a2867f47b1 Mon Sep 17 00:00:00 2001
From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
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.

Link: http://lkml.kernel.org/r/20141104160222.048795666@goodmis.org

Tested-by: Jiri Kosina <jkosina@suse.cz>
Acked-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 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(-)

diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
index 64bf5a43411e..aec09b126082 100644
--- a/include/linux/seq_buf.h
+++ b/include/linux/seq_buf.h
@@ -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);
diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
index 88738b200bf3..ac6eb864c946 100644
--- a/kernel/trace/seq_buf.c
+++ b/kernel/trace/seq_buf.c
@@ -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;
 }
 
 /**
diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
index 3ad8738aea19..64550ed28e76 100644
--- a/kernel/trace/trace_seq.c
+++ b/kernel/trace/trace_seq.c
@@ -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);
 
-- 
2.1.1


^ permalink raw reply related	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
  2014-11-07  9:11             ` Petr Mladek
@ 2014-11-07 18:37               ` Steven Rostedt
  2014-11-10 18:11                 ` Petr Mladek
  0 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-07 18:37 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner


Some more touch ups.

-- Steve

>From 7e724556c21178a9890b31ff57f69761b41f435a Mon Sep 17 00:00:00 2001
From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
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.

Link: http://lkml.kernel.org/r/20141104160222.502133196@goodmis.org

Tested-by: Jiri Kosina <jkosina@suse.cz>
Acked-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 include/linux/seq_buf.h |  6 +++---
 kernel/trace/seq_buf.c  | 19 +++++++++++--------
 2 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
index f68fde850ef7..4aab47d10760 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;
 }
 
 /*
@@ -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)
diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
index ac6eb864c946..8e60b5c1b9f3 100644
--- a/kernel/trace/seq_buf.c
+++ b/kernel/trace/seq_buf.c
@@ -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;
-- 
2.1.1


^ permalink raw reply related	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 08/12 v3] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions
  2014-11-05 16:51   ` Petr Mladek
  2014-11-05 20:26     ` Steven Rostedt
@ 2014-11-07 18:39     ` Steven Rostedt
  2014-11-10 18:33       ` Petr Mladek
  1 sibling, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-07 18:39 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

More updates. Hmm, maybe I should have posted the full series ;-)

-- Steve

>From 41a3f3f5e772ca26ef4441a0312d3f108693d7dc Mon Sep 17 00:00:00 2001
From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
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 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

Tested-by: Jiri Kosina <jkosina@suse.cz>
Acked-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
---
 include/linux/seq_buf.h | 40 ++++++++++++++++++++++++++++++++++++++++
 kernel/trace/seq_buf.c  |  7 +++----
 2 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
index 4aab47d10760..7dacdc791225 100644
--- a/include/linux/seq_buf.h
+++ b/include/linux/seq_buf.h
@@ -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)
diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
index 8e60b5c1b9f3..25090f81ea8a 100644
--- a/kernel/trace/seq_buf.c
+++ b/kernel/trace/seq_buf.c
@@ -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;
 }
-- 
2.1.1


^ permalink raw reply related	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs
  2014-11-06 18:41   ` Petr Mladek
@ 2014-11-07 18:56     ` Steven Rostedt
  2014-11-10 18:58       ` Petr Mladek
  0 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-07 18:56 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner, Paul E. McKenney

On Thu, 6 Nov 2014 19:41:55 +0100
Petr Mladek <pmladek@suse.cz> wrote:
 
> >  /* "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.

I switched it to "start" and "end" to not be confused by the last_i
that is being passed in.

> 
> > +{
> > +	const char *buf = s->buffer + last;
> > +
> > +	printk("%.*s", (pos - last) + 1, buf);
> > +}
> 



> >  
> > +	/*
> > +	 * 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.
> 
> 
> > +		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".

Well, we really don't *need* to ;-)

But for correctness sake, I agree, it should be last_i < i.

> 
> > +			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

> 
> > +			pr_cont("\n");
> > +		}
> > +	}
> > +
> 


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-07 18:30               ` Steven Rostedt
@ 2014-11-07 18:59                 ` Joe Perches
  2014-11-07 19:10                   ` Steven Rostedt
  2014-11-10 13:53                 ` Petr Mladek
  1 sibling, 1 reply; 77+ messages in thread
From: Joe Perches @ 2014-11-07 18:59 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Petr Mladek, linux-kernel, Ingo Molnar, Andrew Morton,
	Jiri Kosina, H. Peter Anvin, Thomas Gleixner

On Fri, 2014-11-07 at 13:30 -0500, Steven Rostedt wrote:
> 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:

> 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
[]
> diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
[]
> +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);

Maybe remove the extern bits from the function definitions?
And maybe the unsigned int len/cnt could be size_t

> diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.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);

Maybe the PAGE_SIZE uses could be ARRAY_SIZE(s->buffer)

> diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
[]
>  /* 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))

min_t?
maybe this should be FIELD_SIZEOF(struct trace_seq, buffer) - 1





^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-07 18:59                 ` Joe Perches
@ 2014-11-07 19:10                   ` Steven Rostedt
  0 siblings, 0 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-07 19:10 UTC (permalink / raw)
  To: Joe Perches
  Cc: Petr Mladek, linux-kernel, Ingo Molnar, Andrew Morton,
	Jiri Kosina, H. Peter Anvin, Thomas Gleixner

On Fri, 07 Nov 2014 10:59:27 -0800
Joe Perches <joe@perches.com> wrote:


> > 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
> []
> > diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> []
> > +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);
> 
> Maybe remove the extern bits from the function definitions?

Yeah, probably should have done that. Not sure why I kept them. Cut and
paste?

> And maybe the unsigned int len/cnt could be size_t

The struct does get changed later to match seq_file.

> 
> > diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.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);
> 
> Maybe the PAGE_SIZE uses could be ARRAY_SIZE(s->buffer)
> 
> > diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
> []
> >  /* 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))
> 
> min_t?
> maybe this should be FIELD_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


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
  2014-11-06 14:39         ` Petr Mladek
@ 2014-11-07 20:36           ` Junio C Hamano
  2014-11-07 21:49             ` Steven Rostedt
  2014-11-10 18:43             ` Petr Mladek
  0 siblings, 2 replies; 77+ messages in thread
From: Junio C Hamano @ 2014-11-07 20:36 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Steven Rostedt, linux-kernel, Ingo Molnar, Andrew Morton,
	Jiri Kosina, H. Peter Anvin, Thomas Gleixner

Petr Mladek <pmladek@suse.cz> writes:

> On Wed 2014-11-05 15:42:03, Steven Rostedt wrote:
> ...
>> 
>> 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.

It is rare to hear somebody talks about Git without having "sucks"
in the same sentence ;-)

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
  2014-11-07 20:36           ` Junio C Hamano
@ 2014-11-07 21:49             ` Steven Rostedt
  2014-11-10 18:43             ` Petr Mladek
  1 sibling, 0 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-07 21:49 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Petr Mladek, linux-kernel, Ingo Molnar, Andrew Morton,
	Jiri Kosina, H. Peter Anvin, Thomas Gleixner

On Fri, 07 Nov 2014 12:36:05 -0800
Junio C Hamano <gitster@pobox.com> wrote:

> Petr Mladek <pmladek@suse.cz> writes:
> 
> > On Wed 2014-11-05 15:42:03, Steven Rostedt wrote:
> > ...
> >> 
> >> 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.
> 
> 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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-07 18:30               ` Steven Rostedt
  2014-11-07 18:59                 ` Joe Perches
@ 2014-11-10 13:53                 ` Petr Mladek
  2014-11-10 17:37                   ` Steven Rostedt
  1 sibling, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-10 13:53 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Fri 2014-11-07 13:30:17, Steven Rostedt wrote:
> 
> 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 11674c8df0580a03a2517e3a8e4705c47c663564 Mon Sep 17 00:00:00 2001
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 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.
> 
> Link: http://lkml.kernel.org/r/20141104160221.864997179@goodmis.org
> 
> Tested-by: Jiri Kosina <jkosina@suse.cz>
> Acked-by: Jiri Kosina <jkosina@suse.cz>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
>  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
> 
> diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> new file mode 100644
> index 000000000000..64bf5a43411e
> --- /dev/null
> +++ b/include/linux/seq_buf.h
> @@ -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;

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.

[...]

> diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
> new file mode 100644
> index 000000000000..88738b200bf3
> --- /dev/null
> +++ b/kernel/trace/seq_buf.c

[...]

> +
> +/**
> + * 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);
> +	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.

> +		if (ret < len) {
> +			s->len += ret;
> +			return 0;
> +		}
> +	}
> +	seq_buf_set_overflow(s);
> +	return -1;
> +}
> +

[...]

> diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
> index 1f24ed99dca2..3ad8738aea19 100644
> --- a/kernel/trace/trace_seq.c
> +++ b/kernel/trace/trace_seq.c

[...]

> @@ -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;
>  	int 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

>  	/* 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;

>  }
>  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;
>  	int 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.

>  	/* 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;

>  }
>  EXPORT_SYMBOL_GPL(trace_seq_bprintf);
>  

[...]

>  /**
>   * trace_seq_putmem_hex - write raw memory into the buffer in ASCII hex
>   * @s: trace sequence descriptor
> @@ -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);
> +	__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

> +
> +	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;

>  }
>  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);
> -	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.

> +	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;

>  }
>  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.

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
  2014-11-07 18:34     ` Steven Rostedt
@ 2014-11-10 14:03       ` Petr Mladek
  2014-11-10 17:38         ` Steven Rostedt
  0 siblings, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-10 14:03 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Fri 2014-11-07 13:34:13, Steven Rostedt wrote:
> 
> I made a few touch ups on this patch.
> 
> -- Steve
> 
> From 309e8ce4cc1605d3038b16b8e43219a2867f47b1 Mon Sep 17 00:00:00 2001
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 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.
> 
> Link: http://lkml.kernel.org/r/20141104160222.048795666@goodmis.org
> 
> Tested-by: Jiri Kosina <jkosina@suse.cz>
> Acked-by: Jiri Kosina <jkosina@suse.cz>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> ---
>  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(-)
> 
> diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> index 64bf5a43411e..aec09b126082 100644
> --- a/include/linux/seq_buf.h
> +++ b/include/linux/seq_buf.h
> @@ -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);
> diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
> index 88738b200bf3..ac6eb864c946 100644
> --- a/kernel/trace/seq_buf.c
> +++ b/kernel/trace/seq_buf.c
> @@ -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:

Reviewed-by: Petr Mladek <pmladek@suse.cz>

Best Regards,
Petr

> -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;
>  }
>  
>  /**
> diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
> index 3ad8738aea19..64550ed28e76 100644
> --- a/kernel/trace/trace_seq.c
> +++ b/kernel/trace/trace_seq.c
> @@ -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);
>  
> -- 
> 2.1.1
> 

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-10 13:53                 ` Petr Mladek
@ 2014-11-10 17:37                   ` Steven Rostedt
  2014-11-10 19:02                     ` Petr Mladek
  0 siblings, 1 reply; 77+ messages in thread
From: Steven Rostedt @ 2014-11-10 17:37 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Mon, 10 Nov 2014 14:53:30 +0100
Petr Mladek <pmladek@suse.cz> wrote:

> > +/*
> > + * 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.

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.

> 
> [...]
> 
> > diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
> > new file mode 100644
> > index 000000000000..88738b200bf3
> > --- /dev/null
> > +++ b/kernel/trace/seq_buf.c
> 
> [...]
> 
> > +
> > +/**
> > + * 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);
> > +	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.

You are correct. But I'll make that a separate patch. This is just
keeping the bug that was in the original code.

> 
> > +		if (ret < len) {
> > +			s->len += ret;
> > +			return 0;
> > +		}
> > +	}
> > +	seq_buf_set_overflow(s);
> > +	return -1;
> > +}
> > +
> 
> [...]
> 
> > diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
> > index 1f24ed99dca2..3ad8738aea19 100644
> > --- a/kernel/trace/trace_seq.c
> > +++ b/kernel/trace/trace_seq.c
> 
> [...]
> 
> > @@ -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;
> >  	int 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
> 
> >  	/* 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;

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.

> 
> >  }
> >  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;
> >  	int 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.
> 
> >  	/* 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

same thing.

> 
> 	return s->seq.len - save_len;
> 
> >  }
> >  EXPORT_SYMBOL_GPL(trace_seq_bprintf);
> >  
> 
> [...]
> 
> >  /**
> >   * trace_seq_putmem_hex - write raw memory into the buffer in ASCII hex
> >   * @s: trace sequence descriptor
> > @@ -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);
> > +	__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
> 
> > +
> > +	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;
> 

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.



> >  }
> >  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);
> > -	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.
> 
> > +	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;
> 
> >  }
> >  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.


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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path()
  2014-11-10 14:03       ` Petr Mladek
@ 2014-11-10 17:38         ` Steven Rostedt
  0 siblings, 0 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-10 17:38 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Mon, 10 Nov 2014 15:03:25 +0100
Petr Mladek <pmladek@suse.cz> wrote:

> On Fri 2014-11-07 13:34:13, Steven Rostedt wrote:
> > 
> > I made a few touch ups on this patch.
> > 
> > -- Steve
> > 
> > From 309e8ce4cc1605d3038b16b8e43219a2867f47b1 Mon Sep 17 00:00:00 2001
> > From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> > 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.
> > 
> > Link: http://lkml.kernel.org/r/20141104160222.048795666@goodmis.org
> > 
> > Tested-by: Jiri Kosina <jkosina@suse.cz>
> > Acked-by: Jiri Kosina <jkosina@suse.cz>
> > Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> > ---
> >  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(-)
> > 
> > diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> > index 64bf5a43411e..aec09b126082 100644
> > --- a/include/linux/seq_buf.h
> > +++ b/include/linux/seq_buf.h
> > @@ -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);
> > diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
> > index 88738b200bf3..ac6eb864c946 100644
> > --- a/kernel/trace/seq_buf.c
> > +++ b/kernel/trace/seq_buf.c
> > @@ -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

Yep.

> 
> 
> This is just a minor issue. I believe the you would fix it. Feel free to add:
> 
> Reviewed-by: Petr Mladek <pmladek@suse.cz>

Thanks,

-- Steve


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer
  2014-11-07 18:37               ` Steven Rostedt
@ 2014-11-10 18:11                 ` Petr Mladek
  0 siblings, 0 replies; 77+ messages in thread
From: Petr Mladek @ 2014-11-10 18:11 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Fri 2014-11-07 13:37:29, Steven Rostedt wrote:
> 
> Some more touch ups.
> 
> -- Steve
> 
> From 7e724556c21178a9890b31ff57f69761b41f435a Mon Sep 17 00:00:00 2001
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 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.
> 
> Link: http://lkml.kernel.org/r/20141104160222.502133196@goodmis.org
> 
> Tested-by: Jiri Kosina <jkosina@suse.cz>
> Acked-by: Jiri Kosina <jkosina@suse.cz>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

Reviewed-by: Petr Mladek <pmladek@suse.cz>

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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 08/12 v3] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions
  2014-11-07 18:39     ` Steven Rostedt
@ 2014-11-10 18:33       ` Petr Mladek
  2014-11-10 19:23         ` Steven Rostedt
  0 siblings, 1 reply; 77+ messages in thread
From: Petr Mladek @ 2014-11-10 18:33 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Fri 2014-11-07 13:39:29, Steven Rostedt wrote:
> More updates. Hmm, maybe I should have posted the full series ;-)
> 
> -- Steve
> 
> From 41a3f3f5e772ca26ef4441a0312d3f108693d7dc Mon Sep 17 00:00:00 2001
> From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> 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 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
> 
> Tested-by: Jiri Kosina <jkosina@suse.cz>
> Acked-by: Jiri Kosina <jkosina@suse.cz>
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

Reviewed-by: Petr Mladek <pmladek@suse.cz>

Well, I am curious about the BUG_ONs, see below.

> ---
>  include/linux/seq_buf.h | 40 ++++++++++++++++++++++++++++++++++++++++
>  kernel/trace/seq_buf.c  |  7 +++----
>  2 files changed, 43 insertions(+), 4 deletions(-)
> 
> diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> index 4aab47d10760..7dacdc791225 100644
> --- a/include/linux/seq_buf.h
> +++ b/include/linux/seq_buf.h
> @@ -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);

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.

> +
> +	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);

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.

> +		s->len += num;
> +	}
> +}
> +

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF
  2014-11-07 20:36           ` Junio C Hamano
  2014-11-07 21:49             ` Steven Rostedt
@ 2014-11-10 18:43             ` Petr Mladek
  1 sibling, 0 replies; 77+ messages in thread
From: Petr Mladek @ 2014-11-10 18:43 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Steven Rostedt, linux-kernel, Ingo Molnar, Andrew Morton,
	Jiri Kosina, H. Peter Anvin, Thomas Gleixner

On Fri 2014-11-07 12:36:05, Junio C Hamano wrote:
> Petr Mladek <pmladek@suse.cz> writes:
> 
> > On Wed 2014-11-05 15:42:03, Steven Rostedt wrote:
> > ...
> >> 
> >> 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.
> 
> 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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs
  2014-11-07 18:56     ` Steven Rostedt
@ 2014-11-10 18:58       ` Petr Mladek
  0 siblings, 0 replies; 77+ messages in thread
From: Petr Mladek @ 2014-11-10 18:58 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner, Paul E. McKenney

On Fri 2014-11-07 13:56:09, Steven Rostedt wrote:
> On Thu, 6 Nov 2014 19:41:55 +0100
> Petr Mladek <pmladek@suse.cz> wrote:
>  
> > >  /* "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.
> 
> I switched it to "start" and "end" to not be confused by the last_i
> that is being passed in.

I like it.

> > 
> > > +{
> > > +	const char *buf = s->buffer + last;
> > > +
> > > +	printk("%.*s", (pos - last) + 1, buf);
> > > +}
> > 
> 
> 
> 
> > >  
> > > +	/*
> > > +	 * 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.
> > 
> > 
> > > +		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".
> 
> 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 :-)

> > 
> > > +			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);

Yup

> 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.

> 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.

Perfect

Thanks a lot for working on it. Please, resend this patch once you are
happy with it.

Best Regards,
Petr

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq
  2014-11-10 17:37                   ` Steven Rostedt
@ 2014-11-10 19:02                     ` Petr Mladek
  0 siblings, 0 replies; 77+ messages in thread
From: Petr Mladek @ 2014-11-10 19:02 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Mon 2014-11-10 12:37:47, Steven Rostedt wrote:
> On Mon, 10 Nov 2014 14:53:30 +0100
> Petr Mladek <pmladek@suse.cz> wrote:
> 
> > > +/*
> > > + * 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.
> 
> 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 :-)
 
> > [...]
> > 
> > > diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
> > > new file mode 100644
> > > index 000000000000..88738b200bf3
> > > --- /dev/null
> > > +++ b/kernel/trace/seq_buf.c
> > 
> > [...]
> > 
> > > +
> > > +/**
> > > + * 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);
> > > +	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.
> 
> 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.

> > 
> > > +		if (ret < len) {
> > > +			s->len += ret;
> > > +			return 0;
> > > +		}
> > > +	}
> > > +	seq_buf_set_overflow(s);
> > > +	return -1;
> > > +}
> > > +
> > 
> > [...]
> > 
> > > diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
> > > index 1f24ed99dca2..3ad8738aea19 100644
> > > --- a/kernel/trace/trace_seq.c
> > > +++ b/kernel/trace/trace_seq.c
> > 
> > [...]
> > 
> > > @@ -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;
> > >  	int 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
> > 
> > >  	/* 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;
> 
> 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.
> 
> 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

^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [RFC][PATCH 08/12 v3] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions
  2014-11-10 18:33       ` Petr Mladek
@ 2014-11-10 19:23         ` Steven Rostedt
  0 siblings, 0 replies; 77+ messages in thread
From: Steven Rostedt @ 2014-11-10 19:23 UTC (permalink / raw)
  To: Petr Mladek
  Cc: linux-kernel, Ingo Molnar, Andrew Morton, Jiri Kosina,
	H. Peter Anvin, Thomas Gleixner

On Mon, 10 Nov 2014 19:33:29 +0100
Petr Mladek <pmladek@suse.cz> wrote:

> On Fri 2014-11-07 13:39:29, Steven Rostedt wrote:
> > More updates. Hmm, maybe I should have posted the full series ;-)
> > 
> > -- Steve
> > 
> > From 41a3f3f5e772ca26ef4441a0312d3f108693d7dc Mon Sep 17 00:00:00 2001
> > From: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
> > 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 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
> > 
> > Tested-by: Jiri Kosina <jkosina@suse.cz>
> > Acked-by: Jiri Kosina <jkosina@suse.cz>
> > Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> 
> Reviewed-by: Petr Mladek <pmladek@suse.cz>
> 
> Well, I am curious about the BUG_ONs, see below.
> 
> > ---
> >  include/linux/seq_buf.h | 40 ++++++++++++++++++++++++++++++++++++++++
> >  kernel/trace/seq_buf.c  |  7 +++----
> >  2 files changed, 43 insertions(+), 4 deletions(-)
> > 
> > diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> > index 4aab47d10760..7dacdc791225 100644
> > --- a/include/linux/seq_buf.h
> > +++ b/include/linux/seq_buf.h
> > @@ -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);
> 
> I just wonder if the BUG_ON() is appropriate here. There is used
> WARN_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.


> 
> 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.
> 
> > +
> > +	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);
> 
> 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.

Yeah, this one is worse than the other one and should bug to prevent
memory corruption.

Thanks for reviewing this,

-- Steve

> 
> > +		s->len += num;
> > +	}
> > +}
> > +
> 
> Best Regards,
> Petr


^ permalink raw reply	[flat|nested] 77+ messages in thread

end of thread, other threads:[~2014-11-10 19:23 UTC | newest]

Thread overview: 77+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-04 15:52 [RFC][PATCH 00/12 v3] seq-buf/x86/printk: Print all stacks from NMI safely Steven Rostedt
2014-11-04 15:52 ` [RFC][PATCH 01/12 v3] x86/kvm/tracing: Use helper function trace_seq_buffer_ptr() Steven Rostedt
2014-11-04 16:27   ` Paolo Bonzini
2014-11-04 17:17   ` Rustad, Mark D
2014-11-04 19:09     ` Steven Rostedt
2014-11-04 19:35       ` Steven Rostedt
2014-11-04 20:09         ` Rustad, Mark D
2014-11-05 10:28   ` Petr Mladek
2014-11-04 15:52 ` [RFC][PATCH 02/12 v3] RAS/tracing: Use trace_seq_buffer_ptr() helper instead of open coded Steven Rostedt
2014-11-04 19:59   ` Borislav Petkov
2014-11-05 10:29   ` Petr Mladek
2014-11-04 15:52 ` [RFC][PATCH 03/12 v3] tracing: Create seq_buf layer in trace_seq Steven Rostedt
2014-11-05 14:22   ` Petr Mladek
2014-11-05 18:41     ` Steven Rostedt
2014-11-05 20:00       ` Steven Rostedt
2014-11-05 21:17         ` Steven Rostedt
2014-11-05 21:21           ` Steven Rostedt
2014-11-06 16:33             ` Petr Mladek
2014-11-07 18:30               ` Steven Rostedt
2014-11-07 18:59                 ` Joe Perches
2014-11-07 19:10                   ` Steven Rostedt
2014-11-10 13:53                 ` Petr Mladek
2014-11-10 17:37                   ` Steven Rostedt
2014-11-10 19:02                     ` Petr Mladek
2014-11-06 16:13       ` Petr Mladek
2014-11-05 14:26   ` Petr Mladek
2014-11-05 18:42     ` Steven Rostedt
2014-11-04 15:52 ` [RFC][PATCH 04/12 v3] tracing: Convert seq_buf_path() to be like seq_path() Steven Rostedt
2014-11-05 14:45   ` Petr Mladek
2014-11-05 20:10     ` Steven Rostedt
2014-11-06 14:18       ` Petr Mladek
2014-11-06 21:09         ` Steven Rostedt
2014-11-06 15:01   ` Petr Mladek
2014-11-07 18:34     ` Steven Rostedt
2014-11-10 14:03       ` Petr Mladek
2014-11-10 17:38         ` Steven Rostedt
2014-11-04 15:52 ` [RFC][PATCH 05/12 v3] tracing: Convert seq_buf fields to be like seq_file fields Steven Rostedt
2014-11-05 15:57   ` Petr Mladek
2014-11-05 20:14     ` Steven Rostedt
2014-11-06 14:24       ` Petr Mladek
2014-11-04 15:52 ` [RFC][PATCH 06/12 v3] tracing: Add a seq_buf_clear() helper and clear len and readpos in init Steven Rostedt
2014-11-05 16:00   ` Petr Mladek
2014-11-04 15:52 ` [RFC][PATCH 07/12 v3] tracing: Have seq_buf use full buffer Steven Rostedt
2014-11-05 16:31   ` Petr Mladek
2014-11-05 20:21     ` Steven Rostedt
2014-11-05 21:06       ` Steven Rostedt
2014-11-06 15:31         ` Petr Mladek
2014-11-06 19:24           ` Steven Rostedt
2014-11-07  9:11             ` Petr Mladek
2014-11-07 18:37               ` Steven Rostedt
2014-11-10 18:11                 ` Petr Mladek
2014-11-06 15:13       ` Petr Mladek
2014-11-04 15:52 ` [RFC][PATCH 08/12 v3] tracing: Add seq_buf_get_buf() and seq_buf_commit() helper functions Steven Rostedt
2014-11-05 16:51   ` Petr Mladek
2014-11-05 20:26     ` Steven Rostedt
2014-11-07 18:39     ` Steven Rostedt
2014-11-10 18:33       ` Petr Mladek
2014-11-10 19:23         ` Steven Rostedt
2014-11-04 15:52 ` [RFC][PATCH 09/12 v3] seq_buf: Move the seq_buf code to lib/ Steven Rostedt
2014-11-05 16:57   ` Petr Mladek
2014-11-05 20:32     ` Steven Rostedt
2014-11-04 15:52 ` [RFC][PATCH 10/12 v3] seq-buf: Make seq_buf_bprintf() conditional on CONFIG_BINARY_PRINTF Steven Rostedt
2014-11-05 17:06   ` Petr Mladek
2014-11-05 20:33     ` Steven Rostedt
2014-11-05 20:42       ` Steven Rostedt
2014-11-06 14:39         ` Petr Mladek
2014-11-07 20:36           ` Junio C Hamano
2014-11-07 21:49             ` Steven Rostedt
2014-11-10 18:43             ` Petr Mladek
2014-11-04 15:52 ` [RFC][PATCH 11/12 v3] printk: Add per_cpu printk func to allow printk to be diverted Steven Rostedt
2014-11-06 16:56   ` Petr Mladek
2014-11-04 15:52 ` [RFC][PATCH 12/12 v3] x86/nmi: Perform a safe NMI stack trace on all CPUs Steven Rostedt
2014-11-04 23:05   ` Jiri Kosina
2014-11-04 23:41     ` Steven Rostedt
2014-11-06 18:41   ` Petr Mladek
2014-11-07 18:56     ` Steven Rostedt
2014-11-10 18:58       ` Petr Mladek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).