aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2014-06-19 17:33:30 -0400
committerSteven Rostedt <rostedt@goodmis.org>2014-11-19 22:01:20 -0500
commit8d58e99af5980d444948720977b0976455885391 (patch)
tree1c40f6ed895112fb34b139a8bcd0e49d321fbd22 /lib
parent2448913ed2aa7a7424d9b9ca79861d13c746a3f1 (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 'lib')
-rw-r--r--lib/Makefile2
-rw-r--r--lib/seq_buf.c359
2 files changed, 360 insertions, 1 deletions
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 \
13 sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \ 13 sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
14 proportions.o flex_proportions.o ratelimit.o show_mem.o \ 14 proportions.o flex_proportions.o ratelimit.o show_mem.o \
15 is_single_threaded.o plist.o decompress.o kobject_uevent.o \ 15 is_single_threaded.o plist.o decompress.o kobject_uevent.o \
16 earlycpio.o 16 earlycpio.o seq_buf.o
17 17
18obj-$(CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS) += usercopy.o 18obj-$(CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS) += usercopy.o
19lib-$(CONFIG_MMU) += ioremap.o 19lib-$(CONFIG_MMU) += ioremap.o
diff --git a/lib/seq_buf.c b/lib/seq_buf.c
new file mode 100644
index 000000000000..4eedfedb9e31
--- /dev/null
+++ b/lib/seq_buf.c
@@ -0,0 +1,359 @@
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 */
27static 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 */
39int 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 */
56int 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 */
82int 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 */
104int 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 */
148int 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 */
176int 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);
184 s->len += len;
185 return 0;
186 }
187 seq_buf_set_overflow(s);
188 return -1;
189}
190
191/**
192 * seq_buf_putc - sequence printing of simple character
193 * @s: seq_buf descriptor
194 * @c: simple character to record
195 *
196 * Copy a single character into the sequence buffer.
197 *
198 * Returns zero on success, -1 on overflow
199 */
200int seq_buf_putc(struct seq_buf *s, unsigned char c)
201{
202 WARN_ON(s->size == 0);
203
204 if (seq_buf_can_fit(s, 1)) {
205 s->buffer[s->len++] = c;
206 return 0;
207 }
208 seq_buf_set_overflow(s);
209 return -1;
210}
211
212/**
213 * seq_buf_putmem - write raw data into the sequenc buffer
214 * @s: seq_buf descriptor
215 * @mem: The raw memory to copy into the buffer
216 * @len: The length of the raw memory to copy (in bytes)
217 *
218 * There may be cases where raw memory needs to be written into the
219 * buffer and a strcpy() would not work. Using this function allows
220 * for such cases.
221 *
222 * Returns zero on success, -1 on overflow
223 */
224int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len)
225{
226 WARN_ON(s->size == 0);
227
228 if (seq_buf_can_fit(s, len)) {
229 memcpy(s->buffer + s->len, mem, len);
230 s->len += len;
231 return 0;
232 }
233 seq_buf_set_overflow(s);
234 return -1;
235}
236
237#define MAX_MEMHEX_BYTES 8U
238#define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1)
239
240/**
241 * seq_buf_putmem_hex - write raw memory into the buffer in ASCII hex
242 * @s: seq_buf descriptor
243 * @mem: The raw memory to write its hex ASCII representation of
244 * @len: The length of the raw memory to copy (in bytes)
245 *
246 * This is similar to seq_buf_putmem() except instead of just copying the
247 * raw memory into the buffer it writes its ASCII representation of it
248 * in hex characters.
249 *
250 * Returns zero on success, -1 on overflow
251 */
252int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,
253 unsigned int len)
254{
255 unsigned char hex[HEX_CHARS];
256 const unsigned char *data = mem;
257 unsigned int start_len;
258 int i, j;
259
260 WARN_ON(s->size == 0);
261
262 while (len) {
263 start_len = min(len, HEX_CHARS - 1);
264#ifdef __BIG_ENDIAN
265 for (i = 0, j = 0; i < start_len; i++) {
266#else
267 for (i = start_len-1, j = 0; i >= 0; i--) {
268#endif
269 hex[j++] = hex_asc_hi(data[i]);
270 hex[j++] = hex_asc_lo(data[i]);
271 }
272 if (WARN_ON_ONCE(j == 0 || j/2 > len))
273 break;
274
275 /* j increments twice per loop */
276 len -= j / 2;
277 hex[j++] = ' ';
278
279 seq_buf_putmem(s, hex, j);
280 if (seq_buf_has_overflowed(s))
281 return -1;
282 }
283 return 0;
284}
285
286/**
287 * seq_buf_path - copy a path into the sequence buffer
288 * @s: seq_buf descriptor
289 * @path: path to write into the sequence buffer.
290 * @esc: set of characters to escape in the output
291 *
292 * Write a path name into the sequence buffer.
293 *
294 * Returns the number of written bytes on success, -1 on overflow
295 */
296int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc)
297{
298 char *buf;
299 size_t size = seq_buf_get_buf(s, &buf);
300 int res = -1;
301
302 WARN_ON(s->size == 0);
303
304 if (size) {
305 char *p = d_path(path, buf, size);
306 if (!IS_ERR(p)) {
307 char *end = mangle_path(buf, p, esc);
308 if (end)
309 res = end - buf;
310 }
311 }
312 seq_buf_commit(s, res);
313
314 return res;
315}
316
317/**
318 * seq_buf_to_user - copy the squence buffer to user space
319 * @s: seq_buf descriptor
320 * @ubuf: The userspace memory location to copy to
321 * @cnt: The amount to copy
322 *
323 * Copies the sequence buffer into the userspace memory pointed to
324 * by @ubuf. It starts from the last read position (@s->readpos)
325 * and writes up to @cnt characters or till it reaches the end of
326 * the content in the buffer (@s->len), which ever comes first.
327 *
328 * On success, it returns a positive number of the number of bytes
329 * it copied.
330 *
331 * On failure it returns -EBUSY if all of the content in the
332 * sequence has been already read, which includes nothing in the
333 * sequence (@s->len == @s->readpos).
334 *
335 * Returns -EFAULT if the copy to userspace fails.
336 */
337int seq_buf_to_user(struct seq_buf *s, char __user *ubuf, int cnt)
338{
339 int len;
340 int ret;
341
342 if (!cnt)
343 return 0;
344
345 if (s->len <= s->readpos)
346 return -EBUSY;
347
348 len = seq_buf_used(s) - s->readpos;
349 if (cnt > len)
350 cnt = len;
351 ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt);
352 if (ret == cnt)
353 return -EFAULT;
354
355 cnt -= ret;
356
357 s->readpos += cnt;
358 return cnt;
359}