summaryrefslogtreecommitdiff
path: root/kernel/trace/ring_buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/ring_buffer.c')
-rw-r--r--kernel/trace/ring_buffer.c243
1 files changed, 157 insertions, 86 deletions
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index b0963ac6fd16..9c03a555a6ba 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -330,6 +330,14 @@ struct buffer_data_read_page {
struct buffer_data_page *data; /* actual data, stored in this page */
};
+static __always_inline unsigned int rb_read_page_capacity(struct buffer_data_read_page *rpage)
+{
+ return (PAGE_SIZE << rpage->order) - BUF_PAGE_HDR_SIZE;
+}
+
+/* The number of bits for static buffer ids */
+#define RB_STATIC_BITS 30
+
/*
* Note, the buffer_page list must be first. The buffer pages
* are allocated in cache lines, which means that each buffer
@@ -345,7 +353,7 @@ struct buffer_page {
local_t entries; /* entries on this page */
unsigned long real_end; /* real end of data */
unsigned order; /* order of the page */
- u32 id:30; /* ID for external mapping */
+ u32 id:RB_STATIC_BITS; /* ID for external mapping */
u32 range:1; /* Mapped via a range */
struct buffer_data_page *page; /* Actual data page */
};
@@ -652,6 +660,15 @@ static bool rb_is_static(struct ring_buffer_per_cpu *cpu_buffer)
return cpu_buffer->user_mapped || cpu_buffer->remote || cpu_buffer->ring_meta;
}
+static unsigned long rb_static_max_pages(void)
+{
+ /*
+ * Static ring buffers are using bpage::id and must account for the
+ * reader page.
+ */
+ return (1UL << RB_STATIC_BITS) - 1;
+}
+
struct ring_buffer_iter {
struct ring_buffer_per_cpu *cpu_buffer;
unsigned long head;
@@ -1669,7 +1686,7 @@ out_locked:
* This is used to help find the next per cpu subbuffer within a mapped range.
*/
static unsigned long
-rb_range_align_subbuf(unsigned long addr, int subbuf_size, int nr_subbufs)
+rb_range_align_subbuf(unsigned long addr, unsigned int subbuf_size, unsigned long nr_subbufs)
{
addr += sizeof(struct ring_buffer_cpu_meta) +
sizeof(int) * nr_subbufs;
@@ -1679,13 +1696,12 @@ rb_range_align_subbuf(unsigned long addr, int subbuf_size, int nr_subbufs)
/*
* Return the ring_buffer_meta for a given @cpu.
*/
-static void *rb_range_meta(struct trace_buffer *buffer, int nr_pages, int cpu)
+static void *rb_range_meta(struct trace_buffer *buffer, unsigned long nr_pages, int cpu)
{
- int subbuf_size = rb_subbuf_size(buffer);
+ unsigned int subbuf_size = rb_subbuf_size(buffer);
struct ring_buffer_cpu_meta *meta;
struct ring_buffer_meta *bmeta;
- unsigned long ptr;
- int nr_subbufs;
+ unsigned long ptr, nr_subbufs;
bmeta = buffer->meta;
if (!bmeta)
@@ -1731,7 +1747,7 @@ static void *rb_range_meta(struct trace_buffer *buffer, int nr_pages, int cpu)
/* Return the start of subbufs given the meta pointer */
static void *rb_subbufs_from_meta(struct ring_buffer_cpu_meta *meta)
{
- int subbuf_size = meta->subbuf_size;
+ unsigned int subbuf_size = meta->subbuf_size;
unsigned long ptr;
ptr = (unsigned long)meta;
@@ -1743,11 +1759,11 @@ static void *rb_subbufs_from_meta(struct ring_buffer_cpu_meta *meta)
/*
* Return a specific sub-buffer for a given @cpu defined by @idx.
*/
-static void *rb_range_buffer(struct ring_buffer_per_cpu *cpu_buffer, int idx)
+static void *rb_range_buffer(struct ring_buffer_per_cpu *cpu_buffer, unsigned long idx)
{
struct ring_buffer_cpu_meta *meta;
+ unsigned int subbuf_size;
unsigned long ptr;
- int subbuf_size;
meta = rb_range_meta(cpu_buffer->buffer, 0, cpu_buffer->cpu);
if (!meta)
@@ -1763,7 +1779,7 @@ static void *rb_range_buffer(struct ring_buffer_per_cpu *cpu_buffer, int idx)
ptr = (unsigned long)rb_subbufs_from_meta(meta);
- ptr += subbuf_size * idx;
+ ptr += (unsigned long)subbuf_size * idx;
if (ptr + subbuf_size > cpu_buffer->buffer->range_addr_end)
return NULL;
@@ -1840,13 +1856,12 @@ static bool rb_meta_init(struct trace_buffer *buffer, int scratch_size)
* must be the same.
*/
static bool rb_cpu_meta_valid(struct ring_buffer_cpu_meta *meta, int cpu,
- struct trace_buffer *buffer, int nr_pages,
+ struct trace_buffer *buffer, unsigned long nr_pages,
unsigned long *subbuf_mask)
{
- int subbuf_size = PAGE_SIZE;
unsigned long buffers_start;
unsigned long buffers_end;
- int i;
+ unsigned long i;
if (!subbuf_mask)
return false;
@@ -1856,8 +1871,13 @@ static bool rb_cpu_meta_valid(struct ring_buffer_cpu_meta *meta, int cpu,
return false;
}
+ if (meta->nr_subbufs != nr_pages + 1) {
+ pr_info("Ring buffer boot meta [%d] invalid nr_subbufs\n", cpu);
+ return false;
+ }
+
buffers_start = meta->first_buffer;
- buffers_end = meta->first_buffer + (subbuf_size * meta->nr_subbufs);
+ buffers_end = meta->first_buffer + (meta->nr_subbufs * PAGE_SIZE);
/* Is the head and commit buffers within the range of buffers? */
if (meta->head_buffer < buffers_start ||
@@ -2095,8 +2115,8 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
struct buffer_page *head_page, *orig_head, *orig_reader;
struct rb_validation_state state = { 0 };
bool skip = false;
+ unsigned long i;
int ret;
- int i;
if (!meta || !meta->head_buffer)
return;
@@ -2147,7 +2167,7 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
rb_validate_buffer(head_page, cpu_buffer, meta, &state, 0, state.ts);
}
if (i)
- pr_info("Ring buffer [%d] rewound %d pages\n", cpu_buffer->cpu, i);
+ pr_info("Ring buffer [%d] rewound %lu pages\n", cpu_buffer->cpu, i);
/* The last rewound page must be skipped. */
if (head_page != orig_head)
@@ -2231,7 +2251,8 @@ static void rb_meta_validate_events(struct ring_buffer_per_cpu *cpu_buffer)
}
}
-static void rb_range_meta_init(struct trace_buffer *buffer, int nr_pages, int scratch_size)
+static void rb_range_meta_init(struct trace_buffer *buffer, unsigned long nr_pages,
+ int scratch_size)
{
struct ring_buffer_cpu_meta *meta;
unsigned long *subbuf_mask;
@@ -2331,8 +2352,8 @@ static int rbm_show(struct seq_file *m, void *v)
rb_meta_subbuf_idx(meta, (void *)meta->head_buffer));
seq_printf(m, "commit_buffer: %d\n",
rb_meta_subbuf_idx(meta, (void *)meta->commit_buffer));
- seq_printf(m, "subbuf_size: %d\n", meta->subbuf_size);
- seq_printf(m, "nr_subbufs: %d\n", meta->nr_subbufs);
+ seq_printf(m, "subbuf_size: %u\n", meta->subbuf_size);
+ seq_printf(m, "nr_subbufs: %u\n", meta->nr_subbufs);
return 0;
}
@@ -2417,7 +2438,7 @@ static void *ring_buffer_desc_page(struct ring_buffer_desc *desc, unsigned int p
}
static int __rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
- long nr_pages, struct list_head *pages)
+ unsigned long nr_pages, struct list_head *pages)
{
struct trace_buffer *buffer = cpu_buffer->buffer;
struct ring_buffer_cpu_meta *meta = NULL;
@@ -2545,7 +2566,7 @@ static int rb_allocate_pages(struct ring_buffer_per_cpu *cpu_buffer,
}
static struct ring_buffer_per_cpu *
-rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
+rb_allocate_cpu_buffer(struct trace_buffer *buffer, unsigned long nr_pages, int cpu)
{
struct ring_buffer_per_cpu *cpu_buffer __free(kfree) =
alloc_cpu_buffer(cpu);
@@ -2600,8 +2621,8 @@ rb_allocate_cpu_buffer(struct trace_buffer *buffer, long nr_pages, int cpu)
cpu_buffer->remote = buffer->remote;
cpu_buffer->meta_page = (struct trace_buffer_meta *)(void *)desc->meta_va;
cpu_buffer->nr_pages = nr_pages;
- cpu_buffer->subbuf_ids = kcalloc(cpu_buffer->nr_pages + 1,
- sizeof(*cpu_buffer->subbuf_ids), GFP_KERNEL);
+ cpu_buffer->subbuf_ids = kzalloc_objs(*cpu_buffer->subbuf_ids,
+ cpu_buffer->nr_pages + 1);
if (!cpu_buffer->subbuf_ids)
goto fail_free_reader;
@@ -2702,8 +2723,8 @@ static void rb_test_inject_invalid_pages(struct trace_buffer *buffer)
struct ring_buffer_cpu_meta *meta;
struct buffer_data_page *dpage;
unsigned long entry_bytes = 0;
+ unsigned int subbuf_size;
unsigned long ptr;
- int subbuf_size;
int invalid = 0;
int cpu;
int i;
@@ -2773,8 +2794,8 @@ static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
struct ring_buffer_remote *remote)
{
struct trace_buffer *buffer __free(kfree) = NULL;
- long nr_pages;
- int subbuf_size;
+ unsigned int subbuf_size;
+ unsigned long nr_pages;
int bsize;
int cpu;
int ret;
@@ -2828,6 +2849,8 @@ static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
size = end - buffers_start;
size = size / nr_cpu_ids;
+ if (size < sizeof(struct ring_buffer_cpu_meta))
+ goto fail_free_buffers;
/*
* The number of sub-buffers (nr_pages) is determined by the
* total size allocated minus the meta data size.
@@ -2837,6 +2860,10 @@ static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
*/
nr_pages = (size - sizeof(struct ring_buffer_cpu_meta)) /
(subbuf_size + sizeof(int));
+
+ if (nr_pages > rb_static_max_pages())
+ goto fail_free_buffers;
+
/* Need at least two pages plus the reader page */
if (nr_pages < 3)
goto fail_free_buffers;
@@ -2869,6 +2896,10 @@ static struct trace_buffer *alloc_buffer(unsigned long size, unsigned flags,
/* The writer is remote. This ring-buffer is read-only */
atomic_inc(&buffer->record_disabled);
nr_pages = desc->nr_page_va - 1;
+
+ if (nr_pages > rb_static_max_pages())
+ goto fail_free_buffers;
+
if (nr_pages < 2)
goto fail_free_buffers;
} else {
@@ -5853,12 +5884,12 @@ __rb_get_reader_page_from_remote(struct ring_buffer_per_cpu *cpu_buffer)
static struct buffer_page *
__rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
{
- int max_loops = cpu_buffer->ring_meta ? cpu_buffer->nr_pages : 3;
+ unsigned long max_loops = cpu_buffer->ring_meta ? cpu_buffer->nr_pages : 3;
struct buffer_page *reader = NULL;
+ unsigned long nr_loops = 0;
unsigned long overwrite;
unsigned long flags;
int missed_events = 0;
- int nr_loops = 0;
bool ret;
local_irq_save(flags);
@@ -6176,8 +6207,8 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts)
struct trace_buffer *buffer;
struct ring_buffer_per_cpu *cpu_buffer;
struct ring_buffer_event *event;
- int nr_loops = 0;
- int max_loops;
+ unsigned long nr_loops = 0;
+ unsigned long max_loops;
if (ts)
*ts = 0;
@@ -6993,56 +7024,78 @@ EXPORT_SYMBOL_GPL(ring_buffer_swap_cpu);
* ring_buffer_alloc_read_page - allocate a page to read from buffer
* @buffer: the buffer to allocate for.
* @cpu: the cpu buffer to allocate.
+ * @rpage: pointer to pass in an already allocated page (can be NULL)
+ * and returns the allocated page.
*
- * This function is used in conjunction with ring_buffer_read_page.
+ * This function is used in conjunction with ring_buffer_read_page().
* When reading a full page from the ring buffer, these functions
* can be used to speed up the process. The calling function should
* allocate a few pages first with this function. Then when it
* needs to get pages from the ring buffer, it passes the result
- * of this function into ring_buffer_read_page, which will swap
+ * of this function into ring_buffer_read_page(), which will swap
* the page that was allocated, with the read page of the buffer.
*
+ * If @rpage is provided, and it has a different order than the current
+ * subbuffer order, its payload will be freed and re-allocated. If it
+ * already matches the order, it is simply returned.
+ *
* Returns:
- * The page allocated, or ERR_PTR
+ * 0 on success, < 0 on error
*/
-struct buffer_data_read_page *
-ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu)
+int ring_buffer_alloc_read_page(struct trace_buffer *buffer, int cpu,
+ struct buffer_data_read_page **rpage)
{
struct ring_buffer_per_cpu *cpu_buffer;
- struct buffer_data_read_page *bpage = NULL;
unsigned long flags;
+ unsigned int order;
if (!cpumask_test_cpu(cpu, buffer->cpumask))
- return ERR_PTR(-ENODEV);
+ return -ENODEV;
- bpage = kzalloc_obj(*bpage);
- if (!bpage)
- return ERR_PTR(-ENOMEM);
+ if (!rpage)
+ return -EINVAL;
- bpage->order = buffer->subbuf_order;
+ order = READ_ONCE(buffer->subbuf_order);
+
+ if (*rpage) {
+ if ((*rpage)->order == order)
+ return 0;
+
+ /* We can reuse rpage, but we discard the payload */
+ free_pages((unsigned long)(*rpage)->data, (*rpage)->order);
+ (*rpage)->data = NULL;
+ } else {
+ *rpage = kzalloc_obj(**rpage);
+ if (!*rpage)
+ return -ENOMEM;
+ }
+
+ (*rpage)->order = order;
cpu_buffer = buffer->buffers[cpu];
+
local_irq_save(flags);
arch_spin_lock(&cpu_buffer->lock);
if (cpu_buffer->free_page.data) {
- *bpage = cpu_buffer->free_page;
+ **rpage = cpu_buffer->free_page;
cpu_buffer->free_page.data = NULL;
}
arch_spin_unlock(&cpu_buffer->lock);
local_irq_restore(flags);
- if (bpage->data) {
- rb_init_data_page(bpage->data);
+ if ((*rpage)->data) {
+ rb_init_data_page((*rpage)->data);
} else {
- bpage->data = alloc_cpu_data(cpu, bpage->order);
- if (!bpage->data) {
- kfree(bpage);
- return ERR_PTR(-ENOMEM);
+ (*rpage)->data = alloc_cpu_data(cpu, (*rpage)->order);
+ if (!(*rpage)->data) {
+ kfree(*rpage);
+ *rpage = NULL;
+ return -ENOMEM;
}
}
- return bpage;
+ return 0;
}
EXPORT_SYMBOL_GPL(ring_buffer_alloc_read_page);
@@ -7050,21 +7103,30 @@ EXPORT_SYMBOL_GPL(ring_buffer_alloc_read_page);
* ring_buffer_free_read_page - free an allocated read page
* @buffer: the buffer the page was allocate for
* @cpu: the cpu buffer the page came from
- * @data_page: the page to free
+ * @rpage: the buffer_data_read_page to free
*
* Free a page allocated from ring_buffer_alloc_read_page.
*/
void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu,
- struct buffer_data_read_page *data_page)
+ struct buffer_data_read_page *rpage)
{
struct ring_buffer_per_cpu *cpu_buffer;
- struct buffer_data_page *dpage = data_page->data;
- struct page *page = virt_to_page(dpage);
+ struct buffer_data_page *dpage;
unsigned long flags;
+ struct page *page;
if (!buffer || !buffer->buffers || !buffer->buffers[cpu])
return;
+ if (!rpage)
+ return;
+
+ dpage = rpage->data;
+ if (!dpage)
+ goto out;
+
+ page = virt_to_page(dpage);
+
cpu_buffer = buffer->buffers[cpu];
/*
@@ -7072,14 +7134,14 @@ void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu,
* is different from the subbuffer order of the buffer -
* we can't reuse it
*/
- if (page_ref_count(page) > 1 || data_page->order != buffer->subbuf_order)
+ if (page_ref_count(page) > 1 || rpage->order != READ_ONCE(buffer->subbuf_order))
goto out;
local_irq_save(flags);
arch_spin_lock(&cpu_buffer->lock);
if (!cpu_buffer->free_page.data) {
- cpu_buffer->free_page = *data_page;
+ cpu_buffer->free_page = *rpage;
dpage = NULL;
}
@@ -7087,8 +7149,8 @@ void ring_buffer_free_read_page(struct trace_buffer *buffer, int cpu,
local_irq_restore(flags);
out:
- free_pages((unsigned long)dpage, data_page->order);
- kfree(data_page);
+ free_pages((unsigned long)dpage, rpage->order);
+ kfree(rpage);
}
EXPORT_SYMBOL_GPL(ring_buffer_free_read_page);
@@ -7159,10 +7221,9 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
if (!dpage)
return -1;
- guard(raw_spinlock_irqsave)(&cpu_buffer->reader_lock);
+ len = min_t(size_t, len, rb_read_page_capacity(data_page));
- if (data_page->order != cpu_buffer->reader_page->order)
- return -1;
+ guard(raw_spinlock_irqsave)(&cpu_buffer->reader_lock);
reader = rb_get_reader_page(cpu_buffer);
if (!reader)
@@ -7177,31 +7238,26 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
/* Check if any events were dropped */
missed_events = cpu_buffer->lost_events;
- /*
- * If this page has been partially read or
- * if len is not big enough to read the rest of the page or
- * a writer is still on the page, then
- * we must copy the data from the page to the buffer.
- * Otherwise, we can simply swap the page with the one passed in.
- */
+ /*
+ * It is not possible to swap the reader page if:
+ * - It has been partially read
+ * - len is not big enough to read it entirely
+ * - A writer is still on it
+ * - The ring buffer is static
+ * - The order doesn't match
+ */
if (read || (len < (size - read)) ||
cpu_buffer->reader_page == cpu_buffer->commit_page ||
- rb_is_static(cpu_buffer)) {
+ rb_is_static(cpu_buffer) ||
+ data_page->order != reader->order) {
struct buffer_data_page *rpage = cpu_buffer->reader_page->page;
unsigned int rpos = read;
unsigned int pos = 0;
unsigned int event_size;
unsigned int flags = 0;
- /*
- * If a full page is expected, this can still be returned
- * if there's been a previous partial read and the
- * rest of the page can be read and the commit page is off
- * the reader page.
- */
- if (full &&
- (!read || (len < (size - read)) ||
- cpu_buffer->reader_page == cpu_buffer->commit_page))
+ /* If a full page is requested, it cannot be the commit page */
+ if (full && cpu_buffer->reader_page == cpu_buffer->commit_page)
return -1;
if (len > (size - read))
@@ -7287,7 +7343,7 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
* missed events, then record it there.
*/
if (missed_events > 0 &&
- rb_page_capacity(reader) - size >= sizeof(missed_events)) {
+ rb_read_page_capacity(data_page) - size >= sizeof(missed_events)) {
memcpy(&dpage->data[size], &missed_events,
sizeof(missed_events));
local_add(RB_MISSED_STORED, &dpage->commit);
@@ -7307,8 +7363,8 @@ int ring_buffer_read_page(struct trace_buffer *buffer,
/*
* This page may be off to user land. Zero it out here.
*/
- if (size < rb_page_capacity(reader))
- memset(&dpage->data[size], 0, rb_page_capacity(reader) - size);
+ if (size < rb_read_page_capacity(data_page))
+ memset(&dpage->data[size], 0, rb_read_page_capacity(data_page) - size);
return read;
}
@@ -7327,6 +7383,18 @@ void *ring_buffer_read_page_data(struct buffer_data_read_page *page)
EXPORT_SYMBOL_GPL(ring_buffer_read_page_data);
/**
+ * ring_buffer_read_page_size - get size of the read page.
+ * @page: the page to get the size from
+ *
+ * Returns size of the page in bytes.
+ */
+unsigned int ring_buffer_read_page_size(struct buffer_data_read_page *rpage)
+{
+ return rpage ? PAGE_SIZE << rpage->order : 0;
+}
+EXPORT_SYMBOL_GPL(ring_buffer_read_page_size);
+
+/**
* ring_buffer_subbuf_size_get - get size of the sub buffer.
* @buffer: the buffer to get the sub buffer size from
*
@@ -7380,8 +7448,8 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
struct ring_buffer_per_cpu *cpu_buffer;
struct buffer_page *bpage, *tmp;
unsigned int old_capacity;
+ unsigned long nr_pages;
int old_order;
- int nr_pages;
int psize;
int err;
int cpu;
@@ -7411,7 +7479,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
/* Make sure all commits have finished */
synchronize_rcu();
- buffer->subbuf_order = order;
+ WRITE_ONCE(buffer->subbuf_order, order);
/* Make sure all new buffers are allocated, before deleting the old ones */
for_each_buffer_cpu(buffer, cpu) {
@@ -7515,7 +7583,7 @@ int ring_buffer_subbuf_order_set(struct trace_buffer *buffer, int order)
return 0;
error:
- buffer->subbuf_order = old_order;
+ WRITE_ONCE(buffer->subbuf_order, old_order);
atomic_dec(&buffer->record_disabled);
@@ -7563,10 +7631,10 @@ static void rb_setup_ids_meta_page(struct ring_buffer_per_cpu *cpu_buffer,
struct buffer_page **subbuf_ids)
{
struct trace_buffer_meta *meta = cpu_buffer->meta_page;
- unsigned int nr_subbufs = cpu_buffer->nr_pages + 1;
+ unsigned long nr_subbufs = cpu_buffer->nr_pages + 1;
struct buffer_page *first_subbuf, *subbuf;
- int cnt = 0;
- int id = 0;
+ unsigned int cnt = 0;
+ unsigned int id = 0;
id = rb_page_id(cpu_buffer, cpu_buffer->reader_page, id);
subbuf_ids[id++] = cpu_buffer->reader_page;
@@ -7794,6 +7862,9 @@ int ring_buffer_map(struct trace_buffer *buffer, int cpu,
/* prevent another thread from changing buffer/sub-buffer sizes */
guard(mutex)(&buffer->mutex);
+ if (cpu_buffer->nr_pages > rb_static_max_pages())
+ return -E2BIG;
+
err = rb_alloc_meta_page(cpu_buffer);
if (err)
return err;