]> Pileus Git - ~andy/linux/commitdiff
ring-buffer: Add per_cpu ring buffer control files
authorVaibhav Nagarnaik <vnagarnaik@google.com>
Thu, 2 Feb 2012 20:00:41 +0000 (12:00 -0800)
committerSteven Rostedt <rostedt@goodmis.org>
Tue, 24 Apr 2012 01:17:51 +0000 (21:17 -0400)
Add a debugfs entry under per_cpu/ folder for each cpu called
buffer_size_kb to control the ring buffer size for each CPU
independently.

If the global file buffer_size_kb is used to set size, the individual
ring buffers will be adjusted to the given size. The buffer_size_kb will
report the common size to maintain backward compatibility.

If the buffer_size_kb file under the per_cpu/ directory is used to
change buffer size for a specific CPU, only the size of the respective
ring buffer is updated. When tracing/buffer_size_kb is read, it reports
'X' to indicate that sizes of per_cpu ring buffers are not equivalent.

Link: http://lkml.kernel.org/r/1328212844-11889-1-git-send-email-vnagarnaik@google.com
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Michael Rubin <mrubin@google.com>
Cc: David Sharp <dhsharp@google.com>
Cc: Justin Teravest <teravest@google.com>
Signed-off-by: Vaibhav Nagarnaik <vnagarnaik@google.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
include/linux/ring_buffer.h
kernel/trace/ring_buffer.c
kernel/trace/trace.c
kernel/trace/trace.h

index 7be2e88f23fdae28f322f484c36a409e00c39eb3..6c8835f74f7982fee7ea2631f26cc40cdd984dd5 100644 (file)
@@ -96,9 +96,11 @@ __ring_buffer_alloc(unsigned long size, unsigned flags, struct lock_class_key *k
        __ring_buffer_alloc((size), (flags), &__key);   \
 })
 
+#define RING_BUFFER_ALL_CPUS -1
+
 void ring_buffer_free(struct ring_buffer *buffer);
 
-int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size);
+int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size, int cpu);
 
 void ring_buffer_change_overwrite(struct ring_buffer *buffer, int val);
 
@@ -129,7 +131,7 @@ ring_buffer_read(struct ring_buffer_iter *iter, u64 *ts);
 void ring_buffer_iter_reset(struct ring_buffer_iter *iter);
 int ring_buffer_iter_empty(struct ring_buffer_iter *iter);
 
-unsigned long ring_buffer_size(struct ring_buffer *buffer);
+unsigned long ring_buffer_size(struct ring_buffer *buffer, int cpu);
 
 void ring_buffer_reset_cpu(struct ring_buffer *buffer, int cpu);
 void ring_buffer_reset(struct ring_buffer *buffer);
