aboutsummaryrefslogtreecommitdiffstats
path: root/arch
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 /arch
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>
Diffstat (limited to 'arch')
-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
4 files changed, 420 insertions, 125 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