Merge branches 'tracing/ftrace' and 'tracing/syscalls'; commit 'v2.6.29-rc8' into...
authorIngo Molnar <mingo@elte.hu>
Fri, 13 Mar 2009 09:23:39 +0000 (10:23 +0100)
committerIngo Molnar <mingo@elte.hu>
Fri, 13 Mar 2009 09:23:39 +0000 (10:23 +0100)
18 files changed:
Makefile
include/linux/interrupt.h
include/linux/kernel.h
include/trace/irq_event_types.h
kernel/softirq.c
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_event_types.h
kernel/trace/trace_events.c
kernel/trace/trace_events_stage_2.h
kernel/trace/trace_functions_graph.c
kernel/trace/trace_mmiotrace.c
kernel/trace/trace_output.c
kernel/trace/trace_printk.c
kernel/trace/trace_stack.c
kernel/trace/trace_workqueue.c
lib/bitmap.c

index 69b8091bfed17ddd10288b7df6c88a55b416c48b..46c04c546ee2d4676693289f54270391fb15ad97 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 29
-EXTRAVERSION = -rc7
+EXTRAVERSION = -rc8
 NAME = Erotic Pickled Herring
 
 # *DOCUMENTATION*
index 472f11765f608318093ed82919f5c7fdf4f00a7d..9b7e9d743476fa096e0c5b156dca5abc85a296d3 100644 (file)
@@ -258,6 +258,11 @@ enum
        NR_SOFTIRQS
 };
 
+/* map softirq index to softirq name. update 'softirq_to_name' in
+ * kernel/softirq.c when adding a new softirq.
+ */
+extern char *softirq_to_name[NR_SOFTIRQS];
+
 /* softirq mask and active fields moved to irq_cpustat_t in
  * asm/hardirq.h to get better cache usage.  KAO
  */
