]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
tracing: Prevent buffer overwrite disabled for latency tracers
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>
Thu, 14 Mar 2013 19:03:53 +0000 (15:03 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Apr 2013 17:16:52 +0000 (10:16 -0700)
commit 613f04a0f51e6e68ac6fe571ab79da3c0a5eb4da upstream.

The latency tracers require the buffers to be in overwrite mode,
otherwise they get screwed up. Force the buffers to stay in overwrite
mode when latency tracers are enabled.

Added a flag_changed() method to the tracer structure to allow
the tracers to see what flags are being changed, and also be able
to prevent the change from happing.

[Backported for 3.4-stable. Re-added current_trace NULL checks; removed
allocated_snapshot field; adapted to tracing_trace_options_write without
trace_set_options.]

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Lingzhu Xiang <lxiang@redhat.com>
Reviewed-by: CAI Qian <caiqian@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_irqsoff.c
kernel/trace/trace_sched_wakeup.c

index 420d49ef3c9f1deb65600e371a47d24f5eca15e3..b3ae845c5041061e0968308866a2b36c1652a820 100644 (file)
@@ -2527,11 +2527,25 @@ static int set_tracer_option(struct tracer *trace, char *cmp, int neg)
        return -EINVAL;
 }
 
-static void set_tracer_flags(unsigned int mask, int enabled)
+/* Some tracers require overwrite to stay enabled */
+int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set)
+{
+       if (tracer->enabled && (mask & TRACE_ITER_OVERWRITE) && !set)
+               return -1;
+
+       return 0;
+}
+
+int set_tracer_flag(unsigned int mask, int enabled)
 {
        /* do nothing if flag is already set */
        if (!!(trace_flags & mask) == !!enabled)
-               return;
+               return 0;
+
+       /* Give the tracer a chance to approve the change */
+       if (current_trace->flag_changed)
+               if (current_trace->flag_changed(current_trace, mask, !!enabled))
+                       return -EINVAL;
 
        if (enabled)
                trace_flags |= mask;
@@ -2543,6 +2557,8 @@ static void set_tracer_flags(unsigned int mask, int enabled)
 
        if (mask == TRACE_ITER_OVERWRITE)
                ring_buffer_change_overwrite(global_trace.buffer, enabled);
+
+       return 0;
 }
 
 static ssize_t
@@ -2552,7 +2568,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
        char buf[64];
        char *cmp;
        int neg = 0;
-       int ret = 0;
+       int ret = -ENODEV;
        int i;
 
        if (cnt >= sizeof(buf))
@@ -2573,7 +2589,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
 
        for (i = 0; trace_options[i]; i++) {
                if (strcmp(cmp, trace_options[i]) == 0) {
-                       set_tracer_flags(1 << i, !neg);
+                       ret = set_tracer_flag(1 << i, !neg);
                        break;
                }
        }
@@ -2584,7 +2600,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
 
        mutex_unlock(&trace_types_lock);
 
-       if (ret)
+       if (ret < 0)
                return ret;
 
        *ppos += cnt;
@@ -2883,6 +2899,9 @@ static int tracing_set_tracer(const char *buf)
                goto out;
 
        trace_branch_disable();
+
+       current_trace->enabled = false;
+
        if (current_trace && current_trace->reset)
                current_trace->reset(tr);
        if (current_trace && current_trace->use_max_tr) {
@@ -2912,6 +2931,7 @@ static int tracing_set_tracer(const char *buf)
                        goto out;
        }
 
+       current_trace->enabled = true;
        trace_branch_enable(tr);
  out:
        mutex_unlock(&trace_types_lock);
@@ -4184,9 +4204,12 @@ trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt,
                return -EINVAL;
 
        mutex_lock(&trace_types_lock);
-       set_tracer_flags(1 << index, val);
+       ret = set_tracer_flag(1 << index, val);
        mutex_unlock(&trace_types_lock);
 
+       if (ret < 0)
+               return ret;
+
        *ppos += cnt;
 
        return cnt;
index f8074072d1112f36e7d8d04b3ff467e2224731a4..123ee281e5b560763717499fed8d7927e044c2fd 100644 (file)
@@ -271,10 +271,14 @@ struct tracer {
        enum print_line_t       (*print_line)(struct trace_iterator *iter);
        /* If you handled the flag setting, return 0 */
        int                     (*set_flag)(u32 old_flags, u32 bit, int set);
+       /* Return 0 if OK with change, else return non-zero */
+       int                     (*flag_changed)(struct tracer *tracer,
+                                               u32 mask, int set);
        struct tracer           *next;
        struct tracer_flags     *flags;
        int                     print_max;
        int                     use_max_tr;
+       bool                    enabled;
 };
 
 
@@ -776,6 +780,9 @@ extern struct list_head ftrace_events;
 extern const char *__start___trace_bprintk_fmt[];
 extern const char *__stop___trace_bprintk_fmt[];
 
+int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set);
+int set_tracer_flag(unsigned int mask, int enabled);
+
 #undef FTRACE_ENTRY
 #define FTRACE_ENTRY(call, struct_name, id, tstruct, print)            \
        extern struct ftrace_event_call                                 \
