accel/qaic: Add AIC200 support
[drm/drm-misc.git] / tools / testing / selftests / net / tcp_ao / lib / ftrace.c
blobe4d0b173bc94bdf326dec1e048b2142b56a196ea
1 // SPDX-License-Identifier: GPL-2.0
2 #include <inttypes.h>
3 #include <pthread.h>
4 #include <stdbool.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <sys/mount.h>
8 #include <sys/time.h>
9 #include <unistd.h>
10 #include "../../../../../include/linux/kernel.h"
11 #include "aolib.h"
13 static char ftrace_path[] = "ksft-ftrace-XXXXXX";
14 static bool ftrace_mounted;
15 uint64_t ns_cookie1, ns_cookie2;
17 struct test_ftracer {
18 pthread_t tracer_thread;
19 int error;
20 char *instance_path;
21 FILE *trace_pipe;
23 enum ftracer_op (*process_line)(const char *line);
24 void (*destructor)(struct test_ftracer *tracer);
25 bool (*expecting_more)(void);
27 char **saved_lines;
28 size_t saved_lines_size;
29 size_t next_line_ind;
31 pthread_cond_t met_all_expected;
32 pthread_mutex_t met_all_expected_lock;
34 struct test_ftracer *next;
37 static struct test_ftracer *ftracers;
38 static pthread_mutex_t ftracers_lock = PTHREAD_MUTEX_INITIALIZER;
40 static int mount_ftrace(void)
42 if (!mkdtemp(ftrace_path))
43 test_error("Can't create temp dir");
45 if (mount("tracefs", ftrace_path, "tracefs", 0, "rw"))
46 return -errno;
48 ftrace_mounted = true;
50 return 0;
53 static void unmount_ftrace(void)
55 if (ftrace_mounted && umount(ftrace_path))
56 test_print("Failed on cleanup: can't unmount tracefs: %m");
58 if (rmdir(ftrace_path))
59 test_error("Failed on cleanup: can't remove ftrace dir %s",
60 ftrace_path);
63 struct opts_list_t {
64 char *opt_name;
65 struct opts_list_t *next;
68 static int disable_trace_options(const char *ftrace_path)
70 struct opts_list_t *opts_list = NULL;
71 char *fopts, *line = NULL;
72 size_t buf_len = 0;
73 ssize_t line_len;
74 int ret = 0;
75 FILE *opts;
77 fopts = test_sprintf("%s/%s", ftrace_path, "trace_options");
78 if (!fopts)
79 return -ENOMEM;
81 opts = fopen(fopts, "r+");
82 if (!opts) {
83 ret = -errno;
84 goto out_free;
87 while ((line_len = getline(&line, &buf_len, opts)) != -1) {
88 struct opts_list_t *tmp;
90 if (!strncmp(line, "no", 2))
91 continue;
93 tmp = malloc(sizeof(*tmp));
94 if (!tmp) {
95 ret = -ENOMEM;
96 goto out_free_opts_list;
98 tmp->next = opts_list;
99 tmp->opt_name = test_sprintf("no%s", line);
100 if (!tmp->opt_name) {
101 ret = -ENOMEM;
102 free(tmp);
103 goto out_free_opts_list;
105 opts_list = tmp;
108 while (opts_list) {
109 struct opts_list_t *tmp = opts_list;
111 fseek(opts, 0, SEEK_SET);
112 fwrite(tmp->opt_name, 1, strlen(tmp->opt_name), opts);
114 opts_list = opts_list->next;
115 free(tmp->opt_name);
116 free(tmp);
119 out_free_opts_list:
120 while (opts_list) {
121 struct opts_list_t *tmp = opts_list;
123 opts_list = opts_list->next;
124 free(tmp->opt_name);
125 free(tmp);
127 free(line);
128 fclose(opts);
129 out_free:
130 free(fopts);
131 return ret;
134 static int setup_buffer_size(const char *ftrace_path, size_t sz)
136 char *fbuf_size = test_sprintf("%s/buffer_size_kb", ftrace_path);
137 int ret;
139 if (!fbuf_size)
140 return -1;
142 ret = test_echo(fbuf_size, 0, "%zu", sz);
143 free(fbuf_size);
144 return ret;
147 static int setup_ftrace_instance(struct test_ftracer *tracer, const char *name)
149 char *tmp;
151 tmp = test_sprintf("%s/instances/ksft-%s-XXXXXX", ftrace_path, name);
152 if (!tmp)
153 return -ENOMEM;
155 tracer->instance_path = mkdtemp(tmp);
156 if (!tracer->instance_path) {
157 free(tmp);
158 return -errno;
161 return 0;
164 static void remove_ftrace_instance(struct test_ftracer *tracer)
166 if (rmdir(tracer->instance_path))
167 test_print("Failed on cleanup: can't remove ftrace instance %s",
168 tracer->instance_path);
169 free(tracer->instance_path);
172 static void tracer_cleanup(void *arg)
174 struct test_ftracer *tracer = arg;
176 fclose(tracer->trace_pipe);
179 static void tracer_set_error(struct test_ftracer *tracer, int error)
181 if (!tracer->error)
182 tracer->error = error;
185 const size_t tracer_get_savedlines_nr(struct test_ftracer *tracer)
187 return tracer->next_line_ind;
190 const char **tracer_get_savedlines(struct test_ftracer *tracer)
192 return (const char **)tracer->saved_lines;
195 static void *tracer_thread_func(void *arg)
197 struct test_ftracer *tracer = arg;
199 pthread_cleanup_push(tracer_cleanup, arg);
201 while (tracer->next_line_ind < tracer->saved_lines_size) {
202 char **lp = &tracer->saved_lines[tracer->next_line_ind];
203 enum ftracer_op op;
204 size_t buf_len = 0;
205 ssize_t line_len;
207 line_len = getline(lp, &buf_len, tracer->trace_pipe);
208 if (line_len == -1)
209 break;
211 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
212 op = tracer->process_line(*lp);
213 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
215 if (tracer->expecting_more) {
216 pthread_mutex_lock(&tracer->met_all_expected_lock);
217 if (!tracer->expecting_more())
218 pthread_cond_signal(&tracer->met_all_expected);
219 pthread_mutex_unlock(&tracer->met_all_expected_lock);
222 if (op == FTRACER_LINE_DISCARD)
223 continue;
224 if (op == FTRACER_EXIT)
225 break;
226 if (op != FTRACER_LINE_PRESERVE)
227 test_error("unexpected tracer command %d", op);
229 tracer->next_line_ind++;
230 buf_len = 0;
232 test_print("too many lines in ftracer buffer %zu, exiting tracer",
233 tracer->next_line_ind);
235 pthread_cleanup_pop(1);
236 return NULL;
239 static int setup_trace_thread(struct test_ftracer *tracer)
241 int ret = 0;
242 char *path;
244 path = test_sprintf("%s/trace_pipe", tracer->instance_path);
245 if (!path)
246 return -ENOMEM;
248 tracer->trace_pipe = fopen(path, "r");
249 if (!tracer->trace_pipe) {
250 ret = -errno;
251 goto out_free;
254 if (pthread_create(&tracer->tracer_thread, NULL,
255 tracer_thread_func, (void *)tracer)) {
256 ret = -errno;
257 fclose(tracer->trace_pipe);
260 out_free:
261 free(path);
262 return ret;
265 static void stop_trace_thread(struct test_ftracer *tracer)
267 void *res;
269 if (pthread_cancel(tracer->tracer_thread)) {
270 test_print("Can't stop tracer pthread: %m");
271 tracer_set_error(tracer, -errno);
273 if (pthread_join(tracer->tracer_thread, &res)) {
274 test_print("Can't join tracer pthread: %m");
275 tracer_set_error(tracer, -errno);
277 if (res != PTHREAD_CANCELED) {
278 test_print("Tracer thread wasn't canceled");
279 tracer_set_error(tracer, -errno);
281 if (tracer->error)
282 test_fail("tracer errored by %s", strerror(tracer->error));
285 static void final_wait_for_events(struct test_ftracer *tracer,
286 unsigned timeout_sec)
288 struct timespec timeout;
289 struct timeval now;
290 int ret = 0;
292 if (!tracer->expecting_more)
293 return;
295 pthread_mutex_lock(&tracer->met_all_expected_lock);
296 gettimeofday(&now, NULL);
297 timeout.tv_sec = now.tv_sec + timeout_sec;
298 timeout.tv_nsec = now.tv_usec * 1000;
300 while (tracer->expecting_more() && ret != ETIMEDOUT)
301 ret = pthread_cond_timedwait(&tracer->met_all_expected,
302 &tracer->met_all_expected_lock, &timeout);
303 pthread_mutex_unlock(&tracer->met_all_expected_lock);
306 int setup_trace_event(struct test_ftracer *tracer,
307 const char *event, const char *filter)
309 char *enable_path, *filter_path, *instance = tracer->instance_path;
310 int ret;
312 enable_path = test_sprintf("%s/events/%s/enable", instance, event);
313 if (!enable_path)
314 return -ENOMEM;
316 filter_path = test_sprintf("%s/events/%s/filter", instance, event);
317 if (!filter_path) {
318 ret = -ENOMEM;
319 goto out_free;
322 ret = test_echo(filter_path, 0, "%s", filter);
323 if (!ret)
324 ret = test_echo(enable_path, 0, "1");
326 out_free:
327 free(filter_path);
328 free(enable_path);
329 return ret;
332 struct test_ftracer *create_ftracer(const char *name,
333 enum ftracer_op (*process_line)(const char *line),
334 void (*destructor)(struct test_ftracer *tracer),
335 bool (*expecting_more)(void),
336 size_t lines_buf_sz, size_t buffer_size_kb)
338 struct test_ftracer *tracer;
339 int err;
341 /* XXX: separate __create_ftracer() helper and do here
342 * if (!kernel_config_has(KCONFIG_FTRACE))
343 * return NULL;
346 tracer = malloc(sizeof(*tracer));
347 if (!tracer) {
348 test_print("malloc()");
349 return NULL;
352 memset(tracer, 0, sizeof(*tracer));
354 err = setup_ftrace_instance(tracer, name);
355 if (err) {
356 test_print("setup_ftrace_instance(): %d", err);
357 goto err_free;
360 err = disable_trace_options(tracer->instance_path);
361 if (err) {
362 test_print("disable_trace_options(): %d", err);
363 goto err_remove;
366 err = setup_buffer_size(tracer->instance_path, buffer_size_kb);
367 if (err) {
368 test_print("disable_trace_options(): %d", err);
369 goto err_remove;
372 tracer->saved_lines = calloc(lines_buf_sz, sizeof(tracer->saved_lines[0]));
373 if (!tracer->saved_lines) {
374 test_print("calloc()");
375 goto err_remove;
377 tracer->saved_lines_size = lines_buf_sz;
379 tracer->process_line = process_line;
380 tracer->destructor = destructor;
381 tracer->expecting_more = expecting_more;
383 err = pthread_cond_init(&tracer->met_all_expected, NULL);
384 if (err) {
385 test_print("pthread_cond_init(): %d", err);
386 goto err_free_lines;
389 err = pthread_mutex_init(&tracer->met_all_expected_lock, NULL);
390 if (err) {
391 test_print("pthread_mutex_init(): %d", err);
392 goto err_cond_destroy;
395 err = setup_trace_thread(tracer);
396 if (err) {
397 test_print("setup_trace_thread(): %d", err);
398 goto err_mutex_destroy;
401 pthread_mutex_lock(&ftracers_lock);
402 tracer->next = ftracers;
403 ftracers = tracer;
404 pthread_mutex_unlock(&ftracers_lock);
406 return tracer;
408 err_mutex_destroy:
409 pthread_mutex_destroy(&tracer->met_all_expected_lock);
410 err_cond_destroy:
411 pthread_cond_destroy(&tracer->met_all_expected);
412 err_free_lines:
413 free(tracer->saved_lines);
414 err_remove:
415 remove_ftrace_instance(tracer);
416 err_free:
417 free(tracer);
418 return NULL;
421 static void __destroy_ftracer(struct test_ftracer *tracer)
423 size_t i;
425 final_wait_for_events(tracer, TEST_TIMEOUT_SEC);
426 stop_trace_thread(tracer);
427 remove_ftrace_instance(tracer);
428 if (tracer->destructor)
429 tracer->destructor(tracer);
430 for (i = 0; i < tracer->saved_lines_size; i++)
431 free(tracer->saved_lines[i]);
432 pthread_cond_destroy(&tracer->met_all_expected);
433 pthread_mutex_destroy(&tracer->met_all_expected_lock);
434 free(tracer);
437 void destroy_ftracer(struct test_ftracer *tracer)
439 pthread_mutex_lock(&ftracers_lock);
440 if (tracer == ftracers) {
441 ftracers = tracer->next;
442 } else {
443 struct test_ftracer *f = ftracers;
445 while (f->next != tracer) {
446 if (!f->next)
447 test_error("tracers list corruption or double free %p", tracer);
448 f = f->next;
450 f->next = tracer->next;
452 tracer->next = NULL;
453 pthread_mutex_unlock(&ftracers_lock);
454 __destroy_ftracer(tracer);
457 static void destroy_all_ftracers(void)
459 struct test_ftracer *f;
461 pthread_mutex_lock(&ftracers_lock);
462 f = ftracers;
463 ftracers = NULL;
464 pthread_mutex_unlock(&ftracers_lock);
466 while (f) {
467 struct test_ftracer *n = f->next;
469 f->next = NULL;
470 __destroy_ftracer(f);
471 f = n;
475 static void test_unset_tracing(void)
477 destroy_all_ftracers();
478 unmount_ftrace();
481 int test_setup_tracing(void)
484 * Just a basic protection - this should be called only once from
485 * lib/kconfig. Not thread safe, which is fine as it's early, before
486 * threads are created.
488 static int already_set;
489 int err;
491 if (already_set)
492 return -1;
494 /* Needs net-namespace cookies for filters */
495 if (ns_cookie1 == ns_cookie2) {
496 test_print("net-namespace cookies: %" PRIu64 " == %" PRIu64 ", can't set up tracing",
497 ns_cookie1, ns_cookie2);
498 return -1;
501 already_set = 1;
503 test_add_destructor(test_unset_tracing);
505 err = mount_ftrace();
506 if (err) {
507 test_print("failed to mount_ftrace(): %d", err);
508 return err;
511 return setup_aolib_ftracer();
514 static int get_ns_cookie(int nsfd, uint64_t *out)
516 int old_ns = switch_save_ns(nsfd);
517 socklen_t size = sizeof(*out);
518 int sk;
520 sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
521 if (sk < 0) {
522 test_print("socket(): %m");
523 return -errno;
526 if (getsockopt(sk, SOL_SOCKET, SO_NETNS_COOKIE, out, &size)) {
527 test_print("getsockopt(SO_NETNS_COOKIE): %m");
528 close(sk);
529 return -errno;
532 close(sk);
533 switch_close_ns(old_ns);
534 return 0;
537 void test_init_ftrace(int nsfd1, int nsfd2)
539 get_ns_cookie(nsfd1, &ns_cookie1);
540 get_ns_cookie(nsfd2, &ns_cookie2);
541 /* Populate kernel config state */
542 kernel_config_has(KCONFIG_FTRACE);