index 7742798c920880f1e194bd2c44eb1a5a47f00288..1daca3b062bb27495e6d5ba4df588e9cd4d17a59 100644 (file)
@@ -452,31 +452,45 @@ do {                                                                      \
 
 #define trace_printk(fmt, args...)                                     \
 do {                                                                   \
-       static const char *trace_printk_fmt                             \
-       __attribute__((section("__trace_printk_fmt")));                 \
-                                                                       \
-       if (!trace_printk_fmt)                                          \
-               trace_printk_fmt = fmt;                                 \
-                                                                       \
        __trace_printk_check_format(fmt, ##args);                       \
-       __trace_printk(_THIS_IP_, trace_printk_fmt, ##args);            \
+       if (__builtin_constant_p(fmt)) {                                \
+               static const char *trace_printk_fmt                     \
+                 __attribute__((section("__trace_printk_fmt"))) =      \
+                       __builtin_constant_p(fmt) ? fmt : NULL;         \
+                                                                       \
+               __trace_bprintk(_THIS_IP_, trace_printk_fmt, ##args);   \
+       } else                                                          \
+               __trace_printk(_THIS_IP_, fmt, ##args);         \
 } while (0)
 
+extern int
+__trace_bprintk(unsigned long ip, const char *fmt, ...)
+       __attribute__ ((format (printf, 2, 3)));
+
 extern int
 __trace_printk(unsigned long ip, const char *fmt, ...)
        __attribute__ ((format (printf, 2, 3)));
 
+/*
+ * The double __builtin_constant_p is because gcc will give us an error
+ * if we try to allocate the static variable to fmt if it is not a
+ * constant. Even with the outer if statement.
+ */
 #define ftrace_vprintk(fmt, vargs)                                     \
 do {                                                                   \
-       static const char *trace_printk_fmt                             \
-       __attribute__((section("__trace_printk_fmt")));                 \
-                                                                       \
-       if (!trace_printk_fmt)                                          \
-               trace_printk_fmt = fmt;                                 \
+       if (__builtin_constant_p(fmt)) {                                \
+               static const char *trace_printk_fmt                     \
+                 __attribute__((section("__trace_printk_fmt"))) =      \
+                       __builtin_constant_p(fmt) ? fmt : NULL;         \
                                                                        \
-       __ftrace_vprintk(_THIS_IP_, trace_printk_fmt, vargs);           \
+               __ftrace_vbprintk(_THIS_IP_, trace_printk_fmt, vargs);  \
+       } else                                                          \
+               __ftrace_vprintk(_THIS_IP_, fmt, vargs);                \
 } while (0)
 
+extern int
+__ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap);
+
 extern int
 __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap);
 
index 214bb928fe9e6d887131c35baef531a3e9a5352c..85964ebd47ec5f63cda19ce7eba5006657d70e31 100644 (file)
@@ -40,4 +40,16 @@ TRACE_EVENT(irq_handler_exit,
                  __entry->irq, __entry->ret ? "handled" : "unhandled")
 );
 
+TRACE_FORMAT(softirq_entry,
+       TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
+       TP_ARGS(h, vec),
+       TP_FMT("softirq=%d action=%s", (int)(h - vec), softirq_to_name[h-vec])
+       );
+
+TRACE_FORMAT(softirq_exit,
+       TP_PROTO(struct softirq_action *h, struct softirq_action *vec),
+       TP_ARGS(h, vec),
+       TP_FMT("softirq=%d action=%s", (int)(h - vec), softirq_to_name[h-vec])
+       );
+
 #undef TRACE_SYSTEM
index 7571bcb71be44f637a2d5a633cbe27dbd4eded01..65ff3e3961b4d60f4f4db24f87daec94e2841872 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/ftrace.h>
 #include <linux/smp.h>
 #include <linux/tick.h>
+#include <trace/irq.h>
 
 #include <asm/irq.h>
 /*
@@ -53,6 +54,11 @@ static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp
 
 static DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
 
+char *softirq_to_name[NR_SOFTIRQS] = {
+       "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK",
+       "TASKLET", "SCHED", "HRTIMER",  "RCU"
+};
+
 /*
  * we cannot loop indefinitely here to avoid userspace starvation,
  * but we also don't want to introduce a worst case 1/HZ latency
@@ -180,6 +186,9 @@ EXPORT_SYMBOL(local_bh_enable_ip);
  */
 #define MAX_SOFTIRQ_RESTART 10
 
+DEFINE_TRACE(softirq_entry);
+DEFINE_TRACE(softirq_exit);
+
 asmlinkage void __do_softirq(void)
 {
        struct softirq_action *h;
@@ -206,12 +215,14 @@ restart:
                if (pending & 1) {
                        int prev_count = preempt_count();
 
+                       trace_softirq_entry(h, softirq_vec);
                        h->action(h);
-
+                       trace_softirq_exit(h, softirq_vec);
                        if (unlikely(prev_count != preempt_count())) {
-                               printk(KERN_ERR "huh, entered softirq %td %p"
+                               printk(KERN_ERR "huh, entered softirq %td %s %p"
                                       "with preempt_count %08x,"
                                       " exited with %08x?\n", h - softirq_vec,
+                                      softirq_to_name[h - softirq_vec],
                                       h->action, prev_count, preempt_count());
                                preempt_count() = prev_count;
                        }
index 178858492a89bcafb3f5ca96dbdfd9ea5ba181d4..58128ad2fde03af48f525f605d8682208c29ad57 100644 (file)
 #include <linux/init.h>
 #include <linux/hash.h>
 #include <linux/list.h>
+#include <linux/cpu.h>
 #include <linux/fs.h>
 
 #include "trace.h"
 
+/*
+ * The ring buffer is made up of a list of pages. A separate list of pages is
+ * allocated for each CPU. A writer may only write to a buffer that is
+ * associated with the CPU it is currently executing on.  A reader may read
+ * from any per cpu buffer.
+ *
+ * The reader is special. For each per cpu buffer, the reader has its own
+ * reader page. When a reader has read the entire reader page, this reader
+ * page is swapped with another page in the ring buffer.
+ *
+ * Now, as long as the writer is off the reader page, the reader can do what
+ * ever it wants with that page. The writer will never write to that page
+ * again (as long as it is out of the ring buffer).
+ *
+ * Here's some silly ASCII art.
+ *
+ *   +------+
+ *   |reader|          RING BUFFER
+ *   |page  |
+ *   +------+        +---+   +---+   +---+
+ *                   |   |-->|   |-->|   |
+ *                   +---+   +---+   +---+
+ *                     ^               |
+ *                     |               |
+ *                     +---------------+
+ *
+ *
+ *   +------+
+ *   |reader|          RING BUFFER
+ *   |page  |------------------v
+ *   +------+        +---+   +---+   +---+
+ *                   |   |-->|   |-->|   |
+ *                   +---+   +---+   +---+
+ *                     ^               |
+ *                     |               |
+ *                     +---------------+
+ *
+ *
+ *   +------+
+ *   |reader|          RING BUFFER
+ *   |page  |------------------v
+ *   +------+        +---+   +---+   +---+
+ *      ^            |   |-->|   |-->|   |
+ *      |            +---+   +---+   +---+
+ *      |                              |
+ *      |                              |
+ *      +------------------------------+
+ *
+ *
+ *   +------+
+ *   |buffer|          RING BUFFER
+ *   |page  |------------------v
+ *   +------+        +---+   +---+   +---+
+ *      ^            |   |   |   |-->|   |
+ *      |   New      +---+   +---+   +---+
+ *      |  Reader------^               |
+ *      |   page                       |
+ *      +------------------------------+
+ *
+ *
+ * After we make this swap, the reader can hand this page off to the splice
+ * code and be done with it. It can even allocate a new page if it needs to
+ * and swap that into the ring buffer.
+ *
+ * We will be using cmpxchg soon to make all this lockless.
+ *
+ */
+
 /*
  * A fast way to enable or disable all ring buffers is to
  * call tracing_on or tracing_off. Turning off the ring buffers
@@ -301,6 +370,10 @@ struct ring_buffer {
        struct mutex                    mutex;
 
        struct ring_buffer_per_cpu      **buffers;
+
+#ifdef CONFIG_HOTPLUG_CPU
+       struct notifier_block           cpu_notify;
+#endif
 };
 
 struct ring_buffer_iter {
@@ -459,6 +532,11 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
  */
 extern int ring_buffer_page_too_big(void);
 
+#ifdef CONFIG_HOTPLUG_CPU
+static int __cpuinit rb_cpu_notify(struct notifier_block *self,
+                                  unsigned long action, void *hcpu);
+#endif
+
 /**
  * ring_buffer_alloc - allocate a new ring_buffer
  * @size: the size in bytes per cpu that is needed.
@@ -496,7 +574,8 @@ struct ring_buffer *ring_buffer_alloc(unsigned long size, unsigned flags)
        if (buffer->pages == 1)
                buffer->pages++;
 
-       cpumask_copy(buffer->cpumask, cpu_possible_mask);
+       get_online_cpus();
+       cpumask_copy(buffer->cpumask, cpu_online_mask);
        buffer->cpus = nr_cpu_ids;
 
        bsize = sizeof(void *) * nr_cpu_ids;
@@ -512,6 +591,13 @@ struct ring_buffer *ring_buffer_alloc(unsigned long size, unsigned flags)
                        goto fail_free_buffers;
        }
 
+#ifdef CONFIG_HOTPLUG_CPU
+       buffer->cpu_notify.notifier_call = rb_cpu_notify;
+       buffer->cpu_notify.priority = 0;
+       register_cpu_notifier(&buffer->cpu_notify);
+#endif
+
+       put_online_cpus();
        mutex_init(&buffer->mutex);
 
        return buffer;
@@ -525,6 +611,7 @@ struct ring_buffer *ring_buffer_alloc(unsigned long size, unsigned flags)
 
  fail_free_cpumask:
        free_cpumask_var(buffer->cpumask);
+       put_online_cpus();
 
  fail_free_buffer:
        kfree(buffer);
@@ -541,9 +628,17 @@ ring_buffer_free(struct ring_buffer *buffer)
 {
        int cpu;
 
+       get_online_cpus();
+
+#ifdef CONFIG_HOTPLUG_CPU
+       unregister_cpu_notifier(&buffer->cpu_notify);
+#endif
+
        for_each_buffer_cpu(buffer, cpu)
                rb_free_cpu_buffer(buffer->buffers[cpu]);
 
+       put_online_cpus();
+
        free_cpumask_var(buffer->cpumask);
 
        kfree(buffer);
@@ -649,16 +744,15 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
                return size;
 
        mutex_lock(&buffer->mutex);
+       get_online_cpus();
 
        nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
 
        if (size < buffer_size) {
 
                /* easy case, just free pages */
-               if (RB_WARN_ON(buffer, nr_pages >= buffer->pages)) {
-                       mutex_unlock(&buffer->mutex);
-                       return -1;
-               }
+               if (RB_WARN_ON(buffer, nr_pages >= buffer->pages))
+                       goto out_fail;
 
                rm_pages = buffer->pages - nr_pages;
 
@@ -677,10 +771,8 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
         * add these pages to the cpu_buffers. Otherwise we just free
         * them all and return -ENOMEM;
         */
-       if (RB_WARN_ON(buffer, nr_pages <= buffer->pages)) {
-               mutex_unlock(&buffer->mutex);
-               return -1;
-       }
+       if (RB_WARN_ON(buffer, nr_pages <= buffer->pages))
+               goto out_fail;
 
        new_pages = nr_pages - buffer->pages;
 
@@ -705,13 +797,12 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
                rb_insert_pages(cpu_buffer, &pages, new_pages);
        }
 
-       if (RB_WARN_ON(buffer, !list_empty(&pages))) {
-               mutex_unlock(&buffer->mutex);
-               return -1;
-       }
+       if (RB_WARN_ON(buffer, !list_empty(&pages)))
+               goto out_fail;
 
  out:
        buffer->pages = nr_pages;
+       put_online_cpus();
        mutex_unlock(&buffer->mutex);
 
        return size;
@@ -721,8 +812,18 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
                list_del_init(&bpage->list);
                free_buffer_page(bpage);
        }
+       put_online_cpus();
        mutex_unlock(&buffer->mutex);
        return -ENOMEM;
+
+       /*
+        * Something went totally wrong, and we are too paranoid
+        * to even clean up the mess.
+        */
+ out_fail:
+       put_online_cpus();
+       mutex_unlock(&buffer->mutex);
+       return -1;
 }
 EXPORT_SYMBOL_GPL(ring_buffer_resize);
 
@@ -1564,12 +1665,15 @@ EXPORT_SYMBOL_GPL(ring_buffer_record_enable_cpu);
 unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu)
 {
        struct ring_buffer_per_cpu *cpu_buffer;
+       unsigned long ret;
 
        if (!cpumask_test_cpu(cpu, buffer->cpumask))
                return 0;
 
        cpu_buffer = buffer->buffers[cpu];
-       return cpu_buffer->entries;
+       ret = cpu_buffer->entries;
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(ring_buffer_entries_cpu);
 
@@ -1581,12 +1685,15 @@ EXPORT_SYMBOL_GPL(ring_buffer_entries_cpu);
 unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu)
 {
        struct ring_buffer_per_cpu *cpu_buffer;
+       unsigned long ret;
 
        if (!cpumask_test_cpu(cpu, buffer->cpumask))
                return 0;
 
        cpu_buffer = buffer->buffers[cpu];
-       return cpu_buffer->overrun;
+       ret = cpu_buffer->overrun;
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(ring_buffer_overrun_cpu);
 
@@ -1663,9 +1770,14 @@ static void rb_iter_reset(struct ring_buffer_iter *iter)
  */
 void ring_buffer_iter_reset(struct ring_buffer_iter *iter)
 {
-       struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer;
+       struct ring_buffer_per_cpu *cpu_buffer;
        unsigned long flags;
 
+       if (!iter)
+               return;
+
+       cpu_buffer = iter->cpu_buffer;
+
        spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
        rb_iter_reset(iter);
        spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
@@ -1900,9 +2012,6 @@ rb_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts)
        struct buffer_page *reader;
        int nr_loops = 0;
 
-       if (!cpumask_test_cpu(cpu, buffer->cpumask))
-               return NULL;
-
        cpu_buffer = buffer->buffers[cpu];
 
  again:
@@ -2031,6 +2140,9 @@ ring_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts)
        struct ring_buffer_event *event;
        unsigned long flags;
 
+       if (!cpumask_test_cpu(cpu, buffer->cpumask))
+               return NULL;
+
        spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
        event = rb_buffer_peek(buffer, cpu, ts);
        spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
@@ -2071,24 +2183,31 @@ ring_buffer_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
 struct ring_buffer_event *
 ring_buffer_consume(struct ring_buffer *buffer, int cpu, u64 *ts)
 {
-       struct ring_buffer_per_cpu *cpu_buffer = buffer->buffers[cpu];
-       struct ring_buffer_event *event;
+       struct ring_buffer_per_cpu *cpu_buffer;
+       struct ring_buffer_event *event = NULL;
        unsigned long flags;
 
+       /* might be called in atomic */
+       preempt_disable();
+
        if (!cpumask_test_cpu(cpu, buffer->cpumask))
-               return NULL;
+               goto out;
 
+       cpu_buffer = buffer->buffers[cpu];
        spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
 
        event = rb_buffer_peek(buffer, cpu, ts);
        if (!event)
-               goto out;
+               goto out_unlock;
 
        rb_advance_reader(cpu_buffer);
 
- out:
+ out_unlock:
        spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
 
+ out:
+       preempt_enable();
+
        return event;
 }
 EXPORT_SYMBOL_GPL(ring_buffer_consume);
@@ -2268,6 +2387,7 @@ int ring_buffer_empty(struct ring_buffer *buffer)
                if (!rb_per_cpu_empty(cpu_buffer))
                        return 0;
        }
