]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - kernel/trace/trace.c
Merge branches 'tracing/profiling', 'tracing/options' and 'tracing/urgent' into traci...
[mv-sheeva.git] / kernel / trace / trace.c
index 5653c6b07ba1d04a6c6dc1ba8b33458d4c5c523a..4ee6f0375222e5d274a045f3ea6617836dab093c 100644 (file)
 unsigned long __read_mostly    tracing_max_latency = (cycle_t)ULONG_MAX;
 unsigned long __read_mostly    tracing_thresh;
 
+/* For tracers that don't implement custom flags */
+static struct tracer_opt dummy_tracer_opt[] = {
+       { }
+};
+
+static struct tracer_flags dummy_tracer_flags = {
+       .val = 0,
+       .opts = dummy_tracer_opt
+};
+
+static int dummy_set_flag(u32 old_flags, u32 bit, int set)
+{
+       return 0;
+}
 
 /*
  * Kill all tracing for good (never come back).
@@ -537,6 +551,14 @@ int register_tracer(struct tracer *type)
                }
        }
 
+       if (!type->set_flag)
+               type->set_flag = &dummy_set_flag;
+       if (!type->flags)
+               type->flags = &dummy_tracer_flags;
+       else
+               if (!type->flags->opts)
+                       type->flags->opts = dummy_tracer_opt;
+
 #ifdef CONFIG_FTRACE_STARTUP_TEST
        if (type->selftest) {
                struct tracer *saved_tracer = current_trace;
@@ -840,6 +862,7 @@ static void __trace_function_return(struct trace_array *tr,
        entry->parent_ip        = trace->ret;
        entry->rettime          = trace->rettime;
        entry->calltime         = trace->calltime;
+       entry->overrun          = trace->overrun;
        ring_buffer_unlock_commit(global_trace.buffer, event, irq_flags);
 }
 #endif
@@ -2436,10 +2459,13 @@ static ssize_t
 tracing_trace_options_read(struct file *filp, char __user *ubuf,
                       size_t cnt, loff_t *ppos)
 {
+       int i;
        char *buf;
        int r = 0;
        int len = 0;
-       int i;
+       u32 tracer_flags = current_trace->flags->val;
+       struct tracer_opt *trace_opts = current_trace->flags->opts;
+
 
        /* calulate max size */
        for (i = 0; trace_options[i]; i++) {
@@ -2447,6 +2473,15 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf,
                len += 3; /* "no" and space */
        }
 
+       /*
+        * Increase the size with names of options specific
+        * of the current tracer.
+        */
+       for (i = 0; trace_opts[i].name; i++) {
+               len += strlen(trace_opts[i].name);
+               len += 3; /* "no" and space */
+       }
+
        /* +2 for \n and \0 */
        buf = kmalloc(len + 2, GFP_KERNEL);
        if (!buf)
@@ -2459,6 +2494,15 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf,
                        r += sprintf(buf + r, "no%s ", trace_options[i]);
        }
 
+       for (i = 0; trace_opts[i].name; i++) {
+               if (tracer_flags & trace_opts[i].bit)
+                       r += sprintf(buf + r, "%s ",
+                               trace_opts[i].name);
+               else
+                       r += sprintf(buf + r, "no%s ",
+                               trace_opts[i].name);
+       }
+
        r += sprintf(buf + r, "\n");
        WARN_ON(r >= len + 2);
 
@@ -2469,6 +2513,40 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf,
        return r;
 }
 
+/* Try to assign a tracer specific option */
+static int set_tracer_option(struct tracer *trace, char *cmp, int neg)
+{
+       struct tracer_flags *trace_flags = trace->flags;
+       struct tracer_opt *opts = NULL;
+       int ret = 0, i = 0;
+       int len;
+
+       for (i = 0; trace_flags->opts[i].name; i++) {
+               opts = &trace_flags->opts[i];
+               len = strlen(opts->name);
+
+               if (strncmp(cmp, opts->name, len) == 0) {
+                       ret = trace->set_flag(trace_flags->val,
+                               opts->bit, !neg);
+                       break;
+               }
+       }
+       /* Not found */
+       if (!trace_flags->opts[i].name)
+               return -EINVAL;
+
+       /* Refused to handle */
+       if (ret)
+               return ret;
+
+       if (neg)
+               trace_flags->val &= ~opts->bit;
+       else
+               trace_flags->val |= opts->bit;
+
+       return 0;
+}
+
 static ssize_t
 tracing_trace_options_write(struct file *filp, const char __user *ubuf,
                        size_t cnt, loff_t *ppos)
@@ -2476,6 +2554,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
        char buf[64];
        char *cmp = buf;
        int neg = 0;
+       int ret;
        int i;
 
        if (cnt >= sizeof(buf))
@@ -2502,11 +2581,13 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
                        break;
                }
        }
-       /*
-        * If no option could be set, return an error:
-        */
-       if (!trace_options[i])
-               return -EINVAL;
+
+       /* If no option could be set, test the specific tracer options */
+       if (!trace_options[i]) {
+               ret = set_tracer_option(current_trace, cmp, neg);
+               if (ret)
+                       return ret;
+       }
 
        filp->f_pos += cnt;