14a27fd15SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2108fc825SYoshihiro YUNOMAE /*
3108fc825SYoshihiro YUNOMAE  * Guest agent for virtio-trace
4108fc825SYoshihiro YUNOMAE  *
5108fc825SYoshihiro YUNOMAE  * Copyright (C) 2012 Hitachi, Ltd.
6108fc825SYoshihiro YUNOMAE  * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com>
7108fc825SYoshihiro YUNOMAE  *            Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
8108fc825SYoshihiro YUNOMAE  */
9108fc825SYoshihiro YUNOMAE 
10108fc825SYoshihiro YUNOMAE #define _GNU_SOURCE
11108fc825SYoshihiro YUNOMAE #include <limits.h>
12108fc825SYoshihiro YUNOMAE #include <stdio.h>
13108fc825SYoshihiro YUNOMAE #include <stdlib.h>
14108fc825SYoshihiro YUNOMAE #include <unistd.h>
15108fc825SYoshihiro YUNOMAE #include "trace-agent.h"
16108fc825SYoshihiro YUNOMAE 
17108fc825SYoshihiro YUNOMAE #define PAGE_SIZE		(sysconf(_SC_PAGE_SIZE))
18108fc825SYoshihiro YUNOMAE #define PIPE_DEF_BUFS		16
19108fc825SYoshihiro YUNOMAE #define PIPE_MIN_SIZE		(PAGE_SIZE*PIPE_DEF_BUFS)
20108fc825SYoshihiro YUNOMAE #define PIPE_MAX_SIZE		(1024*1024)
21*07496eeaSRoss Zwisler #define TRACEFS 		"/sys/kernel/tracing"
22*07496eeaSRoss Zwisler #define DEBUGFS 		"/sys/kernel/debug/tracing"
23*07496eeaSRoss Zwisler #define READ_PATH_FMT		"%s/per_cpu/cpu%d/trace_pipe_raw"
24108fc825SYoshihiro YUNOMAE #define WRITE_PATH_FMT		"/dev/virtio-ports/trace-path-cpu%d"
25108fc825SYoshihiro YUNOMAE #define CTL_PATH		"/dev/virtio-ports/agent-ctl-path"
26108fc825SYoshihiro YUNOMAE 
27108fc825SYoshihiro YUNOMAE pthread_mutex_t mutex_notify = PTHREAD_MUTEX_INITIALIZER;
28108fc825SYoshihiro YUNOMAE pthread_cond_t cond_wakeup = PTHREAD_COND_INITIALIZER;
29108fc825SYoshihiro YUNOMAE 
get_total_cpus(void)30108fc825SYoshihiro YUNOMAE static int get_total_cpus(void)
31108fc825SYoshihiro YUNOMAE {
32108fc825SYoshihiro YUNOMAE 	int nr_cpus = (int)sysconf(_SC_NPROCESSORS_CONF);
33108fc825SYoshihiro YUNOMAE 
34108fc825SYoshihiro YUNOMAE 	if (nr_cpus <= 0) {
35108fc825SYoshihiro YUNOMAE 		pr_err("Could not read cpus\n");
36108fc825SYoshihiro YUNOMAE 		goto error;
37108fc825SYoshihiro YUNOMAE 	} else if (nr_cpus > MAX_CPUS) {
38108fc825SYoshihiro YUNOMAE 		pr_err("Exceed max cpus(%d)\n", (int)MAX_CPUS);
39108fc825SYoshihiro YUNOMAE 		goto error;
40108fc825SYoshihiro YUNOMAE 	}
41108fc825SYoshihiro YUNOMAE 
42108fc825SYoshihiro YUNOMAE 	return nr_cpus;
43108fc825SYoshihiro YUNOMAE 
44108fc825SYoshihiro YUNOMAE error:
45108fc825SYoshihiro YUNOMAE 	exit(EXIT_FAILURE);
46108fc825SYoshihiro YUNOMAE }
47108fc825SYoshihiro YUNOMAE 
agent_info_new(void)48108fc825SYoshihiro YUNOMAE static void *agent_info_new(void)
49108fc825SYoshihiro YUNOMAE {
50108fc825SYoshihiro YUNOMAE 	struct agent_info *s;
51108fc825SYoshihiro YUNOMAE 	int i;
52108fc825SYoshihiro YUNOMAE 
53108fc825SYoshihiro YUNOMAE 	s = zalloc(sizeof(struct agent_info));
54108fc825SYoshihiro YUNOMAE 	if (s == NULL) {
55108fc825SYoshihiro YUNOMAE 		pr_err("agent_info zalloc error\n");
56108fc825SYoshihiro YUNOMAE 		exit(EXIT_FAILURE);
57108fc825SYoshihiro YUNOMAE 	}
58108fc825SYoshihiro YUNOMAE 
59108fc825SYoshihiro YUNOMAE 	s->pipe_size = PIPE_INIT;
60108fc825SYoshihiro YUNOMAE 	s->use_stdout = false;
61108fc825SYoshihiro YUNOMAE 	s->cpus = get_total_cpus();
62108fc825SYoshihiro YUNOMAE 	s->ctl_fd = -1;
63108fc825SYoshihiro YUNOMAE 
64108fc825SYoshihiro YUNOMAE 	/* read/write threads init */
65108fc825SYoshihiro YUNOMAE 	for (i = 0; i < s->cpus; i++)
66108fc825SYoshihiro YUNOMAE 		s->rw_ti[i] = rw_thread_info_new();
67108fc825SYoshihiro YUNOMAE 
68108fc825SYoshihiro YUNOMAE 	return s;
69108fc825SYoshihiro YUNOMAE }
70108fc825SYoshihiro YUNOMAE 
parse_size(const char * arg)71108fc825SYoshihiro YUNOMAE static unsigned long parse_size(const char *arg)
72108fc825SYoshihiro YUNOMAE {
73108fc825SYoshihiro YUNOMAE 	unsigned long value, round;
74108fc825SYoshihiro YUNOMAE 	char *ptr;
75108fc825SYoshihiro YUNOMAE 
76108fc825SYoshihiro YUNOMAE 	value = strtoul(arg, &ptr, 10);
77108fc825SYoshihiro YUNOMAE 	switch (*ptr) {
78108fc825SYoshihiro YUNOMAE 	case 'K': case 'k':
79108fc825SYoshihiro YUNOMAE 		value <<= 10;
80108fc825SYoshihiro YUNOMAE 		break;
81108fc825SYoshihiro YUNOMAE 	case 'M': case 'm':
82108fc825SYoshihiro YUNOMAE 		value <<= 20;
83108fc825SYoshihiro YUNOMAE 		break;
84108fc825SYoshihiro YUNOMAE 	default:
85108fc825SYoshihiro YUNOMAE 		break;
86108fc825SYoshihiro YUNOMAE 	}
87108fc825SYoshihiro YUNOMAE 
88108fc825SYoshihiro YUNOMAE 	if (value > PIPE_MAX_SIZE) {
89108fc825SYoshihiro YUNOMAE 		pr_err("Pipe size must be less than 1MB\n");
90108fc825SYoshihiro YUNOMAE 		goto error;
91108fc825SYoshihiro YUNOMAE 	} else if (value < PIPE_MIN_SIZE) {
92108fc825SYoshihiro YUNOMAE 		pr_err("Pipe size must be over 64KB\n");
93108fc825SYoshihiro YUNOMAE 		goto error;
94108fc825SYoshihiro YUNOMAE 	}
95108fc825SYoshihiro YUNOMAE 
96108fc825SYoshihiro YUNOMAE 	/* Align buffer size with page unit */
97108fc825SYoshihiro YUNOMAE 	round = value & (PAGE_SIZE - 1);
98108fc825SYoshihiro YUNOMAE 	value = value - round;
99108fc825SYoshihiro YUNOMAE 
100108fc825SYoshihiro YUNOMAE 	return value;
101108fc825SYoshihiro YUNOMAE error:
102108fc825SYoshihiro YUNOMAE 	return 0;
103108fc825SYoshihiro YUNOMAE }
104108fc825SYoshihiro YUNOMAE 
usage(char const * prg)105108fc825SYoshihiro YUNOMAE static void usage(char const *prg)
106108fc825SYoshihiro YUNOMAE {
107108fc825SYoshihiro YUNOMAE 	pr_err("usage: %s [-h] [-o] [-s <size of pipe>]\n", prg);
108108fc825SYoshihiro YUNOMAE }
109108fc825SYoshihiro YUNOMAE 
make_path(int cpu_num,bool this_is_write_path)110108fc825SYoshihiro YUNOMAE static const char *make_path(int cpu_num, bool this_is_write_path)
111108fc825SYoshihiro YUNOMAE {
112108fc825SYoshihiro YUNOMAE 	int ret;
113108fc825SYoshihiro YUNOMAE 	char *buf;
114108fc825SYoshihiro YUNOMAE 
115108fc825SYoshihiro YUNOMAE 	buf = zalloc(PATH_MAX);
116108fc825SYoshihiro YUNOMAE 	if (buf == NULL) {
117108fc825SYoshihiro YUNOMAE 		pr_err("Could not allocate buffer\n");
118108fc825SYoshihiro YUNOMAE 		goto error;
119108fc825SYoshihiro YUNOMAE 	}
120108fc825SYoshihiro YUNOMAE 
121108fc825SYoshihiro YUNOMAE 	if (this_is_write_path)
122108fc825SYoshihiro YUNOMAE 		/* write(output) path */
123108fc825SYoshihiro YUNOMAE 		ret = snprintf(buf, PATH_MAX, WRITE_PATH_FMT, cpu_num);
124*07496eeaSRoss Zwisler 	else {
125108fc825SYoshihiro YUNOMAE 		/* read(input) path */
126*07496eeaSRoss Zwisler 		ret = snprintf(buf, PATH_MAX, READ_PATH_FMT, TRACEFS, cpu_num);
127*07496eeaSRoss Zwisler 		if (ret > 0 && access(buf, F_OK) != 0)
128*07496eeaSRoss Zwisler 			ret = snprintf(buf, PATH_MAX, READ_PATH_FMT, DEBUGFS, cpu_num);
129*07496eeaSRoss Zwisler 	}
130108fc825SYoshihiro YUNOMAE 
131108fc825SYoshihiro YUNOMAE 	if (ret <= 0) {
132108fc825SYoshihiro YUNOMAE 		pr_err("Failed to generate %s path(CPU#%d):%d\n",
133108fc825SYoshihiro YUNOMAE 			this_is_write_path ? "read" : "write", cpu_num, ret);
134108fc825SYoshihiro YUNOMAE 		goto error;
135108fc825SYoshihiro YUNOMAE 	}
136108fc825SYoshihiro YUNOMAE 
137108fc825SYoshihiro YUNOMAE 	return buf;
138108fc825SYoshihiro YUNOMAE 
139108fc825SYoshihiro YUNOMAE error:
140108fc825SYoshihiro YUNOMAE 	free(buf);
141108fc825SYoshihiro YUNOMAE 	return NULL;
142108fc825SYoshihiro YUNOMAE }
143108fc825SYoshihiro YUNOMAE 
make_input_path(int cpu_num)144108fc825SYoshihiro YUNOMAE static const char *make_input_path(int cpu_num)
145108fc825SYoshihiro YUNOMAE {
146108fc825SYoshihiro YUNOMAE 	return make_path(cpu_num, false);
147108fc825SYoshihiro YUNOMAE }
148108fc825SYoshihiro YUNOMAE 
make_output_path(int cpu_num)149108fc825SYoshihiro YUNOMAE static const char *make_output_path(int cpu_num)
150108fc825SYoshihiro YUNOMAE {
151108fc825SYoshihiro YUNOMAE 	return make_path(cpu_num, true);
152108fc825SYoshihiro YUNOMAE }
153108fc825SYoshihiro YUNOMAE 
agent_info_init(struct agent_info * s)154108fc825SYoshihiro YUNOMAE static void *agent_info_init(struct agent_info *s)
155108fc825SYoshihiro YUNOMAE {
156108fc825SYoshihiro YUNOMAE 	int cpu;
157108fc825SYoshihiro YUNOMAE 	const char *in_path = NULL;
158108fc825SYoshihiro YUNOMAE 	const char *out_path = NULL;
159108fc825SYoshihiro YUNOMAE 
160108fc825SYoshihiro YUNOMAE 	/* init read/write threads */
161108fc825SYoshihiro YUNOMAE 	for (cpu = 0; cpu < s->cpus; cpu++) {
162108fc825SYoshihiro YUNOMAE 		/* set read(input) path per read/write thread */
163108fc825SYoshihiro YUNOMAE 		in_path = make_input_path(cpu);
164108fc825SYoshihiro YUNOMAE 		if (in_path == NULL)
165108fc825SYoshihiro YUNOMAE 			goto error;
166108fc825SYoshihiro YUNOMAE 
167108fc825SYoshihiro YUNOMAE 		/* set write(output) path per read/write thread*/
168108fc825SYoshihiro YUNOMAE 		if (!s->use_stdout) {
169108fc825SYoshihiro YUNOMAE 			out_path = make_output_path(cpu);
170108fc825SYoshihiro YUNOMAE 			if (out_path == NULL)
171108fc825SYoshihiro YUNOMAE 				goto error;
172108fc825SYoshihiro YUNOMAE 		} else
173108fc825SYoshihiro YUNOMAE 			/* stdout mode */
174108fc825SYoshihiro YUNOMAE 			pr_debug("stdout mode\n");
175108fc825SYoshihiro YUNOMAE 
176108fc825SYoshihiro YUNOMAE 		rw_thread_init(cpu, in_path, out_path, s->use_stdout,
177108fc825SYoshihiro YUNOMAE 						s->pipe_size, s->rw_ti[cpu]);
178108fc825SYoshihiro YUNOMAE 	}
179108fc825SYoshihiro YUNOMAE 
180108fc825SYoshihiro YUNOMAE 	/* init controller of read/write threads */
181108fc825SYoshihiro YUNOMAE 	s->ctl_fd = rw_ctl_init((const char *)CTL_PATH);
182108fc825SYoshihiro YUNOMAE 
183108fc825SYoshihiro YUNOMAE 	return NULL;
184108fc825SYoshihiro YUNOMAE 
185108fc825SYoshihiro YUNOMAE error:
186108fc825SYoshihiro YUNOMAE 	exit(EXIT_FAILURE);
187108fc825SYoshihiro YUNOMAE }
188108fc825SYoshihiro YUNOMAE 
parse_args(int argc,char * argv[],struct agent_info * s)189108fc825SYoshihiro YUNOMAE static void *parse_args(int argc, char *argv[], struct agent_info *s)
190108fc825SYoshihiro YUNOMAE {
191108fc825SYoshihiro YUNOMAE 	int cmd;
192108fc825SYoshihiro YUNOMAE 	unsigned long size;
193108fc825SYoshihiro YUNOMAE 
194108fc825SYoshihiro YUNOMAE 	while ((cmd = getopt(argc, argv, "hos:")) != -1) {
195108fc825SYoshihiro YUNOMAE 		switch (cmd) {
196108fc825SYoshihiro YUNOMAE 		/* stdout mode */
197108fc825SYoshihiro YUNOMAE 		case 'o':
198108fc825SYoshihiro YUNOMAE 			s->use_stdout = true;
199108fc825SYoshihiro YUNOMAE 			break;
200108fc825SYoshihiro YUNOMAE 		/* size of pipe */
201108fc825SYoshihiro YUNOMAE 		case 's':
202108fc825SYoshihiro YUNOMAE 			size = parse_size(optarg);
203108fc825SYoshihiro YUNOMAE 			if (size == 0)
204108fc825SYoshihiro YUNOMAE 				goto error;
205108fc825SYoshihiro YUNOMAE 			s->pipe_size = size;
206108fc825SYoshihiro YUNOMAE 			break;
207108fc825SYoshihiro YUNOMAE 		case 'h':
208108fc825SYoshihiro YUNOMAE 		default:
209108fc825SYoshihiro YUNOMAE 			usage(argv[0]);
210108fc825SYoshihiro YUNOMAE 			goto error;
211108fc825SYoshihiro YUNOMAE 		}
212108fc825SYoshihiro YUNOMAE 	}
213108fc825SYoshihiro YUNOMAE 
214108fc825SYoshihiro YUNOMAE 	agent_info_init(s);
215108fc825SYoshihiro YUNOMAE 
216108fc825SYoshihiro YUNOMAE 	return NULL;
217108fc825SYoshihiro YUNOMAE 
218108fc825SYoshihiro YUNOMAE error:
219108fc825SYoshihiro YUNOMAE 	exit(EXIT_FAILURE);
220108fc825SYoshihiro YUNOMAE }
221108fc825SYoshihiro YUNOMAE 
agent_main_loop(struct agent_info * s)222108fc825SYoshihiro YUNOMAE static void agent_main_loop(struct agent_info *s)
223108fc825SYoshihiro YUNOMAE {
224108fc825SYoshihiro YUNOMAE 	int cpu;
225108fc825SYoshihiro YUNOMAE 	pthread_t rw_thread_per_cpu[MAX_CPUS];
226108fc825SYoshihiro YUNOMAE 
227108fc825SYoshihiro YUNOMAE 	/* Start all read/write threads */
228108fc825SYoshihiro YUNOMAE 	for (cpu = 0; cpu < s->cpus; cpu++)
229108fc825SYoshihiro YUNOMAE 		rw_thread_per_cpu[cpu] = rw_thread_run(s->rw_ti[cpu]);
230108fc825SYoshihiro YUNOMAE 
231108fc825SYoshihiro YUNOMAE 	rw_ctl_loop(s->ctl_fd);
232108fc825SYoshihiro YUNOMAE 
233108fc825SYoshihiro YUNOMAE 	/* Finish all read/write threads */
234108fc825SYoshihiro YUNOMAE 	for (cpu = 0; cpu < s->cpus; cpu++) {
235108fc825SYoshihiro YUNOMAE 		int ret;
236108fc825SYoshihiro YUNOMAE 
237108fc825SYoshihiro YUNOMAE 		ret = pthread_join(rw_thread_per_cpu[cpu], NULL);
238108fc825SYoshihiro YUNOMAE 		if (ret != 0) {
239108fc825SYoshihiro YUNOMAE 			pr_err("pthread_join() error:%d (cpu %d)\n", ret, cpu);
240108fc825SYoshihiro YUNOMAE 			exit(EXIT_FAILURE);
241108fc825SYoshihiro YUNOMAE 		}
242108fc825SYoshihiro YUNOMAE 	}
243108fc825SYoshihiro YUNOMAE }
244108fc825SYoshihiro YUNOMAE 
agent_info_free(struct agent_info * s)245108fc825SYoshihiro YUNOMAE static void agent_info_free(struct agent_info *s)
246108fc825SYoshihiro YUNOMAE {
247108fc825SYoshihiro YUNOMAE 	int i;
248108fc825SYoshihiro YUNOMAE 
249108fc825SYoshihiro YUNOMAE 	close(s->ctl_fd);
250108fc825SYoshihiro YUNOMAE 	for (i = 0; i < s->cpus; i++) {
251108fc825SYoshihiro YUNOMAE 		close(s->rw_ti[i]->in_fd);
252108fc825SYoshihiro YUNOMAE 		close(s->rw_ti[i]->out_fd);
253108fc825SYoshihiro YUNOMAE 		close(s->rw_ti[i]->read_pipe);
254108fc825SYoshihiro YUNOMAE 		close(s->rw_ti[i]->write_pipe);
255108fc825SYoshihiro YUNOMAE 		free(s->rw_ti[i]);
256108fc825SYoshihiro YUNOMAE 	}
257108fc825SYoshihiro YUNOMAE 	free(s);
258108fc825SYoshihiro YUNOMAE }
259108fc825SYoshihiro YUNOMAE 
main(int argc,char * argv[])260108fc825SYoshihiro YUNOMAE int main(int argc, char *argv[])
261108fc825SYoshihiro YUNOMAE {
262108fc825SYoshihiro YUNOMAE 	struct agent_info *s = NULL;
263108fc825SYoshihiro YUNOMAE 
264108fc825SYoshihiro YUNOMAE 	s = agent_info_new();
265108fc825SYoshihiro YUNOMAE 	parse_args(argc, argv, s);
266108fc825SYoshihiro YUNOMAE 
267108fc825SYoshihiro YUNOMAE 	agent_main_loop(s);
268108fc825SYoshihiro YUNOMAE 
269108fc825SYoshihiro YUNOMAE 	agent_info_free(s);
270108fc825SYoshihiro YUNOMAE 
271108fc825SYoshihiro YUNOMAE 	return 0;
272108fc825SYoshihiro YUNOMAE }
273