4 * (C) Copyright 2008 - Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
6 * LTTng channel management.
9 * Mathieu Desnoyers (mathieu.desnoyers@polymtl.ca)
12 #include <linux/module.h>
13 #include <linux/ltt-channels.h>
14 #include <linux/mutex.h>
15 #include <linux/vmalloc.h>
18 * ltt_channel_mutex may be nested inside the LTT trace mutex.
19 * ltt_channel_mutex mutex may be nested inside markers mutex.
21 static DEFINE_MUTEX(ltt_channel_mutex
);
22 static LIST_HEAD(ltt_channels
);
24 * Index of next channel in array. Makes sure that as long as a trace channel is
25 * allocated, no array index will be re-used when a channel is freed and then
26 * another channel is allocated. This index is cleared and the array indexeds
27 * get reassigned when the index_kref goes back to 0, which indicates that no
28 * more trace channels are allocated.
30 static unsigned int free_index
;
31 static struct kref index_kref
; /* Keeps track of allocated trace channels */
33 static struct ltt_channel_setting
*lookup_channel(const char *name
)
35 struct ltt_channel_setting
*iter
;
37 list_for_each_entry(iter
, <t_channels
, list
)
38 if (strcmp(name
, iter
->name
) == 0)
44 * Must be called when channel refcount falls to 0 _and_ also when the last
45 * trace is freed. This function is responsible for compacting the channel and
46 * event IDs when no users are active.
48 * Called with lock_markers() and channels mutex held.
50 static void release_channel_setting(struct kref
*kref
)
52 struct ltt_channel_setting
*setting
= container_of(kref
,
53 struct ltt_channel_setting
, kref
);
54 struct ltt_channel_setting
*iter
;
56 if (atomic_read(&index_kref
.refcount
) == 0
57 && atomic_read(&setting
->kref
.refcount
) == 0) {
58 list_del(&setting
->list
);
62 list_for_each_entry(iter
, <t_channels
, list
) {
63 iter
->index
= free_index
++;
64 iter
->free_event_id
= 0;
66 markers_compact_event_ids();
71 * Perform channel index compaction when the last trace channel is freed.
73 * Called with lock_markers() and channels mutex held.
75 static void release_trace_channel(struct kref
*kref
)
77 struct ltt_channel_setting
*iter
, *n
;
79 list_for_each_entry_safe(iter
, n
, <t_channels
, list
)
80 release_channel_setting(&iter
->kref
);
84 * ltt_channels_register - Register a trace channel.
89 int ltt_channels_register(const char *name
)
91 struct ltt_channel_setting
*setting
;
94 mutex_lock(<t_channel_mutex
);
95 setting
= lookup_channel(name
);
97 if (atomic_read(&setting
->kref
.refcount
) == 0)
100 kref_get(&setting
->kref
);
104 setting
= kzalloc(sizeof(*setting
), GFP_KERNEL
);
109 list_add(&setting
->list
, <t_channels
);
110 strncpy(setting
->name
, name
, PATH_MAX
-1);
111 setting
->index
= free_index
++;
113 kref_init(&setting
->kref
);
115 mutex_unlock(<t_channel_mutex
);
118 EXPORT_SYMBOL_GPL(ltt_channels_register
);
121 * ltt_channels_unregister - Unregister a trace channel.
122 * @name: channel name
124 * Must be called with markers mutex held.
126 int ltt_channels_unregister(const char *name
)
128 struct ltt_channel_setting
*setting
;
131 mutex_lock(<t_channel_mutex
);
132 setting
= lookup_channel(name
);
133 if (!setting
|| atomic_read(&setting
->kref
.refcount
) == 0) {
137 kref_put(&setting
->kref
, release_channel_setting
);
139 mutex_unlock(<t_channel_mutex
);
142 EXPORT_SYMBOL_GPL(ltt_channels_unregister
);
145 * ltt_channels_set_default - Set channel default behavior.
146 * @name: default channel name
147 * @subbuf_size: size of the subbuffers
148 * @subbuf_cnt: number of subbuffers
150 int ltt_channels_set_default(const char *name
,
151 unsigned int subbuf_size
,
152 unsigned int subbuf_cnt
)
154 struct ltt_channel_setting
*setting
;
157 mutex_lock(<t_channel_mutex
);
158 setting
= lookup_channel(name
);
159 if (!setting
|| atomic_read(&setting
->kref
.refcount
) == 0) {
163 setting
->subbuf_size
= subbuf_size
;
164 setting
->subbuf_cnt
= subbuf_cnt
;
166 mutex_unlock(<t_channel_mutex
);
169 EXPORT_SYMBOL_GPL(ltt_channels_set_default
);
172 * ltt_channels_get_name_from_index - get channel name from channel index
173 * @index: channel index
175 * Allows to lookup the channel name given its index. Done to keep the name
176 * information outside of each trace channel instance.
178 const char *ltt_channels_get_name_from_index(unsigned int index
)
180 struct ltt_channel_setting
*iter
;
182 list_for_each_entry(iter
, <t_channels
, list
)
183 if (iter
->index
== index
&& atomic_read(&iter
->kref
.refcount
))
187 EXPORT_SYMBOL_GPL(ltt_channels_get_name_from_index
);
189 static struct ltt_channel_setting
*
190 ltt_channels_get_setting_from_name(const char *name
)
192 struct ltt_channel_setting
*iter
;
194 list_for_each_entry(iter
, <t_channels
, list
)
195 if (!strcmp(iter
->name
, name
)
196 && atomic_read(&iter
->kref
.refcount
))
202 * ltt_channels_get_index_from_name - get channel index from channel name
203 * @name: channel name
205 * Allows to lookup the channel index given its name. Done to keep the name
206 * information outside of each trace channel instance.
207 * Returns -1 if not found.
209 int ltt_channels_get_index_from_name(const char *name
)
211 struct ltt_channel_setting
*setting
;
213 setting
= ltt_channels_get_setting_from_name(name
);
215 return setting
->index
;
219 EXPORT_SYMBOL_GPL(ltt_channels_get_index_from_name
);
222 * ltt_channels_trace_alloc - Allocate channel structures for a trace
223 * @subbuf_size: subbuffer size. 0 uses default.
224 * @subbuf_cnt: number of subbuffers per per-cpu buffers. 0 uses default.
225 * @flags: Default channel flags
227 * Use the current channel list to allocate the channels for a trace.
228 * Called with trace lock held. Does not perform the trace buffer allocation,
229 * because we must let the user overwrite specific channel sizes.
231 struct ltt_channel_struct
*ltt_channels_trace_alloc(unsigned int *nr_channels
,
235 struct ltt_channel_struct
*channel
= NULL
;
236 struct ltt_channel_setting
*iter
;
238 mutex_lock(<t_channel_mutex
);
241 if (!atomic_read(&index_kref
.refcount
))
242 kref_init(&index_kref
);
244 kref_get(&index_kref
);
245 *nr_channels
= free_index
;
246 channel
= kzalloc(sizeof(struct ltt_channel_struct
) * free_index
,
250 list_for_each_entry(iter
, <t_channels
, list
) {
251 if (!atomic_read(&iter
->kref
.refcount
))
253 channel
[iter
->index
].subbuf_size
= iter
->subbuf_size
;
254 channel
[iter
->index
].subbuf_cnt
= iter
->subbuf_cnt
;
255 channel
[iter
->index
].overwrite
= overwrite
;
256 channel
[iter
->index
].active
= active
;
257 channel
[iter
->index
].channel_name
= iter
->name
;
260 mutex_unlock(<t_channel_mutex
);
263 EXPORT_SYMBOL_GPL(ltt_channels_trace_alloc
);
266 * ltt_channels_trace_free - Free one trace's channels
267 * @channels: channels to free
269 * Called with trace lock held. The actual channel buffers must be freed before
270 * this function is called.
272 void ltt_channels_trace_free(struct ltt_channel_struct
*channels
)
275 mutex_lock(<t_channel_mutex
);
277 kref_put(&index_kref
, release_trace_channel
);
278 mutex_unlock(<t_channel_mutex
);
281 EXPORT_SYMBOL_GPL(ltt_channels_trace_free
);
284 * _ltt_channels_get_event_id - get next event ID for a marker
285 * @channel: channel name
288 * Returns a unique event ID (for this channel) or < 0 on error.
289 * Must be called with channels mutex held.
291 int _ltt_channels_get_event_id(const char *channel
, const char *name
)
293 struct ltt_channel_setting
*setting
;
296 setting
= ltt_channels_get_setting_from_name(channel
);
301 if (strcmp(channel
, "metadata") == 0) {
302 if (strcmp(name
, "core_marker_id") == 0)
304 else if (strcmp(name
, "core_marker_format") == 0)
310 if (setting
->free_event_id
== EVENTS_PER_CHANNEL
- 1) {
314 ret
= setting
->free_event_id
++;
320 * ltt_channels_get_event_id - get next event ID for a marker
321 * @channel: channel name
324 * Returns a unique event ID (for this channel) or < 0 on error.
326 int ltt_channels_get_event_id(const char *channel
, const char *name
)
330 mutex_lock(<t_channel_mutex
);
331 ret
= _ltt_channels_get_event_id(channel
, name
);
332 mutex_unlock(<t_channel_mutex
);
336 MODULE_LICENSE("GPL");
337 MODULE_AUTHOR("Mathieu Desnoyers");
338 MODULE_DESCRIPTION("Linux Trace Toolkit Next Generation Channel Management");