aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/ds.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/ds.c')
-rw-r--r--arch/x86/kernel/ds.c92
1 files changed, 14 insertions, 78 deletions
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)