diff options
| author | Markus Metzger <markus.t.metzger@intel.com> | 2009-04-03 10:43:40 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-04-07 07:36:20 -0400 |
| commit | de79f54f5347ad7ec6ff55ccbb6d4ab2a21f6a93 (patch) | |
| tree | dfd3f000600b942a545cbc8acd2f2e67f4518015 /arch | |
| parent | 35bb7600c17762bb129588c1877d2717fe325289 (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.h | 57 | ||||
| -rw-r--r-- | arch/x86/kernel/ds.c | 474 | ||||
| -rw-r--r-- | arch/x86/kernel/ds_selftest.c | 9 | ||||
| -rw-r--r-- | arch/x86/kernel/ptrace.c | 5 |
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 | */ |
| 96 | extern struct bts_tracer *ds_request_bts(struct task_struct *task, | 98 | extern 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); |
| 100 | extern struct pebs_tracer *ds_request_pebs(struct task_struct *task, | 102 | extern 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); | 105 | extern 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); | ||
| 109 | extern 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 | */ |
| 111 | extern void ds_release_bts(struct bts_tracer *tracer); | 122 | extern void ds_release_bts(struct bts_tracer *tracer); |
| @@ -115,6 +126,28 @@ extern void ds_release_pebs(struct pebs_tracer *tracer); | |||
| 115 | extern void ds_suspend_pebs(struct pebs_tracer *tracer); | 126 | extern void ds_suspend_pebs(struct pebs_tracer *tracer); |
| 116 | extern void ds_resume_pebs(struct pebs_tracer *tracer); | 127 | extern 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 | */ | ||
| 144 | extern int ds_release_bts_noirq(struct bts_tracer *tracer); | ||
| 145 | extern int ds_suspend_bts_noirq(struct bts_tracer *tracer); | ||
| 146 | extern int ds_resume_bts_noirq(struct bts_tracer *tracer); | ||
| 147 | extern int ds_release_pebs_noirq(struct pebs_tracer *tracer); | ||
| 148 | extern int ds_suspend_pebs_noirq(struct pebs_tracer *tracer); | ||
| 149 | extern 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 | ||
| 257 | static 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()) | 260 | static DEFINE_PER_CPU(struct ds_context *, cpu_context); |
| 260 | 261 | ||
| 261 | 262 | ||
| 262 | static inline struct ds_context *ds_get_context(struct task_struct *task) | 263 | static 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 | ||
| 309 | static inline void ds_put_context(struct ds_context *context) | 299 | static 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 | ||
| 340 | static 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 | ||
| 631 | static int ds_request(struct ds_tracer *tracer, struct ds_trace *trace, | 654 | static 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 | ||
| 675 | struct bts_tracer *ds_request_bts(struct task_struct *task, | 701 | static 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 | ||
| 738 | struct pebs_tracer *ds_request_pebs(struct task_struct *task, | 767 | struct 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 | |||
| 775 | struct 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 | |||
| 782 | static 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 | ||
| 796 | void ds_release_bts(struct bts_tracer *tracer) | 845 | struct 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) | 853 | struct 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; | 860 | static 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 | ||
| 879 | void 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 | |||
| 890 | int 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 | |||
| 921 | static 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 | |||
| 820 | void ds_suspend_bts(struct bts_tracer *tracer) | 937 | void 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 | ||
| 842 | void ds_resume_bts(struct bts_tracer *tracer) | 964 | int 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 | |||
| 1000 | static 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 | ||
| 869 | void ds_release_pebs(struct pebs_tracer *tracer) | 1013 | void 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 | |||
| 1040 | int 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 | |||
| 1076 | static 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 | ||
| 1091 | void 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 | |||
| 1102 | int 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 | |||
| 889 | void ds_suspend_pebs(struct pebs_tracer *tracer) | 1133 | void ds_suspend_pebs(struct pebs_tracer *tracer) |
| 890 | { | 1134 | { |
| 891 | 1135 | ||
| 892 | } | 1136 | } |
| 893 | 1137 | ||
| 1138 | int ds_suspend_pebs_noirq(struct pebs_tracer *tracer) | ||
| 1139 | { | ||
| 1140 | return 0; | ||
| 1141 | } | ||
| 1142 | |||
| 894 | void ds_resume_pebs(struct pebs_tracer *tracer) | 1143 | void ds_resume_pebs(struct pebs_tracer *tracer) |
| 895 | { | 1144 | { |
| 896 | 1145 | ||
| 897 | } | 1146 | } |
| 898 | 1147 | ||
| 1148 | int ds_resume_pebs_noirq(struct pebs_tracer *tracer) | ||
| 1149 | { | ||
| 1150 | return 0; | ||
| 1151 | } | ||
| 1152 | |||
| 899 | const struct bts_trace *ds_read_bts(struct bts_tracer *tracer) | 1153 | const 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) | |||
| 1127 | void ds_exit_thread(struct task_struct *tsk) | 1361 | void ds_exit_thread(struct task_struct *tsk) |
| 1128 | { | 1362 | { |
| 1129 | } | 1363 | } |
| 1364 | |||
| 1365 | static __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 | } | ||
| 1389 | device_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 | ||
| 20 | static int ds_selftest_bts_consistency(const struct bts_trace *trace) | 21 | static 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 | ||
