diff options
| author | Steven Rostedt (Red Hat) <rostedt@goodmis.org> | 2014-06-19 17:33:30 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2014-11-19 22:01:20 -0500 |
| commit | 8d58e99af5980d444948720977b0976455885391 (patch) | |
| tree | 1c40f6ed895112fb34b139a8bcd0e49d321fbd22 /kernel/trace | |
| parent | 2448913ed2aa7a7424d9b9ca79861d13c746a3f1 (diff) | |
seq_buf: Move the seq_buf code to lib/
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
Tested-by: Jiri Kosina <jkosina@suse.cz>
Acked-by: Jiri Kosina <jkosina@suse.cz>
Reviewed-by: Petr Mladek <pmladek@suse.cz>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/Makefile | 1 | ||||
| -rw-r--r-- | kernel/trace/seq_buf.c | 359 |
2 files changed, 0 insertions, 360 deletions
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 | |||
| 29 | obj-$(CONFIG_TRACING) += trace.o | 29 | obj-$(CONFIG_TRACING) += trace.o |
| 30 | obj-$(CONFIG_TRACING) += trace_output.o | 30 | obj-$(CONFIG_TRACING) += trace_output.o |
| 31 | obj-$(CONFIG_TRACING) += trace_seq.o | 31 | obj-$(CONFIG_TRACING) += trace_seq.o |
| 32 | obj-$(CONFIG_TRACING) += seq_buf.o | ||
| 33 | obj-$(CONFIG_TRACING) += trace_stat.o | 32 | obj-$(CONFIG_TRACING) += trace_stat.o |
| 34 | obj-$(CONFIG_TRACING) += trace_printk.o | 33 | obj-$(CONFIG_TRACING) += trace_printk.o |
| 35 | obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o | 34 | 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 4eedfedb9e31..000000000000 --- a/kernel/trace/seq_buf.c +++ /dev/null | |||
| @@ -1,359 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * seq_buf.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 5 | * | ||
| 6 | * The seq_buf is a handy tool that allows you to pass a descriptor around | ||
| 7 | * to a buffer that other functions can write to. It is similar to the | ||
| 8 | * seq_file functionality but has some differences. | ||
| 9 | * | ||
| 10 | * To use it, the seq_buf must be initialized with seq_buf_init(). | ||
| 11 | * This will set up the counters within the descriptor. You can call | ||
| 12 | * seq_buf_init() more than once to reset the seq_buf to start | ||
| 13 | * from scratch. | ||
| 14 | */ | ||
| 15 | #include <linux/uaccess.h> | ||
| 16 | #include <linux/seq_file.h> | ||
| 17 | #include <linux/seq_buf.h> | ||
| 18 | |||
| 19 | /** | ||
| 20 | * seq_buf_can_fit - can the new data fit in the current buffer? | ||
| 21 | * @s: the seq_buf descriptor | ||
| 22 | * @len: The length to see if it can fit in the current buffer | ||
| 23 | * | ||
| 24 | * Returns true if there's enough unused space in the seq_buf buffer | ||
| 25 | * to fit the amount of new data according to @len. | ||
| 26 | */ | ||
| 27 | static bool seq_buf_can_fit(struct seq_buf *s, size_t len) | ||
| 28 | { | ||
| 29 | return s->len + len <= s->size; | ||
| 30 | } | ||
| 31 | |||
| 32 | /** | ||
| 33 | * seq_buf_print_seq - move the contents of seq_buf into a seq_file | ||
| 34 | * @m: the seq_file descriptor that is the destination | ||
| 35 | * @s: the seq_buf descriptor that is the source. | ||
| 36 | * | ||
| 37 | * Returns zero on success, non zero otherwise | ||
| 38 | */ | ||
| 39 | int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s) | ||
| 40 | { | ||
| 41 | unsigned int len = seq_buf_used(s); | ||
| 42 | |||
| 43 | return seq_write(m, s->buffer, len); | ||
| 44 | } | ||
| 45 | |||
| 46 | /** | ||
| 47 | * seq_buf_vprintf - sequence printing of information. | ||
| 48 | * @s: seq_buf descriptor | ||
| 49 | * @fmt: printf format string | ||
| 50 | * @args: va_list of arguments from a printf() type function | ||
| 51 | * | ||
| 52 | * Writes a vnprintf() format into the sequencce buffer. | ||
| 53 | * | ||
| 54 | * Returns zero on success, -1 on overflow. | ||
| 55 | */ | ||
| 56 | int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args) | ||
| 57 | { | ||
| 58 | int len; | ||
| 59 | |||
| 60 | WARN_ON(s->size == 0); | ||
| 61 | |||
| 62 | if (s->len < s->size) { | ||
| 63 | len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args); | ||
| 64 | if (seq_buf_can_fit(s, len)) { | ||
| 65 | s->len += len; | ||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | } | ||
| 69 | seq_buf_set_overflow(s); | ||
| 70 | return -1; | ||
| 71 | } | ||
| 72 | |||
| 73 | /** | ||
| 74 | * seq_buf_printf - sequence printing of information | ||
| 75 | * @s: seq_buf descriptor | ||
| 76 | * @fmt: printf format string | ||
| 77 | * | ||
| 78 | * Writes a printf() format into the sequence buffer. | ||
| 79 | * | ||
| 80 | * Returns zero on success, -1 on overflow. | ||
| 81 | */ | ||
| 82 | int seq_buf_printf(struct seq_buf *s, const char *fmt, ...) | ||
| 83 | { | ||
| 84 | va_list ap; | ||
| 85 | int ret; | ||
| 86 | |||
| 87 | va_start(ap, fmt); | ||
| 88 | ret = seq_buf_vprintf(s, fmt, ap); | ||
| 89 | va_end(ap); | ||
| 90 | |||
| 91 | return ret; | ||
| 92 | } | ||
| 93 | |||
| 94 | /** | ||
| 95 | * seq_buf_bitmask - write a bitmask array in its ASCII representation | ||
| 96 | * @s: seq_buf descriptor | ||
| 97 | * @maskp: points to an array of unsigned longs that represent a bitmask | ||
| 98 | * @nmaskbits: The number of bits that are valid in @maskp | ||
| 99 | * | ||
| 100 | * Writes a ASCII representation of a bitmask string into @s. | ||
| 101 | * | ||
| 102 | * Returns zero on success, -1 on overflow. | ||
| 103 | */ | ||
| 104 | int seq_buf_bitmask(struct seq_buf *s, const unsigned long *maskp, | ||
| 105 | int nmaskbits) | ||
| 106 | { | ||
| 107 | unsigned int len = seq_buf_buffer_left(s); | ||
| 108 | int ret; | ||
| 109 | |||
| 110 | WARN_ON(s->size == 0); | ||
| 111 | |||
| 112 | /* | ||
| 113 | * Note, because bitmap_scnprintf() only returns the number of bytes | ||
| 114 | * written and not the number that would be written, we use the last | ||
| 115 | * byte of the buffer to let us know if we overflowed. There's a small | ||
| 116 | * chance that the bitmap could have fit exactly inside the buffer, but | ||
| 117 | * it's not that critical if that does happen. | ||
| 118 | */ | ||
| 119 | if (len > 1) { | ||
| 120 | ret = bitmap_scnprintf(s->buffer + s->len, len, maskp, nmaskbits); | ||
| 121 | if (ret < len) { | ||
| 122 | s->len += ret; | ||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | seq_buf_set_overflow(s); | ||
| 127 | return -1; | ||
| 128 | } | ||
| 129 | |||
| 130 | #ifdef CONFIG_BINARY_PRINTF | ||
| 131 | /** | ||
| 132 | * seq_buf_bprintf - Write the printf string from binary arguments | ||
| 133 | * @s: seq_buf descriptor | ||
| 134 | * @fmt: The format string for the @binary arguments | ||
| 135 | * @binary: The binary arguments for @fmt. | ||
| 136 | * | ||
| 137 | * When recording in a fast path, a printf may be recorded with just | ||
| 138 | * saving the format and the arguments as they were passed to the | ||
| 139 | * function, instead of wasting cycles converting the arguments into | ||
| 140 | * ASCII characters. Instead, the arguments are saved in a 32 bit | ||
| 141 | * word array that is defined by the format string constraints. | ||
| 142 | * | ||
| 143 | * This function will take the format and the binary array and finish | ||
| 144 | * the conversion into the ASCII string within the buffer. | ||
| 145 | * | ||
| 146 | * Returns zero on success, -1 on overflow. | ||
| 147 | */ | ||
| 148 | int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary) | ||
| 149 | { | ||
| 150 | unsigned int len = seq_buf_buffer_left(s); | ||
| 151 | int ret; | ||
| 152 | |||
| 153 | WARN_ON(s->size == 0); | ||
| 154 | |||
| 155 | if (s->len < s->size) { | ||
| 156 | ret = bstr_printf(s->buffer + s->len, len, fmt, binary); | ||
| 157 | if (seq_buf_can_fit(s, ret)) { | ||
| 158 | s->len += ret; | ||
| 159 | return 0; | ||
| 160 | } | ||
| 161 | } | ||
| 162 | seq_buf_set_overflow(s); | ||
| 163 | return -1; | ||
| 164 | } | ||
| 165 | #endif /* CONFIG_BINARY_PRINTF */ | ||
| 166 | |||
| 167 | /** | ||
| 168 | * seq_buf_puts - sequence printing of simple string | ||
| 169 | * @s: seq_buf descriptor | ||
| 170 | * @str: simple string to record | ||
| 171 | * | ||
| 172 | * Copy a simple string into the sequence buffer. | ||
| 173 | * | ||
| 174 | * Returns zero on success, -1 on overflow | ||
| 175 | */ | ||
| 176 | int seq_buf_puts(struct seq_buf *s, const char *str) | ||
| 177 | { | ||
| 178 | unsigned int len = strlen(str); | ||
| 179 | |||
| 180 | WARN_ON(s->size == 0); | ||
| 181 | |||
| 182 | if (seq_buf_can_fit(s, len)) { | ||
| 183 | memcpy(s->buffer + s->len, str, len); | ||
