~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/net/tcp_ao/lib/ftrace.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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"
 12 
 13 static char ftrace_path[] = "ksft-ftrace-XXXXXX";
 14 static bool ftrace_mounted;
 15 uint64_t ns_cookie1, ns_cookie2;
 16 
 17 struct test_ftracer {
 18         pthread_t tracer_thread;
 19         int     error;
 20         char    *instance_path;
 21         FILE    *trace_pipe;
 22 
 23         enum ftracer_op (*process_line)(const char *line);
 24         void (*destructor)(struct test_ftracer *tracer);
 25         bool (*expecting_more)(void);
 26 
 27         char    **saved_lines;
 28         size_t  saved_lines_size;
 29         size_t  next_line_ind;
 30 
 31         pthread_cond_t met_all_expected;
 32         pthread_mutex_t met_all_expected_lock;
 33 
 34         struct test_ftracer *next;
 35 };
 36 
 37 static struct test_ftracer *ftracers;
 38 static pthread_mutex_t ftracers_lock = PTHREAD_MUTEX_INITIALIZER;
 39 
 40 static int mount_ftrace(void)
 41 {
 42         if (!mkdtemp(ftrace_path))
 43                 test_error("Can't create temp dir");
 44 
 45         if (mount("tracefs", ftrace_path, "tracefs", 0, "rw"))
 46                 return -errno;
 47 
 48         ftrace_mounted = true;
 49 
 50         return 0;
 51 }
 52 
 53 static void unmount_ftrace(void)
 54 {
 55         if (ftrace_mounted && umount(ftrace_path))
 56                 test_print("Failed on cleanup: can't unmount tracefs: %m");
 57 
 58         if (rmdir(ftrace_path))
 59                 test_error("Failed on cleanup: can't remove ftrace dir %s",
 60                            ftrace_path);
 61 }
 62 
 63 struct opts_list_t {
 64         char *opt_name;
 65         struct opts_list_t *next;
 66 };
 67 
 68 static int disable_trace_options(const char *ftrace_path)
 69 {
 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;
 76 
 77         fopts = test_sprintf("%s/%s", ftrace_path, "trace_options");
 78         if (!fopts)
 79                 return -ENOMEM;
 80 
 81         opts = fopen(fopts, "r+");
 82         if (!opts) {
 83                 ret = -errno;
 84                 goto out_free;
 85         }
 86 
 87         while ((line_len = getline(&line, &buf_len, opts)) != -1) {
 88                 struct opts_list_t *tmp;
 89 
 90                 if (!strncmp(line, "no", 2))
 91                         continue;
 92 
 93                 tmp = malloc(sizeof(*tmp));
 94                 if (!tmp) {
 95                         ret = -ENOMEM;
 96                         goto out_free_opts_list;
 97                 }
 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;
104                 }
105                 opts_list = tmp;
106         }
107 
108         while (opts_list) {
109                 struct opts_list_t *tmp = opts_list;
110 
111                 fseek(opts, 0, SEEK_SET);
112                 fwrite(tmp->opt_name, 1, strlen(tmp->opt_name), opts);
113 
114                 opts_list = opts_list->next;
115                 free(tmp->opt_name);
116                 free(tmp);
117         }
118 
119 out_free_opts_list:
120         while (opts_list) {
121                 struct opts_list_t *tmp = opts_list;
122 
123                 opts_list = opts_list->next;
124                 free(tmp->opt_name);
125                 free(tmp);
126         }
127         free(line);
128         fclose(opts);
129 out_free:
130         free(fopts);
131         return ret;
132 }
133 
134 static int setup_buffer_size(const char *ftrace_path, size_t sz)
135 {
136         char *fbuf_size = test_sprintf("%s/buffer_size_kb", ftrace_path);
137         int ret;
138 
139         if (!fbuf_size)
140                 return -1;
141 
142         ret = test_echo(fbuf_size, 0, "%zu", sz);
143         free(fbuf_size);
144         return ret;
145 }
146 
147 static int setup_ftrace_instance(struct test_ftracer *tracer, const char *name)
148 {
149         char *tmp;
150 
151         tmp = test_sprintf("%s/instances/ksft-%s-XXXXXX", ftrace_path, name);
152         if (!tmp)
153                 return -ENOMEM;
154 
155         tracer->instance_path = mkdtemp(tmp);
156         if (!tracer->instance_path) {
157                 free(tmp);
158                 return -errno;
159         }
160 
161         return 0;
162 }
163 
164 static void remove_ftrace_instance(struct test_ftracer *tracer)
165 {
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);
170 }
171 
172 static void tracer_cleanup(void *arg)
173 {
174         struct test_ftracer *tracer = arg;
175 
176         fclose(tracer->trace_pipe);
177 }
178 
179 static void tracer_set_error(struct test_ftracer *tracer, int error)
180 {
181         if (!tracer->error)
182                 tracer->error = error;
183 }
184 
185 const size_t tracer_get_savedlines_nr(struct test_ftracer *tracer)
186 {
187         return tracer->next_line_ind;
188 }
189 
190 const char **tracer_get_savedlines(struct test_ftracer *tracer)
191 {
192         return (const char **)tracer->saved_lines;
193 }
194 
195 static void *tracer_thread_func(void *arg)
196 {
197         struct test_ftracer *tracer = arg;
198 
199         pthread_cleanup_push(tracer_cleanup, arg);
200 
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;
206 
207                 line_len = getline(lp, &buf_len, tracer->trace_pipe);
208                 if (line_len == -1)
209                         break;
210 
211                 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
212                 op = tracer->process_line(*lp);
213                 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
214 
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);
220                 }
221 
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);
228 
229                 tracer->next_line_ind++;
230                 buf_len = 0;
231         }
232         test_print("too many lines in ftracer buffer %zu, exiting tracer",
233                    tracer->next_line_ind);
234 
235         pthread_cleanup_pop(1);
236         return NULL;
237 }
238 
239 static int setup_trace_thread(struct test_ftracer *tracer)
240 {
241         int ret = 0;
242         char *path;
243 
244         path = test_sprintf("%s/trace_pipe", tracer->instance_path);
245         if (!path)
246                 return -ENOMEM;
247 
248         tracer->trace_pipe = fopen(path, "r");
249         if (!tracer->trace_pipe) {
250                 ret = -errno;
251                 goto out_free;
252         }
253 
254         if (pthread_create(&tracer->tracer_thread, NULL,
255                            tracer_thread_func, (void *)tracer)) {
256                 ret = -errno;
257                 fclose(tracer->trace_pipe);
258         }
259 
260 out_free:
261         free(path);
262         return ret;
263 }
264 
265 static void stop_trace_thread(struct test_ftracer *tracer)
266 {
267         void *res;
268 
269         if (pthread_cancel(tracer->tracer_thread)) {
270                 test_print("Can't stop tracer pthread: %m");
271                 tracer_set_error(tracer, -errno);
272         }
273         if (pthread_join(tracer->tracer_thread, &res)) {
274                 test_print("Can't join tracer pthread: %m");
275                 tracer_set_error(tracer, -errno);
276         }
277         if (res != PTHREAD_CANCELED) {
278                 test_print("Tracer thread wasn't canceled");
279                 tracer_set_error(tracer, -errno);
280         }
281         if (tracer->error)
282                 test_fail("tracer errored by %s", strerror(tracer->error));
283 }
284 
285 static void final_wait_for_events(struct test_ftracer *tracer,
286                                   unsigned timeout_sec)
287 {
288         struct timespec timeout;
289         struct timeval now;
290         int ret = 0;
291 
292         if (!tracer->expecting_more)
293                 return;
294 
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;
299 
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);
304 }
305 
306 int setup_trace_event(struct test_ftracer *tracer,
307                       const char *event, const char *filter)
308 {
309         char *enable_path, *filter_path, *instance = tracer->instance_path;
310         int ret;
311 
312         enable_path = test_sprintf("%s/events/%s/enable", instance, event);
313         if (!enable_path)
314                 return -ENOMEM;
315 
316         filter_path = test_sprintf("%s/events/%s/filter", instance, event);
317         if (!filter_path) {
318                 ret = -ENOMEM;
319                 goto out_free;
320         }
321 
322         ret = test_echo(filter_path, 0, "%s", filter);
323         if (!ret)
324                 ret = test_echo(enable_path, 0, "1");
325 
326 out_free:
327         free(filter_path);
328         free(enable_path);
329         return ret;
330 }
331 
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)
337 {
338         struct test_ftracer *tracer;
339         int err;
340 
341         /* XXX: separate __create_ftracer() helper and do here
342          * if (!kernel_config_has(KCONFIG_FTRACE))
343          *      return NULL;
344          */
345 
346         tracer = malloc(sizeof(*tracer));
347         if (!tracer) {
348                 test_print("malloc()");
349                 return NULL;
350         }
351 
352         memset(tracer, 0, sizeof(*tracer));
353 
354         err = setup_ftrace_instance(tracer, name);
355         if (err) {
356                 test_print("setup_ftrace_instance(): %d", err);
357                 goto err_free;
358         }
359 
360         err = disable_trace_options(tracer->instance_path);
361         if (err) {
362                 test_print("disable_trace_options(): %d", err);
363                 goto err_remove;
364         }
365 
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;
370         }
371 
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;
376         }
377         tracer->saved_lines_size = lines_buf_sz;
378 
379         tracer->process_line    = process_line;
380         tracer->destructor      = destructor;
381         tracer->expecting_more  = expecting_more;
382 
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;
387         }
388 
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;
393         }
394 
395         err = setup_trace_thread(tracer);
396         if (err) {
397                 test_print("setup_trace_thread(): %d", err);
398                 goto err_mutex_destroy;
399         }
400 
401         pthread_mutex_lock(&ftracers_lock);
402         tracer->next = ftracers;
403         ftracers = tracer;
404         pthread_mutex_unlock(&ftracers_lock);
405 
406         return tracer;
407 
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;
419 }
420 
421 static void __destroy_ftracer(struct test_ftracer *tracer)
422 {
423         size_t i;
424 
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);
435 }
436 
437 void destroy_ftracer(struct test_ftracer *tracer)
438 {
439         pthread_mutex_lock(&ftracers_lock);
440         if (tracer == ftracers) {
441                 ftracers = tracer->next;
442         } else {
443                 struct test_ftracer *f = ftracers;
444 
445                 while (f->next != tracer) {
446                         if (!f->next)
447                                 test_error("tracers list corruption or double free %p", tracer);
448                         f = f->next;
449                 }
450                 f->next = tracer->next;
451         }
452         tracer->next = NULL;
453         pthread_mutex_unlock(&ftracers_lock);
454         __destroy_ftracer(tracer);
455 }
456 
457 static void destroy_all_ftracers(void)
458 {
459         struct test_ftracer *f;
460 
461         pthread_mutex_lock(&ftracers_lock);
462         f = ftracers;
463         ftracers = NULL;
464         pthread_mutex_unlock(&ftracers_lock);
465 
466         while (f) {
467                 struct test_ftracer *n = f->next;
468 
469                 f->next = NULL;
470                 __destroy_ftracer(f);
471                 f = n;
472         }
473 }
474 
475 static void test_unset_tracing(void)
476 {
477         destroy_all_ftracers();
478         unmount_ftrace();
479 }
480 
481 int test_setup_tracing(void)
482 {
483         /*
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.
487          */
488         static int already_set;
489         int err;
490 
491         if (already_set)
492                 return -1;
493 
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;
499         }
500 
501         already_set = 1;
502 
503         test_add_destructor(test_unset_tracing);
504 
505         err = mount_ftrace();
506         if (err) {
507                 test_print("failed to mount_ftrace(): %d", err);
508                 return err;
509         }
510 
511         return setup_aolib_ftracer();
512 }
513 
514 static int get_ns_cookie(int nsfd, uint64_t *out)
515 {
516         int old_ns = switch_save_ns(nsfd);
517         socklen_t size = sizeof(*out);
518         int sk;
519 
520         sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
521         if (sk < 0) {
522                 test_print("socket(): %m");
523                 return -errno;
524         }
525 
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;
530         }
531 
532         close(sk);
533         switch_close_ns(old_ns);
534         return 0;
535 }
536 
537 void test_init_ftrace(int nsfd1, int nsfd2)
538 {
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);
543 }
544 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php