*
* It manages:
* - per-thread and per-cpu allocation of BTS and PEBS
- * - buffer memory allocation (optional)
- * - buffer overflow handling
+ * - buffer overflow handling (to be done)
* - buffer access
*
* It assumes:
- * - get_task_struct on all parameter tasks
- * - current is allowed to trace parameter tasks
+ * - get_task_struct on all traced tasks
+ * - current is allowed to trace tasks
*
*
* Copyright (C) 2007-2008 Intel Corporation.
* task: the task to request recording for;
* NULL for per-cpu recording on the current cpu
* base: the base pointer for the (non-pageable) buffer;
- * NULL if buffer allocation requested
- * size: the size of the requested or provided buffer in bytes
+ * size: the size of the provided buffer in bytes
* ovfl: pointer to a function to be called on buffer overflow;
* NULL if cyclic buffer requested
* th: the interrupt threshold in records from the end of the buffer;
/*
* Release BTS or PEBS resources
*
- * Frees buffers allocated on ds_request.
- *
* Returns 0 on success; -Eerrno otherwise
*
* tracer: the tracer handle returned from ds_request_~()
*
* It manages:
* - per-thread and per-cpu allocation of BTS and PEBS
- * - buffer memory allocation (optional)
- * - buffer overflow handling
+ * - buffer overflow handling (to be done)
* - buffer access
*
* It assumes:
- * - get_task_struct on all parameter tasks
- * - current is allowed to trace parameter tasks
+ * - get_task_struct on all traced tasks
+ * - current is allowed to trace tasks
*
*
* Copyright (C) 2007-2008 Intel Corporation.
/* the buffer provided on ds_request() and its size in bytes */
void *buffer;
size_t size;
- /* the number of allocated pages for on-request allocated buffers */
- unsigned int pages;
};
struct bts_tracer {
/*
- * Locking is done only for allocating BTS or PEBS resources and for
- * guarding context and buffer memory allocation.
+ * Locking is done only for allocating BTS or PEBS resources.
*/
static spinlock_t ds_lock = __SPIN_LOCK_UNLOCKED(ds_lock);
}
-/*
- * Allocate a non-pageable buffer of the parameter size.
- * Checks the memory and the locked memory rlimit.
- *
- * Returns the buffer, if successful;
- * NULL, if out of memory or rlimit exceeded.
- *
- * size: the requested buffer size in bytes
- * pages (out): if not NULL, contains the number of pages reserved
- */
-static inline void *ds_allocate_buffer(size_t size, unsigned int *pages)
-{
- unsigned long rlim, vm, pgsz;
- void *buffer = NULL;
-
- pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT;
-
- down_write(¤t->mm->mmap_sem);
-
- rlim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT;
- vm = current->mm->total_vm + pgsz;
- if (rlim < vm)
- goto out;
-
- rlim = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
- vm = current->mm->locked_vm + pgsz;
- if (rlim < vm)
- goto out;
-
- buffer = kzalloc(size, GFP_KERNEL);
- if (!buffer)
- goto out;
-
- current->mm->total_vm += pgsz;
- current->mm->locked_vm += pgsz;
-
- if (pages)
- *pages = pgsz;
-
- out:
- up_write(¤t->mm->mmap_sem);
- return buffer;
-}
-
static void ds_install_ds_config(struct ds_context *context,
enum ds_qualifier qual,
void *base, size_t size, size_t ith)
if (!ds_cfg.sizeof_ds)
goto out;
+ error = -EINVAL;
+ if (!base)
+ goto out;
+
/* we require some space to do alignment adjustments below */
error = -EINVAL;
if (size < (DS_ALIGNMENT + ds_cfg.sizeof_rec[qual]))
goto out;
}
- error = -ENOMEM;
- if (!base) {
- base = ds_allocate_buffer(size, &tracer->pages);
- if (!base)
- goto out;
- }
-
tracer->buffer = base;
tracer->size = size;
return tracer;
out_tracer:
- (void)ds_release_bts(tracer);
+ kfree(tracer);
out:
return ERR_PTR(error);
}
return tracer;
out_tracer:
- (void)ds_release_pebs(tracer);
+ kfree(tracer);
out:
return ERR_PTR(error);
}
static void ds_release(struct ds_tracer *tracer, enum ds_qualifier qual)
{
- if (tracer->context) {
- BUG_ON(tracer->context->owner[qual] != tracer);
- tracer->context->owner[qual] = NULL;
-
- put_tracer(tracer->context->task);
- ds_put_context(tracer->context);
- }
+ BUG_ON(tracer->context->owner[qual] != tracer);
+ tracer->context->owner[qual] = NULL;
- if (tracer->pages) {
- kfree(tracer->buffer);
-
- down_write(¤t->mm->mmap_sem);
-
- current->mm->total_vm -= tracer->pages;
- current->mm->locked_vm -= tracer->pages;
-
- up_write(¤t->mm->mmap_sem);
- }
+ put_tracer(tracer->context->task);
+ ds_put_context(tracer->context);
}
int ds_release_bts(struct bts_tracer *tracer)
bts_ovfl_callback_t ovfl = NULL;
unsigned int sig = 0;
+ error = -EINVAL;
+ if (cfg.size < (10 * bts_cfg.sizeof_bts))
+ goto errout;
+
if (cfg.flags & PTRACE_BTS_O_SIGNAL) {
if (!cfg.signal)
goto errout;
sig = cfg.signal;
}
- if (child->bts)
+ if (child->bts) {
(void)ds_release_bts(child->bts);
+ kfree(child->bts_buffer);
+
+ child->bts = NULL;
+ child->bts_buffer = NULL;
+ }
+
+ error = -ENOMEM;
+ child->bts_buffer = kzalloc(cfg.size, GFP_KERNEL);
+ if (!child->bts_buffer)
+ goto errout;
- child->bts = ds_request_bts(child, /* base = */ NULL, cfg.size,
+ child->bts = ds_request_bts(child, child->bts_buffer, cfg.size,
ovfl, /* th = */ (size_t)-1);
if (IS_ERR(child->bts)) {
error = PTR_ERR(child->bts);
+ kfree(child->bts_buffer);
child->bts = NULL;
+ child->bts_buffer = NULL;
goto errout;
}
#ifdef CONFIG_X86_PTRACE_BTS
if (child->bts) {
(void)ds_release_bts(child->bts);
+ kfree(child->bts_buffer);
+ child->bts_buffer = NULL;
child->thread.debugctlmsr &= ~bts_cfg.debugctl_mask;
if (!child->thread.debugctlmsr)