diff options
-rw-r--r-- | kernel/trace/trace.c | 106 | ||||
-rw-r--r-- | kernel/trace/trace.h | 35 |
2 files changed, 141 insertions, 0 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 3b918283cf94..45c3f0352d78 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -339,6 +339,112 @@ static struct { | |||
339 | 339 | ||
340 | int trace_clock_id; | 340 | int trace_clock_id; |
341 | 341 | ||
342 | /* | ||
343 | * trace_parser_get_init - gets the buffer for trace parser | ||
344 | */ | ||
345 | int trace_parser_get_init(struct trace_parser *parser, int size) | ||
346 | { | ||
347 | memset(parser, 0, sizeof(*parser)); | ||
348 | |||
349 | parser->buffer = kmalloc(size, GFP_KERNEL); | ||
350 | if (!parser->buffer) | ||
351 | return 1; | ||
352 | |||
353 | parser->size = size; | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | /* | ||
358 | * trace_parser_put - frees the buffer for trace parser | ||
359 | */ | ||
360 | void trace_parser_put(struct trace_parser *parser) | ||
361 | { | ||
362 | kfree(parser->buffer); | ||
363 | } | ||
364 | |||
365 | /* | ||
366 | * trace_get_user - reads the user input string separated by space | ||
367 | * (matched by isspace(ch)) | ||
368 | * | ||
369 | * For each string found the 'struct trace_parser' is updated, | ||
370 | * and the function returns. | ||
371 | * | ||
372 | * Returns number of bytes read. | ||
373 | * | ||
374 | * See kernel/trace/trace.h for 'struct trace_parser' details. | ||
375 | */ | ||
376 | int trace_get_user(struct trace_parser *parser, const char __user *ubuf, | ||
377 | size_t cnt, loff_t *ppos) | ||
378 | { | ||
379 | char ch; | ||
380 | size_t read = 0; | ||
381 | ssize_t ret; | ||
382 | |||
383 | if (!*ppos) | ||
384 | trace_parser_clear(parser); | ||
385 | |||
386 | ret = get_user(ch, ubuf++); | ||
387 | if (ret) | ||
388 | goto out; | ||
389 | |||
390 | read++; | ||
391 | cnt--; | ||
392 | |||
393 | /* | ||
394 | * The parser is not finished with the last write, | ||
395 | * continue reading the user input without skipping spaces. | ||
396 | */ | ||
397 | if (!parser->cont) { | ||
398 | /* skip white space */ | ||
399 | while (cnt && isspace(ch)) { | ||
400 | ret = get_user(ch, ubuf++); | ||
401 | if (ret) | ||
402 | goto out; | ||
403 | read++; | ||
404 | cnt--; | ||
405 | } | ||
406 | |||
407 | /* only spaces were written */ | ||
408 | if (isspace(ch)) { | ||
409 | *ppos += read; | ||
410 | ret = read; | ||
411 | goto out; | ||
412 | } | ||
413 | |||
414 | parser->idx = 0; | ||
415 | } | ||
416 | |||
417 | /* read the non-space input */ | ||
418 | while (cnt && !isspace(ch)) { | ||
419 | if (parser->idx < parser->size) | ||
420 | parser->buffer[parser->idx++] = ch; | ||
421 | else { | ||
422 | ret = -EINVAL; | ||
423 | goto out; | ||
424 | } | ||
425 | ret = get_user(ch, ubuf++); | ||
426 | if (ret) | ||
427 | goto out; | ||
428 | read++; | ||
429 | cnt--; | ||
430 | } | ||
431 | |||
432 | /* We either got finished input or we have to wait for another call. */ | ||
433 | if (isspace(ch)) { | ||
434 | parser->buffer[parser->idx] = 0; | ||
435 | parser->cont = false; | ||
436 | } else { | ||
437 | parser->cont = true; | ||
438 | parser->buffer[parser->idx++] = ch; | ||
439 | } | ||
440 | |||
441 | *ppos += read; | ||
442 | ret = read; | ||
443 | |||
444 | out: | ||
445 | return ret; | ||
446 | } | ||
447 | |||
342 | ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) | 448 | ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt) |
343 | { | 449 | { |
344 | int len; | 450 | int len; |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index b69697b4b846..28247cecd955 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -616,6 +616,41 @@ static inline int ftrace_trace_task(struct task_struct *task) | |||
616 | #endif | 616 | #endif |
617 | 617 | ||
618 | /* | 618 | /* |
619 | * struct trace_parser - servers for reading the user input separated by spaces | ||
620 | * @cont: set if the input is not complete - no final space char was found | ||
621 | * @buffer: holds the parsed user input | ||
622 | * @idx: user input lenght | ||
623 | * @size: buffer size | ||
624 | */ | ||
625 | struct trace_parser { | ||
626 | bool cont; | ||
627 | char *buffer; | ||
628 | unsigned idx; | ||
629 | unsigned size; | ||
630 | }; | ||
631 | |||
632 | static inline bool trace_parser_loaded(struct trace_parser *parser) | ||
633 | { | ||
634 | return (parser->idx != 0); | ||
635 | } | ||
636 | |||
637 | static inline bool trace_parser_cont(struct trace_parser *parser) | ||
638 | { | ||
639 | return parser->cont; | ||
640 | } | ||
641 | |||
642 | static inline void trace_parser_clear(struct trace_parser *parser) | ||
643 | { | ||
644 | parser->cont = false; | ||
645 | parser->idx = 0; | ||
646 | } | ||
647 | |||
648 | extern int trace_parser_get_init(struct trace_parser *parser, int size); | ||
649 | extern void trace_parser_put(struct trace_parser *parser); | ||
650 | extern int trace_get_user(struct trace_parser *parser, const char __user *ubuf, | ||
651 | size_t cnt, loff_t *ppos); | ||
652 | |||
653 | /* | ||
619 | * trace_iterator_flags is an enumeration that defines bit | 654 | * trace_iterator_flags is an enumeration that defines bit |
620 | * positions into trace_flags that controls the output. | 655 | * positions into trace_flags that controls the output. |
621 | * | 656 | * |