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