index cf8d11e91efdf92d95dad58d6fa771d2ac998786..2d5eb332082753b7c96df402a2017c03dc96cd45 100644 (file)
@@ -449,6 +449,7 @@ struct ring_buffer_per_cpu {
        raw_spinlock_t                  reader_lock;    /* serialize readers */
        arch_spinlock_t                 lock;
        struct lock_class_key           lock_key;
+       unsigned int                    nr_pages;
        struct list_head                *pages;
        struct buffer_page              *head_page;     /* read from head */
        struct buffer_page              *tail_page;     /* write to tail */
@@ -466,10 +467,12 @@ struct ring_buffer_per_cpu {
        unsigned long                   read_bytes;
        u64                             write_stamp;
        u64                             read_stamp;
+       /* ring buffer pages to update, > 0 to add, < 0 to remove */
+       int                             nr_pages_to_update;
+       struct list_head                new_pages; /* new pages to add */
 };
 
 struct ring_buffer {
-       unsigned                        pages;
        unsigned                        flags;
        int                             cpus;
        atomic_t                        record_disabled;
@@ -963,14 +966,10 @@ static int rb_check_pages(struct ring_buffer_per_cpu *cpu_buffer)
        return 0;
 }
 
-static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
-                            unsigned nr_pages)
+static int __rb_allocate_pages(int nr_pages, struct list_head *pages, int cpu)
 {
+       int i;
        struct buffer_page *bpage, *tmp;
-       LIST_HEAD(pages);
-       unsigned i;
-
-       WARN_ON(!nr_pages);
 
        for (i = 0; i < nr_pages; i++) {
                struct page *page;
@@ -981,15 +980,13 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
                 */
                bpage = kzalloc_node(ALIGN(sizeof(*bpage), cache_line_size()),
                                    GFP_KERNEL | __GFP_NORETRY,
-                                   cpu_to_node(cpu_buffer->cpu));
+                                   cpu_to_node(cpu));
                if (!bpage)
                        goto free_pages;
 
-               rb_check_bpage(cpu_buffer, bpage);
+               list_add(&bpage->list, pages);
 
-               list_add(&bpage->list, &pages);
-
-               page = alloc_pages_node(cpu_to_node(cpu_buffer->cpu),
+               page = alloc_pages_node(cpu_to_node(cpu),
                                        GFP_KERNEL | __GFP_NORETRY, 0);
                if (!page)
                        goto free_pages;
@@ -997,6 +994,27 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
                rb_init_page(bpage->page);
        }
 
+       return 0;
+
+free_pages:
+       list_for_each_entry_safe(bpage, tmp, pages, list) {
+               list_del_init(&bpage->list);
+               free_buffer_page(bpage);
+       }
+
+       return -ENOMEM;
+}
+
+static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
+                            unsigned nr_pages)
+{
+       LIST_HEAD(pages);
+
+       WARN_ON(!nr_pages);
+
+       if (__rb_allocate_pages(nr_pages, &pages, cpu_buffer->cpu))
+               return -ENOMEM;
+
        /*
         * The ring buffer page list is a circular list that does not
         * start and end with a list head. All page list items point to
@@ -1005,20 +1023,15 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
        cpu_buffer->pages = pages.next;
        list_del(&pages);
 
+       cpu_buffer->nr_pages = nr_pages;
+
        rb_check_pages(cpu_buffer);
 
        return 0;
-
- free_pages:
-       list_for_each_entry_safe(bpage, tmp, &pages, list) {
-               list_del_init(&bpage->list);
-               free_buffer_page(bpage);
-       }
-       return -ENOMEM;
 }
 
 static struct ring_buffer_per_cpu *
-rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu)
+rb_allocate_cpu_buffer(struct ring_buffer *buffer, int nr_pages, int cpu)
 {
        struct ring_buffer_per_cpu *cpu_buffer;
        struct buffer_page *bpage;
@@ -1052,7 +1065,7 @@ rb_allocate_cpu_buffer(struct ring_buffer *buffer, int cpu)
 
        INIT_LIST_HEAD(&cpu_buffer->reader_page->list);
 
-       ret = rb_allocate_pages(cpu_buffer, buffer->pages);
+       ret = rb_allocate_pages(cpu_buffer, nr_pages);
        if (ret < 0)
                goto fail_free_reader;
 
@@ -1113,7 +1126,7 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags,
 {
        struct ring_buffer *buffer;
        int bsize;
-       int cpu;
+       int cpu, nr_pages;
 
        /* keep it in its own cache line */
        buffer = kzalloc(ALIGN(sizeof(*buffer), cache_line_size()),
@@ -1124,14 +1137,14 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags,
        if (!alloc_cpumask_var(&buffer->cpumask, GFP_KERNEL))
                goto fail_free_buffer;
 
-       buffer->pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
+       nr_pages = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
        buffer->flags = flags;
        buffer->clock = trace_clock_local;
        buffer->reader_lock_key = key;
 
        /* need at least two pages */
-       if (buffer->pages < 2)
-               buffer->pages = 2;
+       if (nr_pages < 2)
+               nr_pages = 2;
 
        /*
         * In case of non-hotplug cpu, if the ring-buffer is allocated
@@ -1154,7 +1167,7 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags,
 
        for_each_buffer_cpu(buffer, cpu) {
                buffer->buffers[cpu] =
-                       rb_allocate_cpu_buffer(buffer, cpu);
+                       rb_allocate_cpu_buffer(buffer, nr_pages, cpu);
                if (!buffer->buffers[cpu])
                        goto fail_free_buffers;
        }
@@ -1276,6 +1289,18 @@ out:
        raw_spin_unlock_irq(&cpu_buffer->reader_lock);
 }
 
+static void update_pages_handler(struct ring_buffer_per_cpu *cpu_buffer)
+{
+       if (cpu_buffer->nr_pages_to_update > 0)
+               rb_insert_pages(cpu_buffer, &cpu_buffer->new_pages,
+                               cpu_buffer->nr_pages_to_update);
+       else
+               rb_remove_pages(cpu_buffer, -cpu_buffer->nr_pages_to_update);
+       cpu_buffer->nr_pages += cpu_buffer->nr_pages_to_update;
+       /* reset this value */
+       cpu_buffer->nr_pages_to_update = 0;
+}
+
 /**
  * ring_buffer_resize - resize the ring buffer
  * @buffer: the buffer to resize.
@@ -1285,14 +1310,12 @@ out:
  *
  * Returns -1 on failure.
  */
-int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
+int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size,
+                       int cpu_id)
 {
        struct ring_buffer_per_cpu *cpu_buffer;
-       unsigned nr_pages, rm_pages, new_pages;
-       struct buffer_page *bpage, *tmp;
-       unsigned long buffer_size;
-       LIST_HEAD(pages);
-       int i, cpu;
+       unsigned nr_pages;
+       int cpu;
 
        /*
         * Always succeed at resizing a non-existent buffer:
@@ -1302,15 +1325,11 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
 
        size = DIV_ROUND_UP(size, BUF_PAGE_SIZE);
        size *= BUF_PAGE_SIZE;
-       buffer_size = buffer->pages * BUF_PAGE_SIZE;
 
        /* we need a minimum of two pages */
        if (size < BUF_PAGE_SIZE * 2)
                size = BUF_PAGE_SIZE * 2;
 
-       if (size == buffer_size)
-               return size;
-
        atomic_inc(&buffer->record_disabled);
 
        /* Make sure all writers are done with this buffer. */
@@ -1321,68 +1340,56 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
 
        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))
