diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r-- | kernel/trace/ftrace.c | 76 |
1 files changed, 43 insertions, 33 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index a141d8499ab0..4d90c916b2bb 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -401,6 +401,8 @@ static void ftrace_profile_reset(struct ftrace_profile_stat *stat) | |||
401 | int ftrace_profile_pages_init(struct ftrace_profile_stat *stat) | 401 | int ftrace_profile_pages_init(struct ftrace_profile_stat *stat) |
402 | { | 402 | { |
403 | struct ftrace_profile_page *pg; | 403 | struct ftrace_profile_page *pg; |
404 | int functions; | ||
405 | int pages; | ||
404 | int i; | 406 | int i; |
405 | 407 | ||
406 | /* If we already allocated, do nothing */ | 408 | /* If we already allocated, do nothing */ |
@@ -411,22 +413,46 @@ int ftrace_profile_pages_init(struct ftrace_profile_stat *stat) | |||
411 | if (!stat->pages) | 413 | if (!stat->pages) |
412 | return -ENOMEM; | 414 | return -ENOMEM; |
413 | 415 | ||
416 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
417 | functions = ftrace_update_tot_cnt; | ||
418 | #else | ||
419 | /* | ||
420 | * We do not know the number of functions that exist because | ||
421 | * dynamic tracing is what counts them. With past experience | ||
422 | * we have around 20K functions. That should be more than enough. | ||
423 | * It is highly unlikely we will execute every function in | ||
424 | * the kernel. | ||
425 | */ | ||
426 | functions = 20000; | ||
427 | #endif | ||
428 | |||
414 | pg = stat->start = stat->pages; | 429 | pg = stat->start = stat->pages; |
415 | 430 | ||
416 | /* allocate 10 more pages to start */ | 431 | pages = DIV_ROUND_UP(functions, PROFILES_PER_PAGE); |
417 | for (i = 0; i < 10; i++) { | 432 | |
433 | for (i = 0; i < pages; i++) { | ||
418 | pg->next = (void *)get_zeroed_page(GFP_KERNEL); | 434 | pg->next = (void *)get_zeroed_page(GFP_KERNEL); |
419 | /* | ||
420 | * We only care about allocating profile_pages, if | ||
421 | * we failed to allocate here, hopefully we will allocate | ||
422 | * later. | ||
423 | */ | ||
424 | if (!pg->next) | 435 | if (!pg->next) |
425 | break; | 436 | goto out_free; |
426 | pg = pg->next; | 437 | pg = pg->next; |
427 | } | 438 | } |
428 | 439 | ||
429 | return 0; | 440 | return 0; |
441 | |||
442 | out_free: | ||
443 | pg = stat->start; | ||
444 | while (pg) { | ||
445 | unsigned long tmp = (unsigned long)pg; | ||
446 | |||
447 | pg = pg->next; | ||
448 | free_page(tmp); | ||
449 | } | ||
450 | |||
451 | free_page((unsigned long)stat->pages); | ||
452 | stat->pages = NULL; | ||
453 | stat->start = NULL; | ||
454 | |||
455 | return -ENOMEM; | ||
430 | } | 456 | } |
431 | 457 | ||
432 | static int ftrace_profile_init_cpu(int cpu) | 458 | static int ftrace_profile_init_cpu(int cpu) |
@@ -460,7 +486,7 @@ static int ftrace_profile_init_cpu(int cpu) | |||
460 | ftrace_profile_bits++; | 486 | ftrace_profile_bits++; |
461 | } | 487 | } |
462 | 488 | ||
463 | /* Preallocate a few pages */ | 489 | /* Preallocate the function profiling pages */ |
464 | if (ftrace_profile_pages_init(stat) < 0) { | 490 | if (ftrace_profile_pages_init(stat) < 0) { |
465 | kfree(stat->hash); | 491 | kfree(stat->hash); |
466 | stat->hash = NULL; | 492 | stat->hash = NULL; |
@@ -516,24 +542,21 @@ static void ftrace_add_profile(struct ftrace_profile_stat *stat, | |||
516 | hlist_add_head_rcu(&rec->node, &stat->hash[key]); | 542 | hlist_add_head_rcu(&rec->node, &stat->hash[key]); |
517 | } | 543 | } |
518 | 544 | ||
519 | /* Interrupts must be disabled calling this */ | 545 | /* |
546 | * The memory is already allocated, this simply finds a new record to use. | ||
547 | */ | ||
520 | static struct ftrace_profile * | 548 | static struct ftrace_profile * |
521 | ftrace_profile_alloc(struct ftrace_profile_stat *stat, | 549 | ftrace_profile_alloc(struct ftrace_profile_stat *stat, unsigned long ip) |
522 | unsigned long ip, bool alloc_safe) | ||
523 | { | 550 | { |
524 | struct ftrace_profile *rec = NULL; | 551 | struct ftrace_profile *rec = NULL; |
525 | 552 | ||
526 | /* prevent recursion */ | 553 | /* prevent recursion (from NMIs) */ |
527 | if (atomic_inc_return(&stat->disabled) != 1) | 554 | if (atomic_inc_return(&stat->disabled) != 1) |
528 | goto out; | 555 | goto out; |
529 | 556 | ||
530 | /* Try to always keep another page available */ | ||
531 | if (!stat->pages->next && alloc_safe) | ||
532 | stat->pages->next = (void *)get_zeroed_page(GFP_ATOMIC); | ||
533 | |||
534 | /* | 557 | /* |
535 | * Try to find the function again since another | 558 | * Try to find the function again since an NMI |
536 | * task on another CPU could have added it | 559 | * could have added it |
537 | */ | 560 | */ |
538 | rec = ftrace_find_profiled_func(stat, ip); | 561 | rec = ftrace_find_profiled_func(stat, ip); |
539 | if (rec) | 562 | if (rec) |
@@ -555,29 +578,16 @@ ftrace_profile_alloc(struct ftrace_profile_stat *stat, | |||
555 | return rec; | 578 | return rec; |
556 | } | 579 | } |
557 | 580 | ||
558 | /* | ||
559 | * If we are not in an interrupt, or softirq and | ||
560 | * and interrupts are disabled and preemption is not enabled | ||
561 | * (not in a spinlock) then it should be safe to allocate memory. | ||
562 | */ | ||
563 | static bool ftrace_safe_to_allocate(void) | ||
564 | { | ||
565 | return !in_interrupt() && irqs_disabled() && !preempt_count(); | ||
566 | } | ||
567 | |||
568 | static void | 581 | static void |
569 | function_profile_call(unsigned long ip, unsigned long parent_ip) | 582 | function_profile_call(unsigned long ip, unsigned long parent_ip) |
570 | { | 583 | { |
571 | struct ftrace_profile_stat *stat; | 584 | struct ftrace_profile_stat *stat; |
572 | struct ftrace_profile *rec; | 585 | struct ftrace_profile *rec; |
573 | unsigned long flags; | 586 | unsigned long flags; |
574 | bool alloc_safe; | ||
575 | 587 | ||
576 | if (!ftrace_profile_enabled) | 588 | if (!ftrace_profile_enabled) |
577 | return; | 589 | return; |
578 | 590 | ||
579 | alloc_safe = ftrace_safe_to_allocate(); | ||
580 | |||
581 | local_irq_save(flags); | 591 | local_irq_save(flags); |
582 | 592 | ||
583 | stat = &__get_cpu_var(ftrace_profile_stats); | 593 | stat = &__get_cpu_var(ftrace_profile_stats); |
@@ -586,7 +596,7 @@ function_profile_call(unsigned long ip, unsigned long parent_ip) | |||
586 | 596 | ||
587 | rec = ftrace_find_profiled_func(stat, ip); | 597 | rec = ftrace_find_profiled_func(stat, ip); |
588 | if (!rec) { | 598 | if (!rec) { |
589 | rec = ftrace_profile_alloc(stat, ip, alloc_safe); | 599 | rec = ftrace_profile_alloc(stat, ip); |
590 | if (!rec) | 600 | if (!rec) |
591 | goto out; | 601 | goto out; |
592 | } | 602 | } |