1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Guest agent for virtio-trace
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2012 Hitachi, Ltd.
6*4882a593Smuzhiyun * Created by Yoshihiro Yunomae <yoshihiro.yunomae.ez@hitachi.com>
7*4882a593Smuzhiyun * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #define _GNU_SOURCE
11*4882a593Smuzhiyun #include <limits.h>
12*4882a593Smuzhiyun #include <stdio.h>
13*4882a593Smuzhiyun #include <stdlib.h>
14*4882a593Smuzhiyun #include <unistd.h>
15*4882a593Smuzhiyun #include "trace-agent.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #define PAGE_SIZE (sysconf(_SC_PAGE_SIZE))
18*4882a593Smuzhiyun #define PIPE_DEF_BUFS 16
19*4882a593Smuzhiyun #define PIPE_MIN_SIZE (PAGE_SIZE*PIPE_DEF_BUFS)
20*4882a593Smuzhiyun #define PIPE_MAX_SIZE (1024*1024)
21*4882a593Smuzhiyun #define READ_PATH_FMT \
22*4882a593Smuzhiyun "/sys/kernel/debug/tracing/per_cpu/cpu%d/trace_pipe_raw"
23*4882a593Smuzhiyun #define WRITE_PATH_FMT "/dev/virtio-ports/trace-path-cpu%d"
24*4882a593Smuzhiyun #define CTL_PATH "/dev/virtio-ports/agent-ctl-path"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun pthread_mutex_t mutex_notify = PTHREAD_MUTEX_INITIALIZER;
27*4882a593Smuzhiyun pthread_cond_t cond_wakeup = PTHREAD_COND_INITIALIZER;
28*4882a593Smuzhiyun
get_total_cpus(void)29*4882a593Smuzhiyun static int get_total_cpus(void)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun int nr_cpus = (int)sysconf(_SC_NPROCESSORS_CONF);
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun if (nr_cpus <= 0) {
34*4882a593Smuzhiyun pr_err("Could not read cpus\n");
35*4882a593Smuzhiyun goto error;
36*4882a593Smuzhiyun } else if (nr_cpus > MAX_CPUS) {
37*4882a593Smuzhiyun pr_err("Exceed max cpus(%d)\n", (int)MAX_CPUS);
38*4882a593Smuzhiyun goto error;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun return nr_cpus;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun error:
44*4882a593Smuzhiyun exit(EXIT_FAILURE);
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun
agent_info_new(void)47*4882a593Smuzhiyun static void *agent_info_new(void)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun struct agent_info *s;
50*4882a593Smuzhiyun int i;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun s = zalloc(sizeof(struct agent_info));
53*4882a593Smuzhiyun if (s == NULL) {
54*4882a593Smuzhiyun pr_err("agent_info zalloc error\n");
55*4882a593Smuzhiyun exit(EXIT_FAILURE);
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun s->pipe_size = PIPE_INIT;
59*4882a593Smuzhiyun s->use_stdout = false;
60*4882a593Smuzhiyun s->cpus = get_total_cpus();
61*4882a593Smuzhiyun s->ctl_fd = -1;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun /* read/write threads init */
64*4882a593Smuzhiyun for (i = 0; i < s->cpus; i++)
65*4882a593Smuzhiyun s->rw_ti[i] = rw_thread_info_new();
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun return s;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
parse_size(const char * arg)70*4882a593Smuzhiyun static unsigned long parse_size(const char *arg)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun unsigned long value, round;
73*4882a593Smuzhiyun char *ptr;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun value = strtoul(arg, &ptr, 10);
76*4882a593Smuzhiyun switch (*ptr) {
77*4882a593Smuzhiyun case 'K': case 'k':
78*4882a593Smuzhiyun value <<= 10;
79*4882a593Smuzhiyun break;
80*4882a593Smuzhiyun case 'M': case 'm':
81*4882a593Smuzhiyun value <<= 20;
82*4882a593Smuzhiyun break;
83*4882a593Smuzhiyun default:
84*4882a593Smuzhiyun break;
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun if (value > PIPE_MAX_SIZE) {
88*4882a593Smuzhiyun pr_err("Pipe size must be less than 1MB\n");
89*4882a593Smuzhiyun goto error;
90*4882a593Smuzhiyun } else if (value < PIPE_MIN_SIZE) {
91*4882a593Smuzhiyun pr_err("Pipe size must be over 64KB\n");
92*4882a593Smuzhiyun goto error;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun /* Align buffer size with page unit */
96*4882a593Smuzhiyun round = value & (PAGE_SIZE - 1);
97*4882a593Smuzhiyun value = value - round;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun return value;
100*4882a593Smuzhiyun error:
101*4882a593Smuzhiyun return 0;
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
usage(char const * prg)104*4882a593Smuzhiyun static void usage(char const *prg)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun pr_err("usage: %s [-h] [-o] [-s <size of pipe>]\n", prg);
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun
make_path(int cpu_num,bool this_is_write_path)109*4882a593Smuzhiyun static const char *make_path(int cpu_num, bool this_is_write_path)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun int ret;
112*4882a593Smuzhiyun char *buf;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun buf = zalloc(PATH_MAX);
115*4882a593Smuzhiyun if (buf == NULL) {
116*4882a593Smuzhiyun pr_err("Could not allocate buffer\n");
117*4882a593Smuzhiyun goto error;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun if (this_is_write_path)
121*4882a593Smuzhiyun /* write(output) path */
122*4882a593Smuzhiyun ret = snprintf(buf, PATH_MAX, WRITE_PATH_FMT, cpu_num);
123*4882a593Smuzhiyun else
124*4882a593Smuzhiyun /* read(input) path */
125*4882a593Smuzhiyun ret = snprintf(buf, PATH_MAX, READ_PATH_FMT, cpu_num);
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun if (ret <= 0) {
128*4882a593Smuzhiyun pr_err("Failed to generate %s path(CPU#%d):%d\n",
129*4882a593Smuzhiyun this_is_write_path ? "read" : "write", cpu_num, ret);
130*4882a593Smuzhiyun goto error;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun return buf;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun error:
136*4882a593Smuzhiyun free(buf);
137*4882a593Smuzhiyun return NULL;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
make_input_path(int cpu_num)140*4882a593Smuzhiyun static const char *make_input_path(int cpu_num)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun return make_path(cpu_num, false);
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
make_output_path(int cpu_num)145*4882a593Smuzhiyun static const char *make_output_path(int cpu_num)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun return make_path(cpu_num, true);
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
agent_info_init(struct agent_info * s)150*4882a593Smuzhiyun static void *agent_info_init(struct agent_info *s)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun int cpu;
153*4882a593Smuzhiyun const char *in_path = NULL;
154*4882a593Smuzhiyun const char *out_path = NULL;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /* init read/write threads */
157*4882a593Smuzhiyun for (cpu = 0; cpu < s->cpus; cpu++) {
158*4882a593Smuzhiyun /* set read(input) path per read/write thread */
159*4882a593Smuzhiyun in_path = make_input_path(cpu);
160*4882a593Smuzhiyun if (in_path == NULL)
161*4882a593Smuzhiyun goto error;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun /* set write(output) path per read/write thread*/
164*4882a593Smuzhiyun if (!s->use_stdout) {
165*4882a593Smuzhiyun out_path = make_output_path(cpu);
166*4882a593Smuzhiyun if (out_path == NULL)
167*4882a593Smuzhiyun goto error;
168*4882a593Smuzhiyun } else
169*4882a593Smuzhiyun /* stdout mode */
170*4882a593Smuzhiyun pr_debug("stdout mode\n");
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun rw_thread_init(cpu, in_path, out_path, s->use_stdout,
173*4882a593Smuzhiyun s->pipe_size, s->rw_ti[cpu]);
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun /* init controller of read/write threads */
177*4882a593Smuzhiyun s->ctl_fd = rw_ctl_init((const char *)CTL_PATH);
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun return NULL;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun error:
182*4882a593Smuzhiyun exit(EXIT_FAILURE);
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
parse_args(int argc,char * argv[],struct agent_info * s)185*4882a593Smuzhiyun static void *parse_args(int argc, char *argv[], struct agent_info *s)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun int cmd;
188*4882a593Smuzhiyun unsigned long size;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun while ((cmd = getopt(argc, argv, "hos:")) != -1) {
191*4882a593Smuzhiyun switch (cmd) {
192*4882a593Smuzhiyun /* stdout mode */
193*4882a593Smuzhiyun case 'o':
194*4882a593Smuzhiyun s->use_stdout = true;
195*4882a593Smuzhiyun break;
196*4882a593Smuzhiyun /* size of pipe */
197*4882a593Smuzhiyun case 's':
198*4882a593Smuzhiyun size = parse_size(optarg);
199*4882a593Smuzhiyun if (size == 0)
200*4882a593Smuzhiyun goto error;
201*4882a593Smuzhiyun s->pipe_size = size;
202*4882a593Smuzhiyun break;
203*4882a593Smuzhiyun case 'h':
204*4882a593Smuzhiyun default:
205*4882a593Smuzhiyun usage(argv[0]);
206*4882a593Smuzhiyun goto error;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun agent_info_init(s);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun return NULL;
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun error:
215*4882a593Smuzhiyun exit(EXIT_FAILURE);
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
agent_main_loop(struct agent_info * s)218*4882a593Smuzhiyun static void agent_main_loop(struct agent_info *s)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun int cpu;
221*4882a593Smuzhiyun pthread_t rw_thread_per_cpu[MAX_CPUS];
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun /* Start all read/write threads */
224*4882a593Smuzhiyun for (cpu = 0; cpu < s->cpus; cpu++)
225*4882a593Smuzhiyun rw_thread_per_cpu[cpu] = rw_thread_run(s->rw_ti[cpu]);
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun rw_ctl_loop(s->ctl_fd);
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun /* Finish all read/write threads */
230*4882a593Smuzhiyun for (cpu = 0; cpu < s->cpus; cpu++) {
231*4882a593Smuzhiyun int ret;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun ret = pthread_join(rw_thread_per_cpu[cpu], NULL);
234*4882a593Smuzhiyun if (ret != 0) {
235*4882a593Smuzhiyun pr_err("pthread_join() error:%d (cpu %d)\n", ret, cpu);
236*4882a593Smuzhiyun exit(EXIT_FAILURE);
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
agent_info_free(struct agent_info * s)241*4882a593Smuzhiyun static void agent_info_free(struct agent_info *s)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun int i;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun close(s->ctl_fd);
246*4882a593Smuzhiyun for (i = 0; i < s->cpus; i++) {
247*4882a593Smuzhiyun close(s->rw_ti[i]->in_fd);
248*4882a593Smuzhiyun close(s->rw_ti[i]->out_fd);
249*4882a593Smuzhiyun close(s->rw_ti[i]->read_pipe);
250*4882a593Smuzhiyun close(s->rw_ti[i]->write_pipe);
251*4882a593Smuzhiyun free(s->rw_ti[i]);
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun free(s);
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
main(int argc,char * argv[])256*4882a593Smuzhiyun int main(int argc, char *argv[])
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun struct agent_info *s = NULL;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun s = agent_info_new();
261*4882a593Smuzhiyun parse_args(argc, argv, s);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun agent_main_loop(s);
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun agent_info_free(s);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun return 0;
268*4882a593Smuzhiyun }
269