-                       goto out_fail;
-
-               rm_pages = buffer->pages - nr_pages;
-
+       if (cpu_id == RING_BUFFER_ALL_CPUS) {
+               /* calculate the pages to update */
                for_each_buffer_cpu(buffer, cpu) {
                        cpu_buffer = buffer->buffers[cpu];
-                       rb_remove_pages(cpu_buffer, rm_pages);
-               }
-               goto out;
-       }
 
-       /*
-        * This is a bit more difficult. We only want to add pages
-        * when we can allocate enough for all CPUs. We do this
-        * by allocating all the pages and storing them on a local
-        * link list. If we succeed in our allocation, then we
-        * 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))
-               goto out_fail;
+                       cpu_buffer->nr_pages_to_update = nr_pages -
+                                                       cpu_buffer->nr_pages;
 
-       new_pages = nr_pages - buffer->pages;
+                       /*
+                        * nothing more to do for removing pages or no update
+                        */
+                       if (cpu_buffer->nr_pages_to_update <= 0)
+                               continue;
 
-       for_each_buffer_cpu(buffer, cpu) {
-               for (i = 0; i < new_pages; i++) {
-                       struct page *page;
                        /*
-                        * __GFP_NORETRY flag makes sure that the allocation
-                        * fails gracefully without invoking oom-killer and
-                        * the system is not destabilized.
+                        * to add pages, make sure all new pages can be
+                        * allocated without receiving ENOMEM
                         */
-                       bpage = kzalloc_node(ALIGN(sizeof(*bpage),
-                                                 cache_line_size()),
-                                           GFP_KERNEL | __GFP_NORETRY,
-                                           cpu_to_node(cpu));
-                       if (!bpage)
-                               goto free_pages;
-                       list_add(&bpage->list, &pages);
-                       page = alloc_pages_node(cpu_to_node(cpu),
-                                               GFP_KERNEL | __GFP_NORETRY, 0);
-                       if (!page)
-                               goto free_pages;
-                       bpage->page = page_address(page);
-                       rb_init_page(bpage->page);
+                       INIT_LIST_HEAD(&cpu_buffer->new_pages);
+                       if (__rb_allocate_pages(cpu_buffer->nr_pages_to_update,
+                                               &cpu_buffer->new_pages, cpu))
+                               /* not enough memory for new pages */
+                               goto no_mem;
                }
-       }
 
