Skip to content

Commit cf9f0f7

Browse files
vdonnefortrostedt
authored andcommitted
tracing: Allow user-space mapping of the ring-buffer
Currently, user-space extracts data from the ring-buffer via splice, which is handy for storage or network sharing. However, due to splice limitations, it is imposible to do real-time analysis without a copy. A solution for that problem is to let the user-space map the ring-buffer directly. The mapping is exposed via the per-CPU file trace_pipe_raw. The first element of the mapping is the meta-page. It is followed by each subbuffer constituting the ring-buffer, ordered by their unique page ID: * Meta-page -- include/uapi/linux/trace_mmap.h for a description * Subbuf ID 0 * Subbuf ID 1 ... It is therefore easy to translate a subbuf ID into an offset in the mapping: reader_id = meta->reader->id; reader_offset = meta->meta_page_size + reader_id * meta->subbuf_size; When new data is available, the mapper must call a newly introduced ioctl: TRACE_MMAP_IOCTL_GET_READER. This will update the Meta-page reader ID to point to the next reader containing unread data. Mapping will prevent snapshot and buffer size modifications. Link: https://lore.kernel.org/linux-trace-kernel/[email protected] CC: <[email protected]> Signed-off-by: Vincent Donnefort <[email protected]> Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 117c392 commit cf9f0f7

File tree

3 files changed

+102
-5
lines changed

3 files changed

+102
-5
lines changed

include/uapi/linux/trace_mmap.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,6 @@ struct trace_buffer_meta {
4343
__u64 Reserved2;
4444
};
4545

46+
#define TRACE_MMAP_IOCTL_GET_READER _IO('T', 0x1)
47+
4648
#endif /* _TRACE_MMAP_H_ */

kernel/trace/trace.c

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,12 @@ static void tracing_snapshot_instance_cond(struct trace_array *tr,
11911191
return;
11921192
}
11931193

1194+
if (tr->mapped) {
1195+
trace_array_puts(tr, "*** BUFFER MEMORY MAPPED ***\n");
1196+
trace_array_puts(tr, "*** Can not use snapshot (sorry) ***\n");
1197+
return;
1198+
}
1199+
11941200
local_irq_save(flags);
11951201
update_max_tr(tr, current, smp_processor_id(), cond_data);
11961202
local_irq_restore(flags);
@@ -1323,7 +1329,7 @@ static int tracing_arm_snapshot_locked(struct trace_array *tr)
13231329
lockdep_assert_held(&trace_types_lock);
13241330

