aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ftrace.h8
-rw-r--r--kernel/trace/ftrace.c243
-rw-r--r--kernel/trace/trace.c3
3 files changed, 38 insertions, 216 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 1c4835f86911..703eb53cfa2b 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -44,8 +44,6 @@ static inline void ftrace_kill(void) { }
44#endif /* CONFIG_FUNCTION_TRACER */ 44#endif /* CONFIG_FUNCTION_TRACER */
45 45
46#ifdef CONFIG_DYNAMIC_FTRACE 46#ifdef CONFIG_DYNAMIC_FTRACE
47# define FTRACE_HASHBITS 10
48# define FTRACE_HASHSIZE (1<<FTRACE_HASHBITS)
49 47
50enum { 48enum {
51 FTRACE_FL_FREE = (1 << 0), 49 FTRACE_FL_FREE = (1 << 0),
@@ -58,9 +56,9 @@ enum {
58}; 56};
59 57
60struct dyn_ftrace { 58struct dyn_ftrace {
61 struct hlist_node node; 59 struct list_head list;
62 unsigned long ip; /* address of mcount call-site */ 60 unsigned long ip; /* address of mcount call-site */
63 unsigned long flags; 61 unsigned long flags;
64}; 62};
65 63
66int ftrace_force_update(void); 64int ftrace_force_update(void);
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 226fd9132d53..07762c08a944 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -25,7 +25,6 @@
25#include <linux/ftrace.h> 25#include <linux/ftrace.h>
26#include <linux/sysctl.h> 26#include <linux/sysctl.h>
27#include <linux/ctype.h> 27#include <linux/ctype.h>
28#include <linux/hash.h>
29#include <linux/list.h> 28#include <linux/list.h>
30 29
31#include <asm/ftrace.h> 30#include <asm/ftrace.h>
@@ -189,9 +188,7 @@ static int ftrace_filtered;
189static int tracing_on; 188static int tracing_on;
190static int frozen_record_count; 189static int frozen_record_count;
191 190
192static struct hlist_head ftrace_hash[FTRACE_HASHSIZE]; 191static LIST_HEAD(ftrace_new_addrs);
193
194static DEFINE_PER_CPU(int, ftrace_shutdown_disable_cpu);
195 192
196static DEFINE_MUTEX(ftrace_regex_lock); 193static DEFINE_MUTEX(ftrace_regex_lock);
197 194
@@ -210,8 +207,6 @@ struct ftrace_page {
210static struct ftrace_page *ftrace_pages_start; 207static struct ftrace_page *ftrace_pages_start;
211static struct ftrace_page *ftrace_pages; 208static struct ftrace_page *ftrace_pages;
212 209
213static int ftrace_record_suspend;
214
215static struct dyn_ftrace *ftrace_free_records; 210static struct dyn_ftrace *ftrace_free_records;
216 211
217 212
@@ -242,72 +237,6 @@ static inline int record_frozen(struct dyn_ftrace *rec)
242# define record_frozen(rec) ({ 0; }) 237# define record_frozen(rec) ({ 0; })
243#endif /* CONFIG_KPROBES */ 238#endif /* CONFIG_KPROBES */
244 239
245int skip_trace(unsigned long ip)
246{
247 unsigned long fl;
248 struct dyn_ftrace *rec;
249 struct hlist_node *t;
250 struct hlist_head *head;
251
252 if (frozen_record_count == 0)
253 return 0;
254
255 head = &ftrace_hash[hash_long(ip, FTRACE_HASHBITS)];
256 hlist_for_each_entry_rcu(rec, t, head, node) {
257 if (rec->ip == ip) {
258 if (record_frozen(rec)) {
259 if (rec->flags & FTRACE_FL_FAILED)
260 return 1;
261
262 if (!(rec->flags & FTRACE_FL_CONVERTED))
263 return 1;
264
265 if (!tracing_on || !ftrace_enabled)
266 return 1;
267
268 if (ftrace_filtered) {
269 fl = rec->flags & (FTRACE_FL_FILTER |
270 FTRACE_FL_NOTRACE);
271 if (!fl || (fl & FTRACE_FL_NOTRACE))
272 return 1;
273 }
274 }
275 break;
276 }
277 }
278
279 return 0;
280}
281
282static inline int
283ftrace_ip_in_hash(unsigned long ip, unsigned long key)
284{
285 struct dyn_ftrace *p;
286 struct hlist_node *t;
287 int found = 0;
288
289 hlist_for_each_entry_rcu(p, t, &ftrace_hash[key], node) {
290 if (p->ip == ip) {
291 found = 1;
292 break;
293 }
294 }
295
296 return found;
297}
298
299static inline void
300ftrace_add_hash(struct dyn_ftrace *node, unsigned long key)
301{
302 hlist_add_head_rcu(&node->node, &ftrace_hash[key]);
303}
304
305/* called from kstop_machine */
306static inline void ftrace_del_hash(struct dyn_ftrace *node)
307{
308 hlist_del(&node->node);
309}
310
311static void ftrace_free_rec(struct dyn_ftrace *rec) 240static void ftrace_free_rec(struct dyn_ftrace *rec)
312{ 241{
313 rec->ip = (unsigned long)ftrace_free_records; 242 rec->ip = (unsigned long)ftrace_free_records;
@@ -362,69 +291,36 @@ static struct dyn_ftrace *ftrace_alloc_dyn_node(unsigned long ip)
362 } 291 }
363 292
364 if (ftrace_pages->index == ENTRIES_PER_PAGE) { 293 if (ftrace_pages->index == ENTRIES_PER_PAGE) {
365 if (!ftrace_pages->next) 294 if (!ftrace_pages->next) {
366 return NULL; 295 /* allocate another page */
296 ftrace_pages->next =
297 (void *)get_zeroed_page(GFP_KERNEL);
298 if (!ftrace_pages->next)
299 return NULL;
300 }
367 ftrace_pages = ftrace_pages->next; 301 ftrace_pages = ftrace_pages->next;
368 } 302 }
369 303
370 return &ftrace_pages->records[ftrace_pages->index++]; 304 return &ftrace_pages->records[ftrace_pages->index++];
371} 305}
372 306
373static void 307static struct dyn_ftrace *
374ftrace_record_ip(unsigned long ip) 308ftrace_record_ip(unsigned long ip)
375{ 309{
376 struct dyn_ftrace *node; 310 struct dyn_ftrace *rec;
377 unsigned long key;
378 int resched;
379 int cpu;
380 311
381 if (!ftrace_enabled || ftrace_disabled) 312 if (!ftrace_enabled || ftrace_disabled)
382 return; 313 return NULL;
383
384 resched = need_resched();
385 preempt_disable_notrace();
386
387 /*
388 * We simply need to protect against recursion.
389 * Use the the raw version of smp_processor_id and not
390 * __get_cpu_var which can call debug hooks that can
391 * cause a recursive crash here.
392 */
393 cpu = raw_smp_processor_id();
394 per_cpu(ftrace_shutdown_disable_cpu, cpu)++;
395 if (per_cpu(ftrace_shutdown_disable_cpu, cpu) != 1)
396 goto out;
397
398 if (unlikely(ftrace_record_suspend))
399 goto out;
400
401 key = hash_long(ip, FTRACE_HASHBITS);
402
403 FTRACE_WARN_ON_ONCE(key >= FTRACE_HASHSIZE);
404
405 if (ftrace_ip_in_hash(ip, key))
406 goto out;
407
408 /* This ip may have hit the hash before the lock */
409 if (ftrace_ip_in_hash(ip, key))
410 goto out;
411
412 node = ftrace_alloc_dyn_node(ip);
413 if (!node)
414 goto out;
415 314
416 node->ip = ip; 315 rec = ftrace_alloc_dyn_node(ip);
316 if (!rec)
317 return NULL;
417 318
418 ftrace_add_hash(node, key); 319 rec->ip = ip;
419 320
420 out: 321 list_add(&rec->list, &ftrace_new_addrs);
421 per_cpu(ftrace_shutdown_disable_cpu, cpu)--;
422 322
423 /* prevent recursion with scheduler */ 323 return rec;
424 if (resched)
425 preempt_enable_no_resched_notrace();
426 else
427 preempt_enable_notrace();
428} 324}
429 325
430#define FTRACE_ADDR ((long)(ftrace_caller)) 326#define FTRACE_ADDR ((long)(ftrace_caller))
@@ -543,7 +439,6 @@ static void ftrace_replace_code(int enable)
543 rec->flags |= FTRACE_FL_FAILED; 439 rec->flags |= FTRACE_FL_FAILED;
544 if ((system_state == SYSTEM_BOOTING) || 440 if ((system_state == SYSTEM_BOOTING) ||
545 !core_kernel_text(rec->ip)) { 441 !core_kernel_text(rec->ip)) {
546 ftrace_del_hash(rec);
547 ftrace_free_rec(rec); 442 ftrace_free_rec(rec);
548 } 443 }
549 } 444 }
@@ -551,15 +446,6 @@ static void ftrace_replace_code(int enable)
551 } 446 }
552} 447}
553 448
554static void ftrace_shutdown_replenish(void)
555{
556 if (ftrace_pages->next)
557 return;
558
559 /* allocate another page */
560 ftrace_pages->next = (void *)get_zeroed_page(GFP_KERNEL);
561}
562
563static void print_ip_ins(const char *fmt, unsigned char *p) 449static void print_ip_ins(const char *fmt, unsigned char *p)
564{ 450{
565 int i; 451 int i;
@@ -616,18 +502,11 @@ ftrace_code_disable(struct dyn_ftrace *rec)
616 return 1; 502 return 1;
617} 503}
618 504
619static int ftrace_update_code(void *ignore);
620
621static int __ftrace_modify_code(void *data) 505static int __ftrace_modify_code(void *data)
622{ 506{
623 int *command = data; 507 int *command = data;
624 508
625 if (*command & FTRACE_ENABLE_CALLS) { 509 if (*command & FTRACE_ENABLE_CALLS) {
626 /*
627 * Update any recorded ips now that we have the
628 * machine stopped
629 */
630 ftrace_update_code(NULL);
631 ftrace_replace_code(1); 510 ftrace_replace_code(1);
632 tracing_on = 1; 511 tracing_on = 1;
633 } else if (*command & FTRACE_DISABLE_CALLS) { 512 } else if (*command & FTRACE_DISABLE_CALLS) {
@@ -738,84 +617,34 @@ static cycle_t ftrace_update_time;
738static unsigned long ftrace_update_cnt; 617static unsigned long ftrace_update_cnt;
739unsigned long ftrace_update_tot_cnt; 618unsigned long ftrace_update_tot_cnt;
740 619
741static int ftrace_update_code(void *ignore) 620static int ftrace_update_code(void)
742{ 621{
743 int i, save_ftrace_enabled; 622 struct dyn_ftrace *p, *t;
744 cycle_t start, stop; 623 cycle_t start, stop;
745 struct dyn_ftrace *p;
746 struct hlist_node *t, *n;
747 struct hlist_head *head, temp_list;
748
749 /* Don't be recording funcs now */
750 ftrace_record_suspend++;
751 save_ftrace_enabled = ftrace_enabled;
752 ftrace_enabled = 0;
753 624
754 start = ftrace_now(raw_smp_processor_id()); 625 start = ftrace_now(raw_smp_processor_id());
755 ftrace_update_cnt = 0; 626 ftrace_update_cnt = 0;
756 627
757 /* No locks needed, the machine is stopped! */ 628 list_for_each_entry_safe(p, t, &ftrace_new_addrs, list) {
758 for (i = 0; i < FTRACE_HASHSIZE; i++) {
759 INIT_HLIST_HEAD(&temp_list);
760 head = &ftrace_hash[i];
761 629
762 /* all CPUS are stopped, we are safe to modify code */ 630 /* If something went wrong, bail without enabling anything */
763 hlist_for_each_entry_safe(p, t, n, head, node) { 631 if (unlikely(ftrace_disabled))
764 /* Skip over failed records which have not been 632 return -1;
765 * freed. */
766 if (p->flags & FTRACE_FL_FAILED)
767 continue;
768 633
769 /* Unconverted records are always at the head of the 634 list_del_init(&p->list);
770 * hash bucket. Once we encounter a converted record,
771 * simply skip over to the next bucket. Saves ftraced
772 * some processor cycles (ftrace does its bid for
773 * global warming :-p ). */
774 if (p->flags & (FTRACE_FL_CONVERTED))
775 break;
776 635
777 /* Ignore updates to this record's mcount site. 636 /* convert record (i.e, patch mcount-call with NOP) */
778 * Reintroduce this record at the head of this 637 if (ftrace_code_disable(p)) {
779 * bucket to attempt to "convert" it again if 638 p->flags |= FTRACE_FL_CONVERTED;
780 * the kprobe on it is unregistered before the 639 ftrace_update_cnt++;
781 * next run. */ 640 } else
782 if (get_kprobe((void *)p->ip)) { 641 ftrace_free_rec(p);
783 ftrace_del_hash(p);
784 INIT_HLIST_NODE(&p->node);
785 hlist_add_head(&p->node, &temp_list);
786 freeze_record(p);
787 continue;
788 } else {
789 unfreeze_record(p);
790 }
791
792 /* convert record (i.e, patch mcount-call with NOP) */
793 if (ftrace_code_disable(p)) {
794 p->flags |= FTRACE_FL_CONVERTED;
795 ftrace_update_cnt++;
796 } else {
797 if ((system_state == SYSTEM_BOOTING) ||
798 !core_kernel_text(p->ip)) {
799 ftrace_del_hash(p);
800 ftrace_free_rec(p);
801 }
802 }
803 }
804
805 hlist_for_each_entry_safe(p, t, n, &temp_list, node) {
806 hlist_del(&p->node);
807 INIT_HLIST_NODE(&p->node);
808 hlist_add_head(&p->node, head);
809 }
810 } 642 }
811 643
812 stop = ftrace_now(raw_smp_processor_id()); 644 stop = ftrace_now(raw_smp_processor_id());
813 ftrace_update_time = stop - start; 645 ftrace_update_time = stop - start;
814 ftrace_update_tot_cnt += ftrace_update_cnt; 646 ftrace_update_tot_cnt += ftrace_update_cnt;
815 647
816 ftrace_enabled = save_ftrace_enabled;
817 ftrace_record_suspend--;
818
819 return 0; 648 return 0;
820} 649}
821 650
@@ -847,7 +676,7 @@ static int __init ftrace_dyn_table_alloc(unsigned long num_to_init)
847 pg = ftrace_pages = ftrace_pages_start; 676 pg = ftrace_pages = ftrace_pages_start;
848 677
849 cnt = num_to_init / ENTRIES_PER_PAGE; 678 cnt = num_to_init / ENTRIES_PER_PAGE;
850 pr_info("ftrace: allocating %ld hash entries in %d pages\n", 679 pr_info("ftrace: allocating %ld entries in %d pages\n",
851 num_to_init, cnt); 680 num_to_init, cnt);
852 681
853 for (i = 0; i < cnt; i++) { 682 for (i = 0; i < cnt; i++) {
@@ -1451,20 +1280,18 @@ static int ftrace_convert_nops(unsigned long *start,
1451 unsigned long addr; 1280 unsigned long addr;
1452 unsigned long flags; 1281 unsigned long flags;
1453 1282
1283 mutex_lock(&ftrace_start_lock);
1454 p = start; 1284 p = start;
1455 while (p < end) { 1285 while (p < end) {
1456 addr = ftrace_call_adjust(*p++); 1286 addr = ftrace_call_adjust(*p++);
1457 /* should not be called from interrupt context */
1458 spin_lock(&ftrace_lock);
1459 ftrace_record_ip(addr); 1287 ftrace_record_ip(addr);
1460 spin_unlock(&ftrace_lock);
1461 ftrace_shutdown_replenish();
1462 } 1288 }
1463 1289
1464 /* p is ignored */ 1290 /* disable interrupts to prevent kstop machine */
1465 local_irq_save(flags); 1291 local_irq_save(flags);
1466 ftrace_update_code(p); 1292 ftrace_update_code();
1467 local_irq_restore(flags); 1293 local_irq_restore(flags);
1294 mutex_unlock(&ftrace_start_lock);
1468 1295
1469 return 0; 1296 return 0;
1470} 1297}
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 333a5162149b..06951e229443 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -865,9 +865,6 @@ function_trace_call(unsigned long ip, unsigned long parent_ip)
865 if (unlikely(!ftrace_function_enabled)) 865 if (unlikely(!ftrace_function_enabled))
866 return; 866 return;
867 867
868 if (skip_trace(ip))
869 return;
870
871 pc = preempt_count(); 868 pc = preempt_count();
872 resched = need_resched(); 869 resched = need_resched();
873 preempt_disable_notrace(); 870 preempt_disable_notrace();