+
        return 1;
 }
 EXPORT_SYMBOL_GPL(ring_buffer_empty);
@@ -2280,12 +2400,16 @@ EXPORT_SYMBOL_GPL(ring_buffer_empty);
 int ring_buffer_empty_cpu(struct ring_buffer *buffer, int cpu)
 {
        struct ring_buffer_per_cpu *cpu_buffer;
+       int ret;
 
        if (!cpumask_test_cpu(cpu, buffer->cpumask))
                return 1;
 
        cpu_buffer = buffer->buffers[cpu];
-       return rb_per_cpu_empty(cpu_buffer);
+       ret = rb_per_cpu_empty(cpu_buffer);
+
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(ring_buffer_empty_cpu);
 
@@ -2304,32 +2428,35 @@ int ring_buffer_swap_cpu(struct ring_buffer *buffer_a,
 {
        struct ring_buffer_per_cpu *cpu_buffer_a;
        struct ring_buffer_per_cpu *cpu_buffer_b;
+       int ret = -EINVAL;
 
        if (!cpumask_test_cpu(cpu, buffer_a->cpumask) ||
            !cpumask_test_cpu(cpu, buffer_b->cpumask))
-               return -EINVAL;
+               goto out;
 
        /* At least make sure the two buffers are somewhat the same */
        if (buffer_a->pages != buffer_b->pages)
-               return -EINVAL;
+               goto out;
+
+       ret = -EAGAIN;
 
        if (ring_buffer_flags != RB_BUFFERS_ON)
-               return -EAGAIN;
+               goto out;
 
        if (atomic_read(&buffer_a->record_disabled))
-               return -EAGAIN;
+               goto out;
 
        if (atomic_read(&buffer_b->record_disabled))
-               return -EAGAIN;
+               goto out;
 
        cpu_buffer_a = buffer_a->buffers[cpu];
        cpu_buffer_b = buffer_b->buffers[cpu];
 
        if (atomic_read(&cpu_buffer_a->record_disabled))
-               return -EAGAIN;
+               goto out;
 
        if (atomic_read(&cpu_buffer_b->record_disabled))
-               return -EAGAIN;
+               goto out;
 
        /*
         * We can't do a synchronize_sched here because this
@@ -2349,7 +2476,9 @@ int ring_buffer_swap_cpu(struct ring_buffer *buffer_a,
        atomic_dec(&cpu_buffer_a->record_disabled);
        atomic_dec(&cpu_buffer_b->record_disabled);
 
-       return 0;
+       ret = 0;
+out:
+       return ret;
 }
 EXPORT_SYMBOL_GPL(ring_buffer_swap_cpu);
 
@@ -2464,27 +2593,30 @@ int ring_buffer_read_page(struct ring_buffer *buffer,
        u64 save_timestamp;
        int ret = -1;
 
+       if (!cpumask_test_cpu(cpu, buffer->cpumask))
+               goto out;
+
        /*
         * If len is not big enough to hold the page header, then
         * we can not copy anything.
         */
        if (len <= BUF_PAGE_HDR_SIZE)
-               return -1;
+               goto out;
 
        len -= BUF_PAGE_HDR_SIZE;
 
        if (!data_page)
-               return -1;
+               goto out;
 
        bpage = *data_page;
        if (!bpage)
-               return -1;
+               goto out;
 
        spin_lock_irqsave(&cpu_buffer->reader_lock, flags);
 
        reader = rb_get_reader_page(cpu_buffer);
        if (!reader)
-               goto out;
+               goto out_unlock;
 
        event = rb_reader_event(cpu_buffer);
 
@@ -2506,7 +2638,7 @@ int ring_buffer_read_page(struct ring_buffer *buffer,
                unsigned int size;
 
                if (full)
-                       goto out;
+                       goto out_unlock;
 
                if (len > (commit - read))
                        len = (commit - read);
@@ -2514,7 +2646,7 @@ int ring_buffer_read_page(struct ring_buffer *buffer,
                size = rb_event_length(event);
 
                if (len < size)
-                       goto out;
+                       goto out_unlock;
 
                /* save the current timestamp, since the user will need it */
                save_timestamp = cpu_buffer->read_stamp;
@@ -2553,9 +2685,10 @@ int ring_buffer_read_page(struct ring_buffer *buffer,
        }
        ret = read;
 
- out:
+ out_unlock:
        spin_unlock_irqrestore(&cpu_buffer->reader_lock, flags);
 
+ out:
        return ret;
 }
 
@@ -2629,3 +2762,42 @@ static __init int rb_init_debugfs(void)
 }
 
 fs_initcall(rb_init_debugfs);
+
+#ifdef CONFIG_HOTPLUG_CPU
+static int __cpuinit rb_cpu_notify(struct notifier_block *self,
+                                  unsigned long action, void *hcpu)
+{
+       struct ring_buffer *buffer =
+               container_of(self, struct ring_buffer, cpu_notify);
+       long cpu = (long)hcpu;
+
+       switch (action) {
+       case CPU_UP_PREPARE:
+       case CPU_UP_PREPARE_FROZEN:
+               if (cpu_isset(cpu, *buffer->cpumask))
+                       return NOTIFY_OK;
+
+               buffer->buffers[cpu] =
+                       rb_allocate_cpu_buffer(buffer, cpu);
+               if (!buffer->buffers[cpu]) {
+                       WARN(1, "failed to allocate ring buffer on CPU %ld\n",
+                            cpu);
+                       return NOTIFY_OK;
+               }
+               smp_wmb();
+               cpu_set(cpu, *buffer->cpumask);
+               break;
+       case CPU_DOWN_PREPARE:
+       case CPU_DOWN_PREPARE_FROZEN:
+               /*
+                * Do nothing.
+                *  If we were to free the buffer, then the user would
+                *  lose any trace that was in the buffer.
+                */
+               break;
+       default:
+               break;
+       }
+       return NOTIFY_OK;
+}
+#endif
index 5c9c6d9070547724ea979604648f89ed4c424244..efe3202c02092188d14a3eb32f8c9d92024a8dca 100644 (file)
 unsigned long __read_mostly    tracing_max_latency;
 unsigned long __read_mostly    tracing_thresh;
 
+/*
+ * On boot up, the ring buffer is set to the minimum size, so that
+ * we do not waste memory on systems that are not using tracing.
+ */
+static int ring_buffer_expanded;
+
 /*
  * We need to change this state when a selftest is running.
  * A selftest will lurk into the ring-buffer to count the
@@ -128,6 +134,8 @@ static int __init set_ftrace(char *str)
 {
        strncpy(bootup_tracer_buf, str, BOOTUP_TRACER_SIZE);
        default_bootup_tracer = bootup_tracer_buf;
+       /* We are using ftrace early, expand it */
+       ring_buffer_expanded = 1;
        return 1;
 }
 __setup("ftrace=", set_ftrace);
@@ -1171,10 +1179,10 @@ void trace_graph_return(struct ftrace_graph_ret *trace)
 
 
 /**
- * trace_vprintk - write binary msg to tracing buffer
+ * trace_vbprintk - write binary msg to tracing buffer
  *
  */
-int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args)
+int trace_vbprintk(unsigned long ip, int depth, const char *fmt, va_list args)
 {
        static raw_spinlock_t trace_buf_lock =
                (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
@@ -1183,7 +1191,7 @@ int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args)
        struct ring_buffer_event *event;
        struct trace_array *tr = &global_trace;
        struct trace_array_cpu *data;
-       struct print_entry *entry;
+       struct bprint_entry *entry;
        unsigned long flags;
        int resched;
        int cpu, len = 0, size, pc;
@@ -1211,7 +1219,7 @@ int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args)
                goto out_unlock;
 
        size = sizeof(*entry) + sizeof(u32) * len;
-       event = trace_buffer_lock_reserve(tr, TRACE_PRINT, size, flags, pc);
+       event = trace_buffer_lock_reserve(tr, TRACE_BPRINT, size, flags, pc);
        if (!event)
                goto out_unlock;
        entry = ring_buffer_event_data(event);
@@ -1232,6 +1240,60 @@ out:
 
        return len;
 }
