aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/include/asm/ds.h12
-rw-r--r--arch/x86/kernel/ds.c92
-rw-r--r--arch/x86/kernel/ptrace.c22
3 files changed, 38 insertions, 88 deletions
diff --git a/arch/x86/include/asm/ds.h b/arch/x86/include/asm/ds.h
index 0af997de5f01..99b6c39774a4 100644
--- a/arch/x86/include/asm/ds.h
+++ b/arch/x86/include/asm/ds.h
@@ -7,13 +7,12 @@
7 * 7 *
8 * It manages: 8 * It manages:
9 * - per-thread and per-cpu allocation of BTS and PEBS 9 * - per-thread and per-cpu allocation of BTS and PEBS
10 * - buffer memory allocation (optional) 10 * - buffer overflow handling (to be done)
11 * - buffer overflow handling
12 * - buffer access 11 * - buffer access
13 * 12 *
14 * It assumes: 13 * It assumes:
15 * - get_task_struct on all parameter tasks 14 * - get_task_struct on all traced tasks
16 * - current is allowed to trace parameter tasks 15 * - current is allowed to trace tasks
17 * 16 *
18 * 17 *
19 * Copyright (C) 2007-2008 Intel Corporation. 18 * Copyright (C) 2007-2008 Intel Corporation.
@@ -54,8 +53,7 @@ typedef void (*pebs_ovfl_callback_t)(struct pebs_tracer *);
54 * task: the task to request recording for; 53 * task: the task to request recording for;
55 * NULL for per-cpu recording on the current cpu 54 * NULL for per-cpu recording on the current cpu
56 * base: the base pointer for the (non-pageable) buffer; 55 * base: the base pointer for the (non-pageable) buffer;
57 * NULL if buffer allocation requested 56 * size: the size of the provided buffer in bytes
58 * size: the size of the requested or provided buffer in bytes
59 * ovfl: pointer to a function to be called on buffer overflow; 57 * ovfl: pointer to a function to be called on buffer overflow;
60 * NULL if cyclic buffer requested 58 * NULL if cyclic buffer requested
61 * th: the interrupt threshold in records from the end of the buffer; 59 * th: the interrupt threshold in records from the end of the buffer;
@@ -72,8 +70,6 @@ extern struct pebs_tracer *ds_request_pebs(struct task_struct *task,
72/* 70/*
73 * Release BTS or PEBS resources 71 * Release BTS or PEBS resources
74 * 72 *
75 * Frees buffers allocated on ds_request.
76 *
77 * Returns 0 on success; -Eerrno otherwise 73 * Returns 0 on success; -Eerrno otherwise
78 * 74 *
79 * tracer: the tracer handle returned from ds_request_~() 75 * tracer: the tracer handle returned from ds_request_~()
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c
index 96768e9cce99..19a8c2c0389f 100644
--- a/arch/x86/kernel/ds.c
+++ b/arch/x86/kernel/ds.c
@@ -7,13 +7,12 @@
7 * 7 *
8 * It manages: 8 * It manages:
9 * - per-thread and per-cpu allocation of BTS and PEBS 9 * - per-thread and per-cpu allocation of BTS and PEBS
10 * - buffer memory allocation (optional) 10 * - buffer overflow handling (to be done)
11 * - buffer overflow handling
12 * - buffer access 11 * - buffer access
13 * 12 *
14 * It assumes: 13 * It assumes:
15 * - get_task_struct on all parameter tasks 14 * - get_task_struct on all traced tasks
16 * - current is allowed to trace parameter tasks 15 * - current is allowed to trace tasks
17 * 16 *
18 * 17 *
19 * Copyright (C) 2007-2008 Intel Corporation. 18 * Copyright (C) 2007-2008 Intel Corporation.
@@ -57,8 +56,6 @@ struct ds_tracer {
57 /* the buffer provided on ds_request() and its size in bytes */ 56 /* the buffer provided on ds_request() and its size in bytes */
58 void *buffer; 57 void *buffer;
59 size_t size; 58 size_t size;
60 /* the number of allocated pages for on-request allocated buffers */
61 unsigned int pages;
62}; 59};
63 60
64struct bts_tracer { 61struct bts_tracer {
@@ -141,8 +138,7 @@ static inline void ds_set(unsigned char *base, enum ds_qualifier qual,
141 138
142 139
143/* 140/*
144 * Locking is done only for allocating BTS or PEBS resources and for 141 * Locking is done only for allocating BTS or PEBS resources.
145 * guarding context and buffer memory allocation.
146 */ 142 */
147static spinlock_t ds_lock = __SPIN_LOCK_UNLOCKED(ds_lock); 143static spinlock_t ds_lock = __SPIN_LOCK_UNLOCKED(ds_lock);
148 144
@@ -292,50 +288,6 @@ static void ds_overflow(struct ds_context *context, enum ds_qualifier qual)
292} 288}
293 289
294 290
295/*
296 * Allocate a non-pageable buffer of the parameter size.
297 * Checks the memory and the locked memory rlimit.
298 *
299 * Returns the buffer, if successful;
300 * NULL, if out of memory or rlimit exceeded.
301 *
302 * size: the requested buffer size in bytes
303 * pages (out): if not NULL, contains the number of pages reserved
304 */
305static inline void *ds_allocate_buffer(size_t size, unsigned int *pages)
306{
307 unsigned long rlim, vm, pgsz;
308 void *buffer = NULL;
309
310 pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT;
311
312 down_write(&current->mm->mmap_sem);
313
314 rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
315 vm = current->mm->total_vm + pgsz;
316 if (rlim < vm)
317 goto out;
318
319 rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
320 vm = current->mm->locked_vm + pgsz;
321 if (rlim < vm)
322 goto out;
323
324 buffer = kzalloc(size, GFP_KERNEL);
325 if (!buffer)
326 goto out;
327
328 current->mm->total_vm += pgsz;
329 current->mm->locked_vm += pgsz;
330
331 if (pages)
332 *pages = pgsz;
333
334 out:
335 up_write(&current->mm->mmap_sem);
336 return buffer;
337}
338
339static void ds_install_ds_config(struct ds_context *context, 291static void ds_install_ds_config(struct ds_context *context,
340 enum ds_qualifier qual, 292 enum ds_qualifier qual,
341 void *base, size_t size, size_t ith) 293 void *base, size_t size, size_t ith)
@@ -382,6 +334,10 @@ static int ds_request(struct ds_tracer *tracer, enum ds_qualifier qual,
382 if (!ds_cfg.sizeof_ds) 334 if (!ds_cfg.sizeof_ds)
383 goto out; 335 goto out;
384 336
337 error = -EINVAL;
338 if (!base)
339 goto out;
340
385 /* we require some space to do alignment adjustments below */ 341 /* we require some space to do alignment adjustments below */
386 error = -EINVAL; 342 error = -EINVAL;
387 if (size < (DS_ALIGNMENT + ds_cfg.sizeof_rec[qual])) 343 if (size < (DS_ALIGNMENT + ds_cfg.sizeof_rec[qual]))
@@ -395,13 +351,6 @@ static int ds_request(struct ds_tracer *tracer, enum ds_qualifier qual,
395 goto out; 351 goto out;
396 } 352 }
397 353
398 error = -ENOMEM;
399 if (!base) {
400 base = ds_allocate_buffer(size, &tracer->pages);
401 if (!base)
402 goto out;
403 }
404
405 tracer->buffer = base; 354 tracer->buffer = base;
406 tracer->size = size; 355 tracer->size = size;
407 356
@@ -466,7 +415,7 @@ struct bts_tracer *ds_request_bts(struct task_struct *task,
466 return tracer; 415 return tracer;
467 416
468 out_tracer: 417 out_tracer:
469 (void)ds_release_bts(tracer); 418 kfree(tracer);
470 out: 419 out:
471 return ERR_PTR(error); 420 return ERR_PTR(error);
472} 421}
@@ -496,31 +445,18 @@ struct pebs_tracer *ds_request_pebs(struct task_struct *task,
496 return tracer; 445 return tracer;
497 446
498 out_tracer: 447 out_tracer:
499 (void)ds_release_pebs(tracer); 448 kfree(tracer);
500 out: 449 out:
501 return ERR_PTR(error); 450 return ERR_PTR(error);
502} 451}
503 452
504static void ds_release(struct ds_tracer *tracer, enum ds_qualifier qual) 453static void ds_release(struct ds_tracer *tracer, enum ds_qualifier qual)
505{ 454{
506 if (tracer->context) { 455 BUG_ON(tracer->context->owner[qual] != tracer);
507 BUG_ON(tracer->context->owner[qual] != tracer); 456 tracer->context->owner[qual] = NULL;
508 tracer->context->owner[qual] = NULL;
509
510 put_tracer(tracer->context->task);
511 ds_put_context(tracer->context);
512 }
513 457
514 if (tracer->pages) { 458 put_tracer(tracer->context->task);
515 kfree(tracer->buffer); 459 ds_put_context(tracer->context);
516
517 down_write(&current->mm->mmap_sem);
518
519 current->mm->total_vm -= tracer->pages;
520 current->mm->locked_vm -= tracer->pages;
521
522 up_write(&current->mm->mmap_sem);
523 }
524} 460}
525 461
526int ds_release_bts(struct bts_tracer *tracer) 462int ds_release_bts(struct bts_tracer *tracer)
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 76adf5b640ff..2c8ec1ba75e6 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -758,6 +758,10 @@ static int ptrace_bts_config(struct task_struct *child,
758 bts_ovfl_callback_t ovfl = NULL; 758 bts_ovfl_callback_t ovfl = NULL;
759 unsigned int sig = 0; 759 unsigned int sig = 0;
760 760
761 error = -EINVAL;
762 if (cfg.size < (10 * bts_cfg.sizeof_bts))
763 goto errout;
764
761 if (cfg.flags & PTRACE_BTS_O_SIGNAL) { 765 if (cfg.flags & PTRACE_BTS_O_SIGNAL) {
762 if (!cfg.signal) 766 if (!cfg.signal)
763 goto errout; 767 goto errout;
@@ -768,14 +772,26 @@ static int ptrace_bts_config(struct task_struct *child,
768 sig = cfg.signal; 772 sig = cfg.signal;
769 } 773 }
770 774
771 if (child->bts) 775 if (child->bts) {
772 (void)ds_release_bts(child->bts); 776 (void)ds_release_bts(child->bts);
777 kfree(child->bts_buffer);
778
779 child->bts = NULL;
780 child->bts_buffer = NULL;
781 }
782
783 error = -ENOMEM;
784 child->bts_buffer = kzalloc(cfg.size, GFP_KERNEL);
785 if (!child->bts_buffer)
786 goto errout;
773 787
774 child->bts = ds_request_bts(child, /* base = */ NULL, cfg.size, 788 child->bts = ds_request_bts(child, child->bts_buffer, cfg.size,
775 ovfl, /* th = */ (size_t)-1); 789 ovfl, /* th = */ (size_t)-1);
776 if (IS_ERR(child->bts)) { 790 if (IS_ERR(child->bts)) {
777 error = PTR_ERR(child->bts); 791 error = PTR_ERR(child->bts);
792 kfree(child->bts_buffer);
778 child->bts = NULL; 793 child->bts = NULL;
794 child->bts_buffer = NULL;
779 goto errout; 795 goto errout;
780 } 796 }
781 797
@@ -972,6 +988,8 @@ void ptrace_disable(struct task_struct *child)
972#ifdef CONFIG_X86_PTRACE_BTS 988#ifdef CONFIG_X86_PTRACE_BTS
973 if (child->bts) { 989 if (child->bts) {
974 (void)ds_release_bts(child->bts); 990 (void)ds_release_bts(child->bts);
991 kfree(child->bts_buffer);
992 child->bts_buffer = NULL;
975 993
976 child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask; 994 child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask;
977 if (!child->thread.debugctlmsr) 995 if (!child->thread.debugctlmsr)