1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3 * Copyright (C) 2008, 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
4 *
5 * Updates:
6 * Copyright (C) 2019, VMware, Tzvetomir Stoyanov <tz.stoyanov@gmail.com>
7 *
8 */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <ctype.h>
14 #include <errno.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <dirent.h>
18 #include <regex.h>
19 #include <limits.h>
20 #include <pthread.h>
21 #include "tracefs.h"
22 #include "tracefs-local.h"
23
24 enum {
25 FLAG_INSTANCE_NEWLY_CREATED = (1 << 0),
26 FLAG_INSTANCE_DELETED = (1 << 1),
27 };
28
29
30 struct tracefs_options_mask toplevel_supported_opts;
31 struct tracefs_options_mask toplevel_enabled_opts;
32
33 __hidden inline struct tracefs_options_mask *
supported_opts_mask(struct tracefs_instance * instance)34 supported_opts_mask(struct tracefs_instance *instance)
35 {
36 return instance ? &instance->supported_opts : &toplevel_supported_opts;
37 }
38
39 __hidden inline struct tracefs_options_mask *
enabled_opts_mask(struct tracefs_instance * instance)40 enabled_opts_mask(struct tracefs_instance *instance)
41 {
42 return instance ? &instance->enabled_opts : &toplevel_enabled_opts;
43 }
44
45 /**
46 * instance_alloc - allocate a new ftrace instance
47 * @trace_dir - Full path to the tracing directory, where the instance is
48 * @name: The name of the instance (instance will point to this)
49 *
50 * Returns a newly allocated instance, or NULL in case of an error.
51 */
instance_alloc(const char * trace_dir,const char * name)52 static struct tracefs_instance *instance_alloc(const char *trace_dir, const char *name)
53 {
54 struct tracefs_instance *instance;
55
56 instance = calloc(1, sizeof(*instance));
57 if (!instance)
58 goto error;
59 instance->trace_dir = strdup(trace_dir);
60 if (!instance->trace_dir)
61 goto error;
62 if (name) {
63 instance->name = strdup(name);
64 if (!instance->name)
65 goto error;
66 }
67
68 if (pthread_mutex_init(&instance->lock, NULL) < 0)
69 goto error;
70
71 instance->ftrace_filter_fd = -1;
72 instance->ftrace_notrace_fd = -1;
73 instance->ftrace_marker_fd = -1;
74 instance->ftrace_marker_raw_fd = -1;
75
76 return instance;
77
78 error:
79 if (instance) {
80 free(instance->name);
81 free(instance->trace_dir);
82 free(instance);
83 }
84 return NULL;
85 }
86
87
trace_get_instance(struct tracefs_instance * instance)88 __hidden int trace_get_instance(struct tracefs_instance *instance)
89 {
90 int ret;
91
92 pthread_mutex_lock(&instance->lock);
93 if (instance->flags & FLAG_INSTANCE_DELETED) {
94 ret = -1;
95 } else {
96 instance->ref++;
97 ret = 0;
98 }
99 pthread_mutex_unlock(&instance->lock);
100 return ret;
101 }
102
trace_put_instance(struct tracefs_instance * instance)103 __hidden void trace_put_instance(struct tracefs_instance *instance)
104 {
105 pthread_mutex_lock(&instance->lock);
106 if (--instance->ref < 0)
107 instance->flags |= FLAG_INSTANCE_DELETED;
108 pthread_mutex_unlock(&instance->lock);
109
110 if (!(instance->flags & FLAG_INSTANCE_DELETED))
111 return;
112
113 if (instance->ftrace_filter_fd >= 0)
114 close(instance->ftrace_filter_fd);
115
116 if (instance->ftrace_notrace_fd >= 0)
117 close(instance->ftrace_notrace_fd);
118
119 if (instance->ftrace_marker_fd >= 0)
120 close(instance->ftrace_marker_fd);
121
122 if (instance->ftrace_marker_raw_fd >= 0)
123 close(instance->ftrace_marker_raw_fd);
124
125 free(instance->trace_dir);
126 free(instance->name);
127 pthread_mutex_destroy(&instance->lock);
128 free(instance);
129 }
130
131 /**
132 * tracefs_instance_free - Free an instance, previously allocated by
133 tracefs_instance_create()
134 * @instance: Pointer to the instance to be freed
135 *
136 */
tracefs_instance_free(struct tracefs_instance * instance)137 void tracefs_instance_free(struct tracefs_instance *instance)
138 {
139 if (!instance)
140 return;
141
142 trace_put_instance(instance);
143 }
144
get_trace_file_permissions(char * name)145 static mode_t get_trace_file_permissions(char *name)
146 {
147 mode_t rmode = 0;
148 struct stat st;
149 char *path;
150 int ret;
151
152 path = tracefs_get_tracing_file(name);
153 if (!path)
154 return 0;
155 ret = stat(path, &st);
156 if (ret)
157 goto out;
158 rmode = st.st_mode & ACCESSPERMS;
159 out:
160 tracefs_put_tracing_file(path);
161 return rmode;
162 }
163
164 /**
165 * tracefs_instance_is_new - Check if the instance is newly created by the library
166 * @instance: Pointer to an ftrace instance
167 *
168 * Returns true, if the ftrace instance is newly created by the library or
169 * false otherwise.
170 */
tracefs_instance_is_new(struct tracefs_instance * instance)171 bool tracefs_instance_is_new(struct tracefs_instance *instance)
172 {
173 if (instance && (instance->flags & FLAG_INSTANCE_NEWLY_CREATED))
174 return true;
175 return false;
176 }
177
178 /**
179 * tracefs_instance_create - Create a new ftrace instance
180 * @name: Name of the instance to be created
181 *
182 * Allocates and initializes a new instance structure. If the instance does not
183 * exist in the system, create it.
184 * Returns a pointer to a newly allocated instance, or NULL in case of an error.
185 * The returned instance must be freed by tracefs_instance_free().
186 */
tracefs_instance_create(const char * name)187 struct tracefs_instance *tracefs_instance_create(const char *name)
188 {
189 struct tracefs_instance *inst = NULL;
190 char *path = NULL;
191 const char *tdir;
192 struct stat st;
193 mode_t mode;
194 int ret;
195
196 tdir = tracefs_tracing_dir();
197 if (!tdir)
198 return NULL;
199 inst = instance_alloc(tdir, name);
200 if (!inst)
201 return NULL;
202
203 path = tracefs_instance_get_dir(inst);
204 ret = stat(path, &st);
205 if (ret < 0) {
206 /* Cannot create the top instance, if it does not exist! */
207 if (!name)
208 goto error;
209 mode = get_trace_file_permissions("instances");
210 if (mkdir(path, mode))
211 goto error;
212 inst->flags |= FLAG_INSTANCE_NEWLY_CREATED;
213 }
214 tracefs_put_tracing_file(path);
215 return inst;
216
217 error:
218 tracefs_instance_free(inst);
219 return NULL;
220 }
221
222 /**
223 * tracefs_instance_alloc - Allocate an instance structure for existing trace instance
224 * @tracing_dir: full path to the system trace directory, where the new instance is
225 * if NULL, the default top tracing directory is used.
226 * @name: Name of the instance.
227 *
228 * Allocates and initializes a new instance structure. If the instance does not
229 * exist, do not create it and exit with error.
230 * Returns a pointer to a newly allocated instance, or NULL in case of an error
231 * or the requested instance does not exists.
232 * The returned instance must be freed by tracefs_instance_free().
233 */
tracefs_instance_alloc(const char * tracing_dir,const char * name)234 struct tracefs_instance *tracefs_instance_alloc(const char *tracing_dir,
235 const char *name)
236 {
237 struct tracefs_instance *inst = NULL;
238 char file[PATH_MAX];
239 const char *tdir;
240 struct stat st;
241 int ret;
242
243 if (tracing_dir) {
244 ret = stat(tracing_dir, &st);
245 if (ret < 0 || !S_ISDIR(st.st_mode))
246 return NULL;
247 tdir = tracing_dir;
248
249 } else
250 tdir = tracefs_tracing_dir();
251 if (!tdir)
252 return NULL;
253
254 if (name) {
255 sprintf(file, "%s/instances/%s", tdir, name);
256 ret = stat(file, &st);
257 if (ret < 0 || !S_ISDIR(st.st_mode))
258 return NULL;
259 }
260 inst = instance_alloc(tdir, name);
261
262 return inst;
263 }
264
265 /**
266 * tracefs_instance_destroy - Remove a ftrace instance
267 * @instance: Pointer to the instance to be removed
268 *
269 * Returns -1 in case of an error, or 0 otherwise.
270 */
tracefs_instance_destroy(struct tracefs_instance * instance)271 int tracefs_instance_destroy(struct tracefs_instance *instance)
272 {
273 char *path;
274 int ret = -1;
275
276 if (!instance || !instance->name) {
277 tracefs_warning("Cannot remove top instance");
278 return -1;
279 }
280
281 path = tracefs_instance_get_dir(instance);
282 if (path)
283 ret = rmdir(path);
284 tracefs_put_tracing_file(path);
285 if (ret) {
286 pthread_mutex_lock(&instance->lock);
287 instance->flags |= FLAG_INSTANCE_DELETED;
288 pthread_mutex_unlock(&instance->lock);
289 }
290
291 return ret;
292 }
293
294 /**
295 * tracefs_instance_get_file - return the path to an instance file.
296 * @instance: ftrace instance, can be NULL for the top instance
297 * @file: name of file to return
298 *
299 * Returns the path of the @file for the given @instance, or NULL in
300 * case of an error.
301 *
302 * Must use tracefs_put_tracing_file() to free the returned string.
303 */
304 char *
tracefs_instance_get_file(struct tracefs_instance * instance,const char * file)305 tracefs_instance_get_file(struct tracefs_instance *instance, const char *file)
306 {
307 char *path = NULL;
308 int ret;
309
310 if (!instance)
311 return tracefs_get_tracing_file(file);
312 if (!instance->name)
313 ret = asprintf(&path, "%s/%s", instance->trace_dir, file);
314 else
315 ret = asprintf(&path, "%s/instances/%s/%s",
316 instance->trace_dir, instance->name, file);
317 if (ret < 0)
318 return NULL;
319
320 return path;
321 }
322
323 /**
324 * tracefs_instance_get_dir - return the path to the instance directory.
325 * @instance: ftrace instance, can be NULL for the top instance
326 *
327 * Returns the full path to the instance directory
328 *
329 * Must use tracefs_put_tracing_file() to free the returned string.
330 */
tracefs_instance_get_dir(struct tracefs_instance * instance)331 char *tracefs_instance_get_dir(struct tracefs_instance *instance)
332 {
333 char *path = NULL;
334 int ret;
335
336 if (!instance) /* Top instance of default system trace directory */
337 return trace_find_tracing_dir(false);
338
339 if (!instance->name)
340 return strdup(instance->trace_dir);
341
342 ret = asprintf(&path, "%s/instances/%s", instance->trace_dir, instance->name);
343 if (ret < 0) {
344 tracefs_warning("Failed to allocate path for instance %s",
345 instance->name);
346 return NULL;
347 }
348
349 return path;
350 }
351
352 /**
353 * tracefs_instance_get_name - return the name of an instance
354 * @instance: ftrace instance
355 *
356 * Returns the name of the given @instance.
357 * The returned string must *not* be freed.
358 */
tracefs_instance_get_name(struct tracefs_instance * instance)359 const char *tracefs_instance_get_name(struct tracefs_instance *instance)
360 {
361 if (instance)
362 return instance->name;
363 return NULL;
364 }
365
366 /**
367 * tracefs_instance_get_buffer_size - return the buffer size of the ring buffer
368 * @instance: The instance to get the buffer size from
369 * @cpu: if less that zero, will return the total size, otherwise the cpu size
370 *
371 * Returns the buffer size. If @cpu is less than zero, it returns the total size
372 * of the ring buffer otherwise it returs the size of the buffer for the given
373 * CPU.
374 *
375 * Returns -1 on error.
376 */
tracefs_instance_get_buffer_size(struct tracefs_instance * instance,int cpu)377 ssize_t tracefs_instance_get_buffer_size(struct tracefs_instance *instance, int cpu)
378 {
379 unsigned long long size;
380 char *path;
381 char *val;
382 int ret;
383
384 if (cpu < 0) {
385 val = tracefs_instance_file_read(instance, "buffer_total_size_kb", NULL);
386 } else {
387 ret = asprintf(&path, "per_cpu/cpu%d/buffer_size_kb", cpu);
388 if (ret < 0)
389 return ret;
390
391 val = tracefs_instance_file_read(instance, path, NULL);
392 free(path);
393 }
394
395 if (!val)
396 return -1;
397
398 size = strtoull(val, NULL, 0);
399 free(val);
400 return size;
401 }
402
tracefs_instance_set_buffer_size(struct tracefs_instance * instance,size_t size,int cpu)403 int tracefs_instance_set_buffer_size(struct tracefs_instance *instance, size_t size, int cpu)
404 {
405 char *path;
406 char *val;
407 int ret;
408
409 ret = asprintf(&val, "%zd", size);
410 if (ret < 0)
411 return ret;
412
413 if (cpu < 0) {
414 ret = tracefs_instance_file_write(instance, "buffer_size_kb", val);
415 } else {
416 ret = asprintf(&path, "per_cpu/cpu%d/buffer_size_kb", cpu);
417 if (ret < 0) {
418 free(val);
419 return ret;
420 }
421
422 ret = tracefs_instance_file_write(instance, path, val);
423 free(path);
424 }
425 free(val);
426
427 return ret < 0 ? -1 : 0;
428 }
429
430 /**
431 * tracefs_instance_get_trace_dir - return the top trace directory, where the instance is confuigred
432 * @instance: ftrace instance
433 *
434 * Returns the top trace directory where the given @instance is configured.
435 * The returned string must *not* be freed.
436 */
tracefs_instance_get_trace_dir(struct tracefs_instance * instance)437 const char *tracefs_instance_get_trace_dir(struct tracefs_instance *instance)
438 {
439 if (instance)
440 return instance->trace_dir;
441 return NULL;
442 }
443
write_file(const char * file,const char * str,int flags)444 static int write_file(const char *file, const char *str, int flags)
445 {
446 int ret = 0;
447 int fd;
448
449 fd = open(file, flags);
450 if (fd < 0) {
451 tracefs_warning("Failed to open '%s'", file);
452 return -1;
453 }
454
455 if (str)
456 ret = write(fd, str, strlen(str));
457
458 close(fd);
459 return ret;
460 }
461
instance_file_write(struct tracefs_instance * instance,const char * file,const char * str,int flags)462 static int instance_file_write(struct tracefs_instance *instance,
463 const char *file, const char *str, int flags)
464 {
465 struct stat st;
466 char *path;
467 int ret;
468
469 path = tracefs_instance_get_file(instance, file);
470 if (!path)
471 return -1;
472 ret = stat(path, &st);
473 if (ret == 0)
474 ret = write_file(path, str, flags);
475 tracefs_put_tracing_file(path);
476
477 return ret;
478 }
479
480 /**
481 * tracefs_instance_file_write - Write in trace file of specific instance.
482 * @instance: ftrace instance, can be NULL for the top instance
483 * @file: name of the file
484 * @str: nul terminated string, that will be written in the file.
485 *
486 * Returns the number of written bytes, or -1 in case of an error
487 */
tracefs_instance_file_write(struct tracefs_instance * instance,const char * file,const char * str)488 int tracefs_instance_file_write(struct tracefs_instance *instance,
489 const char *file, const char *str)
490 {
491 return instance_file_write(instance, file, str, O_WRONLY | O_TRUNC);
492 }
493
494 /**
495 * tracefs_instance_file_append - Append to a trace file of specific instance.
496 * @instance: ftrace instance, can be NULL for the top instance.
497 * @file: name of the file.
498 * @str: nul terminated string, that will be appended to the file.
499 *
500 * Returns the number of appended bytes, or -1 in case of an error.
501 */
tracefs_instance_file_append(struct tracefs_instance * instance,const char * file,const char * str)502 int tracefs_instance_file_append(struct tracefs_instance *instance,
503 const char *file, const char *str)
504 {
505 return instance_file_write(instance, file, str, O_WRONLY);
506 }
507
508 /**
509 * tracefs_instance_file_clear - Clear a trace file of specific instance.
510 * Note, it only opens with O_TRUNC and closes the file. If the file has
511 * content that does not get cleared in this way, this will not have any
512 * effect. For example, set_ftrace_filter can have probes that are not
513 * cleared by O_TRUNC:
514 *
515 * echo "schedule:stacktrace" > set_ftrace_filter
516 *
517 * This function will not clear the above "set_ftrace_filter" after that
518 * command.
519 * @instance: ftrace instance, can be NULL for the top instance.
520 * @file: name of the file to clear.
521 *
522 * Returns 0 on success, or -1 in case of an error.
523 */
tracefs_instance_file_clear(struct tracefs_instance * instance,const char * file)524 int tracefs_instance_file_clear(struct tracefs_instance *instance,
525 const char *file)
526 {
527 return instance_file_write(instance, file, NULL, O_WRONLY | O_TRUNC);
528 }
529
530 /**
531 * tracefs_instance_file_read - Read from a trace file of specific instance.
532 * @instance: ftrace instance, can be NULL for the top instance
533 * @file: name of the file
534 * @psize: returns the number of bytes read
535 *
536 * Returns a pointer to a nul terminated string, read from the file, or NULL in
537 * case of an error.
538 * The return string must be freed by free()
539 */
tracefs_instance_file_read(struct tracefs_instance * instance,const char * file,int * psize)540 char *tracefs_instance_file_read(struct tracefs_instance *instance,
541 const char *file, int *psize)
542 {
543 char *buf = NULL;
544 int size = 0;
545 char *path;
546
547 path = tracefs_instance_get_file(instance, file);
548 if (!path)
549 return NULL;
550
551 size = str_read_file(path, &buf, true);
552
553 tracefs_put_tracing_file(path);
554 if (buf && psize)
555 *psize = size;
556
557 return buf;
558 }
559
560 /**
561 * tracefs_instance_file_read_number - Read long long integer from a trace file.
562 * @instance: ftrace instance, can be NULL for the top instance
563 * @file: name of the file
564 * @res: The integer from the file.
565 *
566 * Returns 0 if the reading is successful and the result is stored in res, -1
567 * in case of an error.
568 */
tracefs_instance_file_read_number(struct tracefs_instance * instance,const char * file,long long * res)569 int tracefs_instance_file_read_number(struct tracefs_instance *instance,
570 const char *file, long long *res)
571 {
572 long long num;
573 int ret = -1;
574 int size = 0;
575 char *endptr;
576 char *str;
577
578 str = tracefs_instance_file_read(instance, file, &size);
579 if (size && str) {
580 errno = 0;
581 num = strtoll(str, &endptr, 0);
582 if (errno == 0 && str != endptr) {
583 *res = num;
584 ret = 0;
585 }
586 }
587 free(str);
588 return ret;
589 }
590
591 /**
592 * tracefs_instance_file_open - Open a trace file for reading and writing
593 * @instance: ftrace instance, can be NULL for the top instance
594 * @file: name of the file
595 * @mode: file open flags, -1 for default O_RDWR
596 *
597 * Returns -1 in case of an error, or a valid file descriptor otherwise.
598 * The returned FD must be closed with close()
599 */
tracefs_instance_file_open(struct tracefs_instance * instance,const char * file,int mode)600 int tracefs_instance_file_open(struct tracefs_instance *instance,
601 const char *file, int mode)
602 {
603 int flags = O_RDWR;
604 int fd = -1;
605 char *path;
606
607 path = tracefs_instance_get_file(instance, file);
608 if (!path)
609 return -1;
610
611 if (mode >= 0)
612 flags = mode;
613 fd = open(path, flags);
614 tracefs_put_tracing_file(path);
615
616 return fd;
617 }
618
check_file_exists(struct tracefs_instance * instance,const char * name,bool dir)619 static bool check_file_exists(struct tracefs_instance *instance,
620 const char *name, bool dir)
621 {
622 char file[PATH_MAX];
623 struct stat st;
624 char *path;
625 int ret;
626
627 path = tracefs_instance_get_dir(instance);
628 if (name)
629 snprintf(file, PATH_MAX, "%s/%s", path, name);
630 else
631 snprintf(file, PATH_MAX, "%s", path);
632 tracefs_put_tracing_file(path);
633 ret = stat(file, &st);
634 if (ret < 0)
635 return false;
636
637 return !dir == !S_ISDIR(st.st_mode);
638 }
639
640 /**
641 * tracefs_instance_exists - Check an instance with given name exists
642 * @name: name of the instance
643 *
644 * Returns true if the instance exists, false otherwise
645 *
646 */
tracefs_instance_exists(const char * name)647 bool tracefs_instance_exists(const char *name)
648 {
649 char file[PATH_MAX];
650
651 if (!name)
652 return false;
653 snprintf(file, PATH_MAX, "instances/%s", name);
654 return check_file_exists(NULL, file, true);
655 }
656
657 /**
658 * tracefs_file_exists - Check if a file with given name exists in given instance
659 * @instance: ftrace instance, can be NULL for the top instance
660 * @name: name of the file
661 *
662 * Returns true if the file exists, false otherwise
663 *
664 * If a directory with the given name exists, false is returned.
665 */
tracefs_file_exists(struct tracefs_instance * instance,const char * name)666 bool tracefs_file_exists(struct tracefs_instance *instance, const char *name)
667 {
668 return check_file_exists(instance, name, false);
669 }
670
671 /**
672 * tracefs_dir_exists - Check if a directory with given name exists in given instance
673 * @instance: ftrace instance, can be NULL for the top instance
674 * @name: name of the directory
675 *
676 * Returns true if the directory exists, false otherwise
677 */
tracefs_dir_exists(struct tracefs_instance * instance,const char * name)678 bool tracefs_dir_exists(struct tracefs_instance *instance, const char *name)
679 {
680 return check_file_exists(instance, name, true);
681 }
682
683 /**
684 * tracefs_instances_walk - Iterate through all ftrace instances in the system
685 * @callback: user callback, called for each instance. Instance name is passed
686 * as input parameter. If the @callback returns non-zero,
687 * the iteration stops.
688 * @context: user context, passed to the @callback.
689 *
690 * Returns -1 in case of an error, 1 if the iteration was stopped because of the
691 * callback return value or 0 otherwise.
692 */
tracefs_instances_walk(int (* callback)(const char *,void *),void * context)693 int tracefs_instances_walk(int (*callback)(const char *, void *), void *context)
694 {
695 struct dirent *dent;
696 char *path = NULL;
697 DIR *dir = NULL;
698 struct stat st;
699 int fret = -1;
700 int ret;
701
702 path = tracefs_get_tracing_file("instances");
703 if (!path)
704 return -1;
705 ret = stat(path, &st);
706 if (ret < 0 || !S_ISDIR(st.st_mode))
707 goto out;
708
709 dir = opendir(path);
710 if (!dir)
711 goto out;
712 fret = 0;
713 while ((dent = readdir(dir))) {
714 char *instance;
715
716 if (strcmp(dent->d_name, ".") == 0 ||
717 strcmp(dent->d_name, "..") == 0)
718 continue;
719 instance = trace_append_file(path, dent->d_name);
720 ret = stat(instance, &st);
721 free(instance);
722 if (ret < 0 || !S_ISDIR(st.st_mode))
723 continue;
724 if (callback(dent->d_name, context)) {
725 fret = 1;
726 break;
727 }
728 }
729
730 out:
731 if (dir)
732 closedir(dir);
733 tracefs_put_tracing_file(path);
734 return fret;
735 }
736
match(const char * str,regex_t * re)737 static inline bool match(const char *str, regex_t *re)
738 {
739 if (!re)
740 return true;
741 return regexec(re, str, 0, NULL, 0) == 0;
742 }
743
744 struct instance_list {
745 regex_t *re;
746 char **list;
747 int failed;
748 };
749
build_list(const char * name,void * data)750 static int build_list(const char *name, void *data)
751 {
752 struct instance_list *list = data;
753 char **instances;
754 int ret = -1;
755
756 if (!match(name, list->re))
757 return 0;
758
759 instances = tracefs_list_add(list->list, name);
760 if (!instances)
761 goto out;
762
763 list->list = instances;
764 ret = 0;
765
766 out:
767 list->failed = ret;
768 return ret;
769 }
770
771 /**
772 * tracefs_instances - return a list of instance names
773 * @regex: A regex of instances to filter on (NULL to match all)
774 *
775 * Returns a list of names of existing instances, that must be
776 * freed with tracefs_list_free(). Note, if there are no matches
777 * then an empty list will be returned (not NULL).
778 * NULL on error.
779 */
tracefs_instances(const char * regex)780 char **tracefs_instances(const char *regex)
781 {
782 struct instance_list list = { .re = NULL, .list = NULL };
783 regex_t re;
784 int ret;
785
786 if (regex) {
787 ret = regcomp(&re, regex, REG_ICASE|REG_NOSUB);
788 if (ret < 0)
789 return NULL;
790 list.re = &re;
791 }
792
793 ret = tracefs_instances_walk(build_list, &list);
794 if (ret < 0 || list.failed) {
795 tracefs_list_free(list.list);
796 list.list = NULL;
797 } else {
798 /* No matches should produce an empty list */
799 if (!list.list)
800 list.list = trace_list_create_empty();
801 }
802 return list.list;
803 }
804
805 /**
806 * tracefs_get_clock - Get the current trace clock
807 * @instance: ftrace instance, can be NULL for the top instance
808 *
809 * Returns the current trace clock of the given instance, or NULL in
810 * case of an error.
811 * The return string must be freed by free()
812 */
tracefs_get_clock(struct tracefs_instance * instance)813 char *tracefs_get_clock(struct tracefs_instance *instance)
814 {
815 char *all_clocks = NULL;
816 char *ret = NULL;
817 int bytes = 0;
818 char *clock;
819 char *cont;
820
821 all_clocks = tracefs_instance_file_read(instance, "trace_clock", &bytes);
822 if (!all_clocks || !bytes)
823 goto out;
824
825 clock = strstr(all_clocks, "[");
826 if (!clock)
827 goto out;
828 clock++;
829 cont = strstr(clock, "]");
830 if (!cont)
831 goto out;
832 *cont = '\0';
833
834 ret = strdup(clock);
835 out:
836 free(all_clocks);
837 return ret;
838 }
839
840 /**
841 * tracefs_instance_set_affinity_raw - write a hex bitmask into the affinity
842 * @instance: The instance to set affinity to (NULL for top level)
843 * @mask: String containing the hex value to set the tracing affinity to.
844 *
845 * Sets the tracing affinity CPU mask for @instance. The @mask is the raw
846 * value that is used to write into the tracing system.
847 *
848 * Return 0 on success and -1 on error.
849 */
tracefs_instance_set_affinity_raw(struct tracefs_instance * instance,const char * mask)850 int tracefs_instance_set_affinity_raw(struct tracefs_instance *instance,
851 const char *mask)
852 {
853 return tracefs_instance_file_write(instance, "tracing_cpumask", mask);
854 }
855
856 /**
857 * tracefs_instance_set_affinity_set - use a cpu_set to define tracing affinity
858 * @instance: The instance to set affinity to (NULL for top level)
859 * @set: A CPU set that describes the CPU affinity to set tracing to.
860 * @set_size: The size in bytes of @set (use CPU_ALLOC_SIZE() to get this value)
861 *
862 * Sets the tracing affinity CPU mask for @instance. The bits in @set will be
863 * used to set the CPUs to have tracing on.
864 *
865 * If @set is NULL, then all CPUs defined by sysconf(_SC_NPROCESSORS_CONF)
866 * will be set, and @set_size is ignored.
867 *
868 * Return 0 on success and -1 on error.
869 */
tracefs_instance_set_affinity_set(struct tracefs_instance * instance,cpu_set_t * set,size_t set_size)870 int tracefs_instance_set_affinity_set(struct tracefs_instance *instance,
871 cpu_set_t *set, size_t set_size)
872 {
873 struct trace_seq seq;
874 bool free_set = false;
875 bool hit = false;
876 int nr_cpus;
877 int cpu;
878 int ret = -1;
879 int w, n, i;
880
881 trace_seq_init(&seq);
882
883 /* NULL set means all CPUs to be set */
884 if (!set) {
885 nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
886 set = CPU_ALLOC(nr_cpus);
887 if (!set)
888 goto out;
889 set_size = CPU_ALLOC_SIZE(nr_cpus);
890 CPU_ZERO_S(set_size, set);
891 /* Set all CPUS */
892 for (cpu = 0; cpu < nr_cpus; cpu++)
893 CPU_SET_S(cpu, set_size, set);
894 free_set = true;
895 }
896 /* Convert to a bitmask hex string */
897 nr_cpus = (set_size + 1) * 8;
898 if (nr_cpus < 1) {
899 /* Must have at least one bit set */
900 errno = EINVAL;
901 goto out;
902 }
903 /* Start backwards from 32 bits */
904 for (w = ((nr_cpus + 31) / 32) - 1; w >= 0; w--) {
905 /* Now move one nibble at a time */
906 for (n = 7; n >= 0; n--) {
907 int nibble = 0;
908
909 if ((n * 4) + (w * 32) >= nr_cpus)
910 continue;
911
912 /* One bit at a time */
913 for (i = 3; i >= 0; i--) {
914 cpu = (w * 32) + (n * 4) + i;
915 if (cpu >= nr_cpus)
916 continue;
917 if (CPU_ISSET_S(cpu, set_size, set)) {
918 nibble |= 1 << i;
919 hit = true;
920 }
921 }
922 if (hit && trace_seq_printf(&seq, "%x", nibble) < 0)
923 goto out;
924 }
925 if (hit && w)
926 if (trace_seq_putc(&seq, ',') < 0)
927 goto out;
928 }
929 if (!hit) {
930 errno = EINVAL;
931 goto out;
932 }
933 trace_seq_terminate(&seq);
934 ret = tracefs_instance_set_affinity_raw(instance, seq.buffer);
935 out:
936 trace_seq_destroy(&seq);
937 if (free_set)
938 CPU_FREE(set);
939 return ret;
940 }
941
942 /**
943 * tracefs_instance_set_affinity - Set the affinity defined by CPU values.
944 * @instance: The instance to set affinity to (NULL for top level)
945 * @cpu_str: A string of values that define what CPUs to set.
946 *
947 * Sets the tracing affinity CPU mask for @instance. The @cpu_str is a set
948 * of decimal numbers used to state which CPU should be part of the affinity
949 * mask. A range may also be specified via a hyphen.
950 *
951 * For example, "1,4,6-8"
952 *
953 * The numbers do not need to be in order.
954 *
955 * If @cpu_str is NULL, then all CPUs defined by sysconf(_SC_NPROCESSORS_CONF)
956 * will be set.
957 *
958 * Return 0 on success and -1 on error.
959 */
tracefs_instance_set_affinity(struct tracefs_instance * instance,const char * cpu_str)960 int tracefs_instance_set_affinity(struct tracefs_instance *instance,
961 const char *cpu_str)
962 {
963 cpu_set_t *set = NULL;
964 size_t set_size;
965 char *word;
966 char *cpus;
967 char *del;
968 char *c;
969 int max_cpu = 0;
970 int cpu1, cpu2;
971 int len;
972 int ret = -1;
973
974 /* NULL cpu_str means to set all CPUs in the mask */
975 if (!cpu_str)
976 return tracefs_instance_set_affinity_set(instance, NULL, 0);
977
978 /* First, find out how many CPUs are needed */
979 cpus = strdup(cpu_str);
980 if (!cpus)
981 return -1;
982 len = strlen(cpus) + 1;
983 for (word = strtok_r(cpus, ",", &del); word; word = strtok_r(NULL, ",", &del)) {
984 cpu1 = atoi(word);
985 if (cpu1 < 0) {
986 errno = EINVAL;
987 goto out;
988 }
989 if (cpu1 > max_cpu)
990 max_cpu = cpu1;
991 cpu2 = -1;
992 if ((c = strchr(word, '-'))) {
993 c++;
994 cpu2 = atoi(c);
995 if (cpu2 < cpu1) {
996 errno = EINVAL;
997 goto out;
998 }
999 if (cpu2 > max_cpu)
1000 max_cpu = cpu2;
1001 }
1002 }
1003 /*
1004 * Now ideally, cpus should fit cpu_str as it was orginally allocated
1005 * by strdup(). But I'm paranoid, and can imagine someone playing tricks
1006 * with threads, and changes cpu_str from another thread and messes
1007 * with this. At least only copy what we know is allocated.
1008 */
1009 strncpy(cpus, cpu_str, len);
1010
1011 set = CPU_ALLOC(max_cpu + 1);
1012 if (!set)
1013 goto out;
1014 set_size = CPU_ALLOC_SIZE(max_cpu + 1);
1015 CPU_ZERO_S(set_size, set);
1016
1017 for (word = strtok_r(cpus, ",", &del); word; word = strtok_r(NULL, ",", &del)) {
1018 cpu1 = atoi(word);
1019 if (cpu1 < 0 || cpu1 > max_cpu) {
1020 /* Someone playing games? */
1021 errno = EACCES;
1022 goto out;
1023 }
1024 cpu2 = cpu1;
1025 if ((c = strchr(word, '-'))) {
1026 c++;
1027 cpu2 = atoi(c);
1028 if (cpu2 < cpu1 || cpu2 > max_cpu) {
1029 errno = EACCES;
1030 goto out;
1031 }
1032 }
1033 for ( ; cpu1 <= cpu2; cpu1++)
1034 CPU_SET(cpu1, set);
1035 }
1036 ret = tracefs_instance_set_affinity_set(instance, set, set_size);
1037 out:
1038 free(cpus);
1039 CPU_FREE(set);
1040 return ret;
1041 }
1042
1043 /**
1044 * tracefs_instance_get_affinity_raw - read the affinity instance file
1045 * @instance: The instance to get affinity of (NULL for top level)
1046 *
1047 * Reads the affinity file for @instance (or the top level if @instance
1048 * is NULL) and returns it. The returned string must be freed with free().
1049 *
1050 * Returns the affinity mask on success, and must be freed with free()
1051 * or NULL on error.
1052 */
tracefs_instance_get_affinity_raw(struct tracefs_instance * instance)1053 char *tracefs_instance_get_affinity_raw(struct tracefs_instance *instance)
1054 {
1055 return tracefs_instance_file_read(instance, "tracing_cpumask", NULL);
1056 }
1057
update_cpu_set(int cpus,int cpu_set,int cpu,cpu_set_t * set,size_t set_size)1058 static inline int update_cpu_set(int cpus, int cpu_set, int cpu,
1059 cpu_set_t *set, size_t set_size)
1060 {
1061 int bit = 1 << cpu;
1062
1063 if (!(cpus & bit))
1064 return 0;
1065
1066 CPU_SET_S(cpu_set + cpu, set_size, set);
1067
1068 /*
1069 * It is possible that the passed in set_size is not big enough
1070 * to hold the cpu we just set. If that's the case, do not report
1071 * it as being set.
1072 *
1073 * The CPU_ISSET_S() should return false if the CPU given to it
1074 * is bigger than the set itself.
1075 */
1076 return CPU_ISSET_S(cpu_set + cpu, set_size, set) ? 1 : 0;
1077 }
1078
1079 /**
1080 * tracefs_instance_get_affinity_set - Retrieve the cpuset of an instance affinity
1081 * @instance: The instance to get affinity of (NULL for top level)
1082 * @set: A CPU set to put the affinity into.
1083 * @set_size: The size in bytes of @set (use CPU_ALLOC_SIZE() to get this value)
1084 *
1085 * Reads the affinity of a given instance and updates the CPU set by the
1086 * instance.
1087 *
1088 * Returns the number of CPUS that are set, or -1 on error.
1089 */
tracefs_instance_get_affinity_set(struct tracefs_instance * instance,cpu_set_t * set,size_t set_size)1090 int tracefs_instance_get_affinity_set(struct tracefs_instance *instance,
1091 cpu_set_t *set, size_t set_size)
1092 {
1093 char *affinity;
1094 int cpu_set;
1095 int cpus;
1096 int cnt = 0;
1097 int ch;
1098 int i;
1099
1100 if (!set || !set_size) {
1101 errno = -EINVAL;
1102 return -1;
1103 }
1104
1105 affinity = tracefs_instance_get_affinity_raw(instance);
1106 if (!affinity)
1107 return -1;
1108
1109 /*
1110 * The returned affinity should be a comma delimited
1111 * hex string. Work backwards setting the values.
1112 */
1113 cpu_set = 0;
1114 i = strlen(affinity);
1115 for (i--; i >= 0; i--) {
1116 ch = affinity[i];
1117 if (isalnum(ch)) {
1118 ch = tolower(ch);
1119 if (isdigit(ch))
1120 cpus = ch - '0';
1121 else
1122 cpus = ch - 'a' + 10;
1123
1124 cnt += update_cpu_set(cpus, cpu_set, 0, set, set_size);
1125 cnt += update_cpu_set(cpus, cpu_set, 1, set, set_size);
1126 cnt += update_cpu_set(cpus, cpu_set, 2, set, set_size);
1127 cnt += update_cpu_set(cpus, cpu_set, 3, set, set_size);
1128 /* Next nibble */
1129 cpu_set += 4;
1130 }
1131 }
1132
1133 free(affinity);
1134
1135 return cnt;
1136 }
1137
update_cpu(int cpus,int cpu_set,int cpu,int s,char ** set)1138 static inline int update_cpu(int cpus, int cpu_set, int cpu, int s, char **set)
1139 {
1140 char *list;
1141 int bit = 1 << cpu;
1142 int ret;
1143
1144 if (*set == (char *)-1)
1145 return s;
1146
1147 if (cpus & bit) {
1148 /* If the previous CPU is set just return s */
1149 if (s >= 0)
1150 return s;
1151 /* Otherwise, return this cpu */
1152 return cpu_set + cpu;
1153 }
1154
1155 /* If the last CPU wasn't set, just return s */
1156 if (s < 0)
1157 return s;
1158
1159 /* Update the string */
1160 if (s == cpu_set + cpu - 1) {
1161 ret = asprintf(&list, "%s%s%d",
1162 *set ? *set : "", *set ? "," : "", s);
1163 } else {
1164 ret = asprintf(&list, "%s%s%d-%d",
1165 *set ? *set : "", *set ? "," : "",
1166 s, cpu_set + cpu - 1);
1167 }
1168 free(*set);
1169 /* Force *set to be a failure */
1170 if (ret < 0)
1171 *set = (char *)-1;
1172 else
1173 *set = list;
1174 return -1;
1175 }
1176
1177 /**
1178 * tracefs_instance_get_affinity - Retrieve a string of CPUs for instance affinity
1179 * @instance: The instance to get affinity of (NULL for top level)
1180 *
1181 * Reads the affinity of a given instance and returns a CPU count of the
1182 * instance. For example, if it reads "eb" it will return:
1183 * "0-1,3,5-7"
1184 *
1185 * If no CPUs are set, an empty string is returned "\0", and it too needs
1186 * to be freed.
1187 *
1188 * Returns an allocated string containing the CPU affinity in "human readable"
1189 * format which needs to be freed with free(), or NULL on error.
1190 */
tracefs_instance_get_affinity(struct tracefs_instance * instance)1191 char *tracefs_instance_get_affinity(struct tracefs_instance *instance)
1192 {
1193 char *affinity;
1194 char *set = NULL;
1195 int cpu_set;
1196 int cpus;
1197 int ch;
1198 int s = -1;
1199 int i;
1200
1201 affinity = tracefs_instance_get_affinity_raw(instance);
1202 if (!affinity)
1203 return NULL;
1204
1205 /*
1206 * The returned affinity should be a comma delimited
1207 * hex string. Work backwards setting the values.
1208 */
1209 cpu_set = 0;
1210 i = strlen(affinity);
1211 for (i--; i >= 0; i--) {
1212 ch = affinity[i];
1213 if (isalnum(ch)) {
1214 ch = tolower(ch);
1215 if (isdigit(ch))
1216 cpus = ch - '0';
1217 else
1218 cpus = ch - 'a' + 10;
1219 s = update_cpu(cpus, cpu_set, 0, s, &set);
1220 s = update_cpu(cpus, cpu_set, 1, s, &set);
1221 s = update_cpu(cpus, cpu_set, 2, s, &set);
1222 s = update_cpu(cpus, cpu_set, 3, s, &set);
1223
1224 if (set == (char *)-1) {
1225 set = NULL;
1226 goto out;
1227 }
1228 /* Next nibble */
1229 cpu_set += 4;
1230 }
1231 }
1232 /* Clean up in case the last CPU is set */
1233 s = update_cpu(0, cpu_set, 0, s, &set);
1234
1235 if (!set)
1236 set = strdup("");
1237 out:
1238 free(affinity);
1239
1240 return set;
1241 }
1242