diff options
author | Steven Rostedt <srostedt@redhat.com> | 2008-11-18 20:33:02 -0500 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2008-11-19 00:19:47 -0500 |
commit | 32464779a1b8c15e9aa9aa0306b2f735080df9d8 (patch) | |
tree | c26673645d5695f29b15a743476b76ce44048218 /kernel/trace | |
parent | 820432783190b4096499e38a4a4d7095c511913d (diff) |
ftrace: fix dyn ftrace filter selection
Impact: clean up and fix for dyn ftrace filter selection
The previous logic of the dynamic ftrace selection of enabling
or disabling functions was complex and incorrect. This patch simplifies
the code and corrects the usage. This simplification also makes the
code more robust.
Here is the correct logic:
Given a function that can be traced by dynamic ftrace:
If the function is not to be traced, disable it if it was enabled.
(this is if the function is in the set_ftrace_notrace file)
(filter is on if there exists any functions in set_ftrace_filter file)
If the filter is on, and we are enabling functions:
If the function is in set_ftrace_filter, enable it if it is not
already enabled.
If the function is not in set_ftrace_filter, disable it if it is not
already disabled.
Otherwise, if the filter is off and we are enabling function tracing:
Enable the function if it is not already enabled.
Otherwise, if we are disabling function tracing:
Disable the function if it is not already disabled.
This code now sets or clears the ENABLED flag in the record, and at the
end it will enable the function if the flag is set, or disable the function
if the flag is cleared.
The parameters for the function that does the above logic is also
simplified. Instead of passing in confusing "new" and "old" where
they might be swapped if the "enabled" flag is not set. The old logic
even had one of the above always NULL and had to be filled in. The new
logic simply passes in one parameter called "nop". A "call" is calculated
in the code, and at the end of the logic, when we know we need to either
disable or enable the function, we can then use the "nop" and "call"
properly.
This code is more robust than the previous version.
Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/ftrace.c | 108 |
1 files changed, 50 insertions, 58 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 5cbddb59e99f..fdaab04a0282 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -327,96 +327,89 @@ ftrace_record_ip(unsigned long ip) | |||
327 | 327 | ||
328 | static int | 328 | static int |
329 | __ftrace_replace_code(struct dyn_ftrace *rec, | 329 | __ftrace_replace_code(struct dyn_ftrace *rec, |
330 | unsigned char *old, unsigned char *new, int enable) | 330 | unsigned char *nop, int enable) |
331 | { | 331 | { |
332 | unsigned long ip, fl; | 332 | unsigned long ip, fl; |
333 | unsigned char *call, *old, *new; | ||
333 | 334 | ||
334 | ip = rec->ip; | 335 | ip = rec->ip; |
335 | 336 | ||
336 | if (ftrace_filtered && enable) { | 337 | /* |
338 | * If this record is not to be traced and | ||
339 | * it is not enabled then do nothing. | ||
340 | * | ||
341 | * If this record is not to be traced and | ||
342 | * it is enabled then disabled it. | ||
343 | * | ||
344 | */ | ||
345 | if (rec->flags & FTRACE_FL_NOTRACE) { | ||
346 | if (rec->flags & FTRACE_FL_ENABLED) | ||
347 | rec->flags &= ~FTRACE_FL_ENABLED; | ||
348 | else | ||
349 | return 0; | ||
350 | |||
351 | } else if (ftrace_filtered && enable) { | ||
337 | /* | 352 | /* |
338 | * If filtering is on: | 353 | * Filtering is on: |
339 | * | ||
340 | * If this record is set to be filtered and | ||
341 | * is enabled then do nothing. | ||
342 | * | ||
343 | * If this record is set to be filtered and | ||
344 | * it is not enabled, enable it. | ||
345 | * | ||
346 | * If this record is not set to be filtered | ||
347 | * and it is not enabled do nothing. | ||
348 | * | ||
349 | * If this record is set not to trace then | ||
350 | * do nothing. | ||
351 | * | ||
352 | * If this record is set not to trace and | ||
353 | * it is enabled then disable it. | ||
354 | * | ||
355 | * If this record is not set to be filtered and | ||
356 | * it is enabled, disable it. | ||
357 | */ | 354 | */ |
358 | 355 | ||
359 | fl = rec->flags & (FTRACE_FL_FILTER | FTRACE_FL_NOTRACE | | 356 | fl = rec->flags & (FTRACE_FL_FILTER | FTRACE_FL_ENABLED); |
360 | FTRACE_FL_ENABLED); | ||
361 | 357 | ||
362 | if ((fl == (FTRACE_FL_FILTER | FTRACE_FL_ENABLED)) || | 358 | /* Record is filtered and enabled, do nothing */ |
363 | (fl == (FTRACE_FL_FILTER | FTRACE_FL_NOTRACE)) || | 359 | if (fl == (FTRACE_FL_FILTER | FTRACE_FL_ENABLED)) |
364 | !fl || (fl == FTRACE_FL_NOTRACE)) | ||
365 | return 0; | 360 | return 0; |
366 | 361 | ||
367 | /* | 362 | /* Record is not filtered and is not enabled do nothing */ |
368 | * If it is enabled disable it, | 363 | if (!fl) |
369 | * otherwise enable it! | 364 | return 0; |
370 | */ | 365 | |
371 | if (fl & FTRACE_FL_ENABLED) { | 366 | /* Record is not filtered but enabled, disable it */ |
372 | /* swap new and old */ | 367 | if (fl == FTRACE_FL_ENABLED) |
373 | new = old; | ||
374 | old = ftrace_call_replace(ip, FTRACE_ADDR); | ||
375 | rec->flags &= ~FTRACE_FL_ENABLED; | 368 | rec->flags &= ~FTRACE_FL_ENABLED; |
376 | } else { | 369 | else |
377 | new = ftrace_call_replace(ip, FTRACE_ADDR); | 370 | /* Otherwise record is filtered but not enabled, enable it */ |
378 | rec->flags |= FTRACE_FL_ENABLED; | 371 | rec->flags |= FTRACE_FL_ENABLED; |
379 | } | ||
380 | } else { | 372 | } else { |
373 | /* Disable or not filtered */ | ||
381 | 374 | ||
382 | if (enable) { | 375 | if (enable) { |
383 | /* | 376 | /* if record is enabled, do nothing */ |
384 | * If this record is set not to trace and is | ||
385 | * not enabled, do nothing. | ||
386 | */ | ||
387 | fl = rec->flags & (FTRACE_FL_NOTRACE | FTRACE_FL_ENABLED); | ||
388 | if (fl == FTRACE_FL_NOTRACE) | ||
389 | return 0; | ||
390 | |||
391 | new = ftrace_call_replace(ip, FTRACE_ADDR); | ||
392 | } else | ||
393 | old = ftrace_call_replace(ip, FTRACE_ADDR); | ||
394 | |||
395 | if (enable) { | ||
396 | if (rec->flags & FTRACE_FL_ENABLED) | 377 | if (rec->flags & FTRACE_FL_ENABLED) |
397 | return 0; | 378 | return 0; |
379 | |||
398 | rec->flags |= FTRACE_FL_ENABLED; | 380 | rec->flags |= FTRACE_FL_ENABLED; |
381 | |||
399 | } else { | 382 | } else { |
383 | |||
384 | /* if record is not enabled do nothing */ | ||
400 | if (!(rec->flags & FTRACE_FL_ENABLED)) | 385 | if (!(rec->flags & FTRACE_FL_ENABLED)) |
401 | return 0; | 386 | return 0; |
387 | |||
402 | rec->flags &= ~FTRACE_FL_ENABLED; | 388 | rec->flags &= ~FTRACE_FL_ENABLED; |
403 | } | 389 | } |
404 | } | 390 | } |
405 | 391 | ||
392 | call = ftrace_call_replace(ip, FTRACE_ADDR); | ||
393 | |||
394 | if (rec->flags & FTRACE_FL_ENABLED) { | ||
395 | old = nop; | ||
396 | new = call; | ||
397 | } else { | ||
398 | old = call; | ||
399 | new = nop; | ||
400 | } | ||
401 | |||
406 | return ftrace_modify_code(ip, old, new); | 402 | return ftrace_modify_code(ip, old, new); |
407 | } | 403 | } |
408 | 404 | ||
409 | static void ftrace_replace_code(int enable) | 405 | static void ftrace_replace_code(int enable) |
410 | { | 406 | { |
411 | int i, failed; | 407 | int i, failed; |
412 | unsigned char *new = NULL, *old = NULL; | 408 | unsigned char *nop = NULL; |
413 | struct dyn_ftrace *rec; | 409 | struct dyn_ftrace *rec; |
414 | struct ftrace_page *pg; | 410 | struct ftrace_page *pg; |
415 | 411 | ||
416 | if (enable) | 412 | nop = ftrace_nop_replace(); |
417 | old = ftrace_nop_replace(); | ||
418 | else | ||
419 | new = ftrace_nop_replace(); | ||
420 | 413 | ||
421 | for (pg = ftrace_pages_start; pg; pg = pg->next) { | 414 | for (pg = ftrace_pages_start; pg; pg = pg->next) { |
422 | for (i = 0; i < pg->index; i++) { | 415 | for (i = 0; i < pg->index; i++) { |
@@ -434,7 +427,7 @@ static void ftrace_replace_code(int enable) | |||
434 | unfreeze_record(rec); | 427 | unfreeze_record(rec); |
435 | } | 428 | } |
436 | 429 | ||
437 | failed = __ftrace_replace_code(rec, old, new, enable); | 430 | failed = __ftrace_replace_code(rec, nop, enable); |
438 | if (failed && (rec->flags & FTRACE_FL_CONVERTED)) { | 431 | if (failed && (rec->flags & FTRACE_FL_CONVERTED)) { |
439 | rec->flags |= FTRACE_FL_FAILED; | 432 | rec->flags |= FTRACE_FL_FAILED; |
440 | if ((system_state == SYSTEM_BOOTING) || | 433 | if ((system_state == SYSTEM_BOOTING) || |
@@ -538,8 +531,7 @@ static void ftrace_startup(void) | |||
538 | 531 | ||
539 | mutex_lock(&ftrace_start_lock); | 532 | mutex_lock(&ftrace_start_lock); |
540 | ftrace_start++; | 533 | ftrace_start++; |
541 | if (ftrace_start == 1) | 534 | command |= FTRACE_ENABLE_CALLS; |
542 | command |= FTRACE_ENABLE_CALLS; | ||
543 | 535 | ||
544 | if (saved_ftrace_func != ftrace_trace_function) { | 536 | if (saved_ftrace_func != ftrace_trace_function) { |
545 | saved_ftrace_func = ftrace_trace_function; | 537 | saved_ftrace_func = ftrace_trace_function; |