|
@@ -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);
|