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