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