13251331
spin_lock(&tr->snapshot_trigger_lock);
1326-
if (tr->snapshot == UINT_MAX) {
1332+
if (tr->snapshot == UINT_MAX || tr->mapped) {
13271333
spin_unlock(&tr->snapshot_trigger_lock);
13281334
return -EBUSY;
13291335
}
@@ -6068,7 +6074,7 @@ static void tracing_set_nop(struct trace_array *tr)
60686074
{
60696075
if (tr->current_trace == &nop_trace)
60706076
return;
6071-
6077+
60726078
tr->current_trace->enabled--;
60736079

60746080
if (tr->current_trace->reset)
@@ -8194,15 +8200,32 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
81948200
return ret;
81958201
}
81968202

8197-
/* An ioctl call with cmd 0 to the ring buffer file will wake up all waiters */
81988203
static long tracing_buffers_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
81998204
{
82008205
struct ftrace_buffer_info *info = file->private_data;
82018206
struct trace_iterator *iter = &info->iter;
8207+
int err;
8208+
8209+
if (cmd == TRACE_MMAP_IOCTL_GET_READER) {
8210+
if (!(file->f_flags & O_NONBLOCK)) {
8211+
err = ring_buffer_wait(iter->array_buffer->buffer,
8212+
iter->cpu_file,
8213+
iter->tr->buffer_percent,
8214+
NULL, NULL);
8215+
if (err)
8216+
return err;
8217+
}
82028218

8203-
if (cmd)
8204-
return -ENOIOCTLCMD;
8219+
return ring_buffer_map_get_reader(iter->array_buffer->buffer,
8220+
iter->cpu_file);
8221+
} else if (cmd) {
8222+
return -ENOTTY;
8223+
}
82058224

8225+
/*
8226+
* An ioctl call with cmd 0 to the ring buffer file will wake up all
8227+
* waiters
8228+
*/
82068229
mutex_lock(&trace_types_lock);
82078230

82088231
/* Make sure the waiters see the new wait_index */
@@ -8214,6 +8237,76 @@ static long tracing_buffers_ioctl(struct file *file, unsigned int cmd, unsigned
82148237
return 0;
82158238
}
82168239

8240+
#ifdef CONFIG_TRACER_MAX_TRACE
8241+
static int get_snapshot_map(struct trace_array *tr)
8242+
{
8243+
int err = 0;
8244+
8245+
/*
8246+
* Called with mmap_lock held. lockdep would be unhappy if we would now
8247+
* take trace_types_lock. Instead use the specific
8248+
* snapshot_trigger_lock.
8249+
*/
8250+
spin_lock(&tr->snapshot_trigger_lock);
8251+
8252+
if (tr->snapshot || tr->mapped == UINT_MAX)
8253+
err = -EBUSY;
8254+
else
8255+
tr->mapped++;
8256+
8257+
spin_unlock(&tr->snapshot_trigger_lock);
8258+
8259+
/* Wait for update_max_tr() to observe iter->tr->mapped */
8260+
if (tr->mapped == 1)
8261+
synchronize_rcu();
8262+
8263+
return err;
8264+
8265+
}
8266+
static void put_snapshot_map(struct trace_array *tr)
8267+
{
8268+
spin_lock(&tr->snapshot_trigger_lock);
8269+
if (!WARN_ON(!tr->mapped))
8270+
tr->mapped--;
8271+
spin_unlock(&tr->snapshot_trigger_lock);
8272+
}
8273+
#else
8274+
static inline int get_snapshot_map(struct trace_array *tr) { return 0; }
8275+
static inline void put_snapshot_map(struct trace_array *tr) { }
8276+
#endif
8277+
8278+
static void tracing_buffers_mmap_close(struct vm_area_struct *vma)
8279+
{
8280+
struct ftrace_buffer_info *info = vma->vm_file->private_data;
8281+
struct trace_iterator *iter = &info->iter;
8282+
8283+
WARN_ON(ring_buffer_unmap(iter->array_buffer->buffer, iter->cpu_file));
8284+
put_snapshot_map(iter->tr);
8285+
}
8286+
8287+
static const struct vm_operations_struct tracing_buffers_vmops = {
8288+
.close = tracing_buffers_mmap_close,
8289+
};
8290+
8291+
static int tracing_buffers_mmap(struct file *filp, struct vm_area_struct *vma)
8292+
{
8293+
struct ftrace_buffer_info *info = filp->private_data;
8294+
struct trace_iterator *iter = &info->iter;
8295+
int ret = 0;
8296+
8297+
ret = get_snapshot_map(iter->tr);
8298+
if (ret)
8299+
return ret;
8300+
8301+
ret = ring_buffer_map(iter->array_buffer->buffer, iter->cpu_file, vma);
8302+
if (ret)
8303+
put_snapshot_map(iter->tr);
8304+
8305+
vma->vm_ops = &tracing_buffers_vmops;
8306+
8307+
return ret;
8308+
}
8309+
82178310
static const struct file_operations tracing_buffers_fops = {
82188311
.open = tracing_buffers_open,
82198312
.read = tracing_buffers_read,
@@ -8223,6 +8316,7 @@ static const struct file_operations tracing_buffers_fops = {
82238316
.splice_read = tracing_buffers_splice_read,
82248317
.unlocked_ioctl = tracing_buffers_ioctl,
82258318
.llseek = no_llseek,
8319+
.mmap = tracing_buffers_mmap,
82268320
};
82278321

82288322
static ssize_t

kernel/trace/trace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ struct trace_array {
336336
bool allocated_snapshot;
337337
spinlock_t snapshot_trigger_lock;
338338
unsigned int snapshot;
339+
unsigned int mapped;
339340
unsigned long max_latency;
340341
#ifdef CONFIG_FSNOTIFY
341342
struct dentry *d_max_latency;

0 commit comments

Comments
 (0)