aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/ds.c
diff options
context:
space:
mode:
authorMarkus Metzger <markus.t.metzger@intel.com>2009-04-03 10:43:36 -0400
committerIngo Molnar <mingo@elte.hu>2009-04-07 07:36:15 -0400
commit8d99b3ac2726e5edd97ad147fa5c1f2acb63a745 (patch)
tree764aa40840c18187ca11a7b0baf3e24edcc40ec9 /arch/x86/kernel/ds.c
parente2b371f00a6f529f6362654239bdec8dcd510760 (diff)
x86, bts: wait until traced task has been scheduled out
In order to stop branch tracing for a running task, we need to first clear the branch tracing control bits before we may free the tracing buffer. If the traced task is running, the cpu might still trace that task after the branch trace control bits have cleared. Wait until the traced task has been scheduled out before proceeding. A similar problem affects the task debug store context. We first remove the context, then we need to wait until the task has been scheduled out before we can free the context memory. Reviewed-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Markus Metzger <markus.t.metzger@intel.com> Cc: roland@redhat.com Cc: eranian@googlemail.com Cc: juan.villacis@intel.com Cc: ak@linux.jf.intel.com LKML-Reference: <20090403144551.919636000@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/ds.c')
-rw-r--r--arch/x86/kernel/ds.c23
1 files changed, 19 insertions, 4 deletions
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c
index c730155bf54d..5cd137ab2672 100644
--- a/arch/x86/kernel/ds.c
+++ b/arch/x86/kernel/ds.c
@@ -299,6 +299,7 @@ static inline struct ds_context *ds_get_context(struct task_struct *task)
299 299
300static inline void ds_put_context(struct ds_context *context) 300static inline void ds_put_context(struct ds_context *context)
301{ 301{
302 struct task_struct *task;
302 unsigned long irq; 303 unsigned long irq;
303 304
304 if (!context) 305 if (!context)
@@ -313,14 +314,20 @@ static inline void ds_put_context(struct ds_context *context)
313 314
314 *(context->this) = NULL; 315 *(context->this) = NULL;
315 316
316 if (context->task) 317 task = context->task;
317 clear_tsk_thread_flag(context->task, TIF_DS_AREA_MSR); 318
319 if (task)
320 clear_tsk_thread_flag(task, TIF_DS_AREA_MSR);
318 321
319 if (!context->task || (context->task == current)) 322 if (!task || (task == current))
320 wrmsrl(MSR_IA32_DS_AREA, 0); 323 wrmsrl(MSR_IA32_DS_AREA, 0);
321 324
322 spin_unlock_irqrestore(&ds_lock, irq); 325 spin_unlock_irqrestore(&ds_lock, irq);
323 326
327 /* The context might still be in use for context switching. */
328 if (task && (task != current))
329 wait_task_context_switch(task);
330
324 kfree(context); 331 kfree(context);
325} 332}
326 333
@@ -781,15 +788,23 @@ struct pebs_tracer *ds_request_pebs(struct task_struct *task,
781 788
782void ds_release_bts(struct bts_tracer *tracer) 789void ds_release_bts(struct bts_tracer *tracer)
783{ 790{
791 struct task_struct *task;
792
784 if (!tracer) 793 if (!tracer)
785 return; 794 return;
786 795
796 task = tracer->ds.context->task;
797
787 ds_suspend_bts(tracer); 798 ds_suspend_bts(tracer);
788 799
789 WARN_ON_ONCE(tracer->ds.context->bts_master != tracer); 800 WARN_ON_ONCE(tracer->ds.context->bts_master != tracer);
790 tracer->ds.context->bts_master = NULL; 801 tracer->ds.context->bts_master = NULL;
791 802
792 put_tracer(tracer->ds.context->task); 803 /* Make sure tracing stopped and the tracer is not in use. */
804 if (task && (task != current))
805 wait_task_context_switch(task);
806
807 put_tracer(task);
793 ds_put_context(tracer->ds.context); 808 ds_put_context(tracer->ds.context);
794 809
795 kfree(tracer); 810 kfree(tracer);