index c77424be284d503c241a36d290af3a4c6e0ef98b..984aad85aa43b0ce30fdd118150780d4eabbf62d 100644 (file)
@@ -32,7 +32,7 @@ enum {
 
 static int trace_type __read_mostly;
 
-static int save_lat_flag;
+static int save_flags;
 
 static void stop_irqsoff_tracer(struct trace_array *tr, int graph);
 static int start_irqsoff_tracer(struct trace_array *tr, int graph);
@@ -544,8 +544,11 @@ static void stop_irqsoff_tracer(struct trace_array *tr, int graph)
 
 static void __irqsoff_tracer_init(struct trace_array *tr)
 {
-       save_lat_flag = trace_flags & TRACE_ITER_LATENCY_FMT;
-       trace_flags |= TRACE_ITER_LATENCY_FMT;
+       save_flags = trace_flags;
+
+       /* non overwrite screws up the latency tracers */
+       set_tracer_flag(TRACE_ITER_OVERWRITE, 1);
+       set_tracer_flag(TRACE_ITER_LATENCY_FMT, 1);
 
        tracing_max_latency = 0;
        irqsoff_trace = tr;
@@ -559,10 +562,13 @@ static void __irqsoff_tracer_init(struct trace_array *tr)
 
 static void irqsoff_tracer_reset(struct trace_array *tr)
 {
+       int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT;
+       int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE;
+
        stop_irqsoff_tracer(tr, is_graph());
 
-       if (!save_lat_flag)
-               trace_flags &= ~TRACE_ITER_LATENCY_FMT;
+       set_tracer_flag(TRACE_ITER_LATENCY_FMT, lat_flag);
+       set_tracer_flag(TRACE_ITER_OVERWRITE, overwrite_flag);
 }
 
 static void irqsoff_tracer_start(struct trace_array *tr)
@@ -595,6 +601,7 @@ static struct tracer irqsoff_tracer __read_mostly =
        .print_line     = irqsoff_print_line,
        .flags          = &tracer_flags,
        .set_flag       = irqsoff_set_flag,
+       .flag_changed   = trace_keep_overwrite,
 #ifdef CONFIG_FTRACE_SELFTEST
        .selftest    = trace_selftest_startup_irqsoff,
 #endif
@@ -628,6 +635,7 @@ static struct tracer preemptoff_tracer __read_mostly =
        .print_line     = irqsoff_print_line,
        .flags          = &tracer_flags,
        .set_flag       = irqsoff_set_flag,
+       .flag_changed   = trace_keep_overwrite,
 #ifdef CONFIG_FTRACE_SELFTEST
        .selftest    = trace_selftest_startup_preemptoff,
 #endif
@@ -663,6 +671,7 @@ static struct tracer preemptirqsoff_tracer __read_mostly =
        .print_line     = irqsoff_print_line,
        .flags          = &tracer_flags,
        .set_flag       = irqsoff_set_flag,
+       .flag_changed   = trace_keep_overwrite,
 #ifdef CONFIG_FTRACE_SELFTEST
        .selftest    = trace_selftest_startup_preemptirqsoff,
 #endif
index f029dd4fd2cac18eb309a9aab6b13009bd124305..1beb25ec5d9b2075fa74aea4dbbdbfbeae1eefde 100644 (file)
@@ -36,7 +36,7 @@ static void __wakeup_reset(struct trace_array *tr);
 static int wakeup_graph_entry(struct ftrace_graph_ent *trace);
 static void wakeup_graph_return(struct ftrace_graph_ret *trace);
 
-static int save_lat_flag;
+static int save_flags;
 
 #define TRACE_DISPLAY_GRAPH     1
 
@@ -526,8 +526,11 @@ static void stop_wakeup_tracer(struct trace_array *tr)
 
 static int __wakeup_tracer_init(struct trace_array *tr)
 {
-       save_lat_flag = trace_flags & TRACE_ITER_LATENCY_FMT;
-       trace_flags |= TRACE_ITER_LATENCY_FMT;
+       save_flags = trace_flags;
+
+       /* non overwrite screws up the latency tracers */
+       set_tracer_flag(TRACE_ITER_OVERWRITE, 1);
+       set_tracer_flag(TRACE_ITER_LATENCY_FMT, 1);
 
        tracing_max_latency = 0;
        wakeup_trace = tr;
@@ -549,12 +552,15 @@ static int wakeup_rt_tracer_init(struct trace_array *tr)
 
 static void wakeup_tracer_reset(struct trace_array *tr)
 {
+       int lat_flag = save_flags & TRACE_ITER_LATENCY_FMT;
+       int overwrite_flag = save_flags & TRACE_ITER_OVERWRITE;
+
        stop_wakeup_tracer(tr);
        /* make sure we put back any tasks we are tracing */
        wakeup_reset(tr);
 
-       if (!save_lat_flag)
-               trace_flags &= ~TRACE_ITER_LATENCY_FMT;
+       set_tracer_flag(TRACE_ITER_LATENCY_FMT, lat_flag);
+       set_tracer_flag(TRACE_ITER_OVERWRITE, overwrite_flag);
 }
 
 static void wakeup_tracer_start(struct trace_array *tr)
@@ -580,6 +586,7 @@ static struct tracer wakeup_tracer __read_mostly =
        .print_line     = wakeup_print_line,
        .flags          = &tracer_flags,
        .set_flag       = wakeup_set_flag,
+       .flag_changed   = trace_keep_overwrite,
 #ifdef CONFIG_FTRACE_SELFTEST
        .selftest    = trace_selftest_startup_wakeup,
 #endif
@@ -601,6 +608,7 @@ static struct tracer wakeup_rt_tracer __read_mostly =
        .print_line     = wakeup_print_line,
        .flags          = &tracer_flags,
        .set_flag       = wakeup_set_flag,
+       .flag_changed   = trace_keep_overwrite,
 #ifdef CONFIG_FTRACE_SELFTEST
        .selftest    = trace_selftest_startup_wakeup,
 #endif