+EXPORT_SYMBOL_GPL(trace_vbprintk);
+
+int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args)
+{
+       static raw_spinlock_t trace_buf_lock = __RAW_SPIN_LOCK_UNLOCKED;
+       static char trace_buf[TRACE_BUF_SIZE];
+
+       struct ring_buffer_event *event;
+       struct trace_array *tr = &global_trace;
+       struct trace_array_cpu *data;
+       int cpu, len = 0, size, pc;
+       struct print_entry *entry;
+       unsigned long irq_flags;
+
+       if (tracing_disabled || tracing_selftest_running)
+               return 0;
+
+       pc = preempt_count();
+       preempt_disable_notrace();
+       cpu = raw_smp_processor_id();
+       data = tr->data[cpu];
+
+       if (unlikely(atomic_read(&data->disabled)))
+               goto out;
+
+       pause_graph_tracing();
+       raw_local_irq_save(irq_flags);
+       __raw_spin_lock(&trace_buf_lock);
+       len = vsnprintf(trace_buf, TRACE_BUF_SIZE, fmt, args);
+
+       len = min(len, TRACE_BUF_SIZE-1);
+       trace_buf[len] = 0;
+
+       size = sizeof(*entry) + len + 1;
+       event = trace_buffer_lock_reserve(tr, TRACE_PRINT, size, irq_flags, pc);
+       if (!event)
+               goto out_unlock;
+       entry = ring_buffer_event_data(event);
+       entry->ip                       = ip;
+       entry->depth                    = depth;
+
+       memcpy(&entry->buf, trace_buf, len);
+       entry->buf[len] = 0;
+       ring_buffer_unlock_commit(tr->buffer, event);
+
+ out_unlock:
+       __raw_spin_unlock(&trace_buf_lock);
+       raw_local_irq_restore(irq_flags);
+       unpause_graph_tracing();
+ out:
+       preempt_enable_notrace();
+
+       return len;
+}
 EXPORT_SYMBOL_GPL(trace_vprintk);
 
 enum trace_file_type {
@@ -1620,6 +1682,22 @@ static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
        return TRACE_TYPE_HANDLED;
 }
 
+static enum print_line_t print_bprintk_msg_only(struct trace_iterator *iter)
+{
+       struct trace_seq *s = &iter->seq;
+       struct trace_entry *entry = iter->ent;
+       struct bprint_entry *field;
+       int ret;
+
+       trace_assign_type(field, entry);
+
+       ret = trace_seq_bprintf(s, field->fmt, field->buf);
+       if (!ret)
+               return TRACE_TYPE_PARTIAL_LINE;
+
+       return TRACE_TYPE_HANDLED;
+}
+
 static enum print_line_t print_printk_msg_only(struct trace_iterator *iter)
 {
        struct trace_seq *s = &iter->seq;
@@ -1629,7 +1707,7 @@ static enum print_line_t print_printk_msg_only(struct trace_iterator *iter)
 
        trace_assign_type(field, entry);
 
-       ret = trace_seq_bprintf(s, field->fmt, field->buf);
+       ret = trace_seq_printf(s, "%s", field->buf);
        if (!ret)
                return TRACE_TYPE_PARTIAL_LINE;
 
@@ -1658,6 +1736,19 @@ static int trace_empty(struct trace_iterator *iter)
 {
        int cpu;
 
+       /* If we are looking at one CPU buffer, only check that one */
+       if (iter->cpu_file != TRACE_PIPE_ALL_CPU) {
+               cpu = iter->cpu_file;
+               if (iter->buffer_iter[cpu]) {
+                       if (!ring_buffer_iter_empty(iter->buffer_iter[cpu]))
+                               return 0;
+               } else {
+                       if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu))
+                               return 0;
+               }
+               return 1;
+       }
+
        for_each_tracing_cpu(cpu) {
                if (iter->buffer_iter[cpu]) {
                        if (!ring_buffer_iter_empty(iter->buffer_iter[cpu]))
@@ -1681,6 +1772,11 @@ static enum print_line_t print_trace_line(struct trace_iterator *iter)
                        return ret;
        }
 
+       if (iter->ent->type == TRACE_BPRINT &&
+                       trace_flags & TRACE_ITER_PRINTK &&
+                       trace_flags & TRACE_ITER_PRINTK_MSGONLY)
+               return print_bprintk_msg_only(iter);
+
        if (iter->ent->type == TRACE_PRINT &&
                        trace_flags & TRACE_ITER_PRINTK &&
                        trace_flags & TRACE_ITER_PRINTK_MSGONLY)
@@ -1784,17 +1880,11 @@ __tracing_open(struct inode *inode, struct file *file)
 
                        iter->buffer_iter[cpu] =
                                ring_buffer_read_start(iter->tr->buffer, cpu);
-
-                       if (!iter->buffer_iter[cpu])
-                               goto fail_buffer;
                }
        } else {
                cpu = iter->cpu_file;
                iter->buffer_iter[cpu] =
                                ring_buffer_read_start(iter->tr->buffer, cpu);
-
-               if (!iter->buffer_iter[cpu])
-                       goto fail;
        }
 
        /* TODO stop tracer */
