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