• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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