@@ -2315,6 +2405,75 @@ int tracer_init(struct tracer *t, struct trace_array *tr)
        return t->init(tr);
 }
 
+static int tracing_resize_ring_buffer(unsigned long size)
+{
+       int ret;
+
+       /*
+        * If kernel or user changes the size of the ring buffer
+        * we use the size that was given, and we can forget about
+        * expanding it later.
+        */
+       ring_buffer_expanded = 1;
+
+       ret = ring_buffer_resize(global_trace.buffer, size);
+       if (ret < 0)
+               return ret;
+
+       ret = ring_buffer_resize(max_tr.buffer, size);
+       if (ret < 0) {
+               int r;
+
+               r = ring_buffer_resize(global_trace.buffer,
+                                      global_trace.entries);
+               if (r < 0) {
+                       /*
+                        * AARGH! We are left with different
+                        * size max buffer!!!!
+                        * The max buffer is our "snapshot" buffer.
+                        * When a tracer needs a snapshot (one of the
+                        * latency tracers), it swaps the max buffer
+                        * with the saved snap shot. We succeeded to
+                        * update the size of the main buffer, but failed to
+                        * update the size of the max buffer. But when we tried
+                        * to reset the main buffer to the original size, we
+                        * failed there too. This is very unlikely to
+                        * happen, but if it does, warn and kill all
+                        * tracing.
+                        */
+                       WARN_ON(1);
+                       tracing_disabled = 1;
+               }
+               return ret;
+       }
+
+       global_trace.entries = size;
+
+       return ret;
+}
+
+/**
+ * tracing_update_buffers - used by tracing facility to expand ring buffers
+ *
+ * To save on memory when the tracing is never used on a system with it
+ * configured in. The ring buffers are set to a minimum size. But once
+ * a user starts to use the tracing facility, then they need to grow
+ * to their default size.
+ *
+ * This function is to be called when a tracer is about to be used.
+ */
+int tracing_update_buffers(void)
+{
+       int ret = 0;
+
+       mutex_lock(&trace_types_lock);
+       if (!ring_buffer_expanded)
+               ret = tracing_resize_ring_buffer(trace_buf_size);
+       mutex_unlock(&trace_types_lock);
+
+       return ret;
+}
+
 struct trace_option_dentry;
 
 static struct trace_option_dentry *
@@ -2331,6 +2490,14 @@ static int tracing_set_tracer(const char *buf)
        int ret = 0;
 
        mutex_lock(&trace_types_lock);
+
+       if (!ring_buffer_expanded) {
+               ret = tracing_resize_ring_buffer(trace_buf_size);
+               if (ret < 0)
+                       return ret;
+               ret = 0;
+       }
+
        for (t = trace_types; t; t = t->next) {
                if (strcmp(t->name, buf) == 0)
                        break;
@@ -2856,10 +3023,18 @@ tracing_entries_read(struct file *filp, char __user *ubuf,
                     size_t cnt, loff_t *ppos)
 {
        struct trace_array *tr = filp->private_data;
-       char buf[64];
+       char buf[96];
        int r;
 
-       r = sprintf(buf, "%lu\n", tr->entries >> 10);
+       mutex_lock(&trace_types_lock);
+       if (!ring_buffer_expanded)
+               r = sprintf(buf, "%lu (expanded: %lu)\n",
+                           tr->entries >> 10,
+                           trace_buf_size >> 10);
+       else
+               r = sprintf(buf, "%lu\n", tr->entries >> 10);
+       mutex_unlock(&trace_types_lock);
+
        return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
 }
 
@@ -2903,28 +3078,11 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
        val <<= 10;
 
        if (val != global_trace.entries) {
-               ret = ring_buffer_resize(global_trace.buffer, val);
+               ret = tracing_resize_ring_buffer(val);
                if (ret < 0) {
                        cnt = ret;
                        goto out;
                }
-
-               ret = ring_buffer_resize(max_tr.buffer, val);
-               if (ret < 0) {
-                       int r;
-                       cnt = ret;
-                       r = ring_buffer_resize(global_trace.buffer,
-                                              global_trace.entries);
-                       if (r < 0) {
-                               /* AARGH! We are left with different
-                                * size max buffer!!!! */
-                               WARN_ON(1);
-                               tracing_disabled = 1;
-                       }
-                       goto out;
-               }
-
-               global_trace.entries = val;
        }
 
        filp->f_pos += cnt;
@@ -3385,6 +3543,11 @@ static void tracing_init_debugfs_percpu(long cpu)
                                (void *) cpu, &tracing_fops);
        if (!entry)
                pr_warning("Could not create debugfs 'trace' entry\n");
+
+       entry = debugfs_create_file("trace_pipe_raw", 0444, d_cpu,
+                                   (void *) cpu, &tracing_buffers_fops);
+       if (!entry)
+               pr_warning("Could not create debugfs 'trace_pipe_raw' entry\n");
 }
 
 #ifdef CONFIG_FTRACE_SELFTEST
