Move to kernel style SPDX license identifiers
[lttng-ust.git] / liblttng-ust / lttng-context.c
1 /*
2 * SPDX-License-Identifier: LGPL-2.1-only
3 *
4 * Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 *
6 * LTTng UST trace/channel/event context management.
7 */
8
9 #define _LGPL_SOURCE
10 #include <lttng/ust-events.h>
11 #include <lttng/ust-tracer.h>
12 #include <lttng/ust-context-provider.h>
13 #include <lttng/urcu/pointer.h>
14 #include <usterr-signal-safe.h>
15 #include <helper.h>
16 #include <stddef.h>
17 #include <string.h>
18 #include <assert.h>
19 #include "tracepoint-internal.h"
20
21 #include "context-internal.h"
22
23 /*
24 * The filter implementation requires that two consecutive "get" for the
25 * same context performed by the same thread return the same result.
26 */
27
28 int lttng_find_context(struct lttng_ctx *ctx, const char *name)
29 {
30 unsigned int i;
31 const char *subname;
32
33 if (strncmp(name, "$ctx.", strlen("$ctx.")) == 0) {
34 subname = name + strlen("$ctx.");
35 } else {
36 subname = name;
37 }
38 for (i = 0; i < ctx->nr_fields; i++) {
39 /* Skip allocated (but non-initialized) contexts */
40 if (!ctx->fields[i].event_field.name)
41 continue;
42 if (!strcmp(ctx->fields[i].event_field.name, subname))
43 return 1;
44 }
45 return 0;
46 }
47
48 int lttng_get_context_index(struct lttng_ctx *ctx, const char *name)
49 {
50 unsigned int i;
51 const char *subname;
52
53 if (!ctx)
54 return -1;
55 if (strncmp(name, "$ctx.", strlen("$ctx.")) == 0) {
56 subname = name + strlen("$ctx.");
57 } else {
58 subname = name;
59 }
60 for (i = 0; i < ctx->nr_fields; i++) {
61 /* Skip allocated (but non-initialized) contexts */
62 if (!ctx->fields[i].event_field.name)
63 continue;
64 if (!strcmp(ctx->fields[i].event_field.name, subname))
65 return i;
66 }
67 return -1;
68 }
69
70 static int lttng_find_context_provider(struct lttng_ctx *ctx, const char *name)
71 {
72 unsigned int i;
73
74 for (i = 0; i < ctx->nr_fields; i++) {
75 /* Skip allocated (but non-initialized) contexts */
76 if (!ctx->fields[i].event_field.name)
77 continue;
78 if (!strncmp(ctx->fields[i].event_field.name, name,
79 strlen(name)))
80 return 1;
81 }
82 return 0;
83 }
84
85 /*
86 * Note: as we append context information, the pointer location may change.
87 */
88 struct lttng_ctx_field *lttng_append_context(struct lttng_ctx **ctx_p)
89 {
90 struct lttng_ctx_field *field;
91 struct lttng_ctx *ctx;
92
93 if (!*ctx_p) {
94 *ctx_p = zmalloc(sizeof(struct lttng_ctx));
95 if (!*ctx_p)
96 return NULL;
97 (*ctx_p)->largest_align = 1;
98 }
99 ctx = *ctx_p;
100 if (ctx->nr_fields + 1 > ctx->allocated_fields) {
101 struct lttng_ctx_field *new_fields;
102
103 ctx->allocated_fields = max_t(size_t, 1, 2 * ctx->allocated_fields);
104 new_fields = zmalloc(ctx->allocated_fields * sizeof(struct lttng_ctx_field));
105 if (!new_fields)
106 return NULL;
107 if (ctx->fields)
108 memcpy(new_fields, ctx->fields, sizeof(*ctx->fields) * ctx->nr_fields);
109 free(ctx->fields);
110 ctx->fields = new_fields;
111 }
112 field = &ctx->fields[ctx->nr_fields];
113 ctx->nr_fields++;
114 return field;
115 }
116
117 int lttng_context_add_rcu(struct lttng_ctx **ctx_p,
118 const struct lttng_ctx_field *f)
119 {
120 struct lttng_ctx *old_ctx = *ctx_p, *new_ctx = NULL;
121 struct lttng_ctx_field *new_fields = NULL;
122 struct lttng_ctx_field *nf;
123
124 if (old_ctx) {
125 new_ctx = zmalloc(sizeof(struct lttng_ctx));
126 if (!new_ctx)
127 return -ENOMEM;
128 *new_ctx = *old_ctx;
129 new_fields = zmalloc(new_ctx->allocated_fields
130 * sizeof(struct lttng_ctx_field));
131 if (!new_fields) {
132 free(new_ctx);
133 return -ENOMEM;
134 }
135 memcpy(new_fields, old_ctx->fields,
136 sizeof(*old_ctx->fields) * old_ctx->nr_fields);
137 new_ctx->fields = new_fields;
138 }
139 nf = lttng_append_context(&new_ctx);
140 if (!nf) {
141 free(new_fields);
142 free(new_ctx);
143 return -ENOMEM;
144 }
145 *nf = *f;
146 lttng_context_update(new_ctx);
147 lttng_ust_rcu_assign_pointer(*ctx_p, new_ctx);
148 lttng_ust_synchronize_trace();
149 if (old_ctx) {
150 free(old_ctx->fields);
151 free(old_ctx);
152 }
153 return 0;
154 }
155
156 /*
157 * lttng_context_update() should be called at least once between context
158 * modification and trace start.
159 */
160 void lttng_context_update(struct lttng_ctx *ctx)
161 {
162 int i;
163 size_t largest_align = 8; /* in bits */
164
165 for (i = 0; i < ctx->nr_fields; i++) {
166 struct lttng_type *type;
167 size_t field_align = 8;
168
169 type = &ctx->fields[i].event_field.type;
170 switch (type->atype) {
171 case atype_integer:
172 field_align = type->u.integer.alignment;
173 break;
174 case atype_array:
175 {
176 struct lttng_basic_type *btype;
177
178 btype = &type->u.legacy.array.elem_type;
179 switch (btype->atype) {
180 case atype_integer:
181 field_align = btype->u.basic.integer.alignment;
182 break;
183 case atype_string:
184 break;
185
186 case atype_array:
187 case atype_array_nestable:
188 case atype_sequence:
189 case atype_sequence_nestable:
190 default:
191 WARN_ON_ONCE(1);
192 break;
193 }
194 break;
195 }
196 case atype_array_nestable:
197 {
198 const struct lttng_type *nested_type;
199
200 nested_type = type->u.array_nestable.elem_type;
201 switch (nested_type->atype) {
202 case atype_integer:
203 field_align = nested_type->u.integer.alignment;
204 break;
205 case atype_string:
206 break;
207
208 case atype_array:
209 case atype_array_nestable:
210 case atype_sequence:
211 case atype_sequence_nestable:
212 default:
213 WARN_ON_ONCE(1);
214 break;
215 }
216 field_align = max_t(size_t, field_align,
217 type->u.array_nestable.alignment);
218 break;
219 }
220 case atype_sequence:
221 {
222 struct lttng_basic_type *btype;
223
224 btype = &type->u.legacy.sequence.length_type;
225 switch (btype->atype) {
226 case atype_integer:
227 field_align = btype->u.basic.integer.alignment;
228 break;
229
230 case atype_string:
231 case atype_array:
232 case atype_array_nestable:
233 case atype_sequence:
234 case atype_sequence_nestable:
235 default:
236 WARN_ON_ONCE(1);
237 break;
238 }
239
240 btype = &type->u.legacy.sequence.elem_type;
241 switch (btype->atype) {
242 case atype_integer:
243 field_align = max_t(size_t,
244 field_align,
245 btype->u.basic.integer.alignment);
246 break;
247
248 case atype_string:
249 break;
250
251 case atype_array:
252 case atype_array_nestable:
253 case atype_sequence:
254 case atype_sequence_nestable:
255 default:
256 WARN_ON_ONCE(1);
257 break;
258 }
259 break;
260 }
261 case atype_sequence_nestable:
262 {
263 const struct lttng_type *nested_type;
264
265 nested_type = type->u.sequence_nestable.elem_type;
266 switch (nested_type->atype) {
267 case atype_integer:
268 field_align = nested_type->u.integer.alignment;
269 break;
270
271 case atype_string:
272 break;
273
274 case atype_array:
275 case atype_array_nestable:
276 case atype_sequence:
277 case atype_sequence_nestable:
278 default:
279 WARN_ON_ONCE(1);
280 break;
281 }
282 field_align = max_t(size_t, field_align,
283 type->u.sequence_nestable.alignment);
284 break;
285 }
286 case atype_string:
287 break;
288 case atype_dynamic:
289 break;
290 case atype_enum:
291 case atype_enum_nestable:
292 default:
293 WARN_ON_ONCE(1);
294 break;
295 }
296 largest_align = max_t(size_t, largest_align, field_align);
297 }
298 ctx->largest_align = largest_align >> 3; /* bits to bytes */
299 }
300
301 /*
302 * Remove last context field.
303 */
304 void lttng_remove_context_field(struct lttng_ctx **ctx_p,
305 struct lttng_ctx_field *field)
306 {
307 struct lttng_ctx *ctx;
308
309 ctx = *ctx_p;
310 ctx->nr_fields--;
311 assert(&ctx->fields[ctx->nr_fields] == field);
312 assert(field->field_name == NULL);
313 memset(&ctx->fields[ctx->nr_fields], 0, sizeof(struct lttng_ctx_field));
314 }
315
316 void lttng_destroy_context(struct lttng_ctx *ctx)
317 {
318 int i;
319
320 if (!ctx)
321 return;
322 for (i = 0; i < ctx->nr_fields; i++) {
323 if (ctx->fields[i].destroy)
324 ctx->fields[i].destroy(&ctx->fields[i]);
325 free(ctx->fields[i].field_name);
326 }
327 free(ctx->fields);
328 free(ctx);
329 }
330
331 /*
332 * Can be safely performed concurrently with tracing using the struct
333 * lttng_ctx. Using RCU update. Needs to match RCU read-side handling of
334 * contexts.
335 *
336 * This does not allow adding, removing, or changing typing of the
337 * contexts, since this needs to stay invariant for metadata. However,
338 * it allows updating the handlers associated with all contexts matching
339 * a provider (by name) while tracing is using it, in a way that ensures
340 * a single RCU read-side critical section see either all old, or all
341 * new handlers.
342 */
343 int lttng_ust_context_set_provider_rcu(struct lttng_ctx **_ctx,
344 const char *name,
345 size_t (*get_size)(struct lttng_ctx_field *field, size_t offset),
346 void (*record)(struct lttng_ctx_field *field,
347 struct lttng_ust_lib_ring_buffer_ctx *ctx,
348 struct lttng_channel *chan),
349 void (*get_value)(struct lttng_ctx_field *field,
350 struct lttng_ctx_value *value))
351 {
352 int i, ret;
353 struct lttng_ctx *ctx = *_ctx, *new_ctx;
354 struct lttng_ctx_field *new_fields;
355
356 if (!ctx || !lttng_find_context_provider(ctx, name))
357 return 0;
358 /*
359 * We have at least one instance of context for the provider.
360 */
361 new_ctx = zmalloc(sizeof(*new_ctx));
362 if (!new_ctx)
363 return -ENOMEM;
364 *new_ctx = *ctx;
365 new_fields = zmalloc(sizeof(*new_fields) * ctx->allocated_fields);
366 if (!new_fields) {
367 ret = -ENOMEM;
368 goto field_error;
369 }
370 memcpy(new_fields, ctx->fields,
371 sizeof(*new_fields) * ctx->allocated_fields);
372 for (i = 0; i < ctx->nr_fields; i++) {
373 if (strncmp(new_fields[i].event_field.name,
374 name, strlen(name)) != 0)
375 continue;
376 new_fields[i].get_size = get_size;
377 new_fields[i].record = record;
378 new_fields[i].get_value = get_value;
379 }
380 new_ctx->fields = new_fields;
381 lttng_ust_rcu_assign_pointer(*_ctx, new_ctx);
382 lttng_ust_synchronize_trace();
383 free(ctx->fields);
384 free(ctx);
385 return 0;
386
387 field_error:
388 free(new_ctx);
389 return ret;
390 }
391
392 int lttng_context_init_all(struct lttng_ctx **ctx)
393 {
394 int ret;
395
396 ret = lttng_add_pthread_id_to_ctx(ctx);
397 if (ret) {
398 WARN("Cannot add context lttng_add_pthread_id_to_ctx");
399 goto error;
400 }
401 ret = lttng_add_vtid_to_ctx(ctx);
402 if (ret) {
403 WARN("Cannot add context lttng_add_vtid_to_ctx");
404 goto error;
405 }
406 ret = lttng_add_vpid_to_ctx(ctx);
407 if (ret) {
408 WARN("Cannot add context lttng_add_vpid_to_ctx");
409 goto error;
410 }
411 ret = lttng_add_procname_to_ctx(ctx);
412 if (ret) {
413 WARN("Cannot add context lttng_add_procname_to_ctx");
414 goto error;
415 }
416 ret = lttng_add_cpu_id_to_ctx(ctx);
417 if (ret) {
418 WARN("Cannot add context lttng_add_cpu_id_to_ctx");
419 goto error;
420 }
421 ret = lttng_add_cgroup_ns_to_ctx(ctx);
422 if (ret) {
423 WARN("Cannot add context lttng_add_cgroup_ns_to_ctx");
424 goto error;
425 }
426 ret = lttng_add_ipc_ns_to_ctx(ctx);
427 if (ret) {
428 WARN("Cannot add context lttng_add_ipc_ns_to_ctx");
429 goto error;
430 }
431 ret = lttng_add_mnt_ns_to_ctx(ctx);
432 if (ret) {
433 WARN("Cannot add context lttng_add_mnt_ns_to_ctx");
434 goto error;
435 }
436 ret = lttng_add_net_ns_to_ctx(ctx);
437 if (ret) {
438 WARN("Cannot add context lttng_add_net_ns_to_ctx");
439 goto error;
440 }
441 ret = lttng_add_pid_ns_to_ctx(ctx);
442 if (ret) {
443 WARN("Cannot add context lttng_add_pid_ns_to_ctx");
444 goto error;
445 }
446 ret = lttng_add_time_ns_to_ctx(ctx);
447 if (ret) {
448 WARN("Cannot add context lttng_add_time_ns_to_ctx");
449 goto error;
450 }
451 ret = lttng_add_user_ns_to_ctx(ctx);
452 if (ret) {
453 WARN("Cannot add context lttng_add_user_ns_to_ctx");
454 goto error;
455 }
456 ret = lttng_add_uts_ns_to_ctx(ctx);
457 if (ret) {
458 WARN("Cannot add context lttng_add_uts_ns_to_ctx");
459 goto error;
460 }
461 ret = lttng_add_vuid_to_ctx(ctx);
462 if (ret) {
463 WARN("Cannot add context lttng_add_vuid_to_ctx");
464 goto error;
465 }
466 ret = lttng_add_veuid_to_ctx(ctx);
467 if (ret) {
468 WARN("Cannot add context lttng_add_veuid_to_ctx");
469 goto error;
470 }
471 ret = lttng_add_vsuid_to_ctx(ctx);
472 if (ret) {
473 WARN("Cannot add context lttng_add_vsuid_to_ctx");
474 goto error;
475 }
476 ret = lttng_add_vgid_to_ctx(ctx);
477 if (ret) {
478 WARN("Cannot add context lttng_add_vgid_to_ctx");
479 goto error;
480 }
481 ret = lttng_add_vegid_to_ctx(ctx);
482 if (ret) {
483 WARN("Cannot add context lttng_add_vegid_to_ctx");
484 goto error;
485 }
486 ret = lttng_add_vsgid_to_ctx(ctx);
487 if (ret) {
488 WARN("Cannot add context lttng_add_vsgid_to_ctx");
489 goto error;
490 }
491 lttng_context_update(*ctx);
492 return 0;
493
494 error:
495 lttng_destroy_context(*ctx);
496 return ret;
497 }
This page took 0.038196 seconds and 4 git commands to generate.