diff options
Diffstat (limited to 'kernel')
| -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 | * | 
