aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Metzger <markus.t.metzger@intel.com>2009-04-03 10:43:40 -0400
committerIngo Molnar <mingo@elte.hu>2009-04-07 07:36:20 -0400
commitde79f54f5347ad7ec6ff55ccbb6d4ab2a21f6a93 (patch)
treedfd3f000600b942a545cbc8acd2f2e67f4518015
parent35bb7600c17762bb129588c1877d2717fe325289 (diff)
x86, bts, hw-branch-tracer: add _noirq variants to the debug store interface
The hw-branch-tracer uses debug store functions from an on_each_cpu() context, which is simply wrong since the functions may sleep. Add _noirq variants for most functions, which may be called with interrupts disabled. Separate per-cpu and per-task tracing and allow per-cpu tracing to be controlled from any cpu. Make the hw-branch-tracer use the new debug store interface, synchronize with hotplug cpu event using get/put_online_cpus(), and remove the unnecessary spinlock. Make the ptrace bts and the ds selftest code use the new interface. Defer the ds selftest. Signed-off-by: Markus Metzger <markus.t.metzger@intel.com> Cc: roland@redhat.com Cc: eranian@googlemail.com Cc: oleg@redhat.com Cc: juan.villacis@intel.com Cc: ak@linux.jf.intel.com LKML-Reference: <20090403144555.658136000@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/include/asm/ds.h57
-rw-r--r--arch/x86/kernel/ds.c474
-rw-r--r--arch/x86/kernel/ds_selftest.c9
-rw-r--r--arch/x86/kernel/ptrace.c5
-rw-r--r--kernel/trace/trace_hw_branches.c193
5 files changed, 492 insertions, 246 deletions
diff --git a/arch/x86/include/asm/ds.h b/arch/x86/include/asm/ds.h
index 772f141afb9a..413e127e567d 100644
--- a/arch/x86/include/asm/ds.h
+++ b/arch/x86/include/asm/ds.h
@@ -15,8 +15,8 @@
15 * - buffer allocation (memory accounting) 15 * - buffer allocation (memory accounting)
16 * 16 *
17 * 17 *
18 * Copyright (C) 2007-2008 Intel Corporation. 18 * Copyright (C) 2007-2009 Intel Corporation.
19 * Markus Metzger <markus.t.metzger@intel.com>, 2007-2008 19 * Markus Metzger <markus.t.metzger@intel.com>, 2007-2009
20 */ 20 */
21 21
22#ifndef _ASM_X86_DS_H 22#ifndef _ASM_X86_DS_H
@@ -83,8 +83,10 @@ enum ds_feature {
83 * The interrupt threshold is independent from the overflow callback 83 * The interrupt threshold is independent from the overflow callback
84 * to allow users to use their own overflow interrupt handling mechanism. 84 * to allow users to use their own overflow interrupt handling mechanism.
85 * 85 *
86 * task: the task to request recording for; 86 * The function might sleep.
87 * NULL for per-cpu recording on the current cpu 87 *
88 * task: the task to request recording for
89 * cpu: the cpu to request recording for
88 * base: the base pointer for the (non-pageable) buffer; 90 * base: the base pointer for the (non-pageable) buffer;
89 * size: the size of the provided buffer in bytes 91 * size: the size of the provided buffer in bytes
90 * ovfl: pointer to a function to be called on buffer overflow; 92 * ovfl: pointer to a function to be called on buffer overflow;
@@ -93,19 +95,28 @@ enum ds_feature {
93 * -1 if no interrupt threshold is requested. 95 * -1 if no interrupt threshold is requested.
94 * flags: a bit-mask of the above flags 96 * flags: a bit-mask of the above flags
95 */ 97 */
96extern struct bts_tracer *ds_request_bts(struct task_struct *task, 98extern struct bts_tracer *ds_request_bts_task(struct task_struct *task,
97 void *base, size_t size, 99 void *base, size_t size,
98 bts_ovfl_callback_t ovfl, 100 bts_ovfl_callback_t ovfl,
99 size_t th, unsigned int flags); 101 size_t th, unsigned int flags);
100extern struct pebs_tracer *ds_request_pebs(struct task_struct *task, 102extern struct bts_tracer *ds_request_bts_cpu(int cpu, void *base, size_t size,
101 void *base, size_t size, 103 bts_ovfl_callback_t ovfl,
102 pebs_ovfl_callback_t ovfl, 104 size_t th, unsigned int flags);
103 size_t th, unsigned int flags); 105extern struct pebs_tracer *ds_request_pebs_task(struct task_struct *task,
106 void *base, size_t size,
107 pebs_ovfl_callback_t ovfl,
108 size_t th, unsigned int flags);
109extern struct pebs_tracer *ds_request_pebs_cpu(int cpu,
110 void *base, size_t size,
111 pebs_ovfl_callback_t ovfl,
112 size_t th, unsigned int flags);
104 113
105/* 114/*
106 * Release BTS or PEBS resources 115 * Release BTS or PEBS resources
107 * Suspend and resume BTS or PEBS tracing 116 * Suspend and resume BTS or PEBS tracing
108 * 117 *
118 * Must be called with irq's enabled.
119 *
109 * tracer: the tracer handle returned from ds_request_~() 120 * tracer: the tracer handle returned from ds_request_~()
110 */ 121 */
111extern void ds_release_bts(struct bts_tracer *tracer); 122extern void ds_release_bts(struct bts_tracer *tracer);
@@ -115,6 +126,28 @@ extern void ds_release_pebs(struct pebs_tracer *tracer);
115extern void ds_suspend_pebs(struct pebs_tracer *tracer); 126extern void ds_suspend_pebs(struct pebs_tracer *tracer);
116extern void ds_resume_pebs(struct pebs_tracer *tracer); 127extern void ds_resume_pebs(struct pebs_tracer *tracer);
117 128
129/*
130 * Release BTS or PEBS resources
131 * Suspend and resume BTS or PEBS tracing
132 *
133 * Cpu tracers must call this on the traced cpu.
134 * Task tracers must call ds_release_~_noirq() for themselves.
135 *
136 * May be called with irq's disabled.
137 *
138 * Returns 0 if successful;
139 * -EPERM if the cpu tracer does not trace the current cpu.
140 * -EPERM if the task tracer does not trace itself.
141 *
142 * tracer: the tracer handle returned from ds_request_~()
143 */
144extern int ds_release_bts_noirq(struct bts_tracer *tracer);
145extern int ds_suspend_bts_noirq(struct bts_tracer *tracer);
146extern int ds_resume_bts_noirq(struct bts_tracer *tracer);
147extern int ds_release_pebs_noirq(struct pebs_tracer *tracer);
148extern int ds_suspend_pebs_noirq(struct pebs_tracer *tracer);
149extern int ds_resume_pebs_noirq(struct pebs_tracer *tracer);
150
118 151
119/* 152/*
120 * The raw DS buffer state as it is used for BTS and PEBS recording. 153 * The raw DS buffer state as it is used for BTS and PEBS recording.
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c
index 2071b992c35c..21a3852abf68 100644
--- a/arch/x86/kernel/ds.c
+++ b/arch/x86/kernel/ds.c
@@ -245,60 +245,50 @@ struct ds_context {
245 struct pebs_tracer *pebs_master; 245 struct pebs_tracer *pebs_master;
246 246
247 /* Use count: */ 247 /* Use count: */
248 unsigned long count; 248 unsigned long count;
249 249
250 /* Pointer to the context pointer field: */ 250 /* Pointer to the context pointer field: */
251 struct ds_context **this; 251 struct ds_context **this;
252 252
253 /* The traced task; NULL for current cpu: */ 253 /* The traced task; NULL for cpu tracing: */
254 struct task_struct *task; 254 struct task_struct *task;
255};
256 255
257static DEFINE_PER_CPU(struct ds_context *, system_context_array); 256 /* The traced cpu; only valid if task is NULL: */
257 int cpu;
258};
258 259
259#define system_context per_cpu(system_context_array, smp_processor_id()) 260static DEFINE_PER_CPU(struct ds_context *, cpu_context);
260 261
261 262
262static inline struct ds_context *ds_get_context(struct task_struct *task) 263static struct ds_context *ds_get_context(struct task_struct *task, int cpu)
263{ 264{
264 struct ds_context **p_context = 265 struct ds_context **p_context =
265 (task ? &task->thread.ds_ctx : &system_context); 266 (task ? &task->thread.ds_ctx : &per_cpu(cpu_context, cpu));
266 struct ds_context *context = NULL; 267 struct ds_context *context = NULL;
267 struct ds_context *new_context = NULL; 268 struct ds_context *new_context = NULL;
268 unsigned long irq;
269 269
270 /* 270 /* Chances are small that we already have a context. */
271 * Chances are small that we already have a context. 271 new_context = kzalloc(sizeof(*new_context), GFP_KERNEL);
272 *
273 * Contexts for per-cpu tracing are allocated using
274 * smp_call_function(). We must not sleep.
275 */
276 new_context = kzalloc(sizeof(*new_context), GFP_ATOMIC);
277 if (!new_context) 272 if (!new_context)
278 return NULL; 273 return NULL;
279 274
280 spin_lock_irqsave(&ds_lock, irq); 275 spin_lock_irq(&ds_lock);
281 276
282 context = *p_context; 277 context = *p_context;
283 if (!context) { 278 if (likely(!context)) {
284 context = new_context; 279 context = new_context;
285 280
286 context->this = p_context; 281 context->this = p_context;
287 context->task = task; 282 context->task = task;
283 context->cpu = cpu;
288 context->count = 0; 284 context->count = 0;
289 285
290 if (task)
291 set_tsk_thread_flag(task, TIF_DS_AREA_MSR);
292
293 if (!task || (task == current))
294 wrmsrl(MSR_IA32_DS_AREA, (unsigned long)context->ds);
295
296 *p_context = context; 286 *p_context = context;
297 } 287 }
298 288
299 context->count++; 289 context->count++;
300 290
301 spin_unlock_irqrestore(&ds_lock, irq); 291 spin_unlock_irq(&ds_lock);
302 292
303 if (context != new_context) 293 if (context != new_context)
304 kfree(new_context); 294 kfree(new_context);
@@ -306,7 +296,7 @@ static inline struct ds_context *ds_get_context(struct task_struct *task)
306 return context; 296 return context;
307} 297}
308 298
309static inline void ds_put_context(struct ds_context *context) 299static void ds_put_context(struct ds_context *context)
310{ 300{
311 struct task_struct *task; 301 struct task_struct *task;
312 unsigned long irq; 302 unsigned long irq;
@@ -328,8 +318,15 @@ static inline void ds_put_context(struct ds_context *context)
328 if (task) 318 if (task)
329 clear_tsk_thread_flag(task, TIF_DS_AREA_MSR); 319 clear_tsk_thread_flag(task, TIF_DS_AREA_MSR);
330 320
331 if (!task || (task == current)) 321 /*
332 wrmsrl(MSR_IA32_DS_AREA, 0); 322 * We leave the (now dangling) pointer to the DS configuration in
323 * the DS_AREA msr. This is as good or as bad as replacing it with
324 * NULL - the hardware would crash if we enabled tracing.
325 *
326 * This saves us some problems with having to write an msr on a
327 * different cpu while preventing others from doing the same for the
328 * next context for that same cpu.
329 */
333 330
334 spin_unlock_irqrestore(&ds_lock, irq); 331 spin_unlock_irqrestore(&ds_lock, irq);
335 332
@@ -340,6 +337,31 @@ static inline void ds_put_context(struct ds_context *context)
340 kfree(context); 337 kfree(context);
341} 338}
342 339
340static void ds_install_ds_area(struct ds_context *context)
341{
342 unsigned long ds;
343
344 ds = (unsigned long)context->ds;
345
346 /*
347 * There is a race between the bts master and the pebs master.
348 *
349 * The thread/cpu access is synchronized via get/put_cpu() for
350 * task tracing and via wrmsr_on_cpu for cpu tracing.
351 *
352 * If bts and pebs are collected for the same task or same cpu,
353 * the same confiuration is written twice.
354 */
355 if (context->task) {
356 get_cpu();
357 if (context->task == current)
358 wrmsrl(MSR_IA32_DS_AREA, ds);
359 set_tsk_thread_flag(context->task, TIF_DS_AREA_MSR);
360 put_cpu();
361 } else
362 wrmsr_on_cpu(context->cpu, MSR_IA32_DS_AREA,
363 (u32)((u64)ds), (u32)((u64)ds >> 32));
364}
343 365
344/* 366/*
345 * Call the tracer's callback on a buffer overflow. 367 * Call the tracer's callback on a buffer overflow.
@@ -622,6 +644,7 @@ static void ds_init_ds_trace(struct ds_trace *trace, enum ds_qualifier qual,
622 * The value for 'no threshold' is -1, which will set the 644 * The value for 'no threshold' is -1, which will set the
623 * threshold outside of the buffer, just like we want it. 645 * threshold outside of the buffer, just like we want it.
624 */ 646 */
647 ith *= ds_cfg.sizeof_rec[qual];
625 trace->ith = (void *)(buffer + size - ith); 648 trace->ith = (void *)(buffer + size - ith);
626 649
627 trace->flags = flags; 650 trace->flags = flags;
@@ -630,7 +653,7 @@ static void ds_init_ds_trace(struct ds_trace *trace, enum ds_qualifier qual,
630 653
631static int ds_request(struct ds_tracer *tracer, struct ds_trace *trace, 654static int ds_request(struct ds_tracer *tracer, struct ds_trace *trace,
632 enum ds_qualifier qual, struct task_struct *task, 655 enum ds_qualifier qual, struct task_struct *task,
633 void *base, size_t size, size_t th, unsigned int flags) 656 int cpu, void *base, size_t size, size_t th)
634{ 657{
635 struct ds_context *context; 658 struct ds_context *context;
636 int error; 659 int error;
@@ -643,7 +666,7 @@ static int ds_request(struct ds_tracer *tracer, struct ds_trace *trace,
643 if (!base) 666 if (!base)
644 goto out; 667 goto out;
645 668
646 /* We require some space to do alignment adjustments below. */ 669 /* We need space for alignment adjustments in ds_init_ds_trace(). */
647 error = -EINVAL; 670 error = -EINVAL;
648 if (size < (DS_ALIGNMENT + ds_cfg.sizeof_rec[qual])) 671 if (size < (DS_ALIGNMENT + ds_cfg.sizeof_rec[qual]))
649 goto out; 672 goto out;
@@ -660,25 +683,27 @@ static int ds_request(struct ds_tracer *tracer, struct ds_trace *trace,
660 tracer->size = size; 683 tracer->size = size;
661 684
662 error = -ENOMEM; 685 error = -ENOMEM;
663 context = ds_get_context(task); 686 context = ds_get_context(task, cpu);
664 if (!context) 687 if (!context)
665 goto out; 688 goto out;
666 tracer->context = context; 689 tracer->context = context;
667 690
668 ds_init_ds_trace(trace, qual, base, size, th, flags); 691 /*
692 * Defer any tracer-specific initialization work for the context until
693 * context ownership has been clarified.
694 */
669 695
670 error = 0; 696 error = 0;
671 out: 697 out:
672 return error; 698 return error;
673} 699}
674 700
675struct bts_tracer *ds_request_bts(struct task_struct *task, 701static struct bts_tracer *ds_request_bts(struct task_struct *task, int cpu,
676 void *base, size_t size, 702 void *base, size_t size,
677 bts_ovfl_callback_t ovfl, size_t th, 703 bts_ovfl_callback_t ovfl, size_t th,
678 unsigned int flags) 704 unsigned int flags)
679{ 705{
680 struct bts_tracer *tracer; 706 struct bts_tracer *tracer;
681 unsigned long irq;
682 int error; 707 int error;
683 708
684 /* Buffer overflow notification is not yet implemented. */ 709 /* Buffer overflow notification is not yet implemented. */
@@ -690,42 +715,46 @@ struct bts_tracer *ds_request_bts(struct task_struct *task,
690 if (error < 0) 715 if (error < 0)
691 goto out; 716 goto out;
692 717
693 /*
694 * Per-cpu tracing is typically requested using smp_call_function().
695 * We must not sleep.
696 */
697 error = -ENOMEM; 718 error = -ENOMEM;
698 tracer = kzalloc(sizeof(*tracer), GFP_ATOMIC); 719 tracer = kzalloc(sizeof(*tracer), GFP_KERNEL);
699 if (!tracer) 720 if (!tracer)
700 goto out_put_tracer; 721 goto out_put_tracer;
701 tracer->ovfl = ovfl; 722 tracer->ovfl = ovfl;
702 723
724 /* Do some more error checking and acquire a tracing context. */
703 error = ds_request(&tracer->ds, &tracer->trace.ds, 725 error = ds_request(&tracer->ds, &tracer->trace.ds,
704 ds_bts, task, base, size, th, flags); 726 ds_bts, task, cpu, base, size, th);
705 if (error < 0) 727 if (error < 0)
706 goto out_tracer; 728 goto out_tracer;
707 729
708 730 /* Claim the bts part of the tracing context we acquired above. */
709 spin_lock_irqsave(&ds_lock, irq); 731 spin_lock_irq(&ds_lock);
710 732
711 error = -EPERM; 733 error = -EPERM;
712 if (tracer->ds.context->bts_master) 734 if (tracer->ds.context->bts_master)
713 goto out_unlock; 735 goto out_unlock;
714 tracer->ds.context->bts_master = tracer; 736 tracer->ds.context->bts_master = tracer;
715 737
716 spin_unlock_irqrestore(&ds_lock, irq); 738 spin_unlock_irq(&ds_lock);
717 739
740 /*
741 * Now that we own the bts part of the context, let's complete the
742 * initialization for that part.
743 */
744 ds_init_ds_trace(&tracer->trace.ds, ds_bts, base, size, th, flags);
745 ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_bts);
746 ds_install_ds_area(tracer->ds.context);
718 747
719 tracer->trace.read = bts_read; 748 tracer->trace.read = bts_read;
720 tracer->trace.write = bts_write; 749 tracer->trace.write = bts_write;
721 750
722 ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_bts); 751 /* Start tracing. */
723 ds_resume_bts(tracer); 752 ds_resume_bts(tracer);
724 753
725 return tracer; 754 return tracer;
726 755
727 out_unlock: 756 out_unlock:
728 spin_unlock_irqrestore(&ds_lock, irq); 757 spin_unlock_irq(&ds_lock);
729 ds_put_context(tracer->ds.context); 758 ds_put_context(tracer->ds.context);
730 out_tracer: 759 out_tracer:
731 kfree(tracer); 760 kfree(tracer);
@@ -735,13 +764,27 @@ struct bts_tracer *ds_request_bts(struct task_struct *task,
735 return ERR_PTR(error); 764 return ERR_PTR(error);
736} 765}
737 766
738struct pebs_tracer *ds_request_pebs(struct task_struct *task, 767struct bts_tracer *ds_request_bts_task(struct task_struct *task,
739 void *base, size_t size, 768 void *base, size_t size,
740 pebs_ovfl_callback_t ovfl, size_t th, 769 bts_ovfl_callback_t ovfl,
741 unsigned int flags) 770 size_t th, unsigned int flags)
771{
772 return ds_request_bts(task, 0, base, size, ovfl, th, flags);
773}
774
775struct bts_tracer *ds_request_bts_cpu(int cpu, void *base, size_t size,
776 bts_ovfl_callback_t ovfl,
777 size_t th, unsigned int flags)
778{
779 return ds_request_bts(NULL, cpu, base, size, ovfl, th, flags);
780}
781
782static struct pebs_tracer *ds_request_pebs(struct task_struct *task, int cpu,
783 void *base, size_t size,
784 pebs_ovfl_callback_t ovfl, size_t th,
785 unsigned int flags)
742{ 786{
743 struct pebs_tracer *tracer; 787 struct pebs_tracer *tracer;
744 unsigned long irq;
745 int error; 788 int error;
746 789
747 /* Buffer overflow notification is not yet implemented. */ 790 /* Buffer overflow notification is not yet implemented. */
@@ -753,37 +796,43 @@ struct pebs_tracer *ds_request_pebs(struct task_struct *task,
753 if (error < 0) 796 if (error < 0)
754 goto out; 797 goto out;
755 798
756 /*
757 * Per-cpu tracing is typically requested using smp_call_function().
758 * We must not sleep.
759 */
760 error = -ENOMEM; 799 error = -ENOMEM;
761 tracer = kzalloc(sizeof(*tracer), GFP_ATOMIC); 800 tracer = kzalloc(sizeof(*tracer), GFP_KERNEL);
762 if (!tracer) 801 if (!tracer)
763 goto out_put_tracer; 802 goto out_put_tracer;
764 tracer->ovfl = ovfl; 803 tracer->ovfl = ovfl;
765 804
805 /* Do some more error checking and acquire a tracing context. */
766 error = ds_request(&tracer->ds, &tracer->trace.ds, 806 error = ds_request(&tracer->ds, &tracer->trace.ds,
767 ds_pebs, task, base, size, th, flags); 807 ds_pebs, task, cpu, base, size, th);
768 if (error < 0) 808 if (error < 0)
769 goto out_tracer; 809 goto out_tracer;
770 810
771 spin_lock_irqsave(&ds_lock, irq); 811 /* Claim the pebs part of the tracing context we acquired above. */
812 spin_lock_irq(&ds_lock);
772 813
773 error = -EPERM; 814 error = -EPERM;
774 if (tracer->ds.context->pebs_master) 815 if (tracer->ds.context->pebs_master)
775 goto out_unlock; 816 goto out_unlock;
776 tracer->ds.context->pebs_master = tracer; 817 tracer->ds.context->pebs_master = tracer;
777 818
778 spin_unlock_irqrestore(&ds_lock, irq); 819 spin_unlock_irq(&ds_lock);
779 820
821 /*
822 * Now that we own the pebs part of the context, let's complete the
823 * initialization for that part.
824 */
825 ds_init_ds_trace(&tracer->trace.ds, ds_pebs, base, size, th, flags);
780 ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_pebs); 826 ds_write_config(tracer->ds.context, &tracer->trace.ds, ds_pebs);
827 ds_install_ds_area(tracer->ds.context);
828
829 /* Start tracing. */
781 ds_resume_pebs(tracer); 830 ds_resume_pebs(tracer);
782 831
783 return tracer; 832 return tracer;
784 833
785 out_unlock: 834 out_unlock:
786 spin_unlock_irqrestore(&ds_lock, irq); 835 spin_unlock_irq(&ds_lock);
787 ds_put_context(tracer->ds.context); 836 ds_put_context(tracer->ds.context);
788 out_tracer: 837 out_tracer:
789 kfree(tracer); 838 kfree(tracer);
@@ -793,16 +842,26 @@ struct pebs_tracer *ds_request_pebs(struct task_struct *task,
793 return ERR_PTR(error); 842 return ERR_PTR(error);
794} 843}
795 844
796void ds_release_bts(struct bts_tracer *tracer) 845struct pebs_tracer *ds_request_pebs_task(struct task_struct *task,
846 void *base, size_t size,
847 pebs_ovfl_callback_t ovfl,
848 size_t th, unsigned int flags)
797{ 849{
798 struct task_struct *task; 850 return ds_request_pebs(task, 0, base, size, ovfl, th, flags);
851}
799 852
800 if (!tracer) 853struct pebs_tracer *ds_request_pebs_cpu(int cpu, void *base, size_t size,
801 return; 854 pebs_ovfl_callback_t ovfl,
855 size_t th, unsigned int flags)
856{
857 return ds_request_pebs(NULL, cpu, base, size, ovfl, th, flags);
858}
802 859
803 task = tracer->ds.context->task; 860static void ds_free_bts(struct bts_tracer *tracer)
861{
862 struct task_struct *task;
804 863
805 ds_suspend_bts(tracer); 864 task = tracer->ds.context->task;
806 865
807 WARN_ON_ONCE(tracer->ds.context->bts_master != tracer); 866 WARN_ON_ONCE(tracer->ds.context->bts_master != tracer);
808 tracer->ds.context->bts_master = NULL; 867 tracer->ds.context->bts_master = NULL;
@@ -817,9 +876,69 @@ void ds_release_bts(struct bts_tracer *tracer)
817 kfree(tracer); 876 kfree(tracer);
818} 877}
819 878
879void ds_release_bts(struct bts_tracer *tracer)
880{
881 might_sleep();
882
883 if (!tracer)
884 return;
885
886 ds_suspend_bts(tracer);
887 ds_free_bts(tracer);
888}
889
890int ds_release_bts_noirq(struct bts_tracer *tracer)
891{
892 struct task_struct *task;
893 unsigned long irq;
894 int error;
895
896 if (!tracer)
897 return 0;
898
899 task = tracer->ds.context->task;
900
901 local_irq_save(irq);
902
903 error = -EPERM;
904 if (!task &&
905 (tracer->ds.context->cpu != smp_processor_id()))
906 goto out;
907
908 error = -EPERM;
909 if (task && (task != current))
910 goto out;
911
912 ds_suspend_bts_noirq(tracer);
913 ds_free_bts(tracer);
914
915 error = 0;
916 out:
917 local_irq_restore(irq);
918 return error;
919}
920
921static void update_task_debugctlmsr(struct task_struct *task,
922 unsigned long debugctlmsr)
923{
924 task->thread.debugctlmsr = debugctlmsr;
925
926 get_cpu();
927 if (task == current)
928 update_debugctlmsr(debugctlmsr);
929
930 if (task->thread.debugctlmsr)
931 set_tsk_thread_flag(task, TIF_DEBUGCTLMSR);
932 else
933 clear_tsk_thread_flag(task, TIF_DEBUGCTLMSR);
934 put_cpu();
935}
936
820void ds_suspend_bts(struct bts_tracer *tracer) 937void ds_suspend_bts(struct bts_tracer *tracer)
821{ 938{
822 struct task_struct *task; 939 struct task_struct *task;
940 unsigned long debugctlmsr;
941 int cpu;
823 942
824 if (!tracer) 943 if (!tracer)
825 return; 944 return;
@@ -827,29 +946,60 @@ void ds_suspend_bts(struct bts_tracer *tracer)
827 tracer->flags = 0; 946 tracer->flags = 0;
828 947
829 task = tracer->ds.context->task; 948 task = tracer->ds.context->task;
949 cpu = tracer->ds.context->cpu;
830 950
831 if (!task || (task == current)) 951 WARN_ON(!task && irqs_disabled());
832 update_debugctlmsr(get_debugctlmsr() & ~BTS_CONTROL);
833 952
834 if (task) { 953 debugctlmsr = (task ?
835 task->thread.debugctlmsr &= ~BTS_CONTROL; 954 task->thread.debugctlmsr :
955 get_debugctlmsr_on_cpu(cpu));
956 debugctlmsr &= ~BTS_CONTROL;
836 957
837 if (!task->thread.debugctlmsr) 958 if (task)
838 clear_tsk_thread_flag(task, TIF_DEBUGCTLMSR); 959 update_task_debugctlmsr(task, debugctlmsr);
839 } 960 else
961 update_debugctlmsr_on_cpu(cpu, debugctlmsr);
840} 962}
841 963
842void ds_resume_bts(struct bts_tracer *tracer) 964int ds_suspend_bts_noirq(struct bts_tracer *tracer)
843{ 965{
844 struct task_struct *task; 966 struct task_struct *task;
845 unsigned long control; 967 unsigned long debugctlmsr, irq;
968 int cpu, error = 0;
846 969
847 if (!tracer) 970 if (!tracer)
848 return; 971 return 0;
849 972
850 tracer->flags = tracer->trace.ds.flags; 973 tracer->flags = 0;
851 974
852 task = tracer->ds.context->task; 975 task = tracer->ds.context->task;
976 cpu = tracer->ds.context->cpu;
977
978 local_irq_save(irq);
979
980 error = -EPERM;
981 if (!task && (cpu != smp_processor_id()))
982 goto out;
983
984 debugctlmsr = (task ?
985 task->thread.debugctlmsr :
986 get_debugctlmsr());
987 debugctlmsr &= ~BTS_CONTROL;
988
989 if (task)
990 update_task_debugctlmsr(task, debugctlmsr);
991 else
992 update_debugctlmsr(debugctlmsr);
993
994 error = 0;
995 out:
996 local_irq_restore(irq);
997 return error;
998}
999
1000static unsigned long ds_bts_control(struct bts_tracer *tracer)
1001{
1002 unsigned long control;
853 1003
854 control = ds_cfg.ctl[dsf_bts]; 1004 control = ds_cfg.ctl[dsf_bts];
855 if (!(tracer->trace.ds.flags & BTS_KERNEL)) 1005 if (!(tracer->trace.ds.flags & BTS_KERNEL))
@@ -857,25 +1007,77 @@ void ds_resume_bts(struct bts_tracer *tracer)
857 if (!(tracer->trace.ds.flags & BTS_USER)) 1007 if (!(tracer->trace.ds.flags & BTS_USER))
858 control |= ds_cfg.ctl[dsf_bts_user]; 1008 control |= ds_cfg.ctl[dsf_bts_user];
859 1009
860 if (task) { 1010 return control;
861 task->thread.debugctlmsr |= control;
862 set_tsk_thread_flag(task, TIF_DEBUGCTLMSR);
863 }
864
865 if (!task || (task == current))
866 update_debugctlmsr(get_debugctlmsr() | control);
867} 1011}
868 1012
869void ds_release_pebs(struct pebs_tracer *tracer) 1013void ds_resume_bts(struct bts_tracer *tracer)
870{ 1014{
871 struct task_struct *task; 1015 struct task_struct *task;
1016 unsigned long debugctlmsr;
1017 int cpu;
872 1018
873 if (!tracer) 1019 if (!tracer)
874 return; 1020 return;
875 1021
1022 tracer->flags = tracer->trace.ds.flags;
1023
876 task = tracer->ds.context->task; 1024 task = tracer->ds.context->task;
1025 cpu = tracer->ds.context->cpu;
877 1026
878 ds_suspend_pebs(tracer); 1027 WARN_ON(!task && irqs_disabled());
1028
1029 debugctlmsr = (task ?
1030 task->thread.debugctlmsr :
1031 get_debugctlmsr_on_cpu(cpu));
1032 debugctlmsr |= ds_bts_control(tracer);
1033
1034 if (task)
1035 update_task_debugctlmsr(task, debugctlmsr);
1036 else
1037 update_debugctlmsr_on_cpu(cpu, debugctlmsr);
1038}
1039
1040int ds_resume_bts_noirq(struct bts_tracer *tracer)
1041{
1042 struct task_struct *task;
1043 unsigned long debugctlmsr, irq;
1044 int cpu, error = 0;
1045
1046 if (!tracer)
1047 return 0;
1048
1049 tracer->flags = tracer->trace.ds.flags;
1050
1051 task = tracer->ds.context->task;
1052 cpu = tracer->ds.context->cpu;
1053
1054 local_irq_save(irq);
1055
1056 error = -EPERM;
1057 if (!task && (cpu != smp_processor_id()))
1058 goto out;
1059
1060 debugctlmsr = (task ?
1061 task->thread.debugctlmsr :
1062 get_debugctlmsr());
1063 debugctlmsr |= ds_bts_control(tracer);
1064
1065 if (task)
1066 update_task_debugctlmsr(task, debugctlmsr);
1067 else
1068 update_debugctlmsr(debugctlmsr);
1069
1070 error = 0;
1071 out:
1072 local_irq_restore(irq);
1073 return error;
1074}
1075
1076static void ds_free_pebs(struct pebs_tracer *tracer)
1077{
1078 struct task_struct *task;
1079
1080 task = tracer->ds.context->task;
879 1081
880 WARN_ON_ONCE(tracer->ds.context->pebs_master != tracer); 1082 WARN_ON_ONCE(tracer->ds.context->pebs_master != tracer);
881 tracer->ds.context->pebs_master = NULL; 1083 tracer->ds.context->pebs_master = NULL;
@@ -886,16 +1088,68 @@ void ds_release_pebs(struct pebs_tracer *tracer)
886 kfree(tracer); 1088 kfree(tracer);
887} 1089}
888 1090
1091void ds_release_pebs(struct pebs_tracer *tracer)
1092{
1093 might_sleep();
1094
1095 if (!tracer)
1096 return;
1097
1098 ds_suspend_pebs(tracer);
1099 ds_free_pebs(tracer);
1100}
1101
1102int ds_release_pebs_noirq(struct pebs_tracer *tracer)
1103{
1104 struct task_struct *task;
1105 unsigned long irq;
1106 int error;
1107
1108 if (!tracer)
1109 return 0;
1110
1111 task = tracer->ds.context->task;
1112
1113 local_irq_save(irq);
1114
1115 error = -EPERM;
1116 if (!task &&
1117 (tracer->ds.context->cpu != smp_processor_id()))
1118 goto out;
1119
1120 error = -EPERM;
1121 if (task && (task != current))
1122 goto out;
1123
1124 ds_suspend_pebs_noirq(tracer);
1125 ds_free_pebs(tracer);
1126
1127 error = 0;
1128 out:
1129 local_irq_restore(irq);
1130 return error;
1131}
1132
889void ds_suspend_pebs(struct pebs_tracer *tracer) 1133void ds_suspend_pebs(struct pebs_tracer *tracer)
890{ 1134{
891 1135
892} 1136}
893 1137
1138int ds_suspend_pebs_noirq(struct pebs_tracer *tracer)
1139{
1140 return 0;
1141}
1142
894void ds_resume_pebs(struct pebs_tracer *tracer) 1143void ds_resume_pebs(struct pebs_tracer *tracer)
895{ 1144{
896 1145
897} 1146}
898 1147
1148int ds_resume_pebs_noirq(struct pebs_tracer *tracer)
1149{
1150 return 0;
1151}
1152
899const struct bts_trace *ds_read_bts(struct bts_tracer *tracer) 1153const struct bts_trace *ds_read_bts(struct bts_tracer *tracer)
900{ 1154{
901 if (!tracer) 1155 if (!tracer)
@@ -1004,26 +1258,6 @@ ds_configure(const struct ds_configuration *cfg,
1004 printk(KERN_INFO "[ds] pebs not available\n"); 1258 printk(KERN_INFO "[ds] pebs not available\n");
1005 } 1259 }
1006 1260
1007 if (ds_cfg.sizeof_rec[ds_bts]) {
1008 int error;
1009
1010 error = ds_selftest_bts();
1011 if (error) {
1012 WARN(1, "[ds] selftest failed. disabling bts.\n");
1013 ds_cfg.sizeof_rec[ds_bts] = 0;
1014 }
1015 }
1016
1017 if (ds_cfg.sizeof_rec[ds_pebs]) {
1018 int error;
1019
1020 error = ds_selftest_pebs();
1021 if (error) {
1022 WARN(1, "[ds] selftest failed. disabling pebs.\n");
1023 ds_cfg.sizeof_rec[ds_pebs] = 0;
1024 }
1025 }
1026
1027 printk(KERN_INFO "[ds] sizes: address: %u bit, ", 1261 printk(KERN_INFO "[ds] sizes: address: %u bit, ",
1028 8 * ds_cfg.sizeof_ptr_field); 1262 8 * ds_cfg.sizeof_ptr_field);
1029 printk("bts/pebs record: %u/%u bytes\n", 1263 printk("bts/pebs record: %u/%u bytes\n",
@@ -1127,3 +1361,29 @@ void ds_copy_thread(struct task_struct *tsk, struct task_struct *father)
1127void ds_exit_thread(struct task_struct *tsk) 1361void ds_exit_thread(struct task_struct *tsk)
1128{ 1362{
1129} 1363}
1364
1365static __init int ds_selftest(void)
1366{
1367 if (ds_cfg.sizeof_rec[ds_bts]) {
1368 int error;
1369
1370 error = ds_selftest_bts();
1371 if (error) {
1372 WARN(1, "[ds] selftest failed. disabling bts.\n");
1373 ds_cfg.sizeof_rec[ds_bts] = 0;
1374 }
1375 }
1376
1377 if (ds_cfg.sizeof_rec[ds_pebs]) {
1378 int error;
1379
1380 error = ds_selftest_pebs();
1381 if (error) {
1382 WARN(1, "[ds] selftest failed. disabling pebs.\n");
1383 ds_cfg.sizeof_rec[ds_pebs] = 0;
1384 }
1385 }
1386
1387 return 0;
1388}
1389device_initcall(ds_selftest);
diff --git a/arch/x86/kernel/ds_selftest.c b/arch/x86/kernel/ds_selftest.c
index 8c46fbf38c46..e5a263c8a14c 100644
--- a/arch/x86/kernel/ds_selftest.c
+++ b/arch/x86/kernel/ds_selftest.c
@@ -10,11 +10,12 @@
10 10
11#include <linux/kernel.h> 11#include <linux/kernel.h>
12#include <linux/string.h> 12#include <linux/string.h>
13#include <linux/smp.h>
13 14
14#include <asm/ds.h> 15#include <asm/ds.h>
15 16
16 17
17#define DS_SELFTEST_BUFFER_SIZE 1021 /* Intentionally chose an odd size. */ 18#define BUFFER_SIZE 1021 /* Intentionally chose an odd size. */
18 19
19 20
20static int ds_selftest_bts_consistency(const struct bts_trace *trace) 21static int ds_selftest_bts_consistency(const struct bts_trace *trace)
@@ -125,12 +126,12 @@ int ds_selftest_bts(void)
125 struct bts_tracer *tracer; 126 struct bts_tracer *tracer;
126 int error = 0; 127 int error = 0;
127 void *top; 128 void *top;
128 unsigned char buffer[DS_SELFTEST_BUFFER_SIZE]; 129 unsigned char buffer[BUFFER_SIZE];
129 130
130 printk(KERN_INFO "[ds] bts selftest..."); 131 printk(KERN_INFO "[ds] bts selftest...");
131 132
132 tracer = ds_request_bts(NULL, buffer, DS_SELFTEST_BUFFER_SIZE, 133 tracer = ds_request_bts_cpu(smp_processor_id(), buffer, BUFFER_SIZE,
133 NULL, (size_t)-1, BTS_KERNEL); 134 NULL, (size_t)-1, BTS_KERNEL);
134 if (IS_ERR(tracer)) { 135 if (IS_ERR(tracer)) {
135 error = PTR_ERR(tracer); 136 error = PTR_ERR(tracer);
136 tracer = NULL; 137 tracer = NULL;
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 7c21d1e8cae7..adbb24322d8f 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -800,8 +800,9 @@ static int ptrace_bts_config(struct task_struct *child,
800 if (cfg.flags & PTRACE_BTS_O_SCHED) 800 if (cfg.flags & PTRACE_BTS_O_SCHED)
801 flags |= BTS_TIMESTAMPS; 801 flags |= BTS_TIMESTAMPS;
802 802
803 context->tracer = ds_request_bts(child, context->buffer, context->size, 803 context->tracer =
804 NULL, (size_t)-1, flags); 804 ds_request_bts_task(child, context->buffer, context->size,
805 NULL, (size_t)-1, flags);
805 if (unlikely(IS_ERR(context->tracer))) { 806 if (unlikely(IS_ERR(context->tracer))) {
806 int error = PTR_ERR(context->tracer); 807 int error = PTR_ERR(context->tracer);
807 808
diff --git a/kernel/trace/trace_hw_branches.c b/kernel/trace/trace_hw_branches.c
index 8b2109a6c61c..50565d8cd2ed 100644
--- a/kernel/trace/trace_hw_branches.c
+++ b/kernel/trace/trace_hw_branches.c
@@ -4,7 +4,6 @@
4 * Copyright (C) 2008-2009 Intel Corporation. 4 * Copyright (C) 2008-2009 Intel Corporation.
5 * Markus Metzger <markus.t.metzger@gmail.com>, 2008-2009 5 * Markus Metzger <markus.t.metzger@gmail.com>, 2008-2009
6 */ 6 */
7#include <linux/spinlock.h>
8#include <linux/kallsyms.h> 7#include <linux/kallsyms.h>
9#include <linux/debugfs.h> 8#include <linux/debugfs.h>
10#include <linux/ftrace.h> 9#include <linux/ftrace.h>
@@ -21,168 +20,113 @@
21 20
22#define BTS_BUFFER_SIZE (1 << 13) 21#define BTS_BUFFER_SIZE (1 << 13)
23 22
24/*
25 * The tracer lock protects the below per-cpu tracer array.
26 * It needs to be held to:
27 * - start tracing on all cpus
28 * - stop tracing on all cpus
29 * - start tracing on a single hotplug cpu
30 * - stop tracing on a single hotplug cpu
31 * - read the trace from all cpus
32 * - read the trace from a single cpu
33 */
34static DEFINE_SPINLOCK(bts_tracer_lock);
35static DEFINE_PER_CPU(struct bts_tracer *, tracer); 23static DEFINE_PER_CPU(struct bts_tracer *, tracer);
36static DEFINE_PER_CPU(unsigned char[BTS_BUFFER_SIZE], buffer); 24static DEFINE_PER_CPU(unsigned char[BTS_BUFFER_SIZE], buffer);
37 25
38#define this_tracer per_cpu(tracer, smp_processor_id()) 26#define this_tracer per_cpu(tracer, smp_processor_id())
39#define this_buffer per_cpu(buffer, smp_processor_id())
40 27
41static int trace_hw_branches_enabled __read_mostly; 28static int trace_hw_branches_enabled __read_mostly;
42static int trace_hw_branches_suspended __read_mostly; 29static int trace_hw_branches_suspended __read_mostly;
43static struct trace_array *hw_branch_trace __read_mostly; 30static struct trace_array *hw_branch_trace __read_mostly;
44 31
45 32
46/* 33static void bts_trace_init_cpu(int cpu)
47 * Initialize the tracer for the current cpu.
48 * The argument is ignored.
49 *
50 * pre: bts_tracer_lock must be locked.
51 */
52static void bts_trace_init_cpu(void *arg)
53{ 34{
54 if (this_tracer) 35 per_cpu(tracer, cpu) =
55 ds_release_bts(this_tracer); 36 ds_request_bts_cpu(cpu, per_cpu(buffer, cpu), BTS_BUFFER_SIZE,
37 NULL, (size_t)-1, BTS_KERNEL);
56 38
57 this_tracer = ds_request_bts(NULL, this_buffer, BTS_BUFFER_SIZE, 39 if (IS_ERR(per_cpu(tracer, cpu)))
58 NULL, (size_t)-1, BTS_KERNEL); 40 per_cpu(tracer, cpu) = NULL;
59 if (IS_ERR(this_tracer)) {
60 this_tracer = NULL;
61 return;
62 }
63} 41}
64 42
65static int bts_trace_init(struct trace_array *tr) 43static int bts_trace_init(struct trace_array *tr)
66{ 44{
67 int cpu, avail; 45 int cpu;
68
69 spin_lock(&bts_tracer_lock);
70 46
71 hw_branch_trace = tr; 47 hw_branch_trace = tr;
48 trace_hw_branches_enabled = 0;
72 49
73 on_each_cpu(bts_trace_init_cpu, NULL, 1); 50 get_online_cpus();
74 51 for_each_online_cpu(cpu) {
75 /* Check on how many cpus we could enable tracing */ 52 bts_trace_init_cpu(cpu);
76 avail = 0;
77 for_each_online_cpu(cpu)
78 if (per_cpu(tracer, cpu))
79 avail++;
80 53
81 trace_hw_branches_enabled = (avail ? 1 : 0); 54 if (likely(per_cpu(tracer, cpu)))
55 trace_hw_branches_enabled = 1;
56 }
82 trace_hw_branches_suspended = 0; 57 trace_hw_branches_suspended = 0;
83 58 put_online_cpus();
84 spin_unlock(&bts_tracer_lock);
85
86 59
87 /* If we could not enable tracing on a single cpu, we fail. */ 60 /* If we could not enable tracing on a single cpu, we fail. */
88 return avail ? 0 : -EOPNOTSUPP; 61 return trace_hw_branches_enabled ? 0 : -EOPNOTSUPP;
89}
90
91/*
92 * Release the tracer for the current cpu.
93 * The argument is ignored.
94 *
95 * pre: bts_tracer_lock must be locked.
96 */
97static void bts_trace_release_cpu(void *arg)
98{
99 if (this_tracer) {
100 ds_release_bts(this_tracer);
101 this_tracer = NULL;
102 }
103} 62}
104 63
105static void bts_trace_reset(struct trace_array *tr) 64static void bts_trace_reset(struct trace_array *tr)
106{ 65{
107 spin_lock(&bts_tracer_lock); 66 int cpu;
108 67
109 on_each_cpu(bts_trace_release_cpu, NULL, 1); 68 get_online_cpus();
69 for_each_online_cpu(cpu) {
70 if (likely(per_cpu(tracer, cpu))) {
71 ds_release_bts(per_cpu(tracer, cpu));
72 per_cpu(tracer, cpu) = NULL;
73 }
74 }
110 trace_hw_branches_enabled = 0; 75 trace_hw_branches_enabled = 0;
111 trace_hw_branches_suspended = 0; 76 trace_hw_branches_suspended = 0;
112 77 put_online_cpus();
113 spin_unlock(&bts_tracer_lock);
114}
115
116/*
117 * Resume tracing on the current cpu.
118 * The argument is ignored.
119 *
120 * pre: bts_tracer_lock must be locked.
121 */
122static void bts_trace_resume_cpu(void *arg)
123{
124 if (this_tracer)
125 ds_resume_bts(this_tracer);
126} 78}
127 79
128static void bts_trace_start(struct trace_array *tr) 80static void bts_trace_start(struct trace_array *tr)
129{ 81{
130 spin_lock(&bts_tracer_lock); 82 int cpu;
131 83
132 on_each_cpu(bts_trace_resume_cpu, NULL, 1); 84 get_online_cpus();
85 for_each_online_cpu(cpu)
86 if (likely(per_cpu(tracer, cpu)))
87 ds_resume_bts(per_cpu(tracer, cpu));
133 trace_hw_branches_suspended = 0; 88 trace_hw_branches_suspended = 0;
134 89 put_online_cpus();
135 spin_unlock(&bts_tracer_lock);
136}
137
138/*
139 * Suspend tracing on the current cpu.
140 * The argument is ignored.
141 *
142 * pre: bts_tracer_lock must be locked.
143 */
144static void bts_trace_suspend_cpu(void *arg)
145{
146 if (this_tracer)
147 ds_suspend_bts(this_tracer);
148} 90}
149 91
150static void bts_trace_stop(struct trace_array *tr) 92static void bts_trace_stop(struct trace_array *tr)
151{ 93{
152 spin_lock(&bts_tracer_lock); 94 int cpu;
153 95
154 on_each_cpu(bts_trace_suspend_cpu, NULL, 1); 96 get_online_cpus();
97 for_each_online_cpu(cpu)
98 if (likely(per_cpu(tracer, cpu)))
99 ds_suspend_bts(per_cpu(tracer, cpu));
155 trace_hw_branches_suspended = 1; 100 trace_hw_branches_suspended = 1;
156 101 put_online_cpus();
157 spin_unlock(&bts_tracer_lock);
158} 102}
159 103
160static int __cpuinit bts_hotcpu_handler(struct notifier_block *nfb, 104static int __cpuinit bts_hotcpu_handler(struct notifier_block *nfb,
161 unsigned long action, void *hcpu) 105 unsigned long action, void *hcpu)
162{ 106{
163 unsigned int cpu = (unsigned long)hcpu; 107 int cpu = (long)hcpu;
164
165 spin_lock(&bts_tracer_lock);
166
167 if (!trace_hw_branches_enabled)
168 goto out;
169 108
170 switch (action) { 109 switch (action) {
171 case CPU_ONLINE: 110 case CPU_ONLINE:
172 case CPU_DOWN_FAILED: 111 case CPU_DOWN_FAILED:
173 smp_call_function_single(cpu, bts_trace_init_cpu, NULL, 1); 112 /* The notification is sent with interrupts enabled. */
174 113 if (trace_hw_branches_enabled) {
175 if (trace_hw_branches_suspended) 114 bts_trace_init_cpu(cpu);
176 smp_call_function_single(cpu, bts_trace_suspend_cpu, 115
177 NULL, 1); 116 if (trace_hw_branches_suspended &&
117 likely(per_cpu(tracer, cpu)))
118 ds_suspend_bts(per_cpu(tracer, cpu));
119 }
178 break; 120 break;
121
179 case CPU_DOWN_PREPARE: 122 case CPU_DOWN_PREPARE:
180 smp_call_function_single(cpu, bts_trace_release_cpu, NULL, 1); 123 /* The notification is sent with interrupts enabled. */
181 break; 124 if (likely(per_cpu(tracer, cpu))) {
125 ds_release_bts(per_cpu(tracer, cpu));
126 per_cpu(tracer, cpu) = NULL;
127 }
182 } 128 }
183 129
184 out:
185 spin_unlock(&bts_tracer_lock);
186 return NOTIFY_DONE; 130 return NOTIFY_DONE;
187} 131}
188 132
@@ -274,7 +218,7 @@ static void trace_bts_at(const struct bts_trace *trace, void *at)
274/* 218/*
275 * Collect the trace on the current cpu and write it into the ftrace buffer. 219 * Collect the trace on the current cpu and write it into the ftrace buffer.
276 * 220 *
277 * pre: bts_tracer_lock must be locked 221 * pre: tracing must be suspended on the current cpu
278 */ 222 */
279static void trace_bts_cpu(void *arg) 223static void trace_bts_cpu(void *arg)
280{ 224{
@@ -291,10 +235,9 @@ static void trace_bts_cpu(void *arg)
291 if (unlikely(!this_tracer)) 235 if (unlikely(!this_tracer))
292 return; 236 return;
293 237
294 ds_suspend_bts(this_tracer);
295 trace = ds_read_bts(this_tracer); 238 trace = ds_read_bts(this_tracer);
296 if (!trace) 239 if (!trace)
297 goto out; 240 return;
298 241
299 for (at = trace->ds.top; (void *)at < trace->ds.end; 242 for (at = trace->ds.top; (void *)at < trace->ds.end;
300 at += trace->ds.size) 243 at += trace->ds.size)
@@ -303,18 +246,27 @@ static void trace_bts_cpu(void *arg)
303 for (at = trace->ds.begin; (void *)at < trace->ds.top; 246 for (at = trace->ds.begin; (void *)at < trace->ds.top;
304 at += trace->ds.size) 247 at += trace->ds.size)
305 trace_bts_at(trace, at); 248 trace_bts_at(trace, at);
306
307out:
308 ds_resume_bts(this_tracer);
309} 249}
310 250
311static void trace_bts_prepare(struct trace_iterator *iter) 251static void trace_bts_prepare(struct trace_iterator *iter)
312{ 252{
313 spin_lock(&bts_tracer_lock); 253 int cpu;
314 254
255 get_online_cpus();
256 for_each_online_cpu(cpu)
257 if (likely(per_cpu(tracer, cpu)))
258 ds_suspend_bts(per_cpu(tracer, cpu));
259 /*
260 * We need to collect the trace on the respective cpu since ftrace
261 * implicitly adds the record for the current cpu.
262 * Once that is more flexible, we could collect the data from any cpu.
263 */
315 on_each_cpu(trace_bts_cpu, iter->tr, 1); 264 on_each_cpu(trace_bts_cpu, iter->tr, 1);
316 265
317 spin_unlock(&bts_tracer_lock); 266 for_each_online_cpu(cpu)
267 if (likely(per_cpu(tracer, cpu)))
268 ds_resume_bts(per_cpu(tracer, cpu));
269 put_online_cpus();
318} 270}
319 271
320static void trace_bts_close(struct trace_iterator *iter) 272static void trace_bts_close(struct trace_iterator *iter)
@@ -324,12 +276,11 @@ static void trace_bts_close(struct trace_iterator *iter)
324 276
325void trace_hw_branch_oops(void) 277void trace_hw_branch_oops(void)
326{ 278{
327 spin_lock(&bts_tracer_lock); 279 if (this_tracer) {
328 280 ds_suspend_bts_noirq(this_tracer);
329 if (trace_hw_branches_enabled)
330 trace_bts_cpu(hw_branch_trace); 281 trace_bts_cpu(hw_branch_trace);
331 282 ds_resume_bts_noirq(this_tracer);
332 spin_unlock(&bts_tracer_lock); 283 }
333} 284}
334 285
335struct tracer bts_tracer __read_mostly = 286struct tracer bts_tracer __read_mostly =