Add kmalloc failover to vmalloc
[lttng-modules.git] / lib / ringbuffer / ring_buffer_frontend.c
index 68b62382e9fc87c2a307887cc67e144dfe1528a8..c9ab43f92eee39229f1c3892d1c9610691bec614 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/percpu.h>
+#include <asm/cacheflush.h>
 
 #include <wrapper/ringbuffer/config.h>
 #include <wrapper/ringbuffer/backend.h>
@@ -64,6 +65,7 @@
 #include <wrapper/kref.h>
 #include <wrapper/percpu-defs.h>
 #include <wrapper/timer.h>
+#include <wrapper/vmalloc.h>
 
 /*
  * Internal structure representing offsets to use at a sub-buffer switch.
@@ -146,8 +148,8 @@ void lib_ring_buffer_free(struct lib_ring_buffer *buf)
        struct channel *chan = buf->backend.chan;
 
        lib_ring_buffer_print_errors(chan, buf, buf->backend.cpu);
-       kfree(buf->commit_hot);
-       kfree(buf->commit_cold);
+       lttng_kvfree(buf->commit_hot);
+       lttng_kvfree(buf->commit_cold);
 
        lib_ring_buffer_backend_free(&buf->backend);
 }
@@ -244,7 +246,7 @@ int lib_ring_buffer_create(struct lib_ring_buffer *buf,
                return ret;
 
        buf->commit_hot =
-               kzalloc_node(ALIGN(sizeof(*buf->commit_hot)
+               lttng_kvzalloc_node(ALIGN(sizeof(*buf->commit_hot)
                                   * chan->backend.num_subbuf,
                                   1 << INTERNODE_CACHE_SHIFT),
                        GFP_KERNEL | __GFP_NOWARN,
@@ -255,7 +257,7 @@ int lib_ring_buffer_create(struct lib_ring_buffer *buf,
        }
 
        buf->commit_cold =
-               kzalloc_node(ALIGN(sizeof(*buf->commit_cold)
+               lttng_kvzalloc_node(ALIGN(sizeof(*buf->commit_cold)
                                   * chan->backend.num_subbuf,
                                   1 << INTERNODE_CACHE_SHIFT),
                        GFP_KERNEL | __GFP_NOWARN,
@@ -304,9 +306,9 @@ int lib_ring_buffer_create(struct lib_ring_buffer *buf,
 
        /* Error handling */
 free_init:
-       kfree(buf->commit_cold);
+       lttng_kvfree(buf->commit_cold);
 free_commit:
-       kfree(buf->commit_hot);
+       lttng_kvfree(buf->commit_hot);
 free_chanbuf:
        lib_ring_buffer_backend_free(&buf->backend);
        return ret;
@@ -1119,6 +1121,37 @@ nodata:
 }
 EXPORT_SYMBOL_GPL(lib_ring_buffer_snapshot);
 
