• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3  * Copyright (C) 2021, VMware, Tzvetomir Stoyanov <tz.stoyanov@gmail.com>
4  *
5  */
6 
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <stdio.h>
10 #include <pthread.h>
11 
12 #include "tracefs.h"
13 #include "tracefs-local.h"
14 
15 /* File descriptors for Top level trace markers */
16 static int ftrace_marker_fd = -1;
17 static int ftrace_marker_raw_fd = -1;
18 
get_marker_fd(struct tracefs_instance * instance,bool raw)19 static inline int *get_marker_fd(struct tracefs_instance *instance, bool raw)
20 {
21 	if (raw)
22 		return instance ? &instance->ftrace_marker_raw_fd : &ftrace_marker_raw_fd;
23 	return instance ? &instance->ftrace_marker_fd : &ftrace_marker_fd;
24 }
25 
marker_init(struct tracefs_instance * instance,bool raw)26 static int marker_init(struct tracefs_instance *instance, bool raw)
27 {
28 	const char *file = raw ? "trace_marker_raw" : "trace_marker";
29 	pthread_mutex_t *lock = trace_get_lock(instance);
30 	int *fd = get_marker_fd(instance, raw);
31 	int ret;
32 
33 	if (*fd >= 0)
34 		return 0;
35 
36 	/*
37 	 * The mutex is only to hold the integrity of the file descriptor
38 	 * to prevent opening it more than once, or closing the same
39 	 * file descriptor more than once. It does not protect against
40 	 * one thread closing the file descriptor and another thread
41 	 * writing to it. That is up to the application to prevent
42 	 * from happening.
43 	 */
44 	pthread_mutex_lock(lock);
45 	/* The file could have been opened since we taken the lock */
46 	if (*fd < 0)
47 		*fd = tracefs_instance_file_open(instance, file, O_WRONLY | O_CLOEXEC);
48 
49 	ret = *fd < 0 ? -1 : 0;
50 	pthread_mutex_unlock(lock);
51 
52 	return ret;
53 }
54 
marker_close(struct tracefs_instance * instance,bool raw)55 static void marker_close(struct tracefs_instance *instance, bool raw)
56 {
57 	pthread_mutex_t *lock = trace_get_lock(instance);
58 	int *fd = get_marker_fd(instance, raw);
59 
60 	pthread_mutex_lock(lock);
61 	if (*fd >= 0) {
62 		close(*fd);
63 		*fd = -1;
64 	}
65 	pthread_mutex_unlock(lock);
66 }
67 
marker_write(struct tracefs_instance * instance,bool raw,void * data,int len)68 static int marker_write(struct tracefs_instance *instance, bool raw, void *data, int len)
69 {
70 	int *fd = get_marker_fd(instance, raw);
71 	int ret;
72 
73 	/*
74 	 * The lock does not need to be taken for writes. As a write
75 	 * does not modify the file descriptor. It's up to the application
76 	 * to prevent it from being closed if another thread is doing a write.
77 	 */
78 	if (!data || len < 1)
79 		return -1;
80 	if (*fd < 0) {
81 		ret = marker_init(instance, raw);
82 		if (ret < 0)
83 			return ret;
84 	}
85 
86 	ret = write(*fd, data, len);
87 
88 	return ret == len ? 0 : -1;
89 }
90 
91 /**
92  * tracefs_print_init - Open trace marker of selected instance for writing
93  * @instance: ftrace instance, can be NULL for top tracing instance.
94  *
95  * Returns 0 if the trace marker is opened successfully, or -1 in case of an error
96  */
tracefs_print_init(struct tracefs_instance * instance)97 int tracefs_print_init(struct tracefs_instance *instance)
98 {
99 	return marker_init(instance, false);
100 }
101 
102 /**
103  * tracefs_vprintf - Write a formatted string in the trace marker
104  * @instance: ftrace instance, can be NULL for top tracing instance.
105  * @fmt: pritnf formatted string
106  * @ap: list of arguments for the formatted string
107  *
108  * If the trace marker of the desired instance is not open already,
109  * this API will open it for writing. It will stay open until
110  * tracefs_print_close() is called.
111  *
112  * Returns 0 if the string is written correctly, or -1 in case of an error
113  */
tracefs_vprintf(struct tracefs_instance * instance,const char * fmt,va_list ap)114 int tracefs_vprintf(struct tracefs_instance *instance, const char *fmt, va_list ap)
115 {
116 	char *str = NULL;
117 	int ret;
118 
119 	ret = vasprintf(&str, fmt, ap);
120 	if (ret < 0)
121 		return ret;
122 	ret = marker_write(instance, false, str, strlen(str));
123 	free(str);
124 
125 	return ret;
126 }
127 
128 /**
129  * tracefs_printf - Write a formatted string in the trace marker
130  * @instance: ftrace instance, can be NULL for top tracing instance.
131  * @fmt: pritnf formatted string with variable arguments ...
132  *
133  * If the trace marker of the desired instance is not open already,
134  * this API will open it for writing. It will stay open until
135  * tracefs_print_close() is called.
136  *
137  * Returns 0 if the string is written correctly, or -1 in case of an error
138  */
tracefs_printf(struct tracefs_instance * instance,const char * fmt,...)139 int tracefs_printf(struct tracefs_instance *instance, const char *fmt, ...)
140 {
141 	va_list ap;
142 	int ret;
143 
144 	va_start(ap, fmt);
145 	ret = tracefs_vprintf(instance, fmt, ap);
146 	va_end(ap);
147 
148 	return ret;
149 }
150 
151 /**
152  * tracefs_print_close - Close trace marker of selected instance
153  * @instance: ftrace instance, can be NULL for top tracing instance.
154  *
155  * Closes the trace marker, previously opened with any of the other tracefs_print APIs
156  */
tracefs_print_close(struct tracefs_instance * instance)157 void tracefs_print_close(struct tracefs_instance *instance)
158 {
159 	marker_close(instance, false);
160 }
161 
162 /**
163  * tracefs_binary_init - Open raw trace marker of selected instance for writing
164  * @instance: ftrace instance, can be NULL for top tracing instance.
165  *
166  * Returns 0 if the raw trace marker is opened successfully, or -1 in case of an error
167  */
tracefs_binary_init(struct tracefs_instance * instance)168 int tracefs_binary_init(struct tracefs_instance *instance)
169 {
170 	return marker_init(instance, true);
171 }
172 
173 /**
174  * tracefs_binary_write - Write binary data in the raw trace marker
175  * @instance: ftrace instance, can be NULL for top tracing instance.
176  * @data: binary data, that is going to be written in the trace marker
177  * @len: length of the @data
178  *
179  * If the raw trace marker of the desired instance is not open already,
180  * this API will open it for writing. It will stay open until
181  * tracefs_binary_close() is called.
182  *
183  * Returns 0 if the data is written correctly, or -1 in case of an error
184  */
tracefs_binary_write(struct tracefs_instance * instance,void * data,int len)185 int tracefs_binary_write(struct tracefs_instance *instance, void *data, int len)
186 {
187 	return marker_write(instance, true, data, len);
188 }
189 
190 /**
191  * tracefs_binary_close - Close raw trace marker of selected instance
192  * @instance: ftrace instance, can be NULL for top tracing instance.
193  *
194  * Closes the raw trace marker, previously opened with any of the other tracefs_binary APIs
195  */
tracefs_binary_close(struct tracefs_instance * instance)196 void tracefs_binary_close(struct tracefs_instance *instance)
197 {
198 	marker_close(instance, true);
199 }
200