@@ -3668,7 +3831,6 @@ static __init void create_trace_options_dir(void)
 static __init int tracer_init_debugfs(void)
 {
        struct dentry *d_tracer;
-       struct dentry *buffers;
        struct dentry *entry;
        int cpu;
 
@@ -3741,26 +3903,6 @@ static __init int tracer_init_debugfs(void)
                pr_warning("Could not create debugfs "
                           "'trace_marker' entry\n");
 
-       buffers = debugfs_create_dir("binary_buffers", d_tracer);
-
-       if (!buffers)
-               pr_warning("Could not create buffers directory\n");
-       else {
-               int cpu;
-               char buf[64];
-
-               for_each_tracing_cpu(cpu) {
-                       sprintf(buf, "%d", cpu);
-
-                       entry = debugfs_create_file(buf, 0444, buffers,
-                                                   (void *)(long)cpu,
-                                                   &tracing_buffers_fops);
-                       if (!entry)
-                               pr_warning("Could not create debugfs buffers "
-                                          "'%s' entry\n", buf);
-               }
-       }
-
 #ifdef CONFIG_DYNAMIC_FTRACE
        entry = debugfs_create_file("dyn_ftrace_total_info", 0444, d_tracer,
                                    &ftrace_update_tot_cnt,
@@ -3916,6 +4058,7 @@ void ftrace_dump(void)
 __init static int tracer_alloc_buffers(void)
 {
        struct trace_array_cpu *data;
+       int ring_buf_size;
        int i;
        int ret = -ENOMEM;
 
@@ -3928,12 +4071,18 @@ __init static int tracer_alloc_buffers(void)
        if (!alloc_cpumask_var(&tracing_reader_cpumask, GFP_KERNEL))
                goto out_free_tracing_cpumask;
 
+       /* To save memory, keep the ring buffer size to its minimum */
+       if (ring_buffer_expanded)
+               ring_buf_size = trace_buf_size;
+       else
+               ring_buf_size = 1;
+
        cpumask_copy(tracing_buffer_mask, cpu_possible_mask);
        cpumask_copy(tracing_cpumask, cpu_all_mask);
        cpumask_clear(tracing_reader_cpumask);
 
        /* TODO: make the number of buffers hot pluggable with CPUS */
-       global_trace.buffer = ring_buffer_alloc(trace_buf_size,
+       global_trace.buffer = ring_buffer_alloc(ring_buf_size,
                                                   TRACE_BUFFER_FLAGS);
        if (!global_trace.buffer) {
                printk(KERN_ERR "tracer: failed to allocate ring buffer!\n");
@@ -3944,7 +4093,7 @@ __init static int tracer_alloc_buffers(void)
 
 
 #ifdef CONFIG_TRACER_MAX_TRACE
-       max_tr.buffer = ring_buffer_alloc(trace_buf_size,
+       max_tr.buffer = ring_buffer_alloc(ring_buf_size,
                                             TRACE_BUFFER_FLAGS);
        if (!max_tr.buffer) {
                printk(KERN_ERR "tracer: failed to allocate max ring buffer!\n");
index 3d49daae47dcca70bd2d83f227dceb6e2c0b04ce..56ce34d90b030a843420dad0c16c031e8c87d7da 100644 (file)
@@ -20,6 +20,7 @@ enum trace_type {
        TRACE_WAKE,
        TRACE_STACK,
        TRACE_PRINT,
+       TRACE_BPRINT,
        TRACE_SPECIAL,
        TRACE_MMIO_RW,
        TRACE_MMIO_MAP,
@@ -119,7 +120,7 @@ struct userstack_entry {
 /*
  * trace_printk entry:
  */
-struct print_entry {
+struct bprint_entry {
        struct trace_entry      ent;
        unsigned long           ip;
        int                     depth;
@@ -127,6 +128,13 @@ struct print_entry {
        u32                     buf[];
 };
 
+struct print_entry {
+       struct trace_entry      ent;
+       unsigned long           ip;
+       int                     depth;
+       char                    buf[];
+};
+
 #define TRACE_OLD_SIZE         88
 
 struct trace_field_cont {
@@ -288,6 +296,7 @@ extern void __ftrace_bad_type(void);
                IF_ASSIGN(var, ent, struct stack_entry, TRACE_STACK);   \
                IF_ASSIGN(var, ent, struct userstack_entry, TRACE_USER_STACK);\
                IF_ASSIGN(var, ent, struct print_entry, TRACE_PRINT);   \
+               IF_ASSIGN(var, ent, struct bprint_entry, TRACE_BPRINT); \
                IF_ASSIGN(var, ent, struct special_entry, 0);           \
                IF_ASSIGN(var, ent, struct trace_mmiotrace_rw,          \
                          TRACE_MMIO_RW);                               \
@@ -572,6 +581,8 @@ extern int trace_selftest_startup_branch(struct tracer *trace,
 extern void *head_page(struct trace_array_cpu *data);
 extern long ns2usecs(cycle_t nsec);
 extern int
+trace_vbprintk(unsigned long ip, int depth, const char *fmt, va_list args);
+extern int
 trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args);
 
 extern unsigned long trace_flags;
@@ -739,6 +750,9 @@ static inline void trace_branch_disable(void)
 }
 #endif /* CONFIG_BRANCH_TRACER */
 
+/* set ring buffers to default size if not already done so */
+int tracing_update_buffers(void);
+
 /* trace event type bit fields, not numeric */
 enum {
        TRACE_EVENT_TYPE_PRINTF         = 1,
@@ -761,4 +775,26 @@ void event_trace_printk(unsigned long ip, const char *fmt, ...);
 extern struct ftrace_event_call __start_ftrace_events[];
 extern struct ftrace_event_call __stop_ftrace_events[];
 
+extern const char *__start___trace_bprintk_fmt[];
+extern const char *__stop___trace_bprintk_fmt[];
+
+/*
+ * The double __builtin_constant_p is because gcc will give us an error
+ * if we try to allocate the static variable to fmt if it is not a
+ * constant. Even with the outer if statement optimizing out.
+ */
+#define event_trace_printk(ip, fmt, args...)                           \
+do {                                                                   \
+       __trace_printk_check_format(fmt, ##args);                       \
+       tracing_record_cmdline(current);                                \
+       if (__builtin_constant_p(fmt)) {                                \
+               static const char *trace_printk_fmt                     \
+                 __attribute__((section("__trace_printk_fmt"))) =      \
+                       __builtin_constant_p(fmt) ? fmt : NULL;         \
+                                                                       \
+               __trace_bprintk(ip, trace_printk_fmt, ##args);          \
+       } else                                                          \
+               __trace_printk(ip, fmt, ##args);                        \
+} while (0)
+
 #endif /* _LINUX_KERNEL_TRACE_H */
index 5cca4c978bde06a80274446b879a57d97ce8671c..019915063fe611b5748bf5d43c29da00f4ece657 100644 (file)
@@ -102,7 +102,7 @@ TRACE_EVENT_FORMAT(user_stack, TRACE_USER_STACK, userstack_entry, ignore,
                 "\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n")
 );
 
-TRACE_EVENT_FORMAT(print, TRACE_PRINT, print_entry, ignore,
+TRACE_EVENT_FORMAT(bprint, TRACE_BPRINT, bprint_entry, ignore,
        TRACE_STRUCT(
                TRACE_FIELD(unsigned long, ip, ip)
                TRACE_FIELD(unsigned int, depth, depth)
@@ -112,6 +112,15 @@ TRACE_EVENT_FORMAT(print, TRACE_PRINT, print_entry, ignore,
        TP_RAW_FMT("%08lx (%d) fmt:%p %s")
 );
 
+TRACE_EVENT_FORMAT(print, TRACE_PRINT, print_entry, ignore,
+       TRACE_STRUCT(
+               TRACE_FIELD(unsigned long, ip, ip)
+               TRACE_FIELD(unsigned int, depth, depth)
+               TRACE_FIELD_ZERO_CHAR(buf)
+       ),
+       TP_RAW_FMT("%08lx (%d) fmt:%p %s")
+);
+
 TRACE_EVENT_FORMAT(branch, TRACE_BRANCH, trace_branch, ignore,
        TRACE_STRUCT(
                TRACE_FIELD(unsigned int, line, line)
index 769dfd00fc859a1b4ba78b7e30696c651d5b904e..238ea95a41159ddee14b8fa0fb3ae1f765147925 100644 (file)
@@ -24,16 +24,6 @@ static DEFINE_MUTEX(event_mutex);
             (unsigned long)event < (unsigned long)__stop_ftrace_events; \
             event++)
 
-void event_trace_printk(unsigned long ip, const char *fmt, ...)
-{
-       va_list ap;
-
-       va_start(ap, fmt);
-       tracing_record_cmdline(current);
-       trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap);
-       va_end(ap);
-}
-
 static void ftrace_clear_events(void)
 {
        struct ftrace_event_call *call = (void *)__start_ftrace_events;
@@ -141,6 +131,10 @@ ftrace_event_write(struct file *file, const char __user *ubuf,
        if (!cnt || cnt < 0)
                return 0;
 
+       ret = tracing_update_buffers();
+       if (ret < 0)
+               return ret;
+
        ret = get_user(ch, ubuf++);
        if (ret)
                return ret;
@@ -331,6 +325,10 @@ event_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
        if (ret < 0)
                return ret;
 
+       ret = tracing_update_buffers();
+       if (ret < 0)
+               return ret;
+
        switch (val) {
        case 0:
        case 1:
index ca347afd6aa038ff05be1479e787a17ea1c17765..5117c43f5c678c5dc4d46dc278d2f14574a9893c 100644 (file)
@@ -57,7 +57,7 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags)      \
                                                                        \
        field = (typeof(field))entry;                                   \
                                                                        \
-       ret = trace_seq_printf(s, print);                               \
+       ret = trace_seq_printf(s, #call ": " print);                    \
        if (!ret)                                                       \
                return TRACE_TYPE_PARTIAL_LINE;                         \
                                                                        \
index 8566c14b3e9aec899bc1964d20b88cee2fc8660b..4c388607ed67065bb90cb91a1195766878ed465d 100644 (file)
@@ -684,7 +684,7 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
 }
 
 static enum print_line_t
-print_graph_comment(struct print_entry *trace, struct trace_seq *s,
+print_graph_comment(struct bprint_entry *trace, struct trace_seq *s,
                   struct trace_entry *ent, struct trace_iterator *iter)
 {
        int i;
@@ -781,8 +781,8 @@ print_graph_function(struct trace_iterator *iter)
                trace_assign_type(field, entry);
                return print_graph_return(&field->ret, s, entry, iter);
        }
-       case TRACE_PRINT: {
-               struct print_entry *field;
+       case TRACE_BPRINT: {
+               struct bprint_entry *field;
                trace_assign_type(field, entry);
                return print_graph_comment(field, s, entry, iter);
        }
index 23e346a734cac6f1203687edeb266517e423ee6f..f095916e477ffe3e01edf303598a709f6cd09c8d 100644 (file)
@@ -254,6 +254,7 @@ static enum print_line_t mmio_print_mark(struct trace_iterator *iter)
 {
        struct trace_entry *entry = iter->ent;
        struct print_entry *print = (struct print_entry *)entry;
+       const char *msg         = print->buf;
        struct trace_seq *s     = &iter->seq;
        unsigned long long t    = ns2usecs(iter->ts);
        unsigned long usec_rem  = do_div(t, USEC_PER_SEC);
@@ -261,11 +262,7 @@ static enum print_line_t mmio_print_mark(struct trace_iterator *iter)
        int ret;
 
        /* The trailing newline must be in the message. */
-       ret = trace_seq_printf(s, "MARK %u.%06lu ", secs, usec_rem);
-       if (!ret)
-               return TRACE_TYPE_PARTIAL_LINE;
-
-       ret = trace_seq_bprintf(s, print->fmt, print->buf);
+       ret = trace_seq_printf(s, "MARK %u.%06lu %s", secs, usec_rem, msg);
        if (!ret)
                return TRACE_TYPE_PARTIAL_LINE;
 
index 491832af9ba15c8b24b29ff80a00acc122b51caa..ea9d3b410c7a115cc3ab64c1f95c191c82851918 100644 (file)
@@ -832,13 +832,13 @@ static struct trace_event trace_user_stack_event = {
        .binary         = trace_special_bin,
 };
 
-/* TRACE_PRINT */
+/* TRACE_BPRINT */
 static enum print_line_t
-trace_print_print(struct trace_iterator *iter, int flags)
+trace_bprint_print(struct trace_iterator *iter, int flags)
 {
        struct trace_entry *entry = iter->ent;
        struct trace_seq *s = &iter->seq;
-       struct print_entry *field;
+       struct bprint_entry *field;
 
        trace_assign_type(field, entry);
 
@@ -858,9 +858,10 @@ trace_print_print(struct trace_iterator *iter, int flags)
 }
 
 
-static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags)
+static enum print_line_t
+trace_bprint_raw(struct trace_iterator *iter, int flags)
 {
-       struct print_entry *field;
+       struct bprint_entry *field;
        struct trace_seq *s = &iter->seq;
 
        trace_assign_type(field, iter->ent);
@@ -878,12 +879,55 @@ static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags)
 }
 
 
+static struct trace_event trace_bprint_event = {
+       .type           = TRACE_BPRINT,
+       .trace          = trace_bprint_print,
+       .raw            = trace_bprint_raw,
+};
+
+/* TRACE_PRINT */
+static enum print_line_t trace_print_print(struct trace_iterator *iter,
+                                          int flags)
+{
+       struct print_entry *field;
+       struct trace_seq *s = &iter->seq;
+
+       trace_assign_type(field, iter->ent);
+
+       if (!seq_print_ip_sym(s, field->ip, flags))
+               goto partial;
+
+       if (!trace_seq_printf(s, ": %s", field->buf))
+               goto partial;
+
+       return TRACE_TYPE_HANDLED;
+
+ partial:
+       return TRACE_TYPE_PARTIAL_LINE;
+}
+
+static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags)
+{
+       struct print_entry *field;
+
+       trace_assign_type(field, iter->ent);
+
+       if (!trace_seq_printf(&iter->seq, "# %lx %s", field->ip, field->buf))
+               goto partial;
+
+       return TRACE_TYPE_HANDLED;
+
+ partial:
+       return TRACE_TYPE_PARTIAL_LINE;
+}
+
 static struct trace_event trace_print_event = {
-       .type           = TRACE_PRINT,
+       .type           = TRACE_PRINT,
        .trace          = trace_print_print,
        .raw            = trace_print_raw,
 };
 
+
 static struct trace_event *events[] __initdata = {
        &trace_fn_event,
        &trace_ctx_event,
@@ -891,6 +935,7 @@ static struct trace_event *events[] __initdata = {
        &trace_special_event,
        &trace_stack_event,
        &trace_user_stack_event,
+       &trace_bprint_event,
        &trace_print_event,
        NULL
 };
index a50aea22e929d6a1eaf9d402ff6bc341e18e625d..486785214e3ecaaff82ff78b2f64f9171888513e 100644 (file)
@@ -4,18 +4,19 @@
  * Copyright (C) 2008 Lai Jiangshan <laijs@cn.fujitsu.com>
  *
  */
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
 #include <linux/kernel.h>
 #include <linux/ftrace.h>
 #include <linux/string.h>
+#include <linux/module.h>
+#include <linux/marker.h>
+#include <linux/mutex.h>
 #include <linux/ctype.h>
 #include <linux/list.h>
-#include <linux/mutex.h>
 #include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/seq_file.h>
 #include <linux/fs.h>
-#include <linux/marker.h>
-#include <linux/uaccess.h>
 
 #include "trace.h"
 
@@ -99,7 +100,7 @@ struct notifier_block module_trace_bprintk_format_nb = {
        .notifier_call = module_trace_bprintk_format_notify,
 };
 
-int __trace_printk(unsigned long ip, const char *fmt, ...)
+int __trace_bprintk(unsigned long ip, const char *fmt, ...)
  {
        int ret;
        va_list ap;
@@ -111,13 +112,13 @@ int __trace_printk(unsigned long ip, const char *fmt, ...)
                return 0;
 
        va_start(ap, fmt);
-       ret = trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap);
+       ret = trace_vbprintk(ip, task_curr_ret_stack(current), fmt, ap);
        va_end(ap);
        return ret;
 }
-EXPORT_SYMBOL_GPL(__trace_printk);
+EXPORT_SYMBOL_GPL(__trace_bprintk);
 
-int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap)
+int __ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap)
  {
        if (unlikely(!fmt))
                return 0;
@@ -125,10 +126,141 @@ int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap)
        if (!(trace_flags & TRACE_ITER_PRINTK))
                return 0;
 
+       return trace_vbprintk(ip, task_curr_ret_stack(current), fmt, ap);
+}
+EXPORT_SYMBOL_GPL(__ftrace_vbprintk);
+
+int __trace_printk(unsigned long ip, const char *fmt, ...)
+{
+       int ret;
+       va_list ap;
+
+       if (!(trace_flags & TRACE_ITER_PRINTK))
+               return 0;
+
+       va_start(ap, fmt);
+       ret = trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap);
+       va_end(ap);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(__trace_printk);
+
+int __ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap)
+{
+       if (!(trace_flags & TRACE_ITER_PRINTK))
+               return 0;
+
        return trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap);
 }
 EXPORT_SYMBOL_GPL(__ftrace_vprintk);
 
+static void *
+t_next(struct seq_file *m, void *v, loff_t *pos)
+{
+       const char **fmt = m->private;
+       const char **next = fmt;
+
+       (*pos)++;
+
+       if ((unsigned long)fmt >= (unsigned long)__stop___trace_bprintk_fmt)
+               return NULL;
+
+       next = fmt;
+       m->private = ++next;
+
+       return fmt;
+}
+
+static void *t_start(struct seq_file *m, loff_t *pos)
+{
+       return t_next(m, NULL, pos);
+}
+
+static int t_show(struct seq_file *m, void *v)
+{
+       const char **fmt = v;
+       const char *str = *fmt;
+       int i;
+
+       seq_printf(m, "0x%lx : \"", (unsigned long)fmt);
+
+       /*
+        * Tabs and new lines need to be converted.
+        */
+       for (i = 0; str[i]; i++) {
+               switch (str[i]) {
+               case '\n':
+                       seq_puts(m, "\\n");
+                       break;
+               case '\t':
+                       seq_puts(m, "\\t");
+                       break;
+               case '\\':
+                       seq_puts(m, "\\");
+                       break;
+               case '"':
+                       seq_puts(m, "\\\"");
+                       break;
+               default:
+                       seq_putc(m, str[i]);
+               }
+       }
+       seq_puts(m, "\"\n");
+
+       return 0;
+}
+
+static void t_stop(struct seq_file *m, void *p)
+{
+}
+
+static const struct seq_operations show_format_seq_ops = {
+       .start = t_start,
+       .next = t_next,
+       .show = t_show,
+       .stop = t_stop,
+};
+
+static int
+ftrace_formats_open(struct inode *inode, struct file *file)
+{
+       int ret;
+
+       ret = seq_open(file, &show_format_seq_ops);
+       if (!ret) {
+               struct seq_file *m = file->private_data;
+
+               m->private = __start___trace_bprintk_fmt;
+       }
+       return ret;
+}
+
+static const struct file_operations ftrace_formats_fops = {
+       .open = ftrace_formats_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+static __init int init_trace_printk_function_export(void)
+{
+       struct dentry *d_tracer;
+       struct dentry *entry;
+
+       d_tracer = tracing_init_dentry();
+       if (!d_tracer)
+               return 0;
+
+       entry = debugfs_create_file("printk_formats", 0444, d_tracer,
+                                   NULL, &ftrace_formats_fops);
+       if (!entry)
+               pr_warning("Could not create debugfs "
+                          "'printk_formats' entry\n");
+
+       return 0;
+}
+
+fs_initcall(init_trace_printk_function_export);
 
 static __init int init_trace_printk(void)
 {
index d0871bc0aca5d0f670f9363cf49489fd9e85cf0c..c750f65f9661531273ee16553623b405268fc758 100644 (file)
@@ -245,16 +245,31 @@ static int trace_lookup_stack(struct seq_file *m, long i)
 #endif
 }
 
+static void print_disabled(struct seq_file *m)
+{
+       seq_puts(m, "#\n"
+                "#  Stack tracer disabled\n"
+                "#\n"
+                "# To enable the stack tracer, either add 'stacktrace' to the\n"
+                "# kernel command line\n"
+                "# or 'echo 1 > /proc/sys/kernel/stack_tracer_enabled'\n"
+                "#\n");
+}
+
 static int t_show(struct seq_file *m, void *v)
 {
        long i;
        int size;
 
        if (v == SEQ_START_TOKEN) {
-               seq_printf(m, "        Depth   Size      Location"
+               seq_printf(m, "        Depth    Size   Location"
                           "    (%d entries)\n"
-                          "        -----   ----      --------\n",
+                          "        -----    ----   --------\n",
                           max_stack_trace.nr_entries);
+
+               if (!stack_tracer_enabled && !max_stack_size)
+                       print_disabled(m);
+
                return 0;
        }
 
index fb5ccac8bbc0e9af264c53d06e173ff1f7fd2b32..9ab035b58cf1425b4b817dfae37d0b36e5eeada3 100644 (file)
@@ -193,12 +193,20 @@ static int workqueue_stat_show(struct seq_file *s, void *p)
        struct cpu_workqueue_stats *cws = p;
        unsigned long flags;
        int cpu = cws->cpu;
-       struct task_struct *tsk = find_task_by_vpid(cws->pid);
-
-       seq_printf(s, "%3d %6d     %6u       %s\n", cws->cpu,
-                  atomic_read(&cws->inserted),
-                  cws->executed,
-                  tsk ? tsk->comm : "<...>");
+       struct pid *pid;
+       struct task_struct *tsk;
+
+       pid = find_get_pid(cws->pid);
+       if (pid) {
+               tsk = get_pid_task(pid, PIDTYPE_PID);
+               if (tsk) {
+                       seq_printf(s, "%3d %6d     %6u       %s\n", cws->cpu,
+                                  atomic_read(&cws->inserted), cws->executed,
+                                  tsk->comm);
+                       put_task_struct(tsk);
+               }
+               put_pid(pid);
+       }
 
        spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
        if (&cws->list == workqueue_cpu_stat(cpu)->list.next)
index 1338469ac849cb230fc8f1e74441ece4a6cfd58c..35a1f7ff414988d86c6c081d7bbf3671733a15d6 100644 (file)
@@ -948,15 +948,15 @@ done:
  */
 int bitmap_find_free_region(unsigned long *bitmap, int bits, int order)
 {
-       int pos;                /* scans bitmap by regions of size order */
+       int pos, end;           /* scans bitmap by regions of size order */
 
-       for (pos = 0; pos < bits; pos += (1 << order))
-               if (__reg_op(bitmap, pos, order, REG_OP_ISFREE))
-                       break;
-       if (pos == bits)
-               return -ENOMEM;
-       __reg_op(bitmap, pos, order, REG_OP_ALLOC);
-       return pos;
+       for (pos = 0 ; (end = pos + (1 << order)) <= bits; pos = end) {
+               if (!__reg_op(bitmap, pos, order, REG_OP_ISFREE))
+                       continue;
+               __reg_op(bitmap, pos, order, REG_OP_ALLOC);
+               return pos;
+       }
+       return -ENOMEM;
 }
 EXPORT_SYMBOL(bitmap_find_free_region);