xref: /linux/kernel/trace/trace_remote.c (revision 9af4ab0e11e336e2671d303ffcc6578e3546d9fc)
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 
2196e43537SVincent Donnefort struct trace_remote_iterator {
2296e43537SVincent Donnefort 	struct trace_remote		*remote;
2396e43537SVincent Donnefort 	struct trace_seq		seq;
2496e43537SVincent Donnefort 	struct delayed_work		poll_work;
2596e43537SVincent Donnefort 	unsigned long			lost_events;
2696e43537SVincent Donnefort 	u64				ts;
2796e43537SVincent Donnefort 	int				cpu;
2896e43537SVincent Donnefort 	int				evt_cpu;
2996e43537SVincent Donnefort };
3096e43537SVincent Donnefort 
3196e43537SVincent Donnefort struct trace_remote {
3296e43537SVincent Donnefort 	struct trace_remote_callbacks	*cbs;
3396e43537SVincent Donnefort 	void				*priv;
3496e43537SVincent Donnefort 	struct trace_buffer		*trace_buffer;
3596e43537SVincent Donnefort 	struct trace_buffer_desc	*trace_buffer_desc;
3696e43537SVincent Donnefort 	unsigned long			trace_buffer_size;
3796e43537SVincent Donnefort 	struct ring_buffer_remote	rb_remote;
3896e43537SVincent Donnefort 	struct mutex			lock;
3996e43537SVincent Donnefort 	unsigned int			nr_readers;
4096e43537SVincent Donnefort 	unsigned int			poll_ms;
4196e43537SVincent Donnefort 	bool				tracing_on;
4296e43537SVincent Donnefort };
4396e43537SVincent Donnefort 
4496e43537SVincent Donnefort static bool trace_remote_loaded(struct trace_remote *remote)
4596e43537SVincent Donnefort {
4696e43537SVincent Donnefort 	return !!remote->trace_buffer;
4796e43537SVincent Donnefort }
4896e43537SVincent Donnefort 
4996e43537SVincent Donnefort static int trace_remote_load(struct trace_remote *remote)
5096e43537SVincent Donnefort {
5196e43537SVincent Donnefort 	struct ring_buffer_remote *rb_remote = &remote->rb_remote;
5296e43537SVincent Donnefort 	struct trace_buffer_desc *desc;
5396e43537SVincent Donnefort 
5496e43537SVincent Donnefort 	lockdep_assert_held(&remote->lock);
5596e43537SVincent Donnefort 
5696e43537SVincent Donnefort 	if (trace_remote_loaded(remote))
5796e43537SVincent Donnefort 		return 0;
5896e43537SVincent Donnefort 
5996e43537SVincent Donnefort 	desc = remote->cbs->load_trace_buffer(remote->trace_buffer_size, remote->priv);
6096e43537SVincent Donnefort 	if (IS_ERR(desc))
6196e43537SVincent Donnefort 		return PTR_ERR(desc);
6296e43537SVincent Donnefort 
6396e43537SVincent Donnefort 	rb_remote->desc = desc;
6496e43537SVincent Donnefort 	rb_remote->swap_reader_page = remote->cbs->swap_reader_page;
6596e43537SVincent Donnefort 	rb_remote->priv = remote->priv;
66*9af4ab0eSVincent Donnefort 	rb_remote->reset = remote->cbs->reset;
6796e43537SVincent Donnefort 	remote->trace_buffer = ring_buffer_alloc_remote(rb_remote);
6896e43537SVincent Donnefort 	if (!remote->trace_buffer) {
6996e43537SVincent Donnefort 		remote->cbs->unload_trace_buffer(desc, remote->priv);
7096e43537SVincent Donnefort 		return -ENOMEM;
7196e43537SVincent Donnefort 	}
7296e43537SVincent Donnefort 
7396e43537SVincent Donnefort 	remote->trace_buffer_desc = desc;
7496e43537SVincent Donnefort 
7596e43537SVincent Donnefort 	return 0;
7696e43537SVincent Donnefort }
7796e43537SVincent Donnefort 
7896e43537SVincent Donnefort static void trace_remote_try_unload(struct trace_remote *remote)
7996e43537SVincent Donnefort {
8096e43537SVincent Donnefort 	lockdep_assert_held(&remote->lock);
8196e43537SVincent Donnefort 
8296e43537SVincent Donnefort 	if (!trace_remote_loaded(remote))
8396e43537SVincent Donnefort 		return;
8496e43537SVincent Donnefort 
8596e43537SVincent Donnefort 	/* The buffer is being read or writable */
8696e43537SVincent Donnefort 	if (remote->nr_readers || remote->tracing_on)
8796e43537SVincent Donnefort 		return;
8896e43537SVincent Donnefort 
8996e43537SVincent Donnefort 	/* The buffer has readable data */
9096e43537SVincent Donnefort 	if (!ring_buffer_empty(remote->trace_buffer))
9196e43537SVincent Donnefort 		return;
9296e43537SVincent Donnefort 
9396e43537SVincent Donnefort 	ring_buffer_free(remote->trace_buffer);
9496e43537SVincent Donnefort 	remote->trace_buffer = NULL;
9596e43537SVincent Donnefort 	remote->cbs->unload_trace_buffer(remote->trace_buffer_desc, remote->priv);
9696e43537SVincent Donnefort }
9796e43537SVincent Donnefort 
9896e43537SVincent Donnefort static int trace_remote_enable_tracing(struct trace_remote *remote)
9996e43537SVincent Donnefort {
10096e43537SVincent Donnefort 	int ret;
10196e43537SVincent Donnefort 
10296e43537SVincent Donnefort 	lockdep_assert_held(&remote->lock);
10396e43537SVincent Donnefort 
10496e43537SVincent Donnefort 	if (remote->tracing_on)
10596e43537SVincent Donnefort 		return 0;
10696e43537SVincent Donnefort 
10796e43537SVincent Donnefort 	ret = trace_remote_load(remote);
10896e43537SVincent Donnefort 	if (ret)
10996e43537SVincent Donnefort 		return ret;
11096e43537SVincent Donnefort 
11196e43537SVincent Donnefort 	ret = remote->cbs->enable_tracing(true, remote->priv);
11296e43537SVincent Donnefort 	if (ret) {
11396e43537SVincent Donnefort 		trace_remote_try_unload(remote);
11496e43537SVincent Donnefort 		return ret;
11596e43537SVincent Donnefort 	}
11696e43537SVincent Donnefort 
11796e43537SVincent Donnefort 	remote->tracing_on = true;
11896e43537SVincent Donnefort 
11996e43537SVincent Donnefort 	return 0;
12096e43537SVincent Donnefort }
12196e43537SVincent Donnefort 
12296e43537SVincent Donnefort static int trace_remote_disable_tracing(struct trace_remote *remote)
12396e43537SVincent Donnefort {
12496e43537SVincent Donnefort 	int ret;
12596e43537SVincent Donnefort 
12696e43537SVincent Donnefort 	lockdep_assert_held(&remote->lock);
12796e43537SVincent Donnefort 
12896e43537SVincent Donnefort 	if (!remote->tracing_on)
12996e43537SVincent Donnefort 		return 0;
13096e43537SVincent Donnefort 
13196e43537SVincent Donnefort 	ret = remote->cbs->enable_tracing(false, remote->priv);
13296e43537SVincent Donnefort 	if (ret)
13396e43537SVincent Donnefort 		return ret;
13496e43537SVincent Donnefort 
13596e43537SVincent Donnefort 	ring_buffer_poll_remote(remote->trace_buffer, RING_BUFFER_ALL_CPUS);
13696e43537SVincent Donnefort 	remote->tracing_on = false;
13796e43537SVincent Donnefort 	trace_remote_try_unload(remote);
13896e43537SVincent Donnefort 
13996e43537SVincent Donnefort 	return 0;
14096e43537SVincent Donnefort }
14196e43537SVincent Donnefort 
142*9af4ab0eSVincent Donnefort static void trace_remote_reset(struct trace_remote *remote, int cpu)
143*9af4ab0eSVincent Donnefort {
144*9af4ab0eSVincent Donnefort 	lockdep_assert_held(&remote->lock);
145*9af4ab0eSVincent Donnefort 
146*9af4ab0eSVincent Donnefort 	if (!trace_remote_loaded(remote))
147*9af4ab0eSVincent Donnefort 		return;
148*9af4ab0eSVincent Donnefort 
149*9af4ab0eSVincent Donnefort 	if (cpu == RING_BUFFER_ALL_CPUS)
150*9af4ab0eSVincent Donnefort 		ring_buffer_reset(remote->trace_buffer);
151*9af4ab0eSVincent Donnefort 	else
152*9af4ab0eSVincent Donnefort 		ring_buffer_reset_cpu(remote->trace_buffer, cpu);
153*9af4ab0eSVincent Donnefort 
154*9af4ab0eSVincent Donnefort 	trace_remote_try_unload(remote);
155*9af4ab0eSVincent Donnefort }
156*9af4ab0eSVincent Donnefort 
15796e43537SVincent Donnefort static ssize_t
15896e43537SVincent Donnefort tracing_on_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
15996e43537SVincent Donnefort {
16096e43537SVincent Donnefort 	struct trace_remote *remote = filp->private_data;
16196e43537SVincent Donnefort 	unsigned long val;
16296e43537SVincent Donnefort 	int ret;
16396e43537SVincent Donnefort 
16496e43537SVincent Donnefort 	ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
16596e43537SVincent Donnefort 	if (ret)
16696e43537SVincent Donnefort 		return ret;
16796e43537SVincent Donnefort 
16896e43537SVincent Donnefort 	guard(mutex)(&remote->lock);
16996e43537SVincent Donnefort 
17096e43537SVincent Donnefort 	ret = val ? trace_remote_enable_tracing(remote) : trace_remote_disable_tracing(remote);
17196e43537SVincent Donnefort 	if (ret)
17296e43537SVincent Donnefort 		return ret;
17396e43537SVincent Donnefort 
17496e43537SVincent Donnefort 	return cnt;
17596e43537SVincent Donnefort }
17696e43537SVincent Donnefort static int tracing_on_show(struct seq_file *s, void *unused)
17796e43537SVincent Donnefort {
17896e43537SVincent Donnefort 	struct trace_remote *remote = s->private;
17996e43537SVincent Donnefort 
18096e43537SVincent Donnefort 	seq_printf(s, "%d\n", remote->tracing_on);
18196e43537SVincent Donnefort 
18296e43537SVincent Donnefort 	return 0;
18396e43537SVincent Donnefort }
18496e43537SVincent Donnefort DEFINE_SHOW_STORE_ATTRIBUTE(tracing_on);
18596e43537SVincent Donnefort 
18696e43537SVincent Donnefort static ssize_t buffer_size_kb_write(struct file *filp, const char __user *ubuf, size_t cnt,
18796e43537SVincent Donnefort 				    loff_t *ppos)
18896e43537SVincent Donnefort {
18996e43537SVincent Donnefort 	struct trace_remote *remote = filp->private_data;
19096e43537SVincent Donnefort 	unsigned long val;
19196e43537SVincent Donnefort 	int ret;
19296e43537SVincent Donnefort 
19396e43537SVincent Donnefort 	ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
19496e43537SVincent Donnefort 	if (ret)
19596e43537SVincent Donnefort 		return ret;
19696e43537SVincent Donnefort 
19796e43537SVincent Donnefort 	/* KiB to Bytes */
19896e43537SVincent Donnefort 	if (!val || check_shl_overflow(val, 10, &val))
19996e43537SVincent Donnefort 		return -EINVAL;
20096e43537SVincent Donnefort 
20196e43537SVincent Donnefort 	guard(mutex)(&remote->lock);
20296e43537SVincent Donnefort 
20396e43537SVincent Donnefort 	if (trace_remote_loaded(remote))
20496e43537SVincent Donnefort 		return -EBUSY;
20596e43537SVincent Donnefort 
20696e43537SVincent Donnefort 	remote->trace_buffer_size = val;
20796e43537SVincent Donnefort 
20896e43537SVincent Donnefort 	return cnt;
20996e43537SVincent Donnefort }
21096e43537SVincent Donnefort 
21196e43537SVincent Donnefort static int buffer_size_kb_show(struct seq_file *s, void *unused)
21296e43537SVincent Donnefort {
21396e43537SVincent Donnefort 	struct trace_remote *remote = s->private;
21496e43537SVincent Donnefort 
21596e43537SVincent Donnefort 	seq_printf(s, "%lu (%s)\n", remote->trace_buffer_size >> 10,
21696e43537SVincent Donnefort 		   trace_remote_loaded(remote) ? "loaded" : "unloaded");
21796e43537SVincent Donnefort 
21896e43537SVincent Donnefort 	return 0;
21996e43537SVincent Donnefort }
22096e43537SVincent Donnefort DEFINE_SHOW_STORE_ATTRIBUTE(buffer_size_kb);
22196e43537SVincent Donnefort 
22296e43537SVincent Donnefort static int trace_remote_get(struct trace_remote *remote, int cpu)
22396e43537SVincent Donnefort {
22496e43537SVincent Donnefort 	int ret;
22596e43537SVincent Donnefort 
22696e43537SVincent Donnefort 	if (remote->nr_readers == UINT_MAX)
22796e43537SVincent Donnefort 		return -EBUSY;
22896e43537SVincent Donnefort 
22996e43537SVincent Donnefort 	ret = trace_remote_load(remote);
23096e43537SVincent Donnefort 	if (ret)
23196e43537SVincent Donnefort 		return ret;
23296e43537SVincent Donnefort 
23396e43537SVincent Donnefort 	remote->nr_readers++;
23496e43537SVincent Donnefort 
23596e43537SVincent Donnefort 	return 0;
23696e43537SVincent Donnefort }
23796e43537SVincent Donnefort 
23896e43537SVincent Donnefort static void trace_remote_put(struct trace_remote *remote)
23996e43537SVincent Donnefort {
24096e43537SVincent Donnefort 	if (WARN_ON(!remote->nr_readers))
24196e43537SVincent Donnefort 		return;
24296e43537SVincent Donnefort 
24396e43537SVincent Donnefort 	remote->nr_readers--;
24496e43537SVincent Donnefort 	if (remote->nr_readers)
24596e43537SVincent Donnefort 		return;
24696e43537SVincent Donnefort 
24796e43537SVincent Donnefort 	trace_remote_try_unload(remote);
24896e43537SVincent Donnefort }
24996e43537SVincent Donnefort 
25096e43537SVincent Donnefort static void __poll_remote(struct work_struct *work)
25196e43537SVincent Donnefort {
25296e43537SVincent Donnefort 	struct delayed_work *dwork = to_delayed_work(work);
25396e43537SVincent Donnefort 	struct trace_remote_iterator *iter;
25496e43537SVincent Donnefort 
25596e43537SVincent Donnefort 	iter = container_of(dwork, struct trace_remote_iterator, poll_work);
25696e43537SVincent Donnefort 	ring_buffer_poll_remote(iter->remote->trace_buffer, iter->cpu);
25796e43537SVincent Donnefort 	schedule_delayed_work((struct delayed_work *)work,
25896e43537SVincent Donnefort 			      msecs_to_jiffies(iter->remote->poll_ms));
25996e43537SVincent Donnefort }
26096e43537SVincent Donnefort 
26196e43537SVincent Donnefort static struct trace_remote_iterator *trace_remote_iter(struct trace_remote *remote, int cpu)
26296e43537SVincent Donnefort {
26396e43537SVincent Donnefort 	struct trace_remote_iterator *iter = NULL;
26496e43537SVincent Donnefort 	int ret;
26596e43537SVincent Donnefort 
26696e43537SVincent Donnefort 	lockdep_assert_held(&remote->lock);
26796e43537SVincent Donnefort 
26896e43537SVincent Donnefort 
26996e43537SVincent Donnefort 	ret = trace_remote_get(remote, cpu);
27096e43537SVincent Donnefort 	if (ret)
27196e43537SVincent Donnefort 		return ERR_PTR(ret);
27296e43537SVincent Donnefort 
27396e43537SVincent Donnefort 	/* Test the CPU */
27496e43537SVincent Donnefort 	ret = ring_buffer_poll_remote(remote->trace_buffer, cpu);
27596e43537SVincent Donnefort 	if (ret)
27696e43537SVincent Donnefort 		goto err;
27796e43537SVincent Donnefort 
27896e43537SVincent Donnefort 	iter = kzalloc_obj(*iter);
27996e43537SVincent Donnefort 	if (iter) {
28096e43537SVincent Donnefort 		iter->remote = remote;
28196e43537SVincent Donnefort 		iter->cpu = cpu;
28296e43537SVincent Donnefort 		trace_seq_init(&iter->seq);
28396e43537SVincent Donnefort 		INIT_DELAYED_WORK(&iter->poll_work, __poll_remote);
28496e43537SVincent Donnefort 		schedule_delayed_work(&iter->poll_work, msecs_to_jiffies(remote->poll_ms));
28596e43537SVincent Donnefort 
28696e43537SVincent Donnefort 		return iter;
28796e43537SVincent Donnefort 	}
28896e43537SVincent Donnefort 	ret = -ENOMEM;
28996e43537SVincent Donnefort 
29096e43537SVincent Donnefort err:
29196e43537SVincent Donnefort 	kfree(iter);
29296e43537SVincent Donnefort 	trace_remote_put(remote);
29396e43537SVincent Donnefort 
29496e43537SVincent Donnefort 	return ERR_PTR(ret);
29596e43537SVincent Donnefort }
29696e43537SVincent Donnefort 
29796e43537SVincent Donnefort static void trace_remote_iter_free(struct trace_remote_iterator *iter)
29896e43537SVincent Donnefort {
29996e43537SVincent Donnefort 	struct trace_remote *remote;
30096e43537SVincent Donnefort 
30196e43537SVincent Donnefort 	if (!iter)
30296e43537SVincent Donnefort 		return;
30396e43537SVincent Donnefort 
30496e43537SVincent Donnefort 	remote = iter->remote;
30596e43537SVincent Donnefort 
30696e43537SVincent Donnefort 	lockdep_assert_held(&remote->lock);
30796e43537SVincent Donnefort 
30896e43537SVincent Donnefort 	kfree(iter);
30996e43537SVincent Donnefort 	trace_remote_put(remote);
31096e43537SVincent Donnefort }
31196e43537SVincent Donnefort 
31296e43537SVincent Donnefort static bool trace_remote_iter_read_event(struct trace_remote_iterator *iter)
31396e43537SVincent Donnefort {
31496e43537SVincent Donnefort 	struct trace_buffer *trace_buffer = iter->remote->trace_buffer;
31596e43537SVincent Donnefort 	int cpu = iter->cpu;
31696e43537SVincent Donnefort 
31796e43537SVincent Donnefort 	if (cpu != RING_BUFFER_ALL_CPUS) {
31896e43537SVincent Donnefort 		if (ring_buffer_empty_cpu(trace_buffer, cpu))
31996e43537SVincent Donnefort 			return false;
32096e43537SVincent Donnefort 
32196e43537SVincent Donnefort 		if (!ring_buffer_peek(trace_buffer, cpu, &iter->ts, &iter->lost_events))
32296e43537SVincent Donnefort 			return false;
32396e43537SVincent Donnefort 
32496e43537SVincent Donnefort 		iter->evt_cpu = cpu;
32596e43537SVincent Donnefort 		return true;
32696e43537SVincent Donnefort 	}
32796e43537SVincent Donnefort 
32896e43537SVincent Donnefort 	iter->ts = U64_MAX;
32996e43537SVincent Donnefort 	for_each_possible_cpu(cpu) {
33096e43537SVincent Donnefort 		unsigned long lost_events;
33196e43537SVincent Donnefort 		u64 ts;
33296e43537SVincent Donnefort 
33396e43537SVincent Donnefort 		if (ring_buffer_empty_cpu(trace_buffer, cpu))
33496e43537SVincent Donnefort 			continue;
33596e43537SVincent Donnefort 
33696e43537SVincent Donnefort 		if (!ring_buffer_peek(trace_buffer, cpu, &ts, &lost_events))
33796e43537SVincent Donnefort 			continue;
33896e43537SVincent Donnefort 
33996e43537SVincent Donnefort 		if (ts >= iter->ts)
34096e43537SVincent Donnefort 			continue;
34196e43537SVincent Donnefort 
34296e43537SVincent Donnefort 		iter->ts = ts;
34396e43537SVincent Donnefort 		iter->evt_cpu = cpu;
34496e43537SVincent Donnefort 		iter->lost_events = lost_events;
34596e43537SVincent Donnefort 	}
34696e43537SVincent Donnefort 
34796e43537SVincent Donnefort 	return iter->ts != U64_MAX;
34896e43537SVincent Donnefort }
34996e43537SVincent Donnefort 
35096e43537SVincent Donnefort static int trace_remote_iter_print_event(struct trace_remote_iterator *iter)
35196e43537SVincent Donnefort {
35296e43537SVincent Donnefort 	unsigned long usecs_rem;
35396e43537SVincent Donnefort 	u64 ts = iter->ts;
35496e43537SVincent Donnefort 
35596e43537SVincent Donnefort 	if (iter->lost_events)
35696e43537SVincent Donnefort 		trace_seq_printf(&iter->seq, "CPU:%d [LOST %lu EVENTS]\n",
35796e43537SVincent Donnefort 				 iter->evt_cpu, iter->lost_events);
35896e43537SVincent Donnefort 
35996e43537SVincent Donnefort 	do_div(ts, 1000);
36096e43537SVincent Donnefort 	usecs_rem = do_div(ts, USEC_PER_SEC);
36196e43537SVincent Donnefort 
36296e43537SVincent Donnefort 	trace_seq_printf(&iter->seq, "[%03d]\t%5llu.%06lu: ", iter->evt_cpu,
36396e43537SVincent Donnefort 			 ts, usecs_rem);
36496e43537SVincent Donnefort 
36596e43537SVincent Donnefort 	return trace_seq_has_overflowed(&iter->seq) ? -EOVERFLOW : 0;
36696e43537SVincent Donnefort }
36796e43537SVincent Donnefort 
36896e43537SVincent Donnefort static int trace_pipe_open(struct inode *inode, struct file *filp)
36996e43537SVincent Donnefort {
37096e43537SVincent Donnefort 	struct trace_remote *remote = inode->i_private;
37196e43537SVincent Donnefort 	struct trace_remote_iterator *iter;
37296e43537SVincent Donnefort 	int cpu = RING_BUFFER_ALL_CPUS;
37396e43537SVincent Donnefort 
37496e43537SVincent Donnefort 	if (inode->i_cdev)
37596e43537SVincent Donnefort 		cpu = (long)inode->i_cdev - 1;
37696e43537SVincent Donnefort 
37796e43537SVincent Donnefort 	guard(mutex)(&remote->lock);
37896e43537SVincent Donnefort 	iter = trace_remote_iter(remote, cpu);
37996e43537SVincent Donnefort 	filp->private_data = iter;
38096e43537SVincent Donnefort 
38196e43537SVincent Donnefort 	return IS_ERR(iter) ? PTR_ERR(iter) : 0;
38296e43537SVincent Donnefort }
38396e43537SVincent Donnefort 
38496e43537SVincent Donnefort static int trace_pipe_release(struct inode *inode, struct file *filp)
38596e43537SVincent Donnefort {
38696e43537SVincent Donnefort 	struct trace_remote_iterator *iter = filp->private_data;
38796e43537SVincent Donnefort 	struct trace_remote *remote = iter->remote;
38896e43537SVincent Donnefort 
38996e43537SVincent Donnefort 	guard(mutex)(&remote->lock);
39096e43537SVincent Donnefort 
39196e43537SVincent Donnefort 	trace_remote_iter_free(iter);
39296e43537SVincent Donnefort 
39396e43537SVincent Donnefort 	return 0;
39496e43537SVincent Donnefort }
39596e43537SVincent Donnefort 
39696e43537SVincent Donnefort static ssize_t trace_pipe_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
39796e43537SVincent Donnefort {
39896e43537SVincent Donnefort 	struct trace_remote_iterator *iter = filp->private_data;
39996e43537SVincent Donnefort 	struct trace_buffer *trace_buffer = iter->remote->trace_buffer;
40096e43537SVincent Donnefort 	int ret;
40196e43537SVincent Donnefort 
40296e43537SVincent Donnefort copy_to_user:
40396e43537SVincent Donnefort 	ret = trace_seq_to_user(&iter->seq, ubuf, cnt);
40496e43537SVincent Donnefort 	if (ret != -EBUSY)
40596e43537SVincent Donnefort 		return ret;
40696e43537SVincent Donnefort 
40796e43537SVincent Donnefort 	trace_seq_init(&iter->seq);
40896e43537SVincent Donnefort 
40996e43537SVincent Donnefort 	ret = ring_buffer_wait(trace_buffer, iter->cpu, 0, NULL, NULL);
41096e43537SVincent Donnefort 	if (ret < 0)
41196e43537SVincent Donnefort 		return ret;
41296e43537SVincent Donnefort 
41396e43537SVincent Donnefort 	while (trace_remote_iter_read_event(iter)) {
41496e43537SVincent Donnefort 		int prev_len = iter->seq.seq.len;
41596e43537SVincent Donnefort 
41696e43537SVincent Donnefort 		if (trace_remote_iter_print_event(iter)) {
41796e43537SVincent Donnefort 			iter->seq.seq.len = prev_len;
41896e43537SVincent Donnefort 			break;
41996e43537SVincent Donnefort 		}
42096e43537SVincent Donnefort 
42196e43537SVincent Donnefort 		ring_buffer_consume(trace_buffer, iter->evt_cpu, NULL, NULL);
42296e43537SVincent Donnefort 	}
42396e43537SVincent Donnefort 
42496e43537SVincent Donnefort 	goto copy_to_user;
42596e43537SVincent Donnefort }
42696e43537SVincent Donnefort 
42796e43537SVincent Donnefort static const struct file_operations trace_pipe_fops = {
42896e43537SVincent Donnefort 	.open		= trace_pipe_open,
42996e43537SVincent Donnefort 	.read		= trace_pipe_read,
43096e43537SVincent Donnefort 	.release	= trace_pipe_release,
43196e43537SVincent Donnefort };
43296e43537SVincent Donnefort 
433*9af4ab0eSVincent Donnefort static ssize_t trace_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
434*9af4ab0eSVincent Donnefort {
435*9af4ab0eSVincent Donnefort 	struct inode *inode = file_inode(filp);
436*9af4ab0eSVincent Donnefort 	struct trace_remote *remote = inode->i_private;
437*9af4ab0eSVincent Donnefort 	int cpu = RING_BUFFER_ALL_CPUS;
438*9af4ab0eSVincent Donnefort 
439*9af4ab0eSVincent Donnefort 	if (inode->i_cdev)
440*9af4ab0eSVincent Donnefort 		cpu = (long)inode->i_cdev - 1;
441*9af4ab0eSVincent Donnefort 
442*9af4ab0eSVincent Donnefort 	guard(mutex)(&remote->lock);
443*9af4ab0eSVincent Donnefort 
444*9af4ab0eSVincent Donnefort 	trace_remote_reset(remote, cpu);
445*9af4ab0eSVincent Donnefort 
446*9af4ab0eSVincent Donnefort 	return cnt;
447*9af4ab0eSVincent Donnefort }
448*9af4ab0eSVincent Donnefort 
449*9af4ab0eSVincent Donnefort static const struct file_operations trace_fops = {
450*9af4ab0eSVincent Donnefort 	.write		= trace_write,
451*9af4ab0eSVincent Donnefort };
452*9af4ab0eSVincent Donnefort 
45396e43537SVincent Donnefort static int trace_remote_init_tracefs(const char *name, struct trace_remote *remote)
45496e43537SVincent Donnefort {
45596e43537SVincent Donnefort 	struct dentry *remote_d, *percpu_d, *d;
45696e43537SVincent Donnefort 	static struct dentry *root;
45796e43537SVincent Donnefort 	static DEFINE_MUTEX(lock);
45896e43537SVincent Donnefort 	bool root_inited = false;
45996e43537SVincent Donnefort 	int cpu;
46096e43537SVincent Donnefort 
46196e43537SVincent Donnefort 	guard(mutex)(&lock);
46296e43537SVincent Donnefort 
46396e43537SVincent Donnefort 	if (!root) {
46496e43537SVincent Donnefort 		root = tracefs_create_dir(TRACEFS_DIR, NULL);
46596e43537SVincent Donnefort 		if (!root) {
46696e43537SVincent Donnefort 			pr_err("Failed to create tracefs dir "TRACEFS_DIR"\n");
46796e43537SVincent Donnefort 			return -ENOMEM;
46896e43537SVincent Donnefort 		}
46996e43537SVincent Donnefort 		root_inited = true;
47096e43537SVincent Donnefort 	}
47196e43537SVincent Donnefort 
47296e43537SVincent Donnefort 	remote_d = tracefs_create_dir(name, root);
47396e43537SVincent Donnefort 	if (!remote_d) {
47496e43537SVincent Donnefort 		pr_err("Failed to create tracefs dir "TRACEFS_DIR"%s/\n", name);
47596e43537SVincent Donnefort 		goto err;
47696e43537SVincent Donnefort 	}
47796e43537SVincent Donnefort 
47896e43537SVincent Donnefort 	d = trace_create_file("tracing_on", TRACEFS_MODE_WRITE, remote_d, remote, &tracing_on_fops);
47996e43537SVincent Donnefort 	if (!d)
48096e43537SVincent Donnefort 		goto err;
48196e43537SVincent Donnefort 
48296e43537SVincent Donnefort 	d = trace_create_file("buffer_size_kb", TRACEFS_MODE_WRITE, remote_d, remote,
48396e43537SVincent Donnefort 			      &buffer_size_kb_fops);
48496e43537SVincent Donnefort 	if (!d)
48596e43537SVincent Donnefort 		goto err;
48696e43537SVincent Donnefort 
48796e43537SVincent Donnefort 	d = trace_create_file("trace_pipe", TRACEFS_MODE_READ, remote_d, remote, &trace_pipe_fops);
48896e43537SVincent Donnefort 	if (!d)
48996e43537SVincent Donnefort 		goto err;
49096e43537SVincent Donnefort 
491*9af4ab0eSVincent Donnefort 	d = trace_create_file("trace", TRACEFS_MODE_WRITE, remote_d, remote, &trace_fops);
492*9af4ab0eSVincent Donnefort 	if (!d)
493*9af4ab0eSVincent Donnefort 		goto err;
494*9af4ab0eSVincent Donnefort 
49596e43537SVincent Donnefort 	percpu_d = tracefs_create_dir("per_cpu", remote_d);
49696e43537SVincent Donnefort 	if (!percpu_d) {
49796e43537SVincent Donnefort 		pr_err("Failed to create tracefs dir "TRACEFS_DIR"%s/per_cpu/\n", name);
49896e43537SVincent Donnefort 		goto err;
49996e43537SVincent Donnefort 	}
50096e43537SVincent Donnefort 
50196e43537SVincent Donnefort 	for_each_possible_cpu(cpu) {
50296e43537SVincent Donnefort 		struct dentry *cpu_d;
50396e43537SVincent Donnefort 		char cpu_name[16];
50496e43537SVincent Donnefort 
50596e43537SVincent Donnefort 		snprintf(cpu_name, sizeof(cpu_name), "cpu%d", cpu);
50696e43537SVincent Donnefort 		cpu_d = tracefs_create_dir(cpu_name, percpu_d);
50796e43537SVincent Donnefort 		if (!cpu_d) {
50896e43537SVincent Donnefort 			pr_err("Failed to create tracefs dir "TRACEFS_DIR"%s/percpu/cpu%d\n",
50996e43537SVincent Donnefort 			       name, cpu);
51096e43537SVincent Donnefort 			goto err;
51196e43537SVincent Donnefort 		}
51296e43537SVincent Donnefort 
51396e43537SVincent Donnefort 		d = trace_create_cpu_file("trace_pipe", TRACEFS_MODE_READ, cpu_d, remote, cpu,
51496e43537SVincent Donnefort 					  &trace_pipe_fops);
51596e43537SVincent Donnefort 		if (!d)
51696e43537SVincent Donnefort 			goto err;
517*9af4ab0eSVincent Donnefort 
518*9af4ab0eSVincent Donnefort 		d = trace_create_cpu_file("trace", TRACEFS_MODE_WRITE, cpu_d, remote, cpu,
519*9af4ab0eSVincent Donnefort 					  &trace_fops);
520*9af4ab0eSVincent Donnefort 		if (!d)
521*9af4ab0eSVincent Donnefort 			goto err;
52296e43537SVincent Donnefort 	}
52396e43537SVincent Donnefort 
52496e43537SVincent Donnefort 	return 0;
52596e43537SVincent Donnefort 
52696e43537SVincent Donnefort err:
52796e43537SVincent Donnefort 	if (root_inited) {
52896e43537SVincent Donnefort 		tracefs_remove(root);
52996e43537SVincent Donnefort 		root = NULL;
53096e43537SVincent Donnefort 	} else {
53196e43537SVincent Donnefort 		tracefs_remove(remote_d);
53296e43537SVincent Donnefort 	}
53396e43537SVincent Donnefort 
53496e43537SVincent Donnefort 	return -ENOMEM;
53596e43537SVincent Donnefort }
53696e43537SVincent Donnefort 
53796e43537SVincent Donnefort /**
53896e43537SVincent Donnefort  * trace_remote_register() - Register a Tracefs remote
53996e43537SVincent Donnefort  * @name:	Name of the remote, used for the Tracefs remotes/ directory.
54096e43537SVincent Donnefort  * @cbs:	Set of callbacks used to control the remote.
54196e43537SVincent Donnefort  * @priv:	Private data, passed to each callback from @cbs.
54296e43537SVincent Donnefort  * @events:	Array of events. &remote_event.name and &remote_event.id must be
54396e43537SVincent Donnefort  *		filled by the caller.
54496e43537SVincent Donnefort  * @nr_events:	Number of events in the @events array.
54596e43537SVincent Donnefort  *
54696e43537SVincent Donnefort  * A trace remote is an entity, outside of the kernel (most likely firmware or
54796e43537SVincent Donnefort  * hypervisor) capable of writing events into a Tracefs compatible ring-buffer.
54896e43537SVincent Donnefort  * The kernel would then act as a reader.
54996e43537SVincent Donnefort  *
55096e43537SVincent Donnefort  * The registered remote will be found under the Tracefs directory
55196e43537SVincent Donnefort  * remotes/<name>.
55296e43537SVincent Donnefort  *
55396e43537SVincent Donnefort  * Return: 0 on success, negative error code on failure.
55496e43537SVincent Donnefort  */
55596e43537SVincent Donnefort int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs, void *priv)
55696e43537SVincent Donnefort {
55796e43537SVincent Donnefort 	struct trace_remote *remote;
55896e43537SVincent Donnefort 
55996e43537SVincent Donnefort 	remote = kzalloc_obj(*remote);
56096e43537SVincent Donnefort 	if (!remote)
56196e43537SVincent Donnefort 		return -ENOMEM;
56296e43537SVincent Donnefort 
56396e43537SVincent Donnefort 	remote->cbs = cbs;
56496e43537SVincent Donnefort 	remote->priv = priv;
56596e43537SVincent Donnefort 	remote->trace_buffer_size = 7 << 10;
56696e43537SVincent Donnefort 	remote->poll_ms = 100;
56796e43537SVincent Donnefort 	mutex_init(&remote->lock);
56896e43537SVincent Donnefort 
56996e43537SVincent Donnefort 	if (trace_remote_init_tracefs(name, remote)) {
57096e43537SVincent Donnefort 		kfree(remote);
57196e43537SVincent Donnefort 		return -ENOMEM;
57296e43537SVincent Donnefort 	}
57396e43537SVincent Donnefort 
57496e43537SVincent Donnefort 	return 0;
57596e43537SVincent Donnefort }
57696e43537SVincent Donnefort EXPORT_SYMBOL_GPL(trace_remote_register);
57796e43537SVincent Donnefort 
57896e43537SVincent Donnefort /**
57996e43537SVincent Donnefort  * trace_remote_free_buffer() - Free trace buffer allocated with trace_remote_alloc_buffer()
58096e43537SVincent Donnefort  * @desc:	Descriptor of the per-CPU ring-buffers, originally filled by
58196e43537SVincent Donnefort  *		trace_remote_alloc_buffer()
58296e43537SVincent Donnefort  *
58396e43537SVincent Donnefort  * Most likely called from &trace_remote_callbacks.unload_trace_buffer.
58496e43537SVincent Donnefort  */
58596e43537SVincent Donnefort void trace_remote_free_buffer(struct trace_buffer_desc *desc)
58696e43537SVincent Donnefort {
58796e43537SVincent Donnefort 	struct ring_buffer_desc *rb_desc;
58896e43537SVincent Donnefort 	int cpu;
58996e43537SVincent Donnefort 
59096e43537SVincent Donnefort 	for_each_ring_buffer_desc(rb_desc, cpu, desc) {
59196e43537SVincent Donnefort 		unsigned int id;
59296e43537SVincent Donnefort 
59396e43537SVincent Donnefort 		free_page(rb_desc->meta_va);
59496e43537SVincent Donnefort 
59596e43537SVincent Donnefort 		for (id = 0; id < rb_desc->nr_page_va; id++)
59696e43537SVincent Donnefort 			free_page(rb_desc->page_va[id]);
59796e43537SVincent Donnefort 	}
59896e43537SVincent Donnefort }
59996e43537SVincent Donnefort EXPORT_SYMBOL_GPL(trace_remote_free_buffer);
60096e43537SVincent Donnefort 
60196e43537SVincent Donnefort /**
60296e43537SVincent Donnefort  * trace_remote_alloc_buffer() - Dynamically allocate a trace buffer
60396e43537SVincent Donnefort  * @desc:		Uninitialized trace_buffer_desc
60496e43537SVincent Donnefort  * @desc_size:		Size of the trace_buffer_desc. Must be at least equal to
60596e43537SVincent Donnefort  *			trace_buffer_desc_size()
60696e43537SVincent Donnefort  * @buffer_size:	Size in bytes of each per-CPU ring-buffer
60796e43537SVincent Donnefort  * @cpumask:		CPUs to allocate a ring-buffer for
60896e43537SVincent Donnefort  *
60996e43537SVincent Donnefort  * Helper to dynamically allocate a set of pages (enough to cover @buffer_size)
61096e43537SVincent Donnefort  * for each CPU from @cpumask and fill @desc. Most likely called from
61196e43537SVincent Donnefort  * &trace_remote_callbacks.load_trace_buffer.
61296e43537SVincent Donnefort  *
61396e43537SVincent Donnefort  * Return: 0 on success, negative error code on failure.
61496e43537SVincent Donnefort  */
61596e43537SVincent Donnefort int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size, size_t buffer_size,
61696e43537SVincent Donnefort 			      const struct cpumask *cpumask)
61796e43537SVincent Donnefort {
61896e43537SVincent Donnefort 	unsigned int nr_pages = max(DIV_ROUND_UP(buffer_size, PAGE_SIZE), 2UL) + 1;
61996e43537SVincent Donnefort 	void *desc_end = desc + desc_size;
62096e43537SVincent Donnefort 	struct ring_buffer_desc *rb_desc;
62196e43537SVincent Donnefort 	int cpu, ret = -ENOMEM;
62296e43537SVincent Donnefort 
62396e43537SVincent Donnefort 	if (desc_size < struct_size(desc, __data, 0))
62496e43537SVincent Donnefort 		return -EINVAL;
62596e43537SVincent Donnefort 
62696e43537SVincent Donnefort 	desc->nr_cpus = 0;
62796e43537SVincent Donnefort 	desc->struct_len = struct_size(desc, __data, 0);
62896e43537SVincent Donnefort 
62996e43537SVincent Donnefort 	rb_desc = (struct ring_buffer_desc *)&desc->__data[0];
63096e43537SVincent Donnefort 
63196e43537SVincent Donnefort 	for_each_cpu(cpu, cpumask) {
63296e43537SVincent Donnefort 		unsigned int id;
63396e43537SVincent Donnefort 
63496e43537SVincent Donnefort 		if ((void *)rb_desc + struct_size(rb_desc, page_va, nr_pages) > desc_end) {
63596e43537SVincent Donnefort 			ret = -EINVAL;
63696e43537SVincent Donnefort 			goto err;
63796e43537SVincent Donnefort 		}
63896e43537SVincent Donnefort 
63996e43537SVincent Donnefort 		rb_desc->cpu = cpu;
64096e43537SVincent Donnefort 		rb_desc->nr_page_va = 0;
64196e43537SVincent Donnefort 		rb_desc->meta_va = (unsigned long)__get_free_page(GFP_KERNEL);
64296e43537SVincent Donnefort 		if (!rb_desc->meta_va)
64396e43537SVincent Donnefort 			goto err;
64496e43537SVincent Donnefort 
64596e43537SVincent Donnefort 		for (id = 0; id < nr_pages; id++) {
64696e43537SVincent Donnefort 			rb_desc->page_va[id] = (unsigned long)__get_free_page(GFP_KERNEL);
64796e43537SVincent Donnefort 			if (!rb_desc->page_va[id])
64896e43537SVincent Donnefort 				goto err;
64996e43537SVincent Donnefort 
65096e43537SVincent Donnefort 			rb_desc->nr_page_va++;
65196e43537SVincent Donnefort 		}
65296e43537SVincent Donnefort 		desc->nr_cpus++;
65396e43537SVincent Donnefort 		desc->struct_len += offsetof(struct ring_buffer_desc, page_va);
65496e43537SVincent Donnefort 		desc->struct_len += struct_size(rb_desc, page_va, rb_desc->nr_page_va);
65596e43537SVincent Donnefort 		rb_desc = __next_ring_buffer_desc(rb_desc);
65696e43537SVincent Donnefort 	}
65796e43537SVincent Donnefort 
65896e43537SVincent Donnefort 	return 0;
65996e43537SVincent Donnefort 
66096e43537SVincent Donnefort err:
66196e43537SVincent Donnefort 	trace_remote_free_buffer(desc);
66296e43537SVincent Donnefort 	return ret;
66396e43537SVincent Donnefort }
66496e43537SVincent Donnefort EXPORT_SYMBOL_GPL(trace_remote_alloc_buffer);
665