gator-driver: Handle task struct correctly
authorDrew Richardson <drew.richardson@arm.com>
Tue, 17 Dec 2013 23:40:56 +0000 (23:40 +0000)
committerJon Medhurst <tixy@linaro.org>
Wed, 18 Dec 2013 19:03:26 +0000 (19:03 +0000)
Use put_task_struct/get_task_struct to ensure the task_struct pointer
is still valid. Change translate_buffer to ensure that both arguments
are written atomically. Drop additional requests if the
translate_buffer is full.

Signed-off-by: Drew Richardson <drew.richardson@arm.com>
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
driver/gator_cookies.c
driver/gator_iks.c

index 91adfdde9be2e0246e3e173eb6ce14744704715d..eb9b946170c1cd57c17cfd19c305cbbe6abefe10 100644 (file)
 static uint32_t *gator_crc32_table;
 static unsigned int translate_buffer_mask;
 
+struct cookie_args {
+       struct task_struct *task;
+       const char *text;
+};
+
 static DEFINE_PER_CPU(char *, translate_text);
 static DEFINE_PER_CPU(uint32_t, cookie_next_key);
 static DEFINE_PER_CPU(uint64_t *, cookie_keys);
 static DEFINE_PER_CPU(uint32_t *, cookie_values);
 static DEFINE_PER_CPU(int, translate_buffer_read);
 static DEFINE_PER_CPU(int, translate_buffer_write);
-static DEFINE_PER_CPU(void **, translate_buffer);
+static DEFINE_PER_CPU(struct cookie_args *, translate_buffer);
 
 static uint32_t get_cookie(int cpu, struct task_struct *task, const char *text, bool from_wq);
 static void wq_cookie_handler(struct work_struct *unused);
@@ -109,36 +114,58 @@ static void cookiemap_add(uint64_t key, uint32_t value)
 }
 
 #ifndef CONFIG_PREEMPT_RT_FULL
-static void translate_buffer_write_ptr(int cpu, void *x)
+static void translate_buffer_write_args(int cpu, struct task_struct *task, const char *text)
 {
-       per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_write, cpu)++] = x;
-       per_cpu(translate_buffer_write, cpu) &= translate_buffer_mask;
+       unsigned long flags;
+       int write;
+       int next_write;
+       struct cookie_args *args;
+
+       local_irq_save(flags);
+
+       write = per_cpu(translate_buffer_write, cpu);
+       next_write = (write + 1) & translate_buffer_mask;
+
+       // At least one entry must always remain available as when read == write, the queue is empty not full
+       if (next_write != per_cpu(translate_buffer_read, cpu)) {
+               args = &per_cpu(translate_buffer, cpu)[write];
+               args->task = task;
+               args->text = text;
+               get_task_struct(task);
+               per_cpu(translate_buffer_write, cpu) = next_write;
+       }
+
+       local_irq_restore(flags);
 }
 #endif
 
-static void *translate_buffer_read_ptr(int cpu)
+static void translate_buffer_read_args(int cpu, struct cookie_args *args)
 {
-       void *value = per_cpu(translate_buffer, cpu)[per_cpu(translate_buffer_read, cpu)++];
-       per_cpu(translate_buffer_read, cpu) &= translate_buffer_mask;
-       return value;
+       unsigned long flags;
+       int read;
+
+       local_irq_save(flags);
+
+       read = per_cpu(translate_buffer_read, cpu);
+       *args = per_cpu(translate_buffer, cpu)[read];
+       per_cpu(translate_buffer_read, cpu) = (read + 1) & translate_buffer_mask;
+
+       local_irq_restore(flags);
 }
 
 static void wq_cookie_handler(struct work_struct *unused)
 {
-       struct task_struct *task;
-       char *text;
+       struct cookie_args args;
        int cpu = get_physical_cpu(), cookie;
-       unsigned int commit;
 
        mutex_lock(&start_mutex);
 
        if (gator_started != 0) {
-               commit = per_cpu(translate_buffer_write, cpu);
-               while (per_cpu(translate_buffer_read, cpu) != commit) {
-                       task = (struct task_struct *)translate_buffer_read_ptr(cpu);
-                       text = (char *)translate_buffer_read_ptr(cpu);
-                       cookie = get_cookie(cpu, task, text, true);
-                       marshal_link(cookie, task->tgid, task->pid);
+               while (per_cpu(translate_buffer_read, cpu) != per_cpu(translate_buffer_write, cpu)) {
+                       translate_buffer_read_args(cpu, &args);
+                       cookie = get_cookie(cpu, args.task, args.text, true);
+                       marshal_link(cookie, args.task->tgid, args.task->pid);
+                       put_task_struct(args.task);
                }
        }
 
@@ -169,15 +196,14 @@ static int translate_app_process(const char **text, int cpu, struct task_struct
        //   inconsistent during a context switch between android/linux versions
        if (!from_wq) {
                // Check if already in buffer
-               int ptr = per_cpu(translate_buffer_read, cpu);
-               while (ptr != per_cpu(translate_buffer_write, cpu)) {
-                       if (per_cpu(translate_buffer, cpu)[ptr] == (void *)task)
+               int pos = per_cpu(translate_buffer_read, cpu);
+               while (pos != per_cpu(translate_buffer_write, cpu)) {
+                       if (per_cpu(translate_buffer, cpu)[pos].task == task)
                                goto out;
-                       ptr = (ptr + 2) & translate_buffer_mask;
+                       pos = (pos + 1) & translate_buffer_mask;
                }
 
-               translate_buffer_write_ptr(cpu, (void *)task);
-               translate_buffer_write_ptr(cpu, (void *)*text);
+               translate_buffer_write_args(cpu, task, *text);
 
                // Not safe to call in RT-Preempt full in schedule switch context
                mod_timer(&app_process_wake_up_timer, jiffies + 1);
@@ -340,7 +366,7 @@ static int cookies_initialize(void)
                }
                memset(per_cpu(cookie_values, cpu), 0, size);
 
-               per_cpu(translate_buffer, cpu) = (void **)kmalloc(TRANSLATE_BUFFER_SIZE, GFP_KERNEL);
+               per_cpu(translate_buffer, cpu) = (struct cookie_args *)kmalloc(TRANSLATE_BUFFER_SIZE, GFP_KERNEL);
                if (!per_cpu(translate_buffer, cpu)) {
                        err = -ENOMEM;
                        goto cookie_setup_error;
index 24233d775581b284fa76644d93f8bf35ff7f5eb0..0a90bdd1904e95bde89cd08466ad506573971e21 100644 (file)
@@ -147,11 +147,13 @@ static void gator_send_iks_core_names(void)
 {
        int cpu;
        // Send the cpu names
+       preempt_disable();
        for (cpu = 0; cpu < nr_cpu_ids; ++cpu) {
                if (mpidr_cpus[cpu] != NULL) {
                        gator_send_core_name(cpu, mpidr_cpus[cpu]->cpuid, mpidr_cpus[cpu]);
                }
        }
+       preempt_enable();
 }
 
 static int gator_migrate_start(void)