x86, bts, ptrace: move BTS buffer allocation from ds.c into ptrace.c
authorMarkus Metzger <markus.t.metzger@intel.com>
Tue, 25 Nov 2008 08:05:27 +0000 (09:05 +0100)
committerIngo Molnar <mingo@elte.hu>
Tue, 25 Nov 2008 16:31:12 +0000 (17:31 +0100)
Impact: restructure DS memory allocation to be done by the usage site of DS

Require pre-allocated buffers in ds.h.

Move the BTS buffer allocation for ptrace into ptrace.c.
The pointer to the allocated buffer is stored in the traced task's
task_struct together with the handle returned by ds_request_bts().

Removes memory accounting code.

Signed-off-by: Markus Metzger <markus.t.metzger@intel.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/include/asm/ds.h
arch/x86/kernel/ds.c
arch/x86/kernel/ptrace.c
include/linux/sched.h

index 0af997de5f01e834213dc3063a9d02fd52460a76..99b6c39774a44179fcf3554a096449962167d490 100644 (file)
@@ -7,13 +7,12 @@
  *
  * 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.
@@ -54,8 +53,7 @@ typedef void (*pebs_ovfl_callback_t)(struct pebs_tracer *);
  * 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;
@@ -72,8 +70,6 @@ extern struct pebs_tracer *ds_request_pebs(struct task_struct *task,
 /*
  * 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_~()
index 96768e9cce998652dd3174f90b400aca4e036d16..19a8c2c0389f1ab87dfe41193e04a5509f257130 100644 (file)
@@ -7,13 +7,12 @@
  *
  * 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.
@@ -57,8 +56,6 @@ struct ds_tracer {
        /* 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 {
@@ -141,8 +138,7 @@ static inline void ds_set(unsigned char *base, enum ds_qualifier qual,
 
 
 /*
- * 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);
 
@@ -292,50 +288,6 @@ static void ds_overflow(struct ds_context *context, enum ds_qualifier qual)
 }
 
 
-/*
- * 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(&current->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(&current->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)
@@ -382,6 +334,10 @@ static int ds_request(struct ds_tracer *tracer, enum ds_qualifier qual,
        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]))
@@ -395,13 +351,6 @@ static int ds_request(struct ds_tracer *tracer, enum ds_qualifier qual,
                        goto out;
        }
 
-       error = -ENOMEM;
-       if (!base) {
-               base = ds_allocate_buffer(size, &tracer->pages);
-               if (!base)
-                       goto out;
-       }
-
        tracer->buffer = base;
        tracer->size = size;
 
@@ -466,7 +415,7 @@ struct bts_tracer *ds_request_bts(struct task_struct *task,
        return tracer;
 
  out_tracer:
-       (void)ds_release_bts(tracer);
+       kfree(tracer);
  out:
        return ERR_PTR(error);
 }
@@ -496,31 +445,18 @@ struct pebs_tracer *ds_request_pebs(struct task_struct *task,
        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(&current->mm->mmap_sem);
-
-               current->mm->total_vm  -= tracer->pages;
-               current->mm->locked_vm -= tracer->pages;
-
-               up_write(&current->mm->mmap_sem);
-       }
+       put_tracer(tracer->context->task);
+       ds_put_context(tracer->context);
 }
 
 int ds_release_bts(struct bts_tracer *tracer)
index 76adf5b640ffc7e1344a1dbe94d2b6c02515971d..2c8ec1ba75e663e63b4ce2d1740b6db1fb2954d3 100644 (file)
@@ -758,6 +758,10 @@ static int ptrace_bts_config(struct task_struct *child,
                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;
@@ -768,14 +772,26 @@ static int ptrace_bts_config(struct task_struct *child,
                        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;
                }
 
@@ -972,6 +988,8 @@ void ptrace_disable(struct task_struct *child)
 #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)
index a9780eaa67375f015cc5622566f273703b0d3fcd..d02a0ca70ee97e0c9686b97347ba171b8fdb2530 100644 (file)
@@ -1168,6 +1168,10 @@ struct task_struct {
         * This field actually belongs to the ptracer task.
         */
        struct bts_tracer *bts;
+       /*
+        * The buffer to hold the BTS data.
+        */
+       void *bts_buffer;
 #endif /* CONFIG_X86_PTRACE_BTS */
 
        /* PID/PID hash table linkage. */