196e43537SVincent Donnefort // SPDX-License-Identifier: GPL-2.0
296e43537SVincent Donnefort /*
396e43537SVincent Donnefort * Copyright (C) 2025 - Google LLC
496e43537SVincent Donnefort * Author: Vincent Donnefort <vdonnefort@google.com>
596e43537SVincent Donnefort */
696e43537SVincent Donnefort
796e43537SVincent Donnefort #include <linux/kstrtox.h>
896e43537SVincent Donnefort #include <linux/lockdep.h>
996e43537SVincent Donnefort #include <linux/mutex.h>
1096e43537SVincent Donnefort #include <linux/tracefs.h>
1196e43537SVincent Donnefort #include <linux/trace_remote.h>
1296e43537SVincent Donnefort #include <linux/trace_seq.h>
1396e43537SVincent Donnefort #include <linux/types.h>
1496e43537SVincent Donnefort
1596e43537SVincent Donnefort #include "trace.h"
1696e43537SVincent Donnefort
1796e43537SVincent Donnefort #define TRACEFS_DIR "remotes"
1896e43537SVincent Donnefort #define TRACEFS_MODE_WRITE 0640
1996e43537SVincent Donnefort #define TRACEFS_MODE_READ 0440
2096e43537SVincent Donnefort
21330b0cceSVincent Donnefort enum tri_type {
22330b0cceSVincent Donnefort TRI_CONSUMING,
23330b0cceSVincent Donnefort TRI_NONCONSUMING,
24330b0cceSVincent Donnefort };
25330b0cceSVincent Donnefort
2696e43537SVincent Donnefort struct trace_remote_iterator {
2796e43537SVincent Donnefort struct trace_remote *remote;
2896e43537SVincent Donnefort struct trace_seq seq;
2996e43537SVincent Donnefort struct delayed_work poll_work;
3096e43537SVincent Donnefort unsigned long lost_events;
3196e43537SVincent Donnefort u64 ts;
32330b0cceSVincent Donnefort struct ring_buffer_iter *rb_iter;
33330b0cceSVincent Donnefort struct ring_buffer_iter **rb_iters;
3407252915SVincent Donnefort struct remote_event_hdr *evt;
3596e43537SVincent Donnefort int cpu;
3696e43537SVincent Donnefort int evt_cpu;
37330b0cceSVincent Donnefort loff_t pos;
38330b0cceSVincent Donnefort enum tri_type type;
3996e43537SVincent Donnefort };
4096e43537SVincent Donnefort
4196e43537SVincent Donnefort struct trace_remote {
4296e43537SVincent Donnefort struct trace_remote_callbacks *cbs;
4396e43537SVincent Donnefort void *priv;
4496e43537SVincent Donnefort struct trace_buffer *trace_buffer;
4596e43537SVincent Donnefort struct trace_buffer_desc *trace_buffer_desc;
4607252915SVincent Donnefort struct dentry *dentry;
4707252915SVincent Donnefort struct eventfs_inode *eventfs;
4807252915SVincent Donnefort struct remote_event *events;
4907252915SVincent Donnefort unsigned long nr_events;
5096e43537SVincent Donnefort unsigned long trace_buffer_size;
5196e43537SVincent Donnefort struct ring_buffer_remote rb_remote;
5296e43537SVincent Donnefort struct mutex lock;
53330b0cceSVincent Donnefort struct rw_semaphore reader_lock;
54330b0cceSVincent Donnefort struct rw_semaphore *pcpu_reader_locks;
5596e43537SVincent Donnefort unsigned int nr_readers;
5696e43537SVincent Donnefort unsigned int poll_ms;
5796e43537SVincent Donnefort bool tracing_on;
5896e43537SVincent Donnefort };
5996e43537SVincent Donnefort
trace_remote_loaded(struct trace_remote * remote)6096e43537SVincent Donnefort static bool trace_remote_loaded(struct trace_remote *remote)
6196e43537SVincent Donnefort {
6296e43537SVincent Donnefort return !!remote->trace_buffer;
6396e43537SVincent Donnefort }
6496e43537SVincent Donnefort
trace_remote_load(struct trace_remote * remote)6596e43537SVincent Donnefort static int trace_remote_load(struct trace_remote *remote)
6696e43537SVincent Donnefort {
6796e43537SVincent Donnefort struct ring_buffer_remote *rb_remote = &remote->rb_remote;
6896e43537SVincent Donnefort struct trace_buffer_desc *desc;
6996e43537SVincent Donnefort
7096e43537SVincent Donnefort lockdep_assert_held(&remote->lock);
7196e43537SVincent Donnefort
7296e43537SVincent Donnefort if (trace_remote_loaded(remote))
7396e43537SVincent Donnefort return 0;
7496e43537SVincent Donnefort
7596e43537SVincent Donnefort desc = remote->cbs->load_trace_buffer(remote->trace_buffer_size, remote->priv);
7696e43537SVincent Donnefort if (IS_ERR(desc))
7796e43537SVincent Donnefort return PTR_ERR(desc);
7896e43537SVincent Donnefort
7996e43537SVincent Donnefort rb_remote->desc = desc;
8096e43537SVincent Donnefort rb_remote->swap_reader_page = remote->cbs->swap_reader_page;
8196e43537SVincent Donnefort rb_remote->priv = remote->priv;
829af4ab0eSVincent Donnefort rb_remote->reset = remote->cbs->reset;
8396e43537SVincent Donnefort remote->trace_buffer = ring_buffer_alloc_remote(rb_remote);
8496e43537SVincent Donnefort if (!remote->trace_buffer) {
8596e43537SVincent Donnefort remote->cbs->unload_trace_buffer(desc, remote->priv);
8696e43537SVincent Donnefort return -ENOMEM;
8796e43537SVincent Donnefort }
8896e43537SVincent Donnefort
8996e43537SVincent Donnefort remote->trace_buffer_desc = desc;
9096e43537SVincent Donnefort
9196e43537SVincent Donnefort return 0;
9296e43537SVincent Donnefort }
9396e43537SVincent Donnefort
trace_remote_try_unload(struct trace_remote * remote)9496e43537SVincent Donnefort static void trace_remote_try_unload(struct trace_remote *remote)
9596e43537SVincent Donnefort {
9696e43537SVincent Donnefort lockdep_assert_held(&remote->lock);
9796e43537SVincent Donnefort
9896e43537SVincent Donnefort if (!trace_remote_loaded(remote))
9996e43537SVincent Donnefort return;
10096e43537SVincent Donnefort
10196e43537SVincent Donnefort /* The buffer is being read or writable */
10296e43537SVincent Donnefort if (remote->nr_readers || remote->tracing_on)
10396e43537SVincent Donnefort return;
10496e43537SVincent Donnefort
10596e43537SVincent Donnefort /* The buffer has readable data */
10696e43537SVincent Donnefort if (!ring_buffer_empty(remote->trace_buffer))
10796e43537SVincent Donnefort return;
10896e43537SVincent Donnefort
10996e43537SVincent Donnefort ring_buffer_free(remote->trace_buffer);
11096e43537SVincent Donnefort remote->trace_buffer = NULL;
11196e43537SVincent Donnefort remote->cbs->unload_trace_buffer(remote->trace_buffer_desc, remote->priv);
11296e43537SVincent Donnefort }
11396e43537SVincent Donnefort
trace_remote_enable_tracing(struct trace_remote * remote)11496e43537SVincent Donnefort static int trace_remote_enable_tracing(struct trace_remote *remote)
11596e43537SVincent Donnefort {
11696e43537SVincent Donnefort int ret;
11796e43537SVincent Donnefort
11896e43537SVincent Donnefort lockdep_assert_held(&remote->lock);
11996e43537SVincent Donnefort
12096e43537SVincent Donnefort if (remote->tracing_on)
12196e43537SVincent Donnefort return 0;
12296e43537SVincent Donnefort
12396e43537SVincent Donnefort ret = trace_remote_load(remote);
12496e43537SVincent Donnefort if (ret)
12596e43537SVincent Donnefort return ret;
12696e43537SVincent Donnefort
12796e43537SVincent Donnefort ret = remote->cbs->enable_tracing(true, remote->priv);
12896e43537SVincent Donnefort if (ret) {
12996e43537SVincent Donnefort trace_remote_try_unload(remote);
13096e43537SVincent Donnefort return ret;
13196e43537SVincent Donnefort }
13296e43537SVincent Donnefort
13396e43537SVincent Donnefort remote->tracing_on = true;
13496e43537SVincent Donnefort
13596e43537SVincent Donnefort return 0;
13696e43537SVincent Donnefort }
13796e43537SVincent Donnefort
trace_remote_disable_tracing(struct trace_remote * remote)13896e43537SVincent Donnefort static int trace_remote_disable_tracing(struct trace_remote *remote)
13996e43537SVincent Donnefort {
14096e43537SVincent Donnefort int ret;
14196e43537SVincent Donnefort
14296e43537SVincent Donnefort lockdep_assert_held(&remote->lock);
14396e43537SVincent Donnefort
14496e43537SVincent Donnefort if (!remote->tracing_on)
14596e43537SVincent Donnefort return 0;
14696e43537SVincent Donnefort
14796e43537SVincent Donnefort ret = remote->cbs->enable_tracing(false, remote->priv);
14896e43537SVincent Donnefort if (ret)
14996e43537SVincent Donnefort return ret;
15096e43537SVincent Donnefort
15196e43537SVincent Donnefort ring_buffer_poll_remote(remote->trace_buffer, RING_BUFFER_ALL_CPUS);
15296e43537SVincent Donnefort remote->tracing_on = false;
15396e43537SVincent Donnefort trace_remote_try_unload(remote);
15496e43537SVincent Donnefort
15596e43537SVincent Donnefort return 0;
15696e43537SVincent Donnefort }
15796e43537SVincent Donnefort
trace_remote_reset(struct trace_remote * remote,int cpu)1589af4ab0eSVincent Donnefort static void trace_remote_reset(struct trace_remote *remote, int cpu)
1599af4ab0eSVincent Donnefort {
1609af4ab0eSVincent Donnefort lockdep_assert_held(&remote->lock);
1619af4ab0eSVincent Donnefort
1629af4ab0eSVincent Donnefort if (!trace_remote_loaded(remote))
1639af4ab0eSVincent Donnefort return;
1649af4ab0eSVincent Donnefort
1659af4ab0eSVincent Donnefort if (cpu == RING_BUFFER_ALL_CPUS)
1669af4ab0eSVincent Donnefort ring_buffer_reset(remote->trace_buffer);
1679af4ab0eSVincent Donnefort else
1689af4ab0eSVincent Donnefort ring_buffer_reset_cpu(remote->trace_buffer, cpu);
1699af4ab0eSVincent Donnefort
1709af4ab0eSVincent Donnefort trace_remote_try_unload(remote);
1719af4ab0eSVincent Donnefort }
1729af4ab0eSVincent Donnefort
17396e43537SVincent Donnefort static ssize_t
tracing_on_write(struct file * filp,const char __user * ubuf,size_t cnt,loff_t * ppos)17496e43537SVincent Donnefort tracing_on_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
17596e43537SVincent Donnefort {
17607252915SVincent Donnefort struct seq_file *seq = filp->private_data;
17707252915SVincent Donnefort struct trace_remote *remote = seq->private;
17896e43537SVincent Donnefort unsigned long val;
17996e43537SVincent Donnefort int ret;
18096e43537SVincent Donnefort
18196e43537SVincent Donnefort ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
18296e43537SVincent Donnefort if (ret)
18396e43537SVincent Donnefort return ret;
18496e43537SVincent Donnefort
18596e43537SVincent Donnefort guard(mutex)(&remote->lock);
18696e43537SVincent Donnefort
18796e43537SVincent Donnefort ret = val ? trace_remote_enable_tracing(remote) : trace_remote_disable_tracing(remote);
18896e43537SVincent Donnefort if (ret)
18996e43537SVincent Donnefort return ret;
19096e43537SVincent Donnefort
19196e43537SVincent Donnefort return cnt;
19296e43537SVincent Donnefort }
tracing_on_show(struct seq_file * s,void * unused)19396e43537SVincent Donnefort static int tracing_on_show(struct seq_file *s, void *unused)
19496e43537SVincent Donnefort {
19596e43537SVincent Donnefort struct trace_remote *remote = s->private;
19696e43537SVincent Donnefort
19796e43537SVincent Donnefort seq_printf(s, "%d\n", remote->tracing_on);
19896e43537SVincent Donnefort
19996e43537SVincent Donnefort return 0;
20096e43537SVincent Donnefort }
20196e43537SVincent Donnefort DEFINE_SHOW_STORE_ATTRIBUTE(tracing_on);
20296e43537SVincent Donnefort
buffer_size_kb_write(struct file * filp,const char __user * ubuf,size_t cnt,loff_t * ppos)20396e43537SVincent Donnefort static ssize_t buffer_size_kb_write(struct file *filp, const char __user *ubuf, size_t cnt,
20496e43537SVincent Donnefort loff_t *ppos)
20596e43537SVincent Donnefort {
20607252915SVincent Donnefort struct seq_file *seq = filp->private_data;
20707252915SVincent Donnefort struct trace_remote *remote = seq->private;
20896e43537SVincent Donnefort unsigned long val;
20996e43537SVincent Donnefort int ret;
21096e43537SVincent Donnefort
21196e43537SVincent Donnefort ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
21296e43537SVincent Donnefort if (ret)
21396e43537SVincent Donnefort return ret;
21496e43537SVincent Donnefort
21596e43537SVincent Donnefort /* KiB to Bytes */
21696e43537SVincent Donnefort if (!val || check_shl_overflow(val, 10, &val))
21796e43537SVincent Donnefort return -EINVAL;
21896e43537SVincent Donnefort
21996e43537SVincent Donnefort guard(mutex)(&remote->lock);
22096e43537SVincent Donnefort
22196e43537SVincent Donnefort if (trace_remote_loaded(remote))
22296e43537SVincent Donnefort return -EBUSY;
22396e43537SVincent Donnefort
22496e43537SVincent Donnefort remote->trace_buffer_size = val;
22596e43537SVincent Donnefort
22696e43537SVincent Donnefort return cnt;
22796e43537SVincent Donnefort }
22896e43537SVincent Donnefort
buffer_size_kb_show(struct seq_file * s,void * unused)22996e43537SVincent Donnefort static int buffer_size_kb_show(struct seq_file *s, void *unused)
23096e43537SVincent Donnefort {
23196e43537SVincent Donnefort struct trace_remote *remote = s->private;
23296e43537SVincent Donnefort
23396e43537SVincent Donnefort seq_printf(s, "%lu (%s)\n", remote->trace_buffer_size >> 10,
23496e43537SVincent Donnefort trace_remote_loaded(remote) ? "loaded" : "unloaded");
23596e43537SVincent Donnefort
23696e43537SVincent Donnefort return 0;
23796e43537SVincent Donnefort }
23896e43537SVincent Donnefort DEFINE_SHOW_STORE_ATTRIBUTE(buffer_size_kb);
23996e43537SVincent Donnefort
trace_remote_get(struct trace_remote * remote,int cpu)24096e43537SVincent Donnefort static int trace_remote_get(struct trace_remote *remote, int cpu)
24196e43537SVincent Donnefort {
24296e43537SVincent Donnefort int ret;
24396e43537SVincent Donnefort
24496e43537SVincent Donnefort if (remote->nr_readers == UINT_MAX)
24596e43537SVincent Donnefort return -EBUSY;
24696e43537SVincent Donnefort
24796e43537SVincent Donnefort ret = trace_remote_load(remote);
24896e43537SVincent Donnefort if (ret)
24996e43537SVincent Donnefort return ret;
25096e43537SVincent Donnefort
251330b0cceSVincent Donnefort if (cpu != RING_BUFFER_ALL_CPUS && !remote->pcpu_reader_locks) {
252330b0cceSVincent Donnefort int lock_cpu;
253330b0cceSVincent Donnefort
254330b0cceSVincent Donnefort remote->pcpu_reader_locks = kcalloc(nr_cpu_ids, sizeof(*remote->pcpu_reader_locks),
255330b0cceSVincent Donnefort GFP_KERNEL);
256330b0cceSVincent Donnefort if (!remote->pcpu_reader_locks) {
257330b0cceSVincent Donnefort trace_remote_try_unload(remote);
258330b0cceSVincent Donnefort return -ENOMEM;
259330b0cceSVincent Donnefort }
260330b0cceSVincent Donnefort
261330b0cceSVincent Donnefort for_each_possible_cpu(lock_cpu)
262330b0cceSVincent Donnefort init_rwsem(&remote->pcpu_reader_locks[lock_cpu]);
263330b0cceSVincent Donnefort }
264330b0cceSVincent Donnefort
26596e43537SVincent Donnefort remote->nr_readers++;
26696e43537SVincent Donnefort
26796e43537SVincent Donnefort return 0;
26896e43537SVincent Donnefort }
26996e43537SVincent Donnefort
trace_remote_put(struct trace_remote * remote)27096e43537SVincent Donnefort static void trace_remote_put(struct trace_remote *remote)
27196e43537SVincent Donnefort {
27296e43537SVincent Donnefort if (WARN_ON(!remote->nr_readers))
27396e43537SVincent Donnefort return;
27496e43537SVincent Donnefort
27596e43537SVincent Donnefort remote->nr_readers--;
27696e43537SVincent Donnefort if (remote->nr_readers)
27796e43537SVincent Donnefort return;
27896e43537SVincent Donnefort
279330b0cceSVincent Donnefort kfree(remote->pcpu_reader_locks);
280330b0cceSVincent Donnefort remote->pcpu_reader_locks = NULL;
281330b0cceSVincent Donnefort
28296e43537SVincent Donnefort trace_remote_try_unload(remote);
28396e43537SVincent Donnefort }
28496e43537SVincent Donnefort
__poll_remote(struct work_struct * work)28596e43537SVincent Donnefort static void __poll_remote(struct work_struct *work)
28696e43537SVincent Donnefort {
28796e43537SVincent Donnefort struct delayed_work *dwork = to_delayed_work(work);
28896e43537SVincent Donnefort struct trace_remote_iterator *iter;
28996e43537SVincent Donnefort
29096e43537SVincent Donnefort iter = container_of(dwork, struct trace_remote_iterator, poll_work);
29196e43537SVincent Donnefort ring_buffer_poll_remote(iter->remote->trace_buffer, iter->cpu);
29296e43537SVincent Donnefort schedule_delayed_work((struct delayed_work *)work,
29396e43537SVincent Donnefort msecs_to_jiffies(iter->remote->poll_ms));
29496e43537SVincent Donnefort }
29596e43537SVincent Donnefort
__free_ring_buffer_iter(struct trace_remote_iterator * iter,int cpu)296330b0cceSVincent Donnefort static void __free_ring_buffer_iter(struct trace_remote_iterator *iter, int cpu)
297330b0cceSVincent Donnefort {
298330b0cceSVincent Donnefort if (cpu != RING_BUFFER_ALL_CPUS) {
299330b0cceSVincent Donnefort ring_buffer_read_finish(iter->rb_iter);
300330b0cceSVincent Donnefort return;
301330b0cceSVincent Donnefort }
302330b0cceSVincent Donnefort
303330b0cceSVincent Donnefort for_each_possible_cpu(cpu) {
304330b0cceSVincent Donnefort if (iter->rb_iters[cpu])
305330b0cceSVincent Donnefort ring_buffer_read_finish(iter->rb_iters[cpu]);
306330b0cceSVincent Donnefort }
307330b0cceSVincent Donnefort
308330b0cceSVincent Donnefort kfree(iter->rb_iters);
309330b0cceSVincent Donnefort }
310330b0cceSVincent Donnefort
__alloc_ring_buffer_iter(struct trace_remote_iterator * iter,int cpu)311330b0cceSVincent Donnefort static int __alloc_ring_buffer_iter(struct trace_remote_iterator *iter, int cpu)
312330b0cceSVincent Donnefort {
313330b0cceSVincent Donnefort if (cpu != RING_BUFFER_ALL_CPUS) {
314330b0cceSVincent Donnefort iter->rb_iter = ring_buffer_read_start(iter->remote->trace_buffer, cpu, GFP_KERNEL);
315330b0cceSVincent Donnefort
316330b0cceSVincent Donnefort return iter->rb_iter ? 0 : -ENOMEM;
317330b0cceSVincent Donnefort }
318330b0cceSVincent Donnefort
319330b0cceSVincent Donnefort iter->rb_iters = kcalloc(nr_cpu_ids, sizeof(*iter->rb_iters), GFP_KERNEL);
320330b0cceSVincent Donnefort if (!iter->rb_iters)
321330b0cceSVincent Donnefort return -ENOMEM;
322330b0cceSVincent Donnefort
323330b0cceSVincent Donnefort for_each_possible_cpu(cpu) {
324330b0cceSVincent Donnefort iter->rb_iters[cpu] = ring_buffer_read_start(iter->remote->trace_buffer, cpu,
325330b0cceSVincent Donnefort GFP_KERNEL);
326330b0cceSVincent Donnefort if (!iter->rb_iters[cpu]) {
327330b0cceSVincent Donnefort __free_ring_buffer_iter(iter, RING_BUFFER_ALL_CPUS);
328330b0cceSVincent Donnefort return -ENOMEM;
329330b0cceSVincent Donnefort }
330330b0cceSVincent Donnefort }
331330b0cceSVincent Donnefort
332330b0cceSVincent Donnefort return 0;
333330b0cceSVincent Donnefort }
334330b0cceSVincent Donnefort
335330b0cceSVincent Donnefort static struct trace_remote_iterator
trace_remote_iter(struct trace_remote * remote,int cpu,enum tri_type type)336330b0cceSVincent Donnefort *trace_remote_iter(struct trace_remote *remote, int cpu, enum tri_type type)
33796e43537SVincent Donnefort {
33896e43537SVincent Donnefort struct trace_remote_iterator *iter = NULL;
33996e43537SVincent Donnefort int ret;
34096e43537SVincent Donnefort
34196e43537SVincent Donnefort lockdep_assert_held(&remote->lock);
34296e43537SVincent Donnefort
343330b0cceSVincent Donnefort if (type == TRI_NONCONSUMING && !trace_remote_loaded(remote))
344330b0cceSVincent Donnefort return NULL;
34596e43537SVincent Donnefort
34696e43537SVincent Donnefort ret = trace_remote_get(remote, cpu);
34796e43537SVincent Donnefort if (ret)
34896e43537SVincent Donnefort return ERR_PTR(ret);
34996e43537SVincent Donnefort
35096e43537SVincent Donnefort /* Test the CPU */
35196e43537SVincent Donnefort ret = ring_buffer_poll_remote(remote->trace_buffer, cpu);
35296e43537SVincent Donnefort if (ret)
35396e43537SVincent Donnefort goto err;
35496e43537SVincent Donnefort
35596e43537SVincent Donnefort iter = kzalloc_obj(*iter);
35696e43537SVincent Donnefort if (iter) {
35796e43537SVincent Donnefort iter->remote = remote;
35896e43537SVincent Donnefort iter->cpu = cpu;
359330b0cceSVincent Donnefort iter->type = type;
36096e43537SVincent Donnefort trace_seq_init(&iter->seq);
361330b0cceSVincent Donnefort
362330b0cceSVincent Donnefort switch (type) {
363330b0cceSVincent Donnefort case TRI_CONSUMING:
36496e43537SVincent Donnefort INIT_DELAYED_WORK(&iter->poll_work, __poll_remote);
36596e43537SVincent Donnefort schedule_delayed_work(&iter->poll_work, msecs_to_jiffies(remote->poll_ms));
366330b0cceSVincent Donnefort break;
367330b0cceSVincent Donnefort case TRI_NONCONSUMING:
368330b0cceSVincent Donnefort ret = __alloc_ring_buffer_iter(iter, cpu);
369330b0cceSVincent Donnefort break;
370330b0cceSVincent Donnefort }
371330b0cceSVincent Donnefort
372330b0cceSVincent Donnefort if (ret)
373330b0cceSVincent Donnefort goto err;
37496e43537SVincent Donnefort
37596e43537SVincent Donnefort return iter;
37696e43537SVincent Donnefort }
37796e43537SVincent Donnefort ret = -ENOMEM;
37896e43537SVincent Donnefort
37996e43537SVincent Donnefort err:
38096e43537SVincent Donnefort kfree(iter);
38196e43537SVincent Donnefort trace_remote_put(remote);
38296e43537SVincent Donnefort
38396e43537SVincent Donnefort return ERR_PTR(ret);
38496e43537SVincent Donnefort }
38596e43537SVincent Donnefort
trace_remote_iter_free(struct trace_remote_iterator * iter)38696e43537SVincent Donnefort static void trace_remote_iter_free(struct trace_remote_iterator *iter)
38796e43537SVincent Donnefort {
38896e43537SVincent Donnefort struct trace_remote *remote;
38996e43537SVincent Donnefort
39096e43537SVincent Donnefort if (!iter)
39196e43537SVincent Donnefort return;
39296e43537SVincent Donnefort
39396e43537SVincent Donnefort remote = iter->remote;
39496e43537SVincent Donnefort
39596e43537SVincent Donnefort lockdep_assert_held(&remote->lock);
39696e43537SVincent Donnefort
397330b0cceSVincent Donnefort switch (iter->type) {
398330b0cceSVincent Donnefort case TRI_CONSUMING:
399330b0cceSVincent Donnefort cancel_delayed_work_sync(&iter->poll_work);
400330b0cceSVincent Donnefort break;
401330b0cceSVincent Donnefort case TRI_NONCONSUMING:
402330b0cceSVincent Donnefort __free_ring_buffer_iter(iter, iter->cpu);
403330b0cceSVincent Donnefort break;
404330b0cceSVincent Donnefort }
405330b0cceSVincent Donnefort
40696e43537SVincent Donnefort kfree(iter);
40796e43537SVincent Donnefort trace_remote_put(remote);
40896e43537SVincent Donnefort }
40996e43537SVincent Donnefort
trace_remote_iter_read_start(struct trace_remote_iterator * iter)410330b0cceSVincent Donnefort static void trace_remote_iter_read_start(struct trace_remote_iterator *iter)
411330b0cceSVincent Donnefort {
412330b0cceSVincent Donnefort struct trace_remote *remote = iter->remote;
413330b0cceSVincent Donnefort int cpu = iter->cpu;
414330b0cceSVincent Donnefort
415330b0cceSVincent Donnefort /* Acquire global reader lock */
416330b0cceSVincent Donnefort if (cpu == RING_BUFFER_ALL_CPUS && iter->type == TRI_CONSUMING)
417330b0cceSVincent Donnefort down_write(&remote->reader_lock);
418330b0cceSVincent Donnefort else
419330b0cceSVincent Donnefort down_read(&remote->reader_lock);
420330b0cceSVincent Donnefort
421330b0cceSVincent Donnefort if (cpu == RING_BUFFER_ALL_CPUS)
422330b0cceSVincent Donnefort return;
423330b0cceSVincent Donnefort
424330b0cceSVincent Donnefort /*
425330b0cceSVincent Donnefort * No need for the remote lock here, iter holds a reference on
426330b0cceSVincent Donnefort * remote->nr_readers
427330b0cceSVincent Donnefort */
428330b0cceSVincent Donnefort
429330b0cceSVincent Donnefort /* Get the per-CPU one */
430330b0cceSVincent Donnefort if (WARN_ON_ONCE(!remote->pcpu_reader_locks))
431330b0cceSVincent Donnefort return;
432330b0cceSVincent Donnefort
433330b0cceSVincent Donnefort if (iter->type == TRI_CONSUMING)
434330b0cceSVincent Donnefort down_write(&remote->pcpu_reader_locks[cpu]);
435330b0cceSVincent Donnefort else
436330b0cceSVincent Donnefort down_read(&remote->pcpu_reader_locks[cpu]);
437330b0cceSVincent Donnefort }
438330b0cceSVincent Donnefort
trace_remote_iter_read_finished(struct trace_remote_iterator * iter)439330b0cceSVincent Donnefort static void trace_remote_iter_read_finished(struct trace_remote_iterator *iter)
440330b0cceSVincent Donnefort {
441330b0cceSVincent Donnefort struct trace_remote *remote = iter->remote;
442330b0cceSVincent Donnefort int cpu = iter->cpu;
443330b0cceSVincent Donnefort
444330b0cceSVincent Donnefort /* Release per-CPU reader lock */
445330b0cceSVincent Donnefort if (cpu != RING_BUFFER_ALL_CPUS) {
446330b0cceSVincent Donnefort /*
447330b0cceSVincent Donnefort * No need for the remote lock here, iter holds a reference on
448330b0cceSVincent Donnefort * remote->nr_readers
449330b0cceSVincent Donnefort */
450330b0cceSVincent Donnefort if (iter->type == TRI_CONSUMING)
451330b0cceSVincent Donnefort up_write(&remote->pcpu_reader_locks[cpu]);
452330b0cceSVincent Donnefort else
453330b0cceSVincent Donnefort up_read(&remote->pcpu_reader_locks[cpu]);
454330b0cceSVincent Donnefort }
455330b0cceSVincent Donnefort
456330b0cceSVincent Donnefort /* Release global reader lock */
457330b0cceSVincent Donnefort if (cpu == RING_BUFFER_ALL_CPUS && iter->type == TRI_CONSUMING)
458330b0cceSVincent Donnefort up_write(&remote->reader_lock);
459330b0cceSVincent Donnefort else
460330b0cceSVincent Donnefort up_read(&remote->reader_lock);
461330b0cceSVincent Donnefort }
462330b0cceSVincent Donnefort
__get_rb_iter(struct trace_remote_iterator * iter,int cpu)463330b0cceSVincent Donnefort static struct ring_buffer_iter *__get_rb_iter(struct trace_remote_iterator *iter, int cpu)
464330b0cceSVincent Donnefort {
465330b0cceSVincent Donnefort return iter->cpu != RING_BUFFER_ALL_CPUS ? iter->rb_iter : iter->rb_iters[cpu];
466330b0cceSVincent Donnefort }
467330b0cceSVincent Donnefort
468330b0cceSVincent Donnefort static struct ring_buffer_event *
__peek_event(struct trace_remote_iterator * iter,int cpu,u64 * ts,unsigned long * lost_events)469330b0cceSVincent Donnefort __peek_event(struct trace_remote_iterator *iter, int cpu, u64 *ts, unsigned long *lost_events)
470330b0cceSVincent Donnefort {
471330b0cceSVincent Donnefort struct ring_buffer_event *rb_evt;
472330b0cceSVincent Donnefort struct ring_buffer_iter *rb_iter;
473330b0cceSVincent Donnefort
474330b0cceSVincent Donnefort switch (iter->type) {
475330b0cceSVincent Donnefort case TRI_CONSUMING:
476330b0cceSVincent Donnefort return ring_buffer_peek(iter->remote->trace_buffer, cpu, ts, lost_events);
477330b0cceSVincent Donnefort case TRI_NONCONSUMING:
478330b0cceSVincent Donnefort rb_iter = __get_rb_iter(iter, cpu);
479330b0cceSVincent Donnefort rb_evt = ring_buffer_iter_peek(rb_iter, ts);
480330b0cceSVincent Donnefort if (!rb_evt)
481330b0cceSVincent Donnefort return NULL;
482330b0cceSVincent Donnefort
483330b0cceSVincent Donnefort *lost_events = ring_buffer_iter_dropped(rb_iter);
484330b0cceSVincent Donnefort
485330b0cceSVincent Donnefort return rb_evt;
486330b0cceSVincent Donnefort }
487330b0cceSVincent Donnefort
488330b0cceSVincent Donnefort return NULL;
489330b0cceSVincent Donnefort }
490330b0cceSVincent Donnefort
trace_remote_iter_read_event(struct trace_remote_iterator * iter)49196e43537SVincent Donnefort static bool trace_remote_iter_read_event(struct trace_remote_iterator *iter)
49296e43537SVincent Donnefort {
49396e43537SVincent Donnefort struct trace_buffer *trace_buffer = iter->remote->trace_buffer;
49407252915SVincent Donnefort struct ring_buffer_event *rb_evt;
49596e43537SVincent Donnefort int cpu = iter->cpu;
49696e43537SVincent Donnefort
49796e43537SVincent Donnefort if (cpu != RING_BUFFER_ALL_CPUS) {
49896e43537SVincent Donnefort if (ring_buffer_empty_cpu(trace_buffer, cpu))
49996e43537SVincent Donnefort return false;
50096e43537SVincent Donnefort
50107252915SVincent Donnefort rb_evt = __peek_event(iter, cpu, &iter->ts, &iter->lost_events);
50207252915SVincent Donnefort if (!rb_evt)
50396e43537SVincent Donnefort return false;
50496e43537SVincent Donnefort
50596e43537SVincent Donnefort iter->evt_cpu = cpu;
50607252915SVincent Donnefort iter->evt = ring_buffer_event_data(rb_evt);
50796e43537SVincent Donnefort return true;
50896e43537SVincent Donnefort }
50996e43537SVincent Donnefort
51096e43537SVincent Donnefort iter->ts = U64_MAX;
51196e43537SVincent Donnefort for_each_possible_cpu(cpu) {
51296e43537SVincent Donnefort unsigned long lost_events;
51396e43537SVincent Donnefort u64 ts;
51496e43537SVincent Donnefort
51596e43537SVincent Donnefort if (ring_buffer_empty_cpu(trace_buffer, cpu))
51696e43537SVincent Donnefort continue;
51796e43537SVincent Donnefort
51807252915SVincent Donnefort rb_evt = __peek_event(iter, cpu, &ts, &lost_events);
51907252915SVincent Donnefort if (!rb_evt)
52096e43537SVincent Donnefort continue;
52196e43537SVincent Donnefort
52296e43537SVincent Donnefort if (ts >= iter->ts)
52396e43537SVincent Donnefort continue;
52496e43537SVincent Donnefort
52596e43537SVincent Donnefort iter->ts = ts;
52696e43537SVincent Donnefort iter->evt_cpu = cpu;
52707252915SVincent Donnefort iter->evt = ring_buffer_event_data(rb_evt);
52896e43537SVincent Donnefort iter->lost_events = lost_events;
52996e43537SVincent Donnefort }
53096e43537SVincent Donnefort
53196e43537SVincent Donnefort return iter->ts != U64_MAX;
53296e43537SVincent Donnefort }
53396e43537SVincent Donnefort
trace_remote_iter_move(struct trace_remote_iterator * iter)534330b0cceSVincent Donnefort static void trace_remote_iter_move(struct trace_remote_iterator *iter)
535330b0cceSVincent Donnefort {
536330b0cceSVincent Donnefort struct trace_buffer *trace_buffer = iter->remote->trace_buffer;
537330b0cceSVincent Donnefort
538330b0cceSVincent Donnefort switch (iter->type) {
539330b0cceSVincent Donnefort case TRI_CONSUMING:
540330b0cceSVincent Donnefort ring_buffer_consume(trace_buffer, iter->evt_cpu, NULL, NULL);
541330b0cceSVincent Donnefort break;
542330b0cceSVincent Donnefort case TRI_NONCONSUMING:
543330b0cceSVincent Donnefort ring_buffer_iter_advance(__get_rb_iter(iter, iter->evt_cpu));
544330b0cceSVincent Donnefort break;
545330b0cceSVincent Donnefort }
546330b0cceSVincent Donnefort }
547330b0cceSVincent Donnefort
54807252915SVincent Donnefort static struct remote_event *trace_remote_find_event(struct trace_remote *remote, unsigned short id);
54907252915SVincent Donnefort
trace_remote_iter_print_event(struct trace_remote_iterator * iter)55096e43537SVincent Donnefort static int trace_remote_iter_print_event(struct trace_remote_iterator *iter)
55196e43537SVincent Donnefort {
55207252915SVincent Donnefort struct remote_event *evt;
55396e43537SVincent Donnefort unsigned long usecs_rem;
55496e43537SVincent Donnefort u64 ts = iter->ts;
55596e43537SVincent Donnefort
55696e43537SVincent Donnefort if (iter->lost_events)
55796e43537SVincent Donnefort trace_seq_printf(&iter->seq, "CPU:%d [LOST %lu EVENTS]\n",
55896e43537SVincent Donnefort iter->evt_cpu, iter->lost_events);
55996e43537SVincent Donnefort
56096e43537SVincent Donnefort do_div(ts, 1000);
56196e43537SVincent Donnefort usecs_rem = do_div(ts, USEC_PER_SEC);
56296e43537SVincent Donnefort
56396e43537SVincent Donnefort trace_seq_printf(&iter->seq, "[%03d]\t%5llu.%06lu: ", iter->evt_cpu,
56496e43537SVincent Donnefort ts, usecs_rem);
56596e43537SVincent Donnefort
56607252915SVincent Donnefort evt = trace_remote_find_event(iter->remote, iter->evt->id);
56707252915SVincent Donnefort if (!evt)
56807252915SVincent Donnefort trace_seq_printf(&iter->seq, "UNKNOWN id=%d\n", iter->evt->id);
56907252915SVincent Donnefort else
57007252915SVincent Donnefort evt->print(iter->evt, &iter->seq);
57107252915SVincent Donnefort
57296e43537SVincent Donnefort return trace_seq_has_overflowed(&iter->seq) ? -EOVERFLOW : 0;
57396e43537SVincent Donnefort }
57496e43537SVincent Donnefort
trace_pipe_open(struct inode * inode,struct file * filp)57596e43537SVincent Donnefort static int trace_pipe_open(struct inode *inode, struct file *filp)
57696e43537SVincent Donnefort {
57796e43537SVincent Donnefort struct trace_remote *remote = inode->i_private;
57896e43537SVincent Donnefort struct trace_remote_iterator *iter;
579330b0cceSVincent Donnefort int cpu = tracing_get_cpu(inode);
58096e43537SVincent Donnefort
58196e43537SVincent Donnefort guard(mutex)(&remote->lock);
582330b0cceSVincent Donnefort
583330b0cceSVincent Donnefort iter = trace_remote_iter(remote, cpu, TRI_CONSUMING);
584330b0cceSVincent Donnefort if (IS_ERR(iter))
585330b0cceSVincent Donnefort return PTR_ERR(iter);
586330b0cceSVincent Donnefort
58796e43537SVincent Donnefort filp->private_data = iter;
58896e43537SVincent Donnefort
58996e43537SVincent Donnefort return IS_ERR(iter) ? PTR_ERR(iter) : 0;
59096e43537SVincent Donnefort }
59196e43537SVincent Donnefort
trace_pipe_release(struct inode * inode,struct file * filp)59296e43537SVincent Donnefort static int trace_pipe_release(struct inode *inode, struct file *filp)
59396e43537SVincent Donnefort {
59496e43537SVincent Donnefort struct trace_remote_iterator *iter = filp->private_data;
59596e43537SVincent Donnefort struct trace_remote *remote = iter->remote;
59696e43537SVincent Donnefort
59796e43537SVincent Donnefort guard(mutex)(&remote->lock);
59896e43537SVincent Donnefort
59996e43537SVincent Donnefort trace_remote_iter_free(iter);
60096e43537SVincent Donnefort
60196e43537SVincent Donnefort return 0;
60296e43537SVincent Donnefort }
60396e43537SVincent Donnefort
trace_pipe_read(struct file * filp,char __user * ubuf,size_t cnt,loff_t * ppos)60496e43537SVincent Donnefort static ssize_t trace_pipe_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
60596e43537SVincent Donnefort {
60696e43537SVincent Donnefort struct trace_remote_iterator *iter = filp->private_data;
60796e43537SVincent Donnefort struct trace_buffer *trace_buffer = iter->remote->trace_buffer;
60896e43537SVincent Donnefort int ret;
60996e43537SVincent Donnefort
61096e43537SVincent Donnefort copy_to_user:
61196e43537SVincent Donnefort ret = trace_seq_to_user(&iter->seq, ubuf, cnt);
61296e43537SVincent Donnefort if (ret != -EBUSY)
61396e43537SVincent Donnefort return ret;
61496e43537SVincent Donnefort
61596e43537SVincent Donnefort trace_seq_init(&iter->seq);
61696e43537SVincent Donnefort
61796e43537SVincent Donnefort ret = ring_buffer_wait(trace_buffer, iter->cpu, 0, NULL, NULL);
61896e43537SVincent Donnefort if (ret < 0)
61996e43537SVincent Donnefort return ret;
62096e43537SVincent Donnefort
621330b0cceSVincent Donnefort trace_remote_iter_read_start(iter);
622330b0cceSVincent Donnefort
62396e43537SVincent Donnefort while (trace_remote_iter_read_event(iter)) {
62496e43537SVincent Donnefort int prev_len = iter->seq.seq.len;
62596e43537SVincent Donnefort
62696e43537SVincent Donnefort if (trace_remote_iter_print_event(iter)) {
62796e43537SVincent Donnefort iter->seq.seq.len = prev_len;
62896e43537SVincent Donnefort break;
62996e43537SVincent Donnefort }
63096e43537SVincent Donnefort
631330b0cceSVincent Donnefort trace_remote_iter_move(iter);
63296e43537SVincent Donnefort }
63396e43537SVincent Donnefort
634330b0cceSVincent Donnefort trace_remote_iter_read_finished(iter);
635330b0cceSVincent Donnefort
63696e43537SVincent Donnefort goto copy_to_user;
63796e43537SVincent Donnefort }
63896e43537SVincent Donnefort
63996e43537SVincent Donnefort static const struct file_operations trace_pipe_fops = {
64096e43537SVincent Donnefort .open = trace_pipe_open,
64196e43537SVincent Donnefort .read = trace_pipe_read,
64296e43537SVincent Donnefort .release = trace_pipe_release,
64396e43537SVincent Donnefort };
64496e43537SVincent Donnefort
trace_next(struct seq_file * m,void * v,loff_t * pos)645330b0cceSVincent Donnefort static void *trace_next(struct seq_file *m, void *v, loff_t *pos)
646330b0cceSVincent Donnefort {
647330b0cceSVincent Donnefort struct trace_remote_iterator *iter = m->private;
648330b0cceSVincent Donnefort
649330b0cceSVincent Donnefort ++*pos;
650330b0cceSVincent Donnefort
651330b0cceSVincent Donnefort if (!iter || !trace_remote_iter_read_event(iter))
652330b0cceSVincent Donnefort return NULL;
653330b0cceSVincent Donnefort
654330b0cceSVincent Donnefort trace_remote_iter_move(iter);
655330b0cceSVincent Donnefort iter->pos++;
656330b0cceSVincent Donnefort
657330b0cceSVincent Donnefort return iter;
658330b0cceSVincent Donnefort }
659330b0cceSVincent Donnefort
trace_start(struct seq_file * m,loff_t * pos)660330b0cceSVincent Donnefort static void *trace_start(struct seq_file *m, loff_t *pos)
661330b0cceSVincent Donnefort {
662330b0cceSVincent Donnefort struct trace_remote_iterator *iter = m->private;
663330b0cceSVincent Donnefort loff_t i;
664330b0cceSVincent Donnefort
665330b0cceSVincent Donnefort if (!iter)
666330b0cceSVincent Donnefort return NULL;
667330b0cceSVincent Donnefort
668330b0cceSVincent Donnefort trace_remote_iter_read_start(iter);
669330b0cceSVincent Donnefort
670330b0cceSVincent Donnefort if (!*pos) {
671330b0cceSVincent Donnefort iter->pos = -1;
672330b0cceSVincent Donnefort return trace_next(m, NULL, &i);
673330b0cceSVincent Donnefort }
674330b0cceSVincent Donnefort
675330b0cceSVincent Donnefort i = iter->pos;
676330b0cceSVincent Donnefort while (i < *pos) {
677330b0cceSVincent Donnefort iter = trace_next(m, NULL, &i);
678330b0cceSVincent Donnefort if (!iter)
679330b0cceSVincent Donnefort return NULL;
680330b0cceSVincent Donnefort }
681330b0cceSVincent Donnefort
682330b0cceSVincent Donnefort return iter;
683330b0cceSVincent Donnefort }
684330b0cceSVincent Donnefort
trace_show(struct seq_file * m,void * v)685330b0cceSVincent Donnefort static int trace_show(struct seq_file *m, void *v)
686330b0cceSVincent Donnefort {
687330b0cceSVincent Donnefort struct trace_remote_iterator *iter = v;
688330b0cceSVincent Donnefort
689330b0cceSVincent Donnefort trace_seq_init(&iter->seq);
690330b0cceSVincent Donnefort
691330b0cceSVincent Donnefort if (trace_remote_iter_print_event(iter)) {
692330b0cceSVincent Donnefort seq_printf(m, "[EVENT %d PRINT TOO BIG]\n", iter->evt->id);
693330b0cceSVincent Donnefort return 0;
694330b0cceSVincent Donnefort }
695330b0cceSVincent Donnefort
696330b0cceSVincent Donnefort return trace_print_seq(m, &iter->seq);
697330b0cceSVincent Donnefort }
698330b0cceSVincent Donnefort
trace_stop(struct seq_file * m,void * v)699330b0cceSVincent Donnefort static void trace_stop(struct seq_file *m, void *v)
700330b0cceSVincent Donnefort {
701330b0cceSVincent Donnefort struct trace_remote_iterator *iter = m->private;
702330b0cceSVincent Donnefort
703330b0cceSVincent Donnefort if (iter)
704330b0cceSVincent Donnefort trace_remote_iter_read_finished(iter);
705330b0cceSVincent Donnefort }
706330b0cceSVincent Donnefort
707330b0cceSVincent Donnefort static const struct seq_operations trace_sops = {
708330b0cceSVincent Donnefort .start = trace_start,
709330b0cceSVincent Donnefort .next = trace_next,
710330b0cceSVincent Donnefort .show = trace_show,
711330b0cceSVincent Donnefort .stop = trace_stop,
712330b0cceSVincent Donnefort };
713330b0cceSVincent Donnefort
trace_open(struct inode * inode,struct file * filp)714330b0cceSVincent Donnefort static int trace_open(struct inode *inode, struct file *filp)
715330b0cceSVincent Donnefort {
716330b0cceSVincent Donnefort struct trace_remote *remote = inode->i_private;
717330b0cceSVincent Donnefort struct trace_remote_iterator *iter = NULL;
718330b0cceSVincent Donnefort int cpu = tracing_get_cpu(inode);
719330b0cceSVincent Donnefort int ret;
720330b0cceSVincent Donnefort
721330b0cceSVincent Donnefort if (!(filp->f_mode & FMODE_READ))
722330b0cceSVincent Donnefort return 0;
723330b0cceSVincent Donnefort
724330b0cceSVincent Donnefort guard(mutex)(&remote->lock);
725330b0cceSVincent Donnefort
726330b0cceSVincent Donnefort iter = trace_remote_iter(remote, cpu, TRI_NONCONSUMING);
727330b0cceSVincent Donnefort if (IS_ERR(iter))
728330b0cceSVincent Donnefort return PTR_ERR(iter);
729330b0cceSVincent Donnefort
730330b0cceSVincent Donnefort ret = seq_open(filp, &trace_sops);
731330b0cceSVincent Donnefort if (ret) {
732330b0cceSVincent Donnefort trace_remote_iter_free(iter);
733330b0cceSVincent Donnefort return ret;
734330b0cceSVincent Donnefort }
735330b0cceSVincent Donnefort
736330b0cceSVincent Donnefort ((struct seq_file *)filp->private_data)->private = (void *)iter;
737330b0cceSVincent Donnefort
738330b0cceSVincent Donnefort return 0;
739330b0cceSVincent Donnefort }
740330b0cceSVincent Donnefort
trace_release(struct inode * inode,struct file * filp)741330b0cceSVincent Donnefort static int trace_release(struct inode *inode, struct file *filp)
742330b0cceSVincent Donnefort {
743330b0cceSVincent Donnefort struct trace_remote_iterator *iter;
744330b0cceSVincent Donnefort
745330b0cceSVincent Donnefort if (!(filp->f_mode & FMODE_READ))
746330b0cceSVincent Donnefort return 0;
747330b0cceSVincent Donnefort
748330b0cceSVincent Donnefort iter = ((struct seq_file *)filp->private_data)->private;
749330b0cceSVincent Donnefort seq_release(inode, filp);
750330b0cceSVincent Donnefort
751330b0cceSVincent Donnefort if (!iter)
752330b0cceSVincent Donnefort return 0;
753330b0cceSVincent Donnefort
754330b0cceSVincent Donnefort guard(mutex)(&iter->remote->lock);
755330b0cceSVincent Donnefort
756330b0cceSVincent Donnefort trace_remote_iter_free(iter);
757330b0cceSVincent Donnefort
758330b0cceSVincent Donnefort return 0;
759330b0cceSVincent Donnefort }
760330b0cceSVincent Donnefort
trace_write(struct file * filp,const char __user * ubuf,size_t cnt,loff_t * ppos)7619af4ab0eSVincent Donnefort static ssize_t trace_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
7629af4ab0eSVincent Donnefort {
7639af4ab0eSVincent Donnefort struct inode *inode = file_inode(filp);
7649af4ab0eSVincent Donnefort struct trace_remote *remote = inode->i_private;
765330b0cceSVincent Donnefort int cpu = tracing_get_cpu(inode);
7669af4ab0eSVincent Donnefort
7679af4ab0eSVincent Donnefort guard(mutex)(&remote->lock);
7689af4ab0eSVincent Donnefort
7699af4ab0eSVincent Donnefort trace_remote_reset(remote, cpu);
7709af4ab0eSVincent Donnefort
7719af4ab0eSVincent Donnefort return cnt;
7729af4ab0eSVincent Donnefort }
7739af4ab0eSVincent Donnefort
7749af4ab0eSVincent Donnefort static const struct file_operations trace_fops = {
775330b0cceSVincent Donnefort .open = trace_open,
7769af4ab0eSVincent Donnefort .write = trace_write,
777330b0cceSVincent Donnefort .read = seq_read,
778330b0cceSVincent Donnefort .read_iter = seq_read_iter,
779330b0cceSVincent Donnefort .release = trace_release,
7809af4ab0eSVincent Donnefort };
7819af4ab0eSVincent Donnefort
trace_remote_init_tracefs(const char * name,struct trace_remote * remote)78296e43537SVincent Donnefort static int trace_remote_init_tracefs(const char *name, struct trace_remote *remote)
78396e43537SVincent Donnefort {
78496e43537SVincent Donnefort struct dentry *remote_d, *percpu_d, *d;
78596e43537SVincent Donnefort static struct dentry *root;
78696e43537SVincent Donnefort static DEFINE_MUTEX(lock);
78796e43537SVincent Donnefort bool root_inited = false;
78896e43537SVincent Donnefort int cpu;
78996e43537SVincent Donnefort
79096e43537SVincent Donnefort guard(mutex)(&lock);
79196e43537SVincent Donnefort
79296e43537SVincent Donnefort if (!root) {
79396e43537SVincent Donnefort root = tracefs_create_dir(TRACEFS_DIR, NULL);
79496e43537SVincent Donnefort if (!root) {
79596e43537SVincent Donnefort pr_err("Failed to create tracefs dir "TRACEFS_DIR"\n");
79696e43537SVincent Donnefort return -ENOMEM;
79796e43537SVincent Donnefort }
79896e43537SVincent Donnefort root_inited = true;
79996e43537SVincent Donnefort }
80096e43537SVincent Donnefort
80196e43537SVincent Donnefort remote_d = tracefs_create_dir(name, root);
80296e43537SVincent Donnefort if (!remote_d) {
80396e43537SVincent Donnefort pr_err("Failed to create tracefs dir "TRACEFS_DIR"%s/\n", name);
80496e43537SVincent Donnefort goto err;
80596e43537SVincent Donnefort }
80696e43537SVincent Donnefort
80796e43537SVincent Donnefort d = trace_create_file("tracing_on", TRACEFS_MODE_WRITE, remote_d, remote, &tracing_on_fops);
80896e43537SVincent Donnefort if (!d)
80996e43537SVincent Donnefort goto err;
81096e43537SVincent Donnefort
81196e43537SVincent Donnefort d = trace_create_file("buffer_size_kb", TRACEFS_MODE_WRITE, remote_d, remote,
81296e43537SVincent Donnefort &buffer_size_kb_fops);
81396e43537SVincent Donnefort if (!d)
81496e43537SVincent Donnefort goto err;
81596e43537SVincent Donnefort
81696e43537SVincent Donnefort d = trace_create_file("trace_pipe", TRACEFS_MODE_READ, remote_d, remote, &trace_pipe_fops);
81796e43537SVincent Donnefort if (!d)
81896e43537SVincent Donnefort goto err;
81996e43537SVincent Donnefort
8209af4ab0eSVincent Donnefort d = trace_create_file("trace", TRACEFS_MODE_WRITE, remote_d, remote, &trace_fops);
8219af4ab0eSVincent Donnefort if (!d)
8229af4ab0eSVincent Donnefort goto err;
8239af4ab0eSVincent Donnefort
82496e43537SVincent Donnefort percpu_d = tracefs_create_dir("per_cpu", remote_d);
82596e43537SVincent Donnefort if (!percpu_d) {
82696e43537SVincent Donnefort pr_err("Failed to create tracefs dir "TRACEFS_DIR"%s/per_cpu/\n", name);
82796e43537SVincent Donnefort goto err;
82896e43537SVincent Donnefort }
82996e43537SVincent Donnefort
83096e43537SVincent Donnefort for_each_possible_cpu(cpu) {
83196e43537SVincent Donnefort struct dentry *cpu_d;
83296e43537SVincent Donnefort char cpu_name[16];
83396e43537SVincent Donnefort
83496e43537SVincent Donnefort snprintf(cpu_name, sizeof(cpu_name), "cpu%d", cpu);
83596e43537SVincent Donnefort cpu_d = tracefs_create_dir(cpu_name, percpu_d);
83696e43537SVincent Donnefort if (!cpu_d) {
83796e43537SVincent Donnefort pr_err("Failed to create tracefs dir "TRACEFS_DIR"%s/percpu/cpu%d\n",
83896e43537SVincent Donnefort name, cpu);
83996e43537SVincent Donnefort goto err;
84096e43537SVincent Donnefort }
84196e43537SVincent Donnefort
84296e43537SVincent Donnefort d = trace_create_cpu_file("trace_pipe", TRACEFS_MODE_READ, cpu_d, remote, cpu,
84396e43537SVincent Donnefort &trace_pipe_fops);
84496e43537SVincent Donnefort if (!d)
84596e43537SVincent Donnefort goto err;
8469af4ab0eSVincent Donnefort
8479af4ab0eSVincent Donnefort d = trace_create_cpu_file("trace", TRACEFS_MODE_WRITE, cpu_d, remote, cpu,
8489af4ab0eSVincent Donnefort &trace_fops);
8499af4ab0eSVincent Donnefort if (!d)
8509af4ab0eSVincent Donnefort goto err;
85196e43537SVincent Donnefort }
85296e43537SVincent Donnefort
85307252915SVincent Donnefort remote->dentry = remote_d;
85407252915SVincent Donnefort
85596e43537SVincent Donnefort return 0;
85696e43537SVincent Donnefort
85796e43537SVincent Donnefort err:
85896e43537SVincent Donnefort if (root_inited) {
85996e43537SVincent Donnefort tracefs_remove(root);
86096e43537SVincent Donnefort root = NULL;
86196e43537SVincent Donnefort } else {
86296e43537SVincent Donnefort tracefs_remove(remote_d);
86396e43537SVincent Donnefort }
86496e43537SVincent Donnefort
86596e43537SVincent Donnefort return -ENOMEM;
86696e43537SVincent Donnefort }
86796e43537SVincent Donnefort
86807252915SVincent Donnefort static int trace_remote_register_events(const char *remote_name, struct trace_remote *remote,
86907252915SVincent Donnefort struct remote_event *events, size_t nr_events);
87007252915SVincent Donnefort
87196e43537SVincent Donnefort /**
87296e43537SVincent Donnefort * trace_remote_register() - Register a Tracefs remote
87396e43537SVincent Donnefort * @name: Name of the remote, used for the Tracefs remotes/ directory.
87496e43537SVincent Donnefort * @cbs: Set of callbacks used to control the remote.
87596e43537SVincent Donnefort * @priv: Private data, passed to each callback from @cbs.
87696e43537SVincent Donnefort * @events: Array of events. &remote_event.name and &remote_event.id must be
87796e43537SVincent Donnefort * filled by the caller.
87896e43537SVincent Donnefort * @nr_events: Number of events in the @events array.
87996e43537SVincent Donnefort *
88096e43537SVincent Donnefort * A trace remote is an entity, outside of the kernel (most likely firmware or
88196e43537SVincent Donnefort * hypervisor) capable of writing events into a Tracefs compatible ring-buffer.
88296e43537SVincent Donnefort * The kernel would then act as a reader.
88396e43537SVincent Donnefort *
88496e43537SVincent Donnefort * The registered remote will be found under the Tracefs directory
88596e43537SVincent Donnefort * remotes/<name>.
88696e43537SVincent Donnefort *
88796e43537SVincent Donnefort * Return: 0 on success, negative error code on failure.
88896e43537SVincent Donnefort */
trace_remote_register(const char * name,struct trace_remote_callbacks * cbs,void * priv,struct remote_event * events,size_t nr_events)88907252915SVincent Donnefort int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv,
89007252915SVincent Donnefort struct remote_event *events, size_t nr_events)
89196e43537SVincent Donnefort {
89296e43537SVincent Donnefort struct trace_remote *remote;
893bf2ba0f8SVincent Donnefort int ret;
89496e43537SVincent Donnefort
89596e43537SVincent Donnefort remote = kzalloc_obj(*remote);
89696e43537SVincent Donnefort if (!remote)
89796e43537SVincent Donnefort return -ENOMEM;
89896e43537SVincent Donnefort
89996e43537SVincent Donnefort remote->cbs = cbs;
90096e43537SVincent Donnefort remote->priv = priv;
90196e43537SVincent Donnefort remote->trace_buffer_size = 7 << 10;
90296e43537SVincent Donnefort remote->poll_ms = 100;
90396e43537SVincent Donnefort mutex_init(&remote->lock);
904330b0cceSVincent Donnefort init_rwsem(&remote->reader_lock);
90596e43537SVincent Donnefort
90696e43537SVincent Donnefort if (trace_remote_init_tracefs(name, remote)) {
90796e43537SVincent Donnefort kfree(remote);
90896e43537SVincent Donnefort return -ENOMEM;
90996e43537SVincent Donnefort }
91096e43537SVincent Donnefort
91107252915SVincent Donnefort ret = trace_remote_register_events(name, remote, events, nr_events);
91207252915SVincent Donnefort if (ret) {
91307252915SVincent Donnefort pr_err("Failed to register events for trace remote '%s' (%d)\n",
91407252915SVincent Donnefort name, ret);
91507252915SVincent Donnefort return ret;
91607252915SVincent Donnefort }
91707252915SVincent Donnefort
918bf2ba0f8SVincent Donnefort ret = cbs->init ? cbs->init(remote->dentry, priv) : 0;
919bf2ba0f8SVincent Donnefort if (ret)
920bf2ba0f8SVincent Donnefort pr_err("Init failed for trace remote '%s' (%d)\n", name, ret);
921bf2ba0f8SVincent Donnefort
922bf2ba0f8SVincent Donnefort return ret;
92396e43537SVincent Donnefort }
92496e43537SVincent Donnefort EXPORT_SYMBOL_GPL(trace_remote_register);
92596e43537SVincent Donnefort
92696e43537SVincent Donnefort /**
92796e43537SVincent Donnefort * trace_remote_free_buffer() - Free trace buffer allocated with trace_remote_alloc_buffer()
92896e43537SVincent Donnefort * @desc: Descriptor of the per-CPU ring-buffers, originally filled by
92996e43537SVincent Donnefort * trace_remote_alloc_buffer()
93096e43537SVincent Donnefort *
93196e43537SVincent Donnefort * Most likely called from &trace_remote_callbacks.unload_trace_buffer.
93296e43537SVincent Donnefort */
trace_remote_free_buffer(struct trace_buffer_desc * desc)93396e43537SVincent Donnefort void trace_remote_free_buffer(struct trace_buffer_desc *desc)
93496e43537SVincent Donnefort {
93596e43537SVincent Donnefort struct ring_buffer_desc *rb_desc;
93696e43537SVincent Donnefort int cpu;
93796e43537SVincent Donnefort
93896e43537SVincent Donnefort for_each_ring_buffer_desc(rb_desc, cpu, desc) {
93996e43537SVincent Donnefort unsigned int id;
94096e43537SVincent Donnefort
94196e43537SVincent Donnefort free_page(rb_desc->meta_va);
94296e43537SVincent Donnefort
94396e43537SVincent Donnefort for (id = 0; id < rb_desc->nr_page_va; id++)
94496e43537SVincent Donnefort free_page(rb_desc->page_va[id]);
94596e43537SVincent Donnefort }
94696e43537SVincent Donnefort }
94796e43537SVincent Donnefort EXPORT_SYMBOL_GPL(trace_remote_free_buffer);
94896e43537SVincent Donnefort
94996e43537SVincent Donnefort /**
95096e43537SVincent Donnefort * trace_remote_alloc_buffer() - Dynamically allocate a trace buffer
95196e43537SVincent Donnefort * @desc: Uninitialized trace_buffer_desc
95296e43537SVincent Donnefort * @desc_size: Size of the trace_buffer_desc. Must be at least equal to
95396e43537SVincent Donnefort * trace_buffer_desc_size()
95496e43537SVincent Donnefort * @buffer_size: Size in bytes of each per-CPU ring-buffer
95596e43537SVincent Donnefort * @cpumask: CPUs to allocate a ring-buffer for
95696e43537SVincent Donnefort *
95796e43537SVincent Donnefort * Helper to dynamically allocate a set of pages (enough to cover @buffer_size)
95896e43537SVincent Donnefort * for each CPU from @cpumask and fill @desc. Most likely called from
95996e43537SVincent Donnefort * &trace_remote_callbacks.load_trace_buffer.
96096e43537SVincent Donnefort *
96196e43537SVincent Donnefort * Return: 0 on success, negative error code on failure.
96296e43537SVincent Donnefort */
trace_remote_alloc_buffer(struct trace_buffer_desc * desc,size_t desc_size,size_t buffer_size,const struct cpumask * cpumask)96396e43537SVincent Donnefort int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size, size_t buffer_size,
96496e43537SVincent Donnefort const struct cpumask *cpumask)
96596e43537SVincent Donnefort {
96696e43537SVincent Donnefort unsigned int nr_pages = max(DIV_ROUND_UP(buffer_size, PAGE_SIZE), 2UL) + 1;
96796e43537SVincent Donnefort void *desc_end = desc + desc_size;
96896e43537SVincent Donnefort struct ring_buffer_desc *rb_desc;
96996e43537SVincent Donnefort int cpu, ret = -ENOMEM;
97096e43537SVincent Donnefort
97196e43537SVincent Donnefort if (desc_size < struct_size(desc, __data, 0))
97296e43537SVincent Donnefort return -EINVAL;
97396e43537SVincent Donnefort
97496e43537SVincent Donnefort desc->nr_cpus = 0;
97596e43537SVincent Donnefort desc->struct_len = struct_size(desc, __data, 0);
97696e43537SVincent Donnefort
97796e43537SVincent Donnefort rb_desc = (struct ring_buffer_desc *)&desc->__data[0];
97896e43537SVincent Donnefort
97996e43537SVincent Donnefort for_each_cpu(cpu, cpumask) {
98096e43537SVincent Donnefort unsigned int id;
98196e43537SVincent Donnefort
98296e43537SVincent Donnefort if ((void *)rb_desc + struct_size(rb_desc, page_va, nr_pages) > desc_end) {
98396e43537SVincent Donnefort ret = -EINVAL;
98496e43537SVincent Donnefort goto err;
98596e43537SVincent Donnefort }
98696e43537SVincent Donnefort
98796e43537SVincent Donnefort rb_desc->cpu = cpu;
98896e43537SVincent Donnefort rb_desc->nr_page_va = 0;
98996e43537SVincent Donnefort rb_desc->meta_va = (unsigned long)__get_free_page(GFP_KERNEL);
99096e43537SVincent Donnefort if (!rb_desc->meta_va)
99196e43537SVincent Donnefort goto err;
99296e43537SVincent Donnefort
99396e43537SVincent Donnefort for (id = 0; id < nr_pages; id++) {
99496e43537SVincent Donnefort rb_desc->page_va[id] = (unsigned long)__get_free_page(GFP_KERNEL);
99596e43537SVincent Donnefort if (!rb_desc->page_va[id])
99696e43537SVincent Donnefort goto err;
99796e43537SVincent Donnefort
99896e43537SVincent Donnefort rb_desc->nr_page_va++;
99996e43537SVincent Donnefort }
100096e43537SVincent Donnefort desc->nr_cpus++;
100196e43537SVincent Donnefort desc->struct_len += offsetof(struct ring_buffer_desc, page_va);
100296e43537SVincent Donnefort desc->struct_len += struct_size(rb_desc, page_va, rb_desc->nr_page_va);
100396e43537SVincent Donnefort rb_desc = __next_ring_buffer_desc(rb_desc);
100496e43537SVincent Donnefort }
100596e43537SVincent Donnefort
100696e43537SVincent Donnefort return 0;
100796e43537SVincent Donnefort
100896e43537SVincent Donnefort err:
100996e43537SVincent Donnefort trace_remote_free_buffer(desc);
101096e43537SVincent Donnefort return ret;
101196e43537SVincent Donnefort }
101296e43537SVincent Donnefort EXPORT_SYMBOL_GPL(trace_remote_alloc_buffer);
101307252915SVincent Donnefort
101407252915SVincent Donnefort static int
trace_remote_enable_event(struct trace_remote * remote,struct remote_event * evt,bool enable)101507252915SVincent Donnefort trace_remote_enable_event(struct trace_remote *remote, struct remote_event *evt, bool enable)
101607252915SVincent Donnefort {
101707252915SVincent Donnefort int ret;
101807252915SVincent Donnefort
101907252915SVincent Donnefort lockdep_assert_held(&remote->lock);
102007252915SVincent Donnefort
102107252915SVincent Donnefort if (evt->enabled == enable)
102207252915SVincent Donnefort return 0;
102307252915SVincent Donnefort
102407252915SVincent Donnefort ret = remote->cbs->enable_event(evt->id, enable, remote->priv);
102507252915SVincent Donnefort if (ret)
102607252915SVincent Donnefort return ret;
102707252915SVincent Donnefort
102807252915SVincent Donnefort evt->enabled = enable;
102907252915SVincent Donnefort
103007252915SVincent Donnefort return 0;
103107252915SVincent Donnefort }
103207252915SVincent Donnefort
remote_event_enable_show(struct seq_file * s,void * unused)103307252915SVincent Donnefort static int remote_event_enable_show(struct seq_file *s, void *unused)
103407252915SVincent Donnefort {
103507252915SVincent Donnefort struct remote_event *evt = s->private;
103607252915SVincent Donnefort
103707252915SVincent Donnefort seq_printf(s, "%d\n", evt->enabled);
103807252915SVincent Donnefort
103907252915SVincent Donnefort return 0;
104007252915SVincent Donnefort }
104107252915SVincent Donnefort
remote_event_enable_write(struct file * filp,const char __user * ubuf,size_t count,loff_t * ppos)104207252915SVincent Donnefort static ssize_t remote_event_enable_write(struct file *filp, const char __user *ubuf,
104307252915SVincent Donnefort size_t count, loff_t *ppos)
104407252915SVincent Donnefort {
104507252915SVincent Donnefort struct seq_file *seq = filp->private_data;
104607252915SVincent Donnefort struct remote_event *evt = seq->private;
104707252915SVincent Donnefort struct trace_remote *remote = evt->remote;
104807252915SVincent Donnefort u8 enable;
104907252915SVincent Donnefort int ret;
105007252915SVincent Donnefort
105107252915SVincent Donnefort ret = kstrtou8_from_user(ubuf, count, 10, &enable);
105207252915SVincent Donnefort if (ret)
105307252915SVincent Donnefort return ret;
105407252915SVincent Donnefort
105507252915SVincent Donnefort guard(mutex)(&remote->lock);
105607252915SVincent Donnefort
105707252915SVincent Donnefort ret = trace_remote_enable_event(remote, evt, enable);
105807252915SVincent Donnefort if (ret)
105907252915SVincent Donnefort return ret;
106007252915SVincent Donnefort
106107252915SVincent Donnefort return count;
106207252915SVincent Donnefort }
106307252915SVincent Donnefort DEFINE_SHOW_STORE_ATTRIBUTE(remote_event_enable);
106407252915SVincent Donnefort
remote_event_id_show(struct seq_file * s,void * unused)106507252915SVincent Donnefort static int remote_event_id_show(struct seq_file *s, void *unused)
106607252915SVincent Donnefort {
106707252915SVincent Donnefort struct remote_event *evt = s->private;
106807252915SVincent Donnefort
106907252915SVincent Donnefort seq_printf(s, "%d\n", evt->id);
107007252915SVincent Donnefort
107107252915SVincent Donnefort return 0;
107207252915SVincent Donnefort }
107307252915SVincent Donnefort DEFINE_SHOW_ATTRIBUTE(remote_event_id);
107407252915SVincent Donnefort
remote_event_format_show(struct seq_file * s,void * unused)107507252915SVincent Donnefort static int remote_event_format_show(struct seq_file *s, void *unused)
107607252915SVincent Donnefort {
107707252915SVincent Donnefort size_t offset = sizeof(struct remote_event_hdr);
107807252915SVincent Donnefort struct remote_event *evt = s->private;
107907252915SVincent Donnefort struct trace_event_fields *field;
108007252915SVincent Donnefort
108107252915SVincent Donnefort seq_printf(s, "name: %s\n", evt->name);
108207252915SVincent Donnefort seq_printf(s, "ID: %d\n", evt->id);
108307252915SVincent Donnefort seq_puts(s,
108407252915SVincent Donnefort "format:\n\tfield:unsigned short common_type;\toffset:0;\tsize:2;\tsigned:0;\n\n");
108507252915SVincent Donnefort
108607252915SVincent Donnefort field = &evt->fields[0];
108707252915SVincent Donnefort while (field->name) {
108807252915SVincent Donnefort seq_printf(s, "\tfield:%s %s;\toffset:%zu;\tsize:%u;\tsigned:%d;\n",
108907252915SVincent Donnefort field->type, field->name, offset, field->size,
109007252915SVincent Donnefort field->is_signed);
109107252915SVincent Donnefort offset += field->size;
109207252915SVincent Donnefort field++;
109307252915SVincent Donnefort }
109407252915SVincent Donnefort
109507252915SVincent Donnefort if (field != &evt->fields[0])
109607252915SVincent Donnefort seq_puts(s, "\n");
109707252915SVincent Donnefort
109807252915SVincent Donnefort seq_printf(s, "print fmt: %s\n", evt->print_fmt);
109907252915SVincent Donnefort
110007252915SVincent Donnefort return 0;
110107252915SVincent Donnefort }
110207252915SVincent Donnefort DEFINE_SHOW_ATTRIBUTE(remote_event_format);
110307252915SVincent Donnefort
remote_event_callback(const char * name,umode_t * mode,void ** data,const struct file_operations ** fops)110407252915SVincent Donnefort static int remote_event_callback(const char *name, umode_t *mode, void **data,
110507252915SVincent Donnefort const struct file_operations **fops)
110607252915SVincent Donnefort {
110707252915SVincent Donnefort if (!strcmp(name, "enable")) {
110807252915SVincent Donnefort *mode = TRACEFS_MODE_WRITE;
110907252915SVincent Donnefort *fops = &remote_event_enable_fops;
111007252915SVincent Donnefort return 1;
111107252915SVincent Donnefort }
111207252915SVincent Donnefort
111307252915SVincent Donnefort if (!strcmp(name, "id")) {
111407252915SVincent Donnefort *mode = TRACEFS_MODE_READ;
111507252915SVincent Donnefort *fops = &remote_event_id_fops;
111607252915SVincent Donnefort return 1;
111707252915SVincent Donnefort }
111807252915SVincent Donnefort
111907252915SVincent Donnefort if (!strcmp(name, "format")) {
112007252915SVincent Donnefort *mode = TRACEFS_MODE_READ;
112107252915SVincent Donnefort *fops = &remote_event_format_fops;
112207252915SVincent Donnefort return 1;
112307252915SVincent Donnefort }
112407252915SVincent Donnefort
112507252915SVincent Donnefort return 0;
112607252915SVincent Donnefort }
112707252915SVincent Donnefort
remote_events_dir_enable_write(struct file * filp,const char __user * ubuf,size_t count,loff_t * ppos)1128*775cb093SVincent Donnefort static ssize_t remote_events_dir_enable_write(struct file *filp, const char __user *ubuf,
1129*775cb093SVincent Donnefort size_t count, loff_t *ppos)
1130*775cb093SVincent Donnefort {
1131*775cb093SVincent Donnefort struct trace_remote *remote = file_inode(filp)->i_private;
1132*775cb093SVincent Donnefort int i, ret;
1133*775cb093SVincent Donnefort u8 enable;
1134*775cb093SVincent Donnefort
1135*775cb093SVincent Donnefort ret = kstrtou8_from_user(ubuf, count, 10, &enable);
1136*775cb093SVincent Donnefort if (ret)
1137*775cb093SVincent Donnefort return ret;
1138*775cb093SVincent Donnefort
1139*775cb093SVincent Donnefort guard(mutex)(&remote->lock);
1140*775cb093SVincent Donnefort
1141*775cb093SVincent Donnefort for (i = 0; i < remote->nr_events; i++) {
1142*775cb093SVincent Donnefort struct remote_event *evt = &remote->events[i];
1143*775cb093SVincent Donnefort
1144*775cb093SVincent Donnefort trace_remote_enable_event(remote, evt, enable);
1145*775cb093SVincent Donnefort }
1146*775cb093SVincent Donnefort
1147*775cb093SVincent Donnefort return count;
1148*775cb093SVincent Donnefort }
1149*775cb093SVincent Donnefort
remote_events_dir_enable_read(struct file * filp,char __user * ubuf,size_t cnt,loff_t * ppos)1150*775cb093SVincent Donnefort static ssize_t remote_events_dir_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
1151*775cb093SVincent Donnefort loff_t *ppos)
1152*775cb093SVincent Donnefort {
1153*775cb093SVincent Donnefort struct trace_remote *remote = file_inode(filp)->i_private;
1154*775cb093SVincent Donnefort const char enabled_char[] = {'0', '1', 'X'};
1155*775cb093SVincent Donnefort char enabled_str[] = " \n";
1156*775cb093SVincent Donnefort int i, enabled = -1;
1157*775cb093SVincent Donnefort
1158*775cb093SVincent Donnefort guard(mutex)(&remote->lock);
1159*775cb093SVincent Donnefort
1160*775cb093SVincent Donnefort for (i = 0; i < remote->nr_events; i++) {
1161*775cb093SVincent Donnefort struct remote_event *evt = &remote->events[i];
1162*775cb093SVincent Donnefort
1163*775cb093SVincent Donnefort if (enabled == -1) {
1164*775cb093SVincent Donnefort enabled = evt->enabled;
1165*775cb093SVincent Donnefort } else if (enabled != evt->enabled) {
1166*775cb093SVincent Donnefort enabled = 2;
1167*775cb093SVincent Donnefort break;
1168*775cb093SVincent Donnefort }
1169*775cb093SVincent Donnefort }
1170*775cb093SVincent Donnefort
1171*775cb093SVincent Donnefort enabled_str[0] = enabled_char[enabled == -1 ? 0 : enabled];
1172*775cb093SVincent Donnefort
1173*775cb093SVincent Donnefort return simple_read_from_buffer(ubuf, cnt, ppos, enabled_str, 2);
1174*775cb093SVincent Donnefort }
1175*775cb093SVincent Donnefort
1176*775cb093SVincent Donnefort static const struct file_operations remote_events_dir_enable_fops = {
1177*775cb093SVincent Donnefort .write = remote_events_dir_enable_write,
1178*775cb093SVincent Donnefort .read = remote_events_dir_enable_read,
1179*775cb093SVincent Donnefort };
1180*775cb093SVincent Donnefort
1181*775cb093SVincent Donnefort static ssize_t
remote_events_dir_header_page_read(struct file * filp,char __user * ubuf,size_t cnt,loff_t * ppos)1182*775cb093SVincent Donnefort remote_events_dir_header_page_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
1183*775cb093SVincent Donnefort {
1184*775cb093SVincent Donnefort struct trace_seq *s;
1185*775cb093SVincent Donnefort int ret;
1186*775cb093SVincent Donnefort
1187*775cb093SVincent Donnefort s = kmalloc(sizeof(*s), GFP_KERNEL);
1188*775cb093SVincent Donnefort if (!s)
1189*775cb093SVincent Donnefort return -ENOMEM;
1190*775cb093SVincent Donnefort
1191*775cb093SVincent Donnefort trace_seq_init(s);
1192*775cb093SVincent Donnefort
1193*775cb093SVincent Donnefort ring_buffer_print_page_header(NULL, s);
1194*775cb093SVincent Donnefort ret = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, trace_seq_used(s));
1195*775cb093SVincent Donnefort kfree(s);
1196*775cb093SVincent Donnefort
1197*775cb093SVincent Donnefort return ret;
1198*775cb093SVincent Donnefort }
1199*775cb093SVincent Donnefort
1200*775cb093SVincent Donnefort static const struct file_operations remote_events_dir_header_page_fops = {
1201*775cb093SVincent Donnefort .read = remote_events_dir_header_page_read,
1202*775cb093SVincent Donnefort };
1203*775cb093SVincent Donnefort
1204*775cb093SVincent Donnefort static ssize_t
remote_events_dir_header_event_read(struct file * filp,char __user * ubuf,size_t cnt,loff_t * ppos)1205*775cb093SVincent Donnefort remote_events_dir_header_event_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
1206*775cb093SVincent Donnefort {
1207*775cb093SVincent Donnefort struct trace_seq *s;
1208*775cb093SVincent Donnefort int ret;
1209*775cb093SVincent Donnefort
1210*775cb093SVincent Donnefort s = kmalloc(sizeof(*s), GFP_KERNEL);
1211*775cb093SVincent Donnefort if (!s)
1212*775cb093SVincent Donnefort return -ENOMEM;
1213*775cb093SVincent Donnefort
1214*775cb093SVincent Donnefort trace_seq_init(s);
1215*775cb093SVincent Donnefort
1216*775cb093SVincent Donnefort ring_buffer_print_entry_header(s);
1217*775cb093SVincent Donnefort ret = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, trace_seq_used(s));
1218*775cb093SVincent Donnefort kfree(s);
1219*775cb093SVincent Donnefort
1220*775cb093SVincent Donnefort return ret;
1221*775cb093SVincent Donnefort }
1222*775cb093SVincent Donnefort
1223*775cb093SVincent Donnefort static const struct file_operations remote_events_dir_header_event_fops = {
1224*775cb093SVincent Donnefort .read = remote_events_dir_header_event_read,
1225*775cb093SVincent Donnefort };
1226*775cb093SVincent Donnefort
remote_events_dir_callback(const char * name,umode_t * mode,void ** data,const struct file_operations ** fops)1227*775cb093SVincent Donnefort static int remote_events_dir_callback(const char *name, umode_t *mode, void **data,
1228*775cb093SVincent Donnefort const struct file_operations **fops)
1229*775cb093SVincent Donnefort {
1230*775cb093SVincent Donnefort if (!strcmp(name, "enable")) {
1231*775cb093SVincent Donnefort *mode = TRACEFS_MODE_WRITE;
1232*775cb093SVincent Donnefort *fops = &remote_events_dir_enable_fops;
1233*775cb093SVincent Donnefort return 1;
1234*775cb093SVincent Donnefort }
1235*775cb093SVincent Donnefort
1236*775cb093SVincent Donnefort if (!strcmp(name, "header_page")) {
1237*775cb093SVincent Donnefort *mode = TRACEFS_MODE_READ;
1238*775cb093SVincent Donnefort *fops = &remote_events_dir_header_page_fops;
1239*775cb093SVincent Donnefort return 1;
1240*775cb093SVincent Donnefort }
1241*775cb093SVincent Donnefort
1242*775cb093SVincent Donnefort if (!strcmp(name, "header_event")) {
1243*775cb093SVincent Donnefort *mode = TRACEFS_MODE_READ;
1244*775cb093SVincent Donnefort *fops = &remote_events_dir_header_event_fops;
1245*775cb093SVincent Donnefort return 1;
1246*775cb093SVincent Donnefort }
1247*775cb093SVincent Donnefort
1248*775cb093SVincent Donnefort return 0;
1249*775cb093SVincent Donnefort }
1250*775cb093SVincent Donnefort
trace_remote_init_eventfs(const char * remote_name,struct trace_remote * remote,struct remote_event * evt)125107252915SVincent Donnefort static int trace_remote_init_eventfs(const char *remote_name, struct trace_remote *remote,
125207252915SVincent Donnefort struct remote_event *evt)
125307252915SVincent Donnefort {
125407252915SVincent Donnefort struct eventfs_inode *eventfs = remote->eventfs;
1255*775cb093SVincent Donnefort static struct eventfs_entry dir_entries[] = {
1256*775cb093SVincent Donnefort {
1257*775cb093SVincent Donnefort .name = "enable",
1258*775cb093SVincent Donnefort .callback = remote_events_dir_callback,
1259*775cb093SVincent Donnefort }, {
1260*775cb093SVincent Donnefort .name = "header_page",
1261*775cb093SVincent Donnefort .callback = remote_events_dir_callback,
1262*775cb093SVincent Donnefort }, {
1263*775cb093SVincent Donnefort .name = "header_event",
1264*775cb093SVincent Donnefort .callback = remote_events_dir_callback,
1265*775cb093SVincent Donnefort }
1266*775cb093SVincent Donnefort };
126707252915SVincent Donnefort static struct eventfs_entry entries[] = {
126807252915SVincent Donnefort {
126907252915SVincent Donnefort .name = "enable",
127007252915SVincent Donnefort .callback = remote_event_callback,
127107252915SVincent Donnefort }, {
127207252915SVincent Donnefort .name = "id",
127307252915SVincent Donnefort .callback = remote_event_callback,
127407252915SVincent Donnefort }, {
127507252915SVincent Donnefort .name = "format",
127607252915SVincent Donnefort .callback = remote_event_callback,
127707252915SVincent Donnefort }
127807252915SVincent Donnefort };
127907252915SVincent Donnefort bool eventfs_create = false;
128007252915SVincent Donnefort
128107252915SVincent Donnefort if (!eventfs) {
1282*775cb093SVincent Donnefort eventfs = eventfs_create_events_dir("events", remote->dentry, dir_entries,
1283*775cb093SVincent Donnefort ARRAY_SIZE(dir_entries), remote);
128407252915SVincent Donnefort if (IS_ERR(eventfs))
128507252915SVincent Donnefort return PTR_ERR(eventfs);
128607252915SVincent Donnefort
128707252915SVincent Donnefort /*
128807252915SVincent Donnefort * Create similar hierarchy as local events even if a single system is supported at
128907252915SVincent Donnefort * the moment
129007252915SVincent Donnefort */
129107252915SVincent Donnefort eventfs = eventfs_create_dir(remote_name, eventfs, NULL, 0, NULL);
129207252915SVincent Donnefort if (IS_ERR(eventfs))
129307252915SVincent Donnefort return PTR_ERR(eventfs);
129407252915SVincent Donnefort
129507252915SVincent Donnefort remote->eventfs = eventfs;
129607252915SVincent Donnefort eventfs_create = true;
129707252915SVincent Donnefort }
129807252915SVincent Donnefort
129907252915SVincent Donnefort eventfs = eventfs_create_dir(evt->name, eventfs, entries, ARRAY_SIZE(entries), evt);
130007252915SVincent Donnefort if (IS_ERR(eventfs)) {
130107252915SVincent Donnefort if (eventfs_create) {
130207252915SVincent Donnefort eventfs_remove_events_dir(remote->eventfs);
130307252915SVincent Donnefort remote->eventfs = NULL;
130407252915SVincent Donnefort }
130507252915SVincent Donnefort return PTR_ERR(eventfs);
130607252915SVincent Donnefort }
130707252915SVincent Donnefort
130807252915SVincent Donnefort return 0;
130907252915SVincent Donnefort }
131007252915SVincent Donnefort
trace_remote_attach_events(struct trace_remote * remote,struct remote_event * events,size_t nr_events)131107252915SVincent Donnefort static int trace_remote_attach_events(struct trace_remote *remote, struct remote_event *events,
131207252915SVincent Donnefort size_t nr_events)
131307252915SVincent Donnefort {
131407252915SVincent Donnefort int i;
131507252915SVincent Donnefort
131607252915SVincent Donnefort for (i = 0; i < nr_events; i++) {
131707252915SVincent Donnefort struct remote_event *evt = &events[i];
131807252915SVincent Donnefort
131907252915SVincent Donnefort if (evt->remote)
132007252915SVincent Donnefort return -EEXIST;
132107252915SVincent Donnefort
132207252915SVincent Donnefort evt->remote = remote;
132307252915SVincent Donnefort
132407252915SVincent Donnefort /* We need events to be sorted for efficient lookup */
132507252915SVincent Donnefort if (i && evt->id <= events[i - 1].id)
132607252915SVincent Donnefort return -EINVAL;
132707252915SVincent Donnefort }
132807252915SVincent Donnefort
132907252915SVincent Donnefort remote->events = events;
133007252915SVincent Donnefort remote->nr_events = nr_events;
133107252915SVincent Donnefort
133207252915SVincent Donnefort return 0;
133307252915SVincent Donnefort }
133407252915SVincent Donnefort
trace_remote_register_events(const char * remote_name,struct trace_remote * remote,struct remote_event * events,size_t nr_events)133507252915SVincent Donnefort static int trace_remote_register_events(const char *remote_name, struct trace_remote *remote,
133607252915SVincent Donnefort struct remote_event *events, size_t nr_events)
133707252915SVincent Donnefort {
133807252915SVincent Donnefort int i, ret;
133907252915SVincent Donnefort
134007252915SVincent Donnefort ret = trace_remote_attach_events(remote, events, nr_events);
134107252915SVincent Donnefort if (ret)
134207252915SVincent Donnefort return ret;
134307252915SVincent Donnefort
134407252915SVincent Donnefort for (i = 0; i < nr_events; i++) {
134507252915SVincent Donnefort struct remote_event *evt = &events[i];
134607252915SVincent Donnefort
134707252915SVincent Donnefort ret = trace_remote_init_eventfs(remote_name, remote, evt);
134807252915SVincent Donnefort if (ret)
134907252915SVincent Donnefort pr_warn("Failed to init eventfs for event '%s' (%d)",
135007252915SVincent Donnefort evt->name, ret);
135107252915SVincent Donnefort }
135207252915SVincent Donnefort
135307252915SVincent Donnefort return 0;
135407252915SVincent Donnefort }
135507252915SVincent Donnefort
__cmp_events(const void * key,const void * data)135607252915SVincent Donnefort static int __cmp_events(const void *key, const void *data)
135707252915SVincent Donnefort {
135807252915SVincent Donnefort const struct remote_event *evt = data;
135907252915SVincent Donnefort int id = (int)((long)key);
136007252915SVincent Donnefort
136107252915SVincent Donnefort return id - (int)evt->id;
136207252915SVincent Donnefort }
136307252915SVincent Donnefort
trace_remote_find_event(struct trace_remote * remote,unsigned short id)136407252915SVincent Donnefort static struct remote_event *trace_remote_find_event(struct trace_remote *remote, unsigned short id)
136507252915SVincent Donnefort {
136607252915SVincent Donnefort return bsearch((const void *)(unsigned long)id, remote->events, remote->nr_events,
136707252915SVincent Donnefort sizeof(*remote->events), __cmp_events);
136807252915SVincent Donnefort }
1369