-       for_each_buffer_cpu(buffer, cpu) {
-               cpu_buffer = buffer->buffers[cpu];
-               rb_insert_pages(cpu_buffer, &pages, new_pages);
-       }
+               /* wait for all the updates to complete */
+               for_each_buffer_cpu(buffer, cpu) {
+                       cpu_buffer = buffer->buffers[cpu];
+                       if (cpu_buffer->nr_pages_to_update) {
+                               update_pages_handler(cpu_buffer);
+                       }
+               }
+       } else {
+               cpu_buffer = buffer->buffers[cpu_id];
+               if (nr_pages == cpu_buffer->nr_pages)
+                       goto out;
 
-       if (RB_WARN_ON(buffer, !list_empty(&pages)))
-               goto out_fail;
+               cpu_buffer->nr_pages_to_update = nr_pages -
+                                               cpu_buffer->nr_pages;
+
+               INIT_LIST_HEAD(&cpu_buffer->new_pages);
+               if (cpu_buffer->nr_pages_to_update > 0 &&
+                       __rb_allocate_pages(cpu_buffer->nr_pages_to_update,
+                                               &cpu_buffer->new_pages, cpu_id))
+                       goto no_mem;
+
+               update_pages_handler(cpu_buffer);
+       }
 
  out:
-       buffer->pages = nr_pages;
        put_online_cpus();
        mutex_unlock(&buffer->mutex);
 
@@ -1390,25 +1397,24 @@ int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size)
 
        return size;
 
- free_pages:
-       list_for_each_entry_safe(bpage, tmp, &pages, list) {
-               list_del_init(&bpage->list);
-               free_buffer_page(bpage);
+ no_mem:
+       for_each_buffer_cpu(buffer, cpu) {
+               struct buffer_page *bpage, *tmp;
+               cpu_buffer = buffer->buffers[cpu];
+               /* reset this number regardless */
+               cpu_buffer->nr_pages_to_update = 0;
+               if (list_empty(&cpu_buffer->new_pages))
+                       continue;
+               list_for_each_entry_safe(bpage, tmp, &cpu_buffer->new_pages,
+                                       list) {
+                       list_del_init(&bpage->list);
+                       free_buffer_page(bpage);
+               }
        }
        put_online_cpus();
        mutex_unlock(&buffer->mutex);
        atomic_dec(&buffer->record_disabled);
        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);
-       atomic_dec(&buffer->record_disabled);
-       return -1;
 }
 EXPORT_SYMBOL_GPL(ring_buffer_resize);
 
@@ -1510,7 +1516,7 @@ rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer)
         * assign the commit to the tail.
         */
  again:
