aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/ftrace.c
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-02-13 12:43:56 -0500
committerSteven Rostedt <srostedt@redhat.com>2009-02-16 16:25:12 -0500
commit265c831cb03d533cbe159af45798ac9fef534260 (patch)
treed00548a034b3092f8f42086f348c70b784c1df5e /kernel/trace/ftrace.c
parent0c75a3ed633419d75d823d5dcb05d42924c6ae61 (diff)
ftrace: add do_for_each_ftrace_rec and while_for_each_ftrace_rec
Impact: clean up To iterate over all the functions that dynamic trace knows about it requires two for loops. One to iterate over the pages and the other to iterate over the records within the page. There are several duplications of these loops in ftrace.c. This patch creates the macros do_for_each_ftrace_rec and while_for_each_ftrace_rec to handle this logic, and removes the duplicate code. While making this change, I also discovered and fixed a small bug that one of the iterations should exit the loop after it found the record it was searching for. This used a break when it should have used a goto, since there were two loops it needed to break out from. No real harm was done by this bug since it would only continue to search the other records, and the code was in a slow path anyway. Signed-off-by: Steven Rostedt <srostedt@redhat.com>
Diffstat (limited to 'kernel/trace/ftrace.c')
-rw-r--r--kernel/trace/ftrace.c208
1 files changed, 101 insertions, 107 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 369fb78bd4ab..fed1ebc3a133 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -297,6 +297,19 @@ static struct ftrace_page *ftrace_pages;
297 297
298static struct dyn_ftrace *ftrace_free_records; 298static struct dyn_ftrace *ftrace_free_records;
299 299
300/*
301 * This is a double for. Do not use 'break' to break out of the loop,
302 * you must use a goto.
303 */
304#define do_for_each_ftrace_rec(pg, rec) \
305 for (pg = ftrace_pages_start; pg; pg = pg->next) { \
306 int _____i; \
307 for (_____i = 0; _____i < pg->index; _____i++) { \
308 rec = &pg->records[_____i];
309
310#define while_for_each_ftrace_rec() \
311 } \
312 }
300 313
301#ifdef CONFIG_KPROBES 314#ifdef CONFIG_KPROBES
302 315
@@ -341,7 +354,6 @@ void ftrace_release(void *start, unsigned long size)
341 struct ftrace_page *pg; 354 struct ftrace_page *pg;
342 unsigned long s = (unsigned long)start; 355 unsigned long s = (unsigned long)start;
343 unsigned long e = s + size; 356 unsigned long e = s + size;
344 int i;
345 357
346 if (ftrace_disabled || !start) 358 if (ftrace_disabled || !start)
347 return; 359 return;
@@ -349,14 +361,11 @@ void ftrace_release(void *start, unsigned long size)
349 /* should not be called from interrupt context */ 361 /* should not be called from interrupt context */
350 spin_lock(&ftrace_lock); 362 spin_lock(&ftrace_lock);
351 363
352 for (pg = ftrace_pages_start; pg; pg = pg->next) { 364 do_for_each_ftrace_rec(pg, rec) {
353 for (i = 0; i < pg->index; i++) { 365 if ((rec->ip >= s) && (rec->ip < e))
354 rec = &pg->records[i]; 366 ftrace_free_rec(rec);
367 } while_for_each_ftrace_rec();
355 368
356 if ((rec->ip >= s) && (rec->ip < e))
357 ftrace_free_rec(rec);
358 }
359 }
360 spin_unlock(&ftrace_lock); 369 spin_unlock(&ftrace_lock);
361} 370}
362 371
@@ -523,41 +532,37 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable)
523 532
524static void ftrace_replace_code(int enable) 533static void ftrace_replace_code(int enable)
525{ 534{
526 int i, failed; 535 int failed;
527 struct dyn_ftrace *rec; 536 struct dyn_ftrace *rec;
528 struct ftrace_page *pg; 537 struct ftrace_page *pg;
529 538
530 for (pg = ftrace_pages_start; pg; pg = pg->next) { 539 do_for_each_ftrace_rec(pg, rec) {
531 for (i = 0; i < pg->index; i++) { 540 /*
532 rec = &pg->records[i]; 541 * Skip over free records and records that have
533 542 * failed.
534 /* 543 */
535 * Skip over free records and records that have 544 if (rec->flags & FTRACE_FL_FREE ||
536 * failed. 545 rec->flags & FTRACE_FL_FAILED)
537 */ 546 continue;
538 if (rec->flags & FTRACE_FL_FREE ||
539 rec->flags & FTRACE_FL_FAILED)
540 continue;
541
542 /* ignore updates to this record's mcount site */
543 if (get_kprobe((void *)rec->ip)) {
544 freeze_record(rec);
545 continue;
546 } else {
547 unfreeze_record(rec);
548 }
549 547
550 failed = __ftrace_replace_code(rec, enable); 548 /* ignore updates to this record's mcount site */
551 if (failed && (rec->flags & FTRACE_FL_CONVERTED)) { 549 if (get_kprobe((void *)rec->ip)) {
552 rec->flags |= FTRACE_FL_FAILED; 550 freeze_record(rec);
553 if ((system_state == SYSTEM_BOOTING) || 551 continue;
554 !core_kernel_text(rec->ip)) { 552 } else {
555 ftrace_free_rec(rec); 553 unfreeze_record(rec);
556 } else
557 ftrace_bug(failed, rec->ip);
558 }
559 } 554 }
560 } 555
556 failed = __ftrace_replace_code(rec, enable);
557 if (failed && (rec->flags & FTRACE_FL_CONVERTED)) {
558 rec->flags |= FTRACE_FL_FAILED;
559 if ((system_state == SYSTEM_BOOTING) ||
560 !core_kernel_text(rec->ip)) {
561 ftrace_free_rec(rec);
562 } else
563 ftrace_bug(failed, rec->ip);
564 }
565 } while_for_each_ftrace_rec();
561} 566}
562 567
563static int 568static int
@@ -956,22 +961,17 @@ static void ftrace_filter_reset(int enable)
956 struct ftrace_page *pg; 961 struct ftrace_page *pg;
957 struct dyn_ftrace *rec; 962 struct dyn_ftrace *rec;
958 unsigned long type = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; 963 unsigned long type = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
959 unsigned i;
960 964
961 /* should not be called from interrupt context */ 965 /* should not be called from interrupt context */
962 spin_lock(&ftrace_lock); 966 spin_lock(&ftrace_lock);
963 if (enable) 967 if (enable)
964 ftrace_filtered = 0; 968 ftrace_filtered = 0;
965 pg = ftrace_pages_start; 969 do_for_each_ftrace_rec(pg, rec) {
966 while (pg) { 970 if (rec->flags & FTRACE_FL_FAILED)
967 for (i = 0; i < pg->index; i++) { 971 continue;
968 rec = &pg->records[i]; 972 rec->flags &= ~type;
969 if (rec->flags & FTRACE_FL_FAILED) 973 } while_for_each_ftrace_rec();
970 continue; 974
971 rec->flags &= ~type;
972 }
973 pg = pg->next;
974 }
975 spin_unlock(&ftrace_lock); 975 spin_unlock(&ftrace_lock);
976} 976}
977 977
@@ -1094,44 +1094,39 @@ ftrace_match(unsigned char *buff, int len, int enable)
1094 spin_lock(&ftrace_lock); 1094 spin_lock(&ftrace_lock);
1095 if (enable) 1095 if (enable)
1096 ftrace_filtered = 1; 1096 ftrace_filtered = 1;
1097 pg = ftrace_pages_start; 1097 do_for_each_ftrace_rec(pg, rec) {
1098 while (pg) { 1098 int matched = 0;
1099 for (i = 0; i < pg->index; i++) { 1099 char *ptr;
1100 int matched = 0; 1100
1101 char *ptr; 1101 if (rec->flags & FTRACE_FL_FAILED)
1102 1102 continue;
1103 rec = &pg->records[i]; 1103 kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
1104 if (rec->flags & FTRACE_FL_FAILED) 1104 switch (type) {
1105 continue; 1105 case MATCH_FULL:
1106 kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); 1106 if (strcmp(str, buff) == 0)
1107 switch (type) { 1107 matched = 1;
1108 case MATCH_FULL: 1108 break;
1109 if (strcmp(str, buff) == 0) 1109 case MATCH_FRONT_ONLY:
1110 matched = 1; 1110 if (memcmp(str, buff, match) == 0)
1111 break; 1111 matched = 1;
1112 case MATCH_FRONT_ONLY: 1112 break;
1113 if (memcmp(str, buff, match) == 0) 1113 case MATCH_MIDDLE_ONLY:
1114 matched = 1; 1114 if (strstr(str, search))
1115 break; 1115 matched = 1;
1116 case MATCH_MIDDLE_ONLY: 1116 break;
1117 if (strstr(str, search)) 1117 case MATCH_END_ONLY:
1118 matched = 1; 1118 ptr = strstr(str, search);
1119 break; 1119 if (ptr && (ptr[search_len] == 0))
1120 case MATCH_END_ONLY: 1120 matched = 1;
1121 ptr = strstr(str, search); 1121 break;
1122 if (ptr && (ptr[search_len] == 0))
1123 matched = 1;
1124 break;
1125 }
1126 if (matched) {
1127 if (not)
1128 rec->flags &= ~flag;
1129 else
1130 rec->flags |= flag;
1131 }
1132 } 1122 }
1133 pg = pg->next; 1123 if (matched) {
1134 } 1124 if (not)
1125 rec->flags &= ~flag;
1126 else
1127 rec->flags |= flag;
1128 }
1129 } while_for_each_ftrace_rec();
1135 spin_unlock(&ftrace_lock); 1130 spin_unlock(&ftrace_lock);
1136} 1131}
1137 1132
@@ -1452,7 +1447,7 @@ ftrace_set_func(unsigned long *array, int idx, char *buffer)
1452 struct dyn_ftrace *rec; 1447 struct dyn_ftrace *rec;
1453 struct ftrace_page *pg; 1448 struct ftrace_page *pg;
1454 int found = 0; 1449 int found = 0;
1455 int i, j; 1450 int j;
1456 1451
1457 if (ftrace_disabled) 1452 if (ftrace_disabled)
1458 return -ENODEV; 1453 return -ENODEV;
@@ -1460,27 +1455,26 @@ ftrace_set_func(unsigned long *array, int idx, char *buffer)
1460 /* should not be called from interrupt context */ 1455 /* should not be called from interrupt context */
1461 spin_lock(&ftrace_lock); 1456 spin_lock(&ftrace_lock);
1462 1457
1463 for (pg = ftrace_pages_start; pg; pg = pg->next) { 1458 do_for_each_ftrace_rec(pg, rec) {
1464 for (i = 0; i < pg->index; i++) { 1459
1465 rec = &pg->records[i]; 1460 if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE))
1466 1461 continue;
1467 if (rec->flags & (FTRACE_FL_FAILED | FTRACE_FL_FREE)) 1462
1468 continue; 1463 kallsyms_lookup(rec->ip, NULL, NULL, NULL, str);
1469 1464 if (strcmp(str, buffer) == 0) {
1470 kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); 1465 /* Return 1 if we add it to the array */
1471 if (strcmp(str, buffer) == 0) { 1466 found = 1;
1472 found = 1; 1467 for (j = 0; j < idx; j++)
1473 for (j = 0; j < idx; j++) 1468 if (array[j] == rec->ip) {
1474 if (array[j] == rec->ip) { 1469 found = 0;
1475 found = 0; 1470 break;
1476 break; 1471 }
1477 } 1472 if (found)
1478 if (found) 1473 array[idx] = rec->ip;
1479 array[idx] = rec->ip; 1474 goto out;
1480 break;
1481 }
1482 } 1475 }
1483 } 1476 } while_for_each_ftrace_rec();
1477 out:
1484 spin_unlock(&ftrace_lock); 1478 spin_unlock(&ftrace_lock);
1485 1479
1486 return found ? 0 : -EINVAL; 1480 return found ? 0 : -EINVAL;