aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_functions.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/trace_functions.c')
-rw-r--r--kernel/trace/trace_functions.c123
1 files changed, 85 insertions, 38 deletions
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index b99f6231281e..d9cbde8575a8 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -267,10 +267,12 @@ static struct tracer function_trace __tracer_data =
267}; 267};
268 268
269#ifdef CONFIG_DYNAMIC_FTRACE 269#ifdef CONFIG_DYNAMIC_FTRACE
270static void update_traceon_count(void **data, bool on) 270static void update_traceon_count(struct ftrace_probe_ops *ops,
271 unsigned long ip, bool on)
271{ 272{
272 long *count = (long *)data; 273 struct ftrace_func_mapper *mapper = ops->private_data;
273 long old_count = *count; 274 long *count;
275 long old_count;
274 276
275 /* 277 /*
276 * Tracing gets disabled (or enabled) once per count. 278 * Tracing gets disabled (or enabled) once per count.
@@ -301,7 +303,10 @@ static void update_traceon_count(void **data, bool on)
301 * setting the tracing_on file. But we currently don't care 303 * setting the tracing_on file. But we currently don't care
302 * about that. 304 * about that.
303 */ 305 */
304 if (!old_count) 306 count = (long *)ftrace_func_mapper_find_ip(mapper, ip);
307 old_count = *count;
308
309 if (old_count <= 0)
305 return; 310 return;
306 311
307 /* Make sure we see count before checking tracing state */ 312 /* Make sure we see count before checking tracing state */
@@ -315,10 +320,6 @@ static void update_traceon_count(void **data, bool on)
315 else 320 else
316 tracing_off(); 321 tracing_off();
317 322
318 /* unlimited? */
319 if (old_count == -1)
320 return;
321
322 /* Make sure tracing state is visible before updating count */ 323 /* Make sure tracing state is visible before updating count */
323 smp_wmb(); 324 smp_wmb();
324 325
@@ -329,14 +330,14 @@ static void
329ftrace_traceon_count(unsigned long ip, unsigned long parent_ip, 330ftrace_traceon_count(unsigned long ip, unsigned long parent_ip,
330 struct ftrace_probe_ops *ops, void **data) 331 struct ftrace_probe_ops *ops, void **data)
331{ 332{
332 update_traceon_count(data, 1); 333 update_traceon_count(ops, ip, 1);
333} 334}
334 335
335static void 336static void
336ftrace_traceoff_count(unsigned long ip, unsigned long parent_ip, 337ftrace_traceoff_count(unsigned long ip, unsigned long parent_ip,
337 struct ftrace_probe_ops *ops, void **data) 338 struct ftrace_probe_ops *ops, void **data)
338{ 339{
339 update_traceon_count(data, 0); 340 update_traceon_count(ops, ip, 0);
340} 341}
341 342
342static void 343static void
@@ -379,47 +380,56 @@ static void
379ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip, 380ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip,
380 struct ftrace_probe_ops *ops, void **data) 381 struct ftrace_probe_ops *ops, void **data)
381{ 382{
382 long *count = (long *)data; 383 struct ftrace_func_mapper *mapper = ops->private_data;
384 long *count;
383 long old_count; 385 long old_count;
384 long new_count; 386 long new_count;
385 387
388 if (!tracing_is_on())
389 return;
390
391 /* unlimited? */
392 if (!mapper) {
393 trace_dump_stack(STACK_SKIP);
394 return;
395 }
396
397 count = (long *)ftrace_func_mapper_find_ip(mapper, ip);
398
386 /* 399 /*
387 * Stack traces should only execute the number of times the 400 * Stack traces should only execute the number of times the
388 * user specified in the counter. 401 * user specified in the counter.
389 */ 402 */
390 do { 403 do {
391
392 if (!tracing_is_on())
393 return;
394
395 old_count = *count; 404 old_count = *count;
396 405
397 if (!old_count) 406 if (!old_count)
398 return; 407 return;
399 408
400 /* unlimited? */
401 if (old_count == -1) {
402 trace_dump_stack(STACK_SKIP);
403 return;
404 }
405
406 new_count = old_count - 1; 409 new_count = old_count - 1;
407 new_count = cmpxchg(count, old_count, new_count); 410 new_count = cmpxchg(count, old_count, new_count);
408 if (new_count == old_count) 411 if (new_count == old_count)
409 trace_dump_stack(STACK_SKIP); 412 trace_dump_stack(STACK_SKIP);
410 413
414 if (!tracing_is_on())
415 return;
416
411 } while (new_count != old_count); 417 } while (new_count != old_count);
412} 418}
413 419
414static int update_count(void **data) 420static int update_count(struct ftrace_probe_ops *ops, unsigned long ip)
415{ 421{
416 unsigned long *count = (long *)data; 422 struct ftrace_func_mapper *mapper = ops->private_data;
423 long *count = NULL;
417 424
418 if (!*count) 425 if (mapper)
419 return 0; 426 count = (long *)ftrace_func_mapper_find_ip(mapper, ip);
420 427
421 if (*count != -1) 428 if (count) {
429 if (*count <= 0)
430 return 0;
422 (*count)--; 431 (*count)--;
432 }
423 433
424 return 1; 434 return 1;
425} 435}
@@ -428,7 +438,7 @@ static void
428ftrace_dump_probe(unsigned long ip, unsigned long parent_ip, 438ftrace_dump_probe(unsigned long ip, unsigned long parent_ip,
429 struct ftrace_probe_ops *ops, void **data) 439 struct ftrace_probe_ops *ops, void **data)
430{ 440{
431 if (update_count(data)) 441 if (update_count(ops, ip))
432 ftrace_dump(DUMP_ALL); 442 ftrace_dump(DUMP_ALL);
433} 443}
434 444
@@ -437,22 +447,26 @@ static void
437ftrace_cpudump_probe(unsigned long ip, unsigned long parent_ip, 447ftrace_cpudump_probe(unsigned long ip, unsigned long parent_ip,
438 struct ftrace_probe_ops *ops, void **data) 448 struct ftrace_probe_ops *ops, void **data)
439{ 449{
440 if (update_count(data)) 450 if (update_count(ops, ip))
441 ftrace_dump(DUMP_ORIG); 451 ftrace_dump(DUMP_ORIG);
442} 452}
443 453
444static int 454static int
445ftrace_probe_print(const char *name, struct seq_file *m, 455ftrace_probe_print(const char *name, struct seq_file *m,
446 unsigned long ip, void *data) 456 unsigned long ip, struct ftrace_probe_ops *ops)
447{ 457{
448 long count = (long)data; 458 struct ftrace_func_mapper *mapper = ops->private_data;
459 long *count = NULL;
449 460
450 seq_printf(m, "%ps:%s", (void *)ip, name); 461 seq_printf(m, "%ps:%s", (void *)ip, name);
451 462
452 if (count == -1) 463 if (mapper)
453 seq_puts(m, ":unlimited\n"); 464 count = (long *)ftrace_func_mapper_find_ip(mapper, ip);
465
466 if (count)
467 seq_printf(m, ":count=%ld\n", *count);
454 else 468 else
455 seq_printf(m, ":count=%ld\n", count); 469 seq_puts(m, ":unlimited\n");
456 470
457 return 0; 471 return 0;
458} 472}
@@ -461,55 +475,82 @@ static int
461ftrace_traceon_print(struct seq_file *m, unsigned long ip, 475ftrace_traceon_print(struct seq_file *m, unsigned long ip,
462 struct ftrace_probe_ops *ops, void *data) 476 struct ftrace_probe_ops *ops, void *data)
463{ 477{
464 return ftrace_probe_print("traceon", m, ip, data); 478 return ftrace_probe_print("traceon", m, ip, ops);
465} 479}
466 480
467static int 481static int
468ftrace_traceoff_print(struct seq_file *m, unsigned long ip, 482ftrace_traceoff_print(struct seq_file *m, unsigned long ip,
469 struct ftrace_probe_ops *ops, void *data) 483 struct ftrace_probe_ops *ops, void *data)
470{ 484{
471 return ftrace_probe_print("traceoff", m, ip, data); 485 return ftrace_probe_print("traceoff", m, ip, ops);
472} 486}
473 487
474static int 488static int
475ftrace_stacktrace_print(struct seq_file *m, unsigned long ip, 489ftrace_stacktrace_print(struct seq_file *m, unsigned long ip,
476 struct ftrace_probe_ops *ops, void *data) 490 struct ftrace_probe_ops *ops, void *data)
477{ 491{
478 return ftrace_probe_print("stacktrace", m, ip, data); 492 return ftrace_probe_print("stacktrace", m, ip, ops);
479} 493}
480 494
481static int 495static int
482ftrace_dump_print(struct seq_file *m, unsigned long ip, 496ftrace_dump_print(struct seq_file *m, unsigned long ip,
483 struct ftrace_probe_ops *ops, void *data) 497 struct ftrace_probe_ops *ops, void *data)
484{ 498{
485 return ftrace_probe_print("dump", m, ip, data); 499 return ftrace_probe_print("dump", m, ip, ops);
486} 500}
487 501
488static int 502static int
489ftrace_cpudump_print(struct seq_file *m, unsigned long ip, 503ftrace_cpudump_print(struct seq_file *m, unsigned long ip,
490 struct ftrace_probe_ops *ops, void *data) 504 struct ftrace_probe_ops *ops, void *data)
491{ 505{
492 return ftrace_probe_print("cpudump", m, ip, data); 506 return ftrace_probe_print("cpudump", m, ip, ops);
507}
508
509
510static int
511ftrace_count_init(struct ftrace_probe_ops *ops, unsigned long ip,
512 void **data)
513{
514 struct ftrace_func_mapper *mapper = ops->private_data;
515
516 return ftrace_func_mapper_add_ip(mapper, ip, *data);
517}
518
519static void
520ftrace_count_free(struct ftrace_probe_ops *ops, unsigned long ip,
521 void **_data)
522{
523 struct ftrace_func_mapper *mapper = ops->private_data;
524
525 ftrace_func_mapper_remove_ip(mapper, ip);
493} 526}
494 527
495static struct ftrace_probe_ops traceon_count_probe_ops = { 528static struct ftrace_probe_ops traceon_count_probe_ops = {
496 .func = ftrace_traceon_count, 529 .func = ftrace_traceon_count,
497 .print = ftrace_traceon_print, 530 .print = ftrace_traceon_print,
531 .init = ftrace_count_init,
532 .free = ftrace_count_free,
498}; 533};
499 534
500static struct ftrace_probe_ops traceoff_count_probe_ops = { 535static struct ftrace_probe_ops traceoff_count_probe_ops = {
501 .func = ftrace_traceoff_count, 536 .func = ftrace_traceoff_count,
502 .print = ftrace_traceoff_print, 537 .print = ftrace_traceoff_print,
538 .init = ftrace_count_init,
539 .free = ftrace_count_free,
503}; 540};
504 541
505static struct ftrace_probe_ops stacktrace_count_probe_ops = { 542static struct ftrace_probe_ops stacktrace_count_probe_ops = {
506 .func = ftrace_stacktrace_count, 543 .func = ftrace_stacktrace_count,
507 .print = ftrace_stacktrace_print, 544 .print = ftrace_stacktrace_print,
545 .init = ftrace_count_init,
546 .free = ftrace_count_free,
508}; 547};
509 548
510static struct ftrace_probe_ops dump_probe_ops = { 549static struct ftrace_probe_ops dump_probe_ops = {
511 .func = ftrace_dump_probe, 550 .func = ftrace_dump_probe,
512 .print = ftrace_dump_print, 551 .print = ftrace_dump_print,
552 .init = ftrace_count_init,
553 .free = ftrace_count_free,
513}; 554};
514 555
515static struct ftrace_probe_ops cpudump_probe_ops = { 556static struct ftrace_probe_ops cpudump_probe_ops = {
@@ -558,6 +599,12 @@ ftrace_trace_probe_callback(struct ftrace_probe_ops *ops,
558 if (!strlen(number)) 599 if (!strlen(number))
559 goto out_reg; 600 goto out_reg;
560 601
602 if (!ops->private_data) {
603 ops->private_data = allocate_ftrace_func_mapper();
604 if (!ops->private_data)
605 return -ENOMEM;
606 }
607
561 /* 608 /*
562 * We use the callback data field (which is a pointer) 609 * We use the callback data field (which is a pointer)
563 * as our counter. 610 * as our counter.