-       max_count = cpu_buffer->buffer->pages * 100;
+       max_count = cpu_buffer->nr_pages * 100;
 
        while (cpu_buffer->commit_page != cpu_buffer->tail_page) {
                if (RB_WARN_ON(cpu_buffer, !(--max_count)))
@@ -3588,9 +3594,18 @@ EXPORT_SYMBOL_GPL(ring_buffer_read);
  * ring_buffer_size - return the size of the ring buffer (in bytes)
  * @buffer: The ring buffer.
  */
-unsigned long ring_buffer_size(struct ring_buffer *buffer)
+unsigned long ring_buffer_size(struct ring_buffer *buffer, int cpu)
 {
-       return BUF_PAGE_SIZE * buffer->pages;
+       /*
+        * Earlier, this method returned
+        *      BUF_PAGE_SIZE * buffer->nr_pages
+        * Since the nr_pages field is now removed, we have converted this to
+        * return the per cpu buffer value.
+        */
+       if (!cpumask_test_cpu(cpu, buffer->cpumask))
+               return 0;
+
+       return BUF_PAGE_SIZE * buffer->buffers[cpu]->nr_pages;
 }
 EXPORT_SYMBOL_GPL(ring_buffer_size);
 
@@ -3765,8 +3780,11 @@ int ring_buffer_swap_cpu(struct ring_buffer *buffer_a,
            !cpumask_test_cpu(cpu, buffer_b->cpumask))
                goto out;
 
+       cpu_buffer_a = buffer_a->buffers[cpu];
+       cpu_buffer_b = buffer_b->buffers[cpu];
+
        /* At least make sure the two buffers are somewhat the same */
-       if (buffer_a->pages != buffer_b->pages)
+       if (cpu_buffer_a->nr_pages != cpu_buffer_b->nr_pages)
                goto out;
 
        ret = -EAGAIN;
@@ -3780,9 +3798,6 @@ int ring_buffer_swap_cpu(struct ring_buffer *buffer_a,
        if (atomic_read(&buffer_b->record_disabled))
                goto out;
 
-       cpu_buffer_a = buffer_a->buffers[cpu];
-       cpu_buffer_b = buffer_b->buffers[cpu];
-
        if (atomic_read(&cpu_buffer_a->record_disabled))
                goto out;
 
@@ -4071,6 +4086,8 @@ static int rb_cpu_notify(struct notifier_block *self,
        struct ring_buffer *buffer =
                container_of(self, struct ring_buffer, cpu_notify);
        long cpu = (long)hcpu;
+       int cpu_i, nr_pages_same;
+       unsigned int nr_pages;
 
        switch (action) {
        case CPU_UP_PREPARE:
@@ -4078,8 +4095,23 @@ static int rb_cpu_notify(struct notifier_block *self,
                if (cpumask_test_cpu(cpu, buffer->cpumask))
                        return NOTIFY_OK;
 
+               nr_pages = 0;
+               nr_pages_same = 1;
+               /* check if all cpu sizes are same */
+               for_each_buffer_cpu(buffer, cpu_i) {
+                       /* fill in the size from first enabled cpu */
+                       if (nr_pages == 0)
+                               nr_pages = buffer->buffers[cpu_i]->nr_pages;
+                       if (nr_pages != buffer->buffers[cpu_i]->nr_pages) {
+                               nr_pages_same = 0;
+                               break;
+                       }
+               }
+               /* allocate minimum pages, user can later expand it */
+               if (!nr_pages_same)
+                       nr_pages = 2;
                buffer->buffers[cpu] =
-                       rb_allocate_cpu_buffer(buffer, cpu);
+                       rb_allocate_cpu_buffer(buffer, nr_pages, cpu);
                if (!buffer->buffers[cpu]) {
                        WARN(1, "failed to allocate ring buffer on CPU %ld\n",
                             cpu);
index bbcde546f9f76fcc4bc4b7af53ab1182693a0e30..f11a285ee5bb4f87d139ca1f938c9652490322e7 100644 (file)
@@ -838,7 +838,8 @@ __acquires(kernel_lock)
 
                /* If we expanded the buffers, make sure the max is expanded too */
                if (ring_buffer_expanded && type->use_max_tr)
-                       ring_buffer_resize(max_tr.buffer, trace_buf_size);
+                       ring_buffer_resize(max_tr.buffer, trace_buf_size,
+                                               RING_BUFFER_ALL_CPUS);
 
                /* the test is responsible for initializing and enabling */
                pr_info("Testing tracer %s: ", type->name);
@@ -854,7 +855,8 @@ __acquires(kernel_lock)
 
                /* Shrink the max buffer again */
                if (ring_buffer_expanded && type->use_max_tr)
-                       ring_buffer_resize(max_tr.buffer, 1);
+                       ring_buffer_resize(max_tr.buffer, 1,
+                                               RING_BUFFER_ALL_CPUS);
 
                printk(KERN_CONT "PASSED\n");
        }
@@ -3053,7 +3055,14 @@ int tracer_init(struct tracer *t, struct trace_array *tr)
        return t->init(tr);
 }
 
-static int __tracing_resize_ring_buffer(unsigned long size)
+static void set_buffer_entries(struct trace_array *tr, unsigned long val)
+{
+       int cpu;
+       for_each_tracing_cpu(cpu)
+               tr->data[cpu]->entries = val;
+}
+
+static int __tracing_resize_ring_buffer(unsigned long size, int cpu)
 {
        int ret;
 
@@ -3064,19 +3073,32 @@ static int __tracing_resize_ring_buffer(unsigned long size)
         */
        ring_buffer_expanded = 1;
 
-       ret = ring_buffer_resize(global_trace.buffer, size);
+       ret = ring_buffer_resize(global_trace.buffer, size, cpu);
        if (ret < 0)
                return ret;
 
        if (!current_trace->use_max_tr)
                goto out;
 
-       ret = ring_buffer_resize(max_tr.buffer, size);
+       ret = ring_buffer_resize(max_tr.buffer, size, cpu);
        if (ret < 0) {
-               int r;
+               int r = 0;
+
+               if (cpu == RING_BUFFER_ALL_CPUS) {
+                       int i;
+                       for_each_tracing_cpu(i) {
+                               r = ring_buffer_resize(global_trace.buffer,
+                                               global_trace.data[i]->entries,
+                                               i);
+                               if (r < 0)
+                                       break;
+                       }
+               } else {
+                       r = ring_buffer_resize(global_trace.buffer,
+                                               global_trace.data[cpu]->entries,
+                                               cpu);
+               }
 
-               r = ring_buffer_resize(global_trace.buffer,
-                                      global_trace.entries);
                if (r < 0) {
                        /*
                         * AARGH! We are left with different
@@ -3098,14 +3120,21 @@ static int __tracing_resize_ring_buffer(unsigned long size)
                return ret;
        }
 
-       max_tr.entries = size;
+       if (cpu == RING_BUFFER_ALL_CPUS)
+               set_buffer_entries(&max_tr, size);
+       else
+               max_tr.data[cpu]->entries = size;
+
  out:
-       global_trace.entries = size;
+       if (cpu == RING_BUFFER_ALL_CPUS)
+               set_buffer_entries(&global_trace, size);
+       else
+               global_trace.data[cpu]->entries = size;
 
        return ret;
 }
 
-static ssize_t tracing_resize_ring_buffer(unsigned long size)
+static ssize_t tracing_resize_ring_buffer(unsigned long size, int cpu_id)
 {
        int cpu, ret = size;
 
@@ -3121,12 +3150,19 @@ static ssize_t tracing_resize_ring_buffer(unsigned long size)
                        atomic_inc(&max_tr.data[cpu]->disabled);
        }
 
-       if (size != global_trace.entries)
-               ret = __tracing_resize_ring_buffer(size);
+       if (cpu_id != RING_BUFFER_ALL_CPUS) {
+               /* make sure, this cpu is enabled in the mask */
+               if (!cpumask_test_cpu(cpu_id, tracing_buffer_mask)) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
 
+       ret = __tracing_resize_ring_buffer(size, cpu_id);
        if (ret < 0)
                ret = -ENOMEM;
 
+out:
        for_each_tracing_cpu(cpu) {
                if (global_trace.data[cpu])
                        atomic_dec(&global_trace.data[cpu]->disabled);
@@ -3157,7 +3193,8 @@ int tracing_update_buffers(void)
 
        mutex_lock(&trace_types_lock);
        if (!ring_buffer_expanded)
-               ret = __tracing_resize_ring_buffer(trace_buf_size);
+               ret = __tracing_resize_ring_buffer(trace_buf_size,
+                                               RING_BUFFER_ALL_CPUS);
        mutex_unlock(&trace_types_lock);
 
        return ret;
@@ -3181,7 +3218,8 @@ static int tracing_set_tracer(const char *buf)
        mutex_lock(&trace_types_lock);
 
        if (!ring_buffer_expanded) {
-               ret = __tracing_resize_ring_buffer(trace_buf_size);
+               ret = __tracing_resize_ring_buffer(trace_buf_size,
+                                               RING_BUFFER_ALL_CPUS);
                if (ret < 0)
                        goto out;
                ret = 0;
@@ -3207,8 +3245,8 @@ static int tracing_set_tracer(const char *buf)
                 * The max_tr ring buffer has some state (e.g. ring->clock) and
                 * we want preserve it.
                 */
-               ring_buffer_resize(max_tr.buffer, 1);
-               max_tr.entries = 1;
+               ring_buffer_resize(max_tr.buffer, 1, RING_BUFFER_ALL_CPUS);
+               set_buffer_entries(&max_tr, 1);
        }
        destroy_trace_option_files(topts);
 
@@ -3216,10 +3254,17 @@ static int tracing_set_tracer(const char *buf)
 
        topts = create_trace_option_files(current_trace);
        if (current_trace->use_max_tr) {
-               ret = ring_buffer_resize(max_tr.buffer, global_trace.entries);
-               if (ret < 0)
-                       goto out;
-               max_tr.entries = global_trace.entries;
+               int cpu;
+               /* we need to make per cpu buffer sizes equivalent */
+               for_each_tracing_cpu(cpu) {
+                       ret = ring_buffer_resize(max_tr.buffer,
+                                               global_trace.data[cpu]->entries,
+                                               cpu);
+                       if (ret < 0)
+                               goto out;
+                       max_tr.data[cpu]->entries =
+                                       global_trace.data[cpu]->entries;
+               }
        }
 
        if (t->init) {
@@ -3721,30 +3766,82 @@ out_err:
        goto out;
 }
 
+struct ftrace_entries_info {
+       struct trace_array      *tr;
+       int                     cpu;
+};
+
+static int tracing_entries_open(struct inode *inode, struct file *filp)
+{
+       struct ftrace_entries_info *info;
+
+       if (tracing_disabled)
+               return -ENODEV;
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       info->tr = &global_trace;
+       info->cpu = (unsigned long)inode->i_private;
+
+       filp->private_data = info;
+
+       return 0;
+}
+
 static ssize_t
 tracing_entries_read(struct file *filp, char __user *ubuf,
                     size_t cnt, loff_t *ppos)
 {
-       struct trace_array *tr = filp->private_data;
-       char buf[96];
-       int r;
+       struct ftrace_entries_info *info = filp->private_data;
+       struct trace_array *tr = info->tr;
+       char buf[64];
+       int r = 0;
+       ssize_t ret;
 
        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);
+
+       if (info->cpu == RING_BUFFER_ALL_CPUS) {
+               int cpu, buf_size_same;
+               unsigned long size;
+
+               size = 0;
+               buf_size_same = 1;
+               /* check if all cpu sizes are same */
+               for_each_tracing_cpu(cpu) {
+                       /* fill in the size from first enabled cpu */
+                       if (size == 0)
+                               size = tr->data[cpu]->entries;
+                       if (size != tr->data[cpu]->entries) {
+                               buf_size_same = 0;
+                               break;
+                       }
+               }
+
+               if (buf_size_same) {
+                       if (!ring_buffer_expanded)
+                               r = sprintf(buf, "%lu (expanded: %lu)\n",
+                                           size >> 10,
+                                           trace_buf_size >> 10);
+                       else
+                               r = sprintf(buf, "%lu\n", size >> 10);
+               } else
+                       r = sprintf(buf, "X\n");
+       } else
+               r = sprintf(buf, "%lu\n", tr->data[info->cpu]->entries >> 10);
+
        mutex_unlock(&trace_types_lock);
 
-       return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+       ret = simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
+       return ret;
 }
 
 static ssize_t
 tracing_entries_write(struct file *filp, const char __user *ubuf,
                      size_t cnt, loff_t *ppos)
 {
+       struct ftrace_entries_info *info = filp->private_data;
        unsigned long val;
        int ret;
 
@@ -3759,7 +3856,7 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
        /* value is in KB */
        val <<= 10;
 
-       ret = tracing_resize_ring_buffer(val);
+       ret = tracing_resize_ring_buffer(val, info->cpu);
        if (ret < 0)
                return ret;
 
@@ -3768,6 +3865,16 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
        return cnt;
 }
 
+static int
+tracing_entries_release(struct inode *inode, struct file *filp)
+{
+       struct ftrace_entries_info *info = filp->private_data;
+
+       kfree(info);
+
+       return 0;
+}
+
 static ssize_t
 tracing_total_entries_read(struct file *filp, char __user *ubuf,
                                size_t cnt, loff_t *ppos)
@@ -3779,7 +3886,7 @@ tracing_total_entries_read(struct file *filp, char __user *ubuf,
 
        mutex_lock(&trace_types_lock);
        for_each_tracing_cpu(cpu) {
-               size += tr->entries >> 10;
+               size += tr->data[cpu]->entries >> 10;
                if (!ring_buffer_expanded)
                        expanded_size += trace_buf_size >> 10;
        }
@@ -3813,7 +3920,7 @@ tracing_free_buffer_release(struct inode *inode, struct file *filp)
        if (trace_flags & TRACE_ITER_STOP_ON_FREE)
                tracing_off();
        /* resize the ring buffer to 0 */
-       tracing_resize_ring_buffer(0);
+       tracing_resize_ring_buffer(0, RING_BUFFER_ALL_CPUS);
 
        return 0;
 }
@@ -4012,9 +4119,10 @@ static const struct file_operations tracing_pipe_fops = {
 };
 
 static const struct file_operations tracing_entries_fops = {
-       .open           = tracing_open_generic,
+       .open           = tracing_entries_open,
        .read           = tracing_entries_read,
        .write          = tracing_entries_write,
+       .release        = tracing_entries_release,
        .llseek         = generic_file_llseek,
 };
 
@@ -4466,6 +4574,9 @@ static void tracing_init_debugfs_percpu(long cpu)
 
        trace_create_file("stats", 0444, d_cpu,
                        (void *) cpu, &tracing_stats_fops);
+
+       trace_create_file("buffer_size_kb", 0444, d_cpu,
+                       (void *) cpu, &tracing_entries_fops);
 }
 
 #ifdef CONFIG_FTRACE_SELFTEST
@@ -4795,7 +4906,7 @@ static __init int tracer_init_debugfs(void)
                        (void *) TRACE_PIPE_ALL_CPU, &tracing_pipe_fops);
 
        trace_create_file("buffer_size_kb", 0644, d_tracer,
-                       &global_trace, &tracing_entries_fops);
+                       (void *) RING_BUFFER_ALL_CPUS, &tracing_entries_fops);
 
        trace_create_file("buffer_total_size_kb", 0444, d_tracer,
                        &global_trace, &tracing_total_entries_fops);
@@ -5056,7 +5167,6 @@ __init static int tracer_alloc_buffers(void)
                WARN_ON(1);
                goto out_free_cpumask;
        }
-       global_trace.entries = ring_buffer_size(global_trace.buffer);
        if (global_trace.buffer_disabled)
                tracing_off();
 
@@ -5069,7 +5179,6 @@ __init static int tracer_alloc_buffers(void)
                ring_buffer_free(global_trace.buffer);
                goto out_free_cpumask;
        }
-       max_tr.entries = 1;
 #endif
 
        /* Allocate the first page for all buffers */
@@ -5078,6 +5187,11 @@ __init static int tracer_alloc_buffers(void)
                max_tr.data[i] = &per_cpu(max_tr_data, i);
        }
 
+       set_buffer_entries(&global_trace, ring_buf_size);
+#ifdef CONFIG_TRACER_MAX_TRACE
+       set_buffer_entries(&max_tr, 1);
+#endif
+
        trace_init_cmdlines();
 
        register_tracer(&nop_trace);
index f9d85504f04bcc24b16ccf55f8b2d7e38ab723e3..1c8b7c6f7b3b11bb978362a30bfaf5698ba4f9b8 100644 (file)
@@ -131,6 +131,7 @@ struct trace_array_cpu {
        atomic_t                disabled;
        void                    *buffer_page;   /* ring buffer spare */
 
+       unsigned long           entries;
        unsigned long           saved_latency;
        unsigned long           critical_start;
        unsigned long           critical_end;
@@ -152,7 +153,6 @@ struct trace_array_cpu {
  */
 struct trace_array {
        struct ring_buffer      *buffer;
-       unsigned long           entries;
        int                     cpu;
        int                     buffer_disabled;
        cycle_t                 time_start;