trace-agent.c 5.1 KB

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