+/**
+ * Performs the same function as lib_ring_buffer_snapshot(), but the positions
+ * are saved regardless of whether the consumed and produced positions are
+ * in the same subbuffer.
+ * @buf: ring buffer
+ * @consumed: consumed byte count indicating the last position read
+ * @produced: produced byte count indicating the last position written
+ *
+ * This function is meant to provide information on the exact producer and
+ * consumer positions without regard for the "snapshot" feature.
+ */
+int lib_ring_buffer_snapshot_sample_positions(struct lib_ring_buffer *buf,
+               unsigned long *consumed, unsigned long *produced)
+{
+       struct channel *chan = buf->backend.chan;
+       const struct lib_ring_buffer_config *config = &chan->backend.config;
+
+       smp_rmb();
+       *consumed = atomic_long_read(&buf->consumed);
+       /*
+        * No need to issue a memory barrier between consumed count read and
+        * write offset read, because consumed count can only change
+        * concurrently in overwrite mode, and we keep a sequence counter
+        * identifier derived from the write offset to check we are getting
+        * the same sub-buffer we are expecting (the sub-buffers are atomically
+        * "tagged" upon writes, tags are checked upon read).
+        */
+       *produced = v_read(config, &buf->offset);
+       return 0;
+}
+
 /**
  * lib_ring_buffer_put_snapshot - move consumed counter forward
  *
@@ -1149,6 +1182,47 @@ void lib_ring_buffer_move_consumer(struct lib_ring_buffer *buf,
 }
 EXPORT_SYMBOL_GPL(lib_ring_buffer_move_consumer);
 
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
+static void lib_ring_buffer_flush_read_subbuf_dcache(
+               const struct lib_ring_buffer_config *config,
+               struct channel *chan,
+               struct lib_ring_buffer *buf)
+{
+       struct lib_ring_buffer_backend_pages *pages;
+       unsigned long sb_bindex, id, i, nr_pages;
+
+       if (config->output != RING_BUFFER_MMAP)
+               return;
+
+       /*
+        * Architectures with caches aliased on virtual addresses may
+        * use different cache lines for the linear mapping vs
+        * user-space memory mapping. Given that the ring buffer is
+        * based on the kernel linear mapping, aligning it with the
+        * user-space mapping is not straightforward, and would require
+        * extra TLB entries. Therefore, simply flush the dcache for the
+        * entire sub-buffer before reading it.
+        */
+       id = buf->backend.buf_rsb.id;
+       sb_bindex = subbuffer_id_get_index(config, id);
+       pages = buf->backend.array[sb_bindex];
+       nr_pages = buf->backend.num_pages_per_subbuf;
+       for (i = 0; i < nr_pages; i++) {
+               struct lib_ring_buffer_backend_page *backend_page;
+
+               backend_page = &pages->p[i];
+               flush_dcache_page(pfn_to_page(backend_page->pfn));
+       }
+}
+#else
+static void lib_ring_buffer_flush_read_subbuf_dcache(
+               const struct lib_ring_buffer_config *config,
+               struct channel *chan,
+               struct lib_ring_buffer *buf)
+{
+}
+#endif
+
 /**
  * lib_ring_buffer_get_subbuf - get exclusive access to subbuffer for reading
  * @buf: ring buffer
@@ -1291,6 +1365,8 @@ retry:
        buf->get_subbuf_consumed = consumed;
        buf->get_subbuf = 1;
 
+       lib_ring_buffer_flush_read_subbuf_dcache(config, chan, buf);
+
        return 0;
 
 nodata:
@@ -1464,8 +1540,7 @@ void lib_ring_buffer_print_errors(struct channel *chan,
 /*
  * lib_ring_buffer_switch_old_start: Populate old subbuffer header.
  *
- * Only executed by SWITCH_FLUSH, which can be issued while tracing is active
- * or at buffer finalization (destroy).
+ * Only executed when the buffer is finalized, in SWITCH_FLUSH.
  */
 static
 void lib_ring_buffer_switch_old_start(struct lib_ring_buffer *buf,
@@ -1661,14 +1736,12 @@ int lib_ring_buffer_try_switch_slow(enum switch_mode mode,
                unsigned long sb_index, commit_count;
 
                /*
-                * We are performing a SWITCH_FLUSH. There may be concurrent
-                * writes into the buffer if e.g. invoked while performing a
-                * snapshot on an active trace.
+                * We are performing a SWITCH_FLUSH. At this stage, there are no
+                * concurrent writes into the buffer.
                 *
-                * If the client does not save any header information (sub-buffer
-                * header size == 0), don't switch empty subbuffer on finalize,
-                * because it is invalid to deliver a completely empty
-                * subbuffer.
+                * The client does not save any header information.  Don't
+                * switch empty subbuffer on finalize, because it is invalid to
+                * deliver a completely empty subbuffer.
                 */
                if (!config->cb.subbuffer_header_size())
                        return -1;
@@ -1833,6 +1906,7 @@ static void _lib_ring_buffer_switch_remote(struct lib_ring_buffer *buf,
        put_online_cpus();
 }
 
+/* Switch sub-buffer if current sub-buffer is non-empty. */
 void lib_ring_buffer_switch_remote(struct lib_ring_buffer *buf)
 {
        _lib_ring_buffer_switch_remote(buf, SWITCH_ACTIVE);
@@ -1857,7 +1931,8 @@ static
 int lib_ring_buffer_try_reserve_slow(struct lib_ring_buffer *buf,
                                     struct channel *chan,
                                     struct switch_offsets *offsets,
-                                    struct lib_ring_buffer_ctx *ctx)
+                                    struct lib_ring_buffer_ctx *ctx,
+                                    void *client_ctx)
 {
        const struct lib_ring_buffer_config *config = &chan->backend.config;
        unsigned long reserve_commit_diff, offset_cmp;
@@ -1883,7 +1958,7 @@ retry:
                offsets->size = config->cb.record_header_size(config, chan,
                                                offsets->begin,
                                                &offsets->pre_header_padding,
-                                               ctx);
+                                               ctx, client_ctx);
                offsets->size +=
                        lib_ring_buffer_align(offsets->begin + offsets->size,
                                              ctx->largest_align)
@@ -1967,7 +2042,7 @@ retry:
                        config->cb.record_header_size(config, chan,
                                                offsets->begin,
                                                &offsets->pre_header_padding,
-                                               ctx);
+                                               ctx, client_ctx);
                offsets->size +=
                        lib_ring_buffer_align(offsets->begin + offsets->size,
                                              ctx->largest_align)
@@ -2031,7 +2106,8 @@ EXPORT_SYMBOL_GPL(lib_ring_buffer_lost_event_too_big);
  * -EIO for other errors, else returns 0.
  * It will take care of sub-buffer switching.
  */
-int lib_ring_buffer_reserve_slow(struct lib_ring_buffer_ctx *ctx)
+int lib_ring_buffer_reserve_slow(struct lib_ring_buffer_ctx *ctx,
+               void *client_ctx)
 {
        struct channel *chan = ctx->chan;
        const struct lib_ring_buffer_config *config = &chan->backend.config;
@@ -2044,7 +2120,7 @@ int lib_ring_buffer_reserve_slow(struct lib_ring_buffer_ctx *ctx)
 
        do {
                ret = lib_ring_buffer_try_reserve_slow(buf, chan, &offsets,
-                                                      ctx);
+                                                      ctx, client_ctx);
                if (unlikely(ret))
                        return ret;
        } while (unlikely(v_cmpxchg(config, &buf->offset, offsets.old,
This page took 0.029332 seconds and 4 git commands to generate.