diff options
Diffstat (limited to 'arch/x86/kernel/ds.c')
-rw-r--r-- | arch/x86/kernel/ds.c | 92 |
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 | ||
64 | struct bts_tracer { | 61 | struct 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 | */ |
147 | static spinlock_t ds_lock = __SPIN_LOCK_UNLOCKED(ds_lock); | 143 | static 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 | */ | ||
305 | static 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(¤t->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(¤t->mm->mmap_sem); | ||
336 | return buffer; | ||
337 | } | ||
338 | |||
339 | static void ds_install_ds_config(struct ds_context *context, | 291 | static 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 | ||
504 | static void ds_release(struct ds_tracer *tracer, enum ds_qualifier qual) | 453 | static 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(¤t->mm->mmap_sem); | ||
518 | |||
519 | current->mm->total_vm -= tracer->pages; | ||
520 | current->mm->locked_vm -= tracer->pages; | ||
521 | |||
522 | up_write(¤t->mm->mmap_sem); | ||
523 | } | ||
524 | } | 460 | } |
525 | 461 | ||
526 | int ds_release_bts(struct bts_tracer *tracer) | 462 | int ds_release_bts(struct bts_tracer *tracer) |