aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2008-11-18 20:33:02 -0500
committerSteven Rostedt <rostedt@goodmis.org>2008-11-19 00:19:47 -0500
commit32464779a1b8c15e9aa9aa0306b2f735080df9d8 (patch)
treec26673645d5695f29b15a743476b76ce44048218 /kernel
parent820432783190b4096499e38a4a4d7095c511913d (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')
-rw-r--r--kernel/trace/ftrace.c108
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
328static int 328static 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
409static void ftrace_replace_code(int enable) 405static 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;