Commit | Line | Data |
---|---|---|
999af9c1 JR |
1 | /* |
2 | * Copyright (C) 2021 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com> | |
3 | * | |
4 | * SPDX-License-Identifier: LGPL-2.1-only | |
5 | * | |
6 | */ | |
7 | ||
c9e313bc SM |
8 | #include <common/buffer-view.hpp> |
9 | #include <common/dynamic-array.hpp> | |
10 | #include <common/dynamic-buffer.hpp> | |
11 | #include <common/error.hpp> | |
12 | #include <common/macros.hpp> | |
13 | #include <common/sessiond-comm/sessiond-comm.hpp> | |
56047f5a | 14 | #include <common/urcu.hpp> |
28ab034a | 15 | |
c9e313bc | 16 | #include <lttng/channel-internal.hpp> |
999af9c1 JR |
17 | #include <lttng/channel.h> |
18 | #include <lttng/constant.h> | |
c9e313bc | 19 | #include <lttng/userspace-probe-internal.hpp> |
999af9c1 | 20 | |
28ab034a JG |
21 | static enum lttng_error_code flatten_lttng_channels(struct lttng_dynamic_pointer_array *channels, |
22 | struct lttng_channel **flattened_channels); | |
999af9c1 | 23 | |
28ab034a JG |
24 | static enum lttng_error_code |
25 | channel_list_create_from_buffer(const struct lttng_buffer_view *buffer, | |
26 | uint32_t count, | |
27 | struct lttng_dynamic_pointer_array *channel_list); | |
999af9c1 JR |
28 | |
29 | static void channel_list_destructor(void *ptr) | |
30 | { | |
31 | struct lttng_channel *element = (struct lttng_channel *) ptr; | |
32 | ||
33 | lttng_channel_destroy(element); | |
34 | } | |
35 | ||
36 | struct lttng_channel *lttng_channel_copy(const struct lttng_channel *src) | |
37 | { | |
38 | struct lttng_channel_extended *extended = nullptr; | |
39 | struct lttng_channel *channel = nullptr, *ret = nullptr; | |
40 | ||
64803277 | 41 | channel = zmalloc<lttng_channel>(); |
999af9c1 JR |
42 | if (!channel) { |
43 | goto end; | |
44 | } | |
45 | ||
46 | *channel = *src; | |
47 | ||
48 | if (src->attr.extended.ptr) { | |
64803277 | 49 | extended = zmalloc<lttng_channel_extended>(); |
999af9c1 JR |
50 | if (!extended) { |
51 | goto end; | |
52 | } | |
53 | memcpy(extended, src->attr.extended.ptr, sizeof(*extended)); | |
54 | channel->attr.extended.ptr = extended; | |
55 | extended = nullptr; | |
56 | } | |
57 | ||
58 | ret = channel; | |
59 | channel = nullptr; | |
60 | end: | |
61 | free(channel); | |
62 | free(extended); | |
63 | return ret; | |
64 | } | |
65 | ||
66 | /* | |
67 | * The channel object is NOT populated. | |
68 | */ | |
cd9adb8b | 69 | struct lttng_channel *lttng_channel_create_internal() |
999af9c1 JR |
70 | { |
71 | struct lttng_channel *local_channel = nullptr, *ret = nullptr; | |
72 | struct lttng_channel_extended *extended = nullptr; | |
73 | ||
64803277 | 74 | local_channel = zmalloc<lttng_channel>(); |
999af9c1 JR |
75 | if (!local_channel) { |
76 | goto end; | |
77 | } | |
78 | ||
79 | /* Extended struct */ | |
64803277 | 80 | extended = zmalloc<lttng_channel_extended>(); |
999af9c1 JR |
81 | if (!extended) { |
82 | goto end; | |
83 | } | |
84 | ||
85 | local_channel->attr.extended.ptr = extended; | |
86 | extended = nullptr; | |
87 | ||
88 | ret = local_channel; | |
89 | local_channel = nullptr; | |
90 | end: | |
91 | free(extended); | |
92 | free(local_channel); | |
93 | return ret; | |
94 | } | |
95 | ||
96 | ssize_t lttng_channel_create_from_buffer(const struct lttng_buffer_view *view, | |
28ab034a | 97 | struct lttng_channel **channel) |
999af9c1 JR |
98 | { |
99 | ssize_t ret, offset = 0; | |
100 | struct lttng_channel *local_channel = nullptr; | |
101 | const struct lttng_channel_comm *channel_comm; | |
102 | struct lttng_channel_extended *extended = nullptr; | |
103 | ||
104 | assert(channel); | |
105 | ||
106 | if (!view || !channel) { | |
107 | ret = -1; | |
108 | goto end; | |
109 | } | |
110 | ||
111 | /* | |
112 | * Create an 'internal' channel since `lttng_create_channel` requires a | |
113 | * domain and we cannot infer the domain from the payload. | |
114 | */ | |
115 | local_channel = lttng_channel_create_internal(); | |
116 | if (!local_channel) { | |
117 | ret = -1; | |
118 | goto end; | |
119 | } | |
120 | ||
121 | extended = (typeof(extended)) local_channel->attr.extended.ptr; | |
122 | ||
123 | /* lttng_trigger_comm header */ | |
124 | { | |
125 | const struct lttng_buffer_view comm_view = | |
28ab034a | 126 | lttng_buffer_view_from_view(view, offset, sizeof(*channel_comm)); |
999af9c1 JR |
127 | |
128 | if (!lttng_buffer_view_is_valid(&comm_view)) { | |
129 | ret = -1; | |
130 | goto end; | |
131 | } | |
132 | ||
28ab034a | 133 | channel_comm = (const struct lttng_channel_comm *) comm_view.data; |
999af9c1 JR |
134 | offset += sizeof(*channel_comm); |
135 | } | |
136 | ||
137 | { | |
138 | const char *name; | |
139 | const struct lttng_buffer_view name_view = | |
28ab034a | 140 | lttng_buffer_view_from_view(view, offset, channel_comm->name_len); |
999af9c1 | 141 | |
999af9c1 | 142 | name = name_view.data; |
28ab034a | 143 | if (!lttng_buffer_view_contains_string(&name_view, name, channel_comm->name_len)) { |
999af9c1 JR |
144 | ret = -1; |
145 | goto end; | |
146 | } | |
147 | ||
28ab034a | 148 | ret = lttng_strncpy(local_channel->name, name, sizeof(local_channel->name)); |
2d6df81a JG |
149 | if (ret) { |
150 | goto end; | |
151 | } | |
152 | ||
999af9c1 JR |
153 | offset += channel_comm->name_len; |
154 | } | |
155 | ||
156 | /* Populate the channel */ | |
157 | local_channel->enabled = channel_comm->enabled; | |
158 | ||
159 | /* attr */ | |
160 | local_channel->attr.overwrite = channel_comm->overwrite; | |
161 | local_channel->attr.subbuf_size = channel_comm->subbuf_size; | |
162 | local_channel->attr.num_subbuf = channel_comm->num_subbuf; | |
28ab034a JG |
163 | local_channel->attr.switch_timer_interval = channel_comm->switch_timer_interval; |
164 | local_channel->attr.read_timer_interval = channel_comm->read_timer_interval; | |
999af9c1 JR |
165 | local_channel->attr.output = (enum lttng_event_output) channel_comm->output; |
166 | local_channel->attr.tracefile_size = channel_comm->tracefile_size; | |
167 | local_channel->attr.tracefile_count = channel_comm->tracefile_count; | |
28ab034a | 168 | local_channel->attr.live_timer_interval = channel_comm->live_timer_interval; |
999af9c1 JR |
169 | |
170 | extended->discarded_events = channel_comm->discarded_events; | |
171 | extended->lost_packets = channel_comm->lost_packets; | |
172 | extended->monitor_timer_interval = channel_comm->monitor_timer_interval; | |
173 | extended->blocking_timeout = channel_comm->blocking_timeout; | |
174 | ||
175 | *channel = local_channel; | |
176 | local_channel = nullptr; | |
177 | ||
178 | ret = offset; | |
179 | end: | |
180 | lttng_channel_destroy(local_channel); | |
181 | return ret; | |
182 | } | |
183 | ||
28ab034a | 184 | int lttng_channel_serialize(struct lttng_channel *channel, struct lttng_dynamic_buffer *buf) |
999af9c1 JR |
185 | { |
186 | int ret; | |
187 | size_t name_len; | |
1c9a0b0e | 188 | struct lttng_channel_comm channel_comm = {}; |
999af9c1 JR |
189 | struct lttng_channel_extended *extended; |
190 | ||
191 | assert(channel); | |
192 | assert(buf); | |
193 | ||
194 | extended = (struct lttng_channel_extended *) channel->attr.extended.ptr; | |
195 | ||
196 | name_len = lttng_strnlen(channel->name, LTTNG_SYMBOL_NAME_LEN); | |
197 | if (name_len == LTTNG_SYMBOL_NAME_LEN) { | |
198 | /* channel name is not nullptr-terminated. */ | |
199 | ret = -1; | |
200 | goto end; | |
201 | } | |
202 | ||
203 | /* Include string termination. */ | |
204 | name_len += 1; | |
205 | ||
206 | /* Base field */ | |
207 | channel_comm.name_len = (uint32_t) name_len; | |
208 | channel_comm.enabled = channel->enabled; | |
209 | ||
210 | /* attr */ | |
211 | channel_comm.overwrite = channel->attr.overwrite; | |
212 | channel_comm.subbuf_size = channel->attr.subbuf_size; | |
213 | channel_comm.num_subbuf = channel->attr.num_subbuf; | |
28ab034a | 214 | channel_comm.switch_timer_interval = channel->attr.switch_timer_interval; |
999af9c1 JR |
215 | channel_comm.read_timer_interval = channel->attr.read_timer_interval; |
216 | channel_comm.output = channel->attr.output; | |
217 | channel_comm.tracefile_size = channel->attr.tracefile_size; | |
218 | channel_comm.tracefile_count = channel->attr.tracefile_count; | |
219 | channel_comm.live_timer_interval = channel->attr.live_timer_interval; | |
220 | ||
221 | /* Extended struct */ | |
222 | channel_comm.discarded_events = extended->discarded_events; | |
223 | channel_comm.lost_packets = extended->lost_packets; | |
224 | channel_comm.monitor_timer_interval = extended->monitor_timer_interval; | |
225 | channel_comm.blocking_timeout = extended->blocking_timeout; | |
226 | ||
227 | /* Header */ | |
28ab034a | 228 | ret = lttng_dynamic_buffer_append(buf, &channel_comm, sizeof(channel_comm)); |
999af9c1 JR |
229 | if (ret) { |
230 | goto end; | |
231 | } | |
232 | ||
233 | /* channel name */ | |
234 | ret = lttng_dynamic_buffer_append(buf, channel->name, name_len); | |
235 | if (ret) { | |
236 | goto end; | |
237 | } | |
238 | end: | |
239 | return ret; | |
240 | } | |
241 | ||
242 | void lttng_channel_set_default_extended_attr(struct lttng_domain *domain, | |
28ab034a | 243 | struct lttng_channel_extended *extended_attr) |
999af9c1 JR |
244 | { |
245 | assert(domain); | |
246 | assert(extended_attr); | |
247 | ||
248 | memset(extended_attr, 0, sizeof(*extended_attr)); | |
249 | ||
250 | switch (domain->type) { | |
251 | case LTTNG_DOMAIN_KERNEL: | |
28ab034a JG |
252 | extended_attr->monitor_timer_interval = DEFAULT_KERNEL_CHANNEL_MONITOR_TIMER; |
253 | extended_attr->blocking_timeout = DEFAULT_KERNEL_CHANNEL_BLOCKING_TIMEOUT; | |
999af9c1 JR |
254 | break; |
255 | case LTTNG_DOMAIN_UST: | |
256 | switch (domain->buf_type) { | |
257 | case LTTNG_BUFFER_PER_UID: | |
258 | extended_attr->monitor_timer_interval = | |
28ab034a JG |
259 | DEFAULT_UST_UID_CHANNEL_MONITOR_TIMER; |
260 | extended_attr->blocking_timeout = DEFAULT_UST_UID_CHANNEL_BLOCKING_TIMEOUT; | |
999af9c1 JR |
261 | break; |
262 | case LTTNG_BUFFER_PER_PID: | |
263 | default: | |
264 | if (extended_attr) { | |
265 | extended_attr->monitor_timer_interval = | |
28ab034a | 266 | DEFAULT_UST_PID_CHANNEL_MONITOR_TIMER; |
999af9c1 | 267 | extended_attr->blocking_timeout = |
28ab034a | 268 | DEFAULT_UST_PID_CHANNEL_BLOCKING_TIMEOUT; |
999af9c1 JR |
269 | } |
270 | break; | |
271 | } | |
272 | default: | |
273 | /* Default behavior: leave set to 0. */ | |
274 | break; | |
275 | } | |
276 | } | |
277 | ||
28ab034a JG |
278 | static enum lttng_error_code |
279 | channel_list_create_from_buffer(const struct lttng_buffer_view *view, | |
280 | unsigned int count, | |
281 | struct lttng_dynamic_pointer_array *channel_list) | |
999af9c1 JR |
282 | { |
283 | enum lttng_error_code ret_code; | |
284 | int ret, i; | |
285 | int offset = 0; | |
286 | ||
287 | assert(view); | |
288 | assert(channel_list); | |
289 | ||
290 | for (i = 0; i < count; i++) { | |
291 | ssize_t channel_size; | |
292 | struct lttng_channel *channel = nullptr; | |
293 | const struct lttng_buffer_view channel_view = | |
28ab034a | 294 | lttng_buffer_view_from_view(view, offset, -1); |
999af9c1 | 295 | |
28ab034a | 296 | channel_size = lttng_channel_create_from_buffer(&channel_view, &channel); |
999af9c1 JR |
297 | if (channel_size < 0) { |
298 | ret_code = LTTNG_ERR_INVALID; | |
299 | goto end; | |
300 | } | |
301 | ||
302 | /* Lifetime and management of the object is now bound to the array. */ | |
303 | ret = lttng_dynamic_pointer_array_add_pointer(channel_list, channel); | |
304 | if (ret) { | |
305 | lttng_channel_destroy(channel); | |
306 | ret_code = LTTNG_ERR_NOMEM; | |
307 | goto end; | |
308 | } | |
309 | offset += channel_size; | |
310 | } | |
311 | ||
312 | if (view->size != offset) { | |
313 | ret_code = LTTNG_ERR_INVALID; | |
314 | goto end; | |
315 | } | |
316 | ||
317 | ret_code = LTTNG_OK; | |
318 | ||
319 | end: | |
320 | return ret_code; | |
321 | } | |
322 | ||
323 | static enum lttng_error_code flatten_lttng_channels(struct lttng_dynamic_pointer_array *channels, | |
28ab034a | 324 | struct lttng_channel **flattened_channels) |
999af9c1 JR |
325 | { |
326 | enum lttng_error_code ret_code; | |
327 | int ret, i; | |
328 | size_t storage_req = 0; | |
329 | struct lttng_dynamic_buffer local_flattened_channels; | |
330 | int nb_channels; | |
331 | ||
332 | assert(channels); | |
333 | assert(flattened_channels); | |
334 | ||
335 | lttng_dynamic_buffer_init(&local_flattened_channels); | |
336 | nb_channels = lttng_dynamic_pointer_array_get_count(channels); | |
337 | ||
338 | storage_req += sizeof(struct lttng_channel) * nb_channels; | |
339 | storage_req += sizeof(struct lttng_channel_extended) * nb_channels; | |
340 | ||
341 | /* | |
342 | * We must ensure that "local_flattened_channels" is never resized so as | |
343 | * to preserve the validity of the flattened objects. | |
344 | */ | |
28ab034a | 345 | ret = lttng_dynamic_buffer_set_capacity(&local_flattened_channels, storage_req); |
999af9c1 JR |
346 | if (ret) { |
347 | ret_code = LTTNG_ERR_NOMEM; | |
348 | goto end; | |
349 | } | |
350 | ||
351 | /* Start by laying the struct lttng_channel */ | |
352 | for (i = 0; i < nb_channels; i++) { | |
28ab034a JG |
353 | const auto *element = |
354 | (const struct lttng_channel *) lttng_dynamic_pointer_array_get_pointer( | |
355 | channels, i); | |
999af9c1 JR |
356 | |
357 | if (!element) { | |
358 | ret_code = LTTNG_ERR_FATAL; | |
359 | goto end; | |
360 | } | |
361 | ||
28ab034a JG |
362 | ret = lttng_dynamic_buffer_append( |
363 | &local_flattened_channels, element, sizeof(struct lttng_channel)); | |
999af9c1 JR |
364 | if (ret) { |
365 | ret_code = LTTNG_ERR_NOMEM; | |
366 | goto end; | |
367 | } | |
368 | } | |
369 | ||
370 | /* Flatten the extended data */ | |
371 | for (i = 0; i < nb_channels; i++) { | |
28ab034a JG |
372 | const auto *element = |
373 | (const struct lttng_channel *) lttng_dynamic_pointer_array_get_pointer( | |
374 | channels, i); | |
999af9c1 JR |
375 | /* |
376 | * Sample the location of the flattened channel we are about | |
377 | * to modify. | |
378 | */ | |
28ab034a JG |
379 | auto *channel = (struct lttng_channel *) (local_flattened_channels.data + |
380 | (sizeof(struct lttng_channel) * i)); | |
999af9c1 JR |
381 | /* |
382 | * Sample the location of the extended attributes we are about | |
383 | * to add. | |
384 | */ | |
28ab034a JG |
385 | const auto *channel_extended = |
386 | (struct lttng_channel_extended *) (local_flattened_channels.data + | |
387 | local_flattened_channels.size); | |
999af9c1 JR |
388 | |
389 | if (!element) { | |
390 | ret_code = LTTNG_ERR_FATAL; | |
391 | goto end; | |
392 | } | |
393 | ||
394 | ret = lttng_dynamic_buffer_append(&local_flattened_channels, | |
28ab034a JG |
395 | element->attr.extended.ptr, |
396 | sizeof(struct lttng_channel_extended)); | |
999af9c1 JR |
397 | if (ret) { |
398 | ret_code = LTTNG_ERR_NOMEM; | |
399 | goto end; | |
400 | } | |
401 | ||
402 | /* | |
403 | * Update the flattened lttng_channel object with its flattened | |
404 | * extended object location. | |
405 | */ | |
406 | channel->attr.extended.ptr = (void *) channel_extended; | |
407 | } | |
408 | ||
409 | /* Don't reset local_flattened_channels buffer as we return its content. */ | |
410 | *flattened_channels = (struct lttng_channel *) local_flattened_channels.data; | |
411 | lttng_dynamic_buffer_init(&local_flattened_channels); | |
412 | ret_code = LTTNG_OK; | |
413 | end: | |
414 | lttng_dynamic_buffer_reset(&local_flattened_channels); | |
415 | return ret_code; | |
416 | } | |
417 | ||
418 | enum lttng_error_code lttng_channels_create_and_flatten_from_buffer( | |
28ab034a | 419 | const struct lttng_buffer_view *view, uint32_t count, struct lttng_channel **channels) |
999af9c1 JR |
420 | { |
421 | enum lttng_error_code ret_code; | |
422 | struct lttng_dynamic_pointer_array local_channels; | |
423 | ||
424 | lttng_dynamic_pointer_array_init(&local_channels, channel_list_destructor); | |
425 | ||
426 | /* Deserialize the channels */ | |
427 | { | |
428 | const struct lttng_buffer_view channels_view = | |
28ab034a | 429 | lttng_buffer_view_from_view(view, 0, -1); |
999af9c1 | 430 | |
28ab034a | 431 | ret_code = channel_list_create_from_buffer(&channels_view, count, &local_channels); |
999af9c1 JR |
432 | if (ret_code != LTTNG_OK) { |
433 | goto end; | |
434 | } | |
435 | } | |
436 | ||
437 | ret_code = flatten_lttng_channels(&local_channels, channels); | |
438 | ||
439 | end: | |
440 | lttng_dynamic_pointer_array_reset(&local_channels); | |
441 | return ret_code; | |
442 | } |