Implement event notifier error counter
[lttng-modules.git] / src / lttng-event-notifier-notification.c
CommitLineData
21f58fb7
FD
1/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
2 *
3 * lttng-event-notifier-notification.c
4 *
5 * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
6 */
7
42f3ef8c
FD
8#include <linux/bug.h>
9
10#include <lttng/lttng-bytecode.h>
21f58fb7 11#include <lttng/events.h>
42f3ef8c 12#include <lttng/msgpack.h>
21f58fb7
FD
13#include <lttng/event-notifier-notification.h>
14
99d223ad 15/*
e699ee6c
MD
16 * The capture buffer size needs to be below 1024 bytes to avoid the
17 * frame to be larger than the 1024 limit enforced by the kernel. If we
18 * ever need to increase it, we will need to use a memory allocation
19 * scheme which allows allocating temporary memory chunks from the
20 * instrumentation sites. This could be done by adapting lttng
21 * tp-mempool to become nmi-safe and lock-free.
99d223ad
FD
22 */
23#define CAPTURE_BUFFER_SIZE 512
24
25struct lttng_event_notifier_notification {
26 int notification_fd;
27 uint64_t event_notifier_token;
28 uint8_t capture_buf[CAPTURE_BUFFER_SIZE];
29 struct lttng_msgpack_writer writer;
30 bool has_captures;
31};
32
42f3ef8c
FD
33static
34int capture_enum(struct lttng_msgpack_writer *writer,
35 struct lttng_interpreter_output *output)
36{
37 int ret;
38
39 /*
40 * Enums are captured as a map containing 2 key-value pairs. Such as:
41 * - type: enum
42 * value: 177
43 */
44 ret = lttng_msgpack_begin_map(writer, 2);
45 if (ret) {
46 WARN_ON_ONCE(1);
47 goto end;
48 }
49
50 ret = lttng_msgpack_write_str(writer, "type");
51 if (ret) {
52 WARN_ON_ONCE(1);
53 goto end;
54 }
55
56 ret = lttng_msgpack_write_str(writer, "enum");
57 if (ret) {
58 WARN_ON_ONCE(1);
59 goto end;
60 }
61
62 ret = lttng_msgpack_write_str(writer, "value");
63 if (ret) {
64 WARN_ON_ONCE(1);
65 goto end;
66 }
67
68 switch (output->type) {
69 case LTTNG_INTERPRETER_TYPE_SIGNED_ENUM:
70 ret = lttng_msgpack_write_signed_integer(writer, output->u.s);
71 if (ret) {
72 WARN_ON_ONCE(1);
73 goto end;
74 }
75 break;
76 case LTTNG_INTERPRETER_TYPE_UNSIGNED_ENUM:
77 ret = lttng_msgpack_write_signed_integer(writer, output->u.u);
78 if (ret) {
79 WARN_ON_ONCE(1);
80 goto end;
81 }
82 break;
83 default:
84 WARN_ON(1);
85 }
86
87 ret = lttng_msgpack_end_map(writer);
88 if (ret)
89 WARN_ON_ONCE(1);
90
91end:
92 return ret;
93}
94
95static
96int64_t capture_sequence_element_signed(uint8_t *ptr,
97 const struct lttng_integer_type *type)
98{
99 int64_t value = 0;
100 unsigned int size = type->size;
101 bool byte_order_reversed = type->reverse_byte_order;
102
103 switch (size) {
104 case 8:
105 value = *ptr;
106 break;
107 case 16:
108 {
109 int16_t tmp;
110 tmp = *(int16_t *) ptr;
111 if (byte_order_reversed)
112 __swab16s(&tmp);
113
114 value = tmp;
115 break;
116 }
117 case 32:
118 {
119 int32_t tmp;
120 tmp = *(int32_t *) ptr;
121 if (byte_order_reversed)
122 __swab32s(&tmp);
123
124 value = tmp;
125 break;
126 }
127 case 64:
128 {
129 int64_t tmp;
130 tmp = *(int64_t *) ptr;
131 if (byte_order_reversed)
132 __swab64s(&tmp);
133
134 value = tmp;
135 break;
136 }
137 default:
138 WARN_ON(1);
139 }
140
141 return value;
142}
143
144static
145uint64_t capture_sequence_element_unsigned(uint8_t *ptr,
146 const struct lttng_integer_type *type)
147{
148 uint64_t value = 0;
149 unsigned int size = type->size;
150 bool byte_order_reversed = type->reverse_byte_order;
151
152 switch (size) {
153 case 8:
154 value = *ptr;
155 break;
156 case 16:
157 {
158 uint16_t tmp;
159 tmp = *(uint16_t *) ptr;
160 if (byte_order_reversed)
161 __swab16s(&tmp);
162
163 value = tmp;
164 break;
165 }
166 case 32:
167 {
168 uint32_t tmp;
169 tmp = *(uint32_t *) ptr;
170 if (byte_order_reversed)
171 __swab32s(&tmp);
172
173 value = tmp;
174 break;
175 }
176 case 64:
177 {
178 uint64_t tmp;
179 tmp = *(uint64_t *) ptr;
180 if (byte_order_reversed)
181 __swab64s(&tmp);
182
183 value = tmp;
184 break;
185 }
186 default:
187 WARN_ON(1);
188 }
189
190 return value;
191}
192
42f3ef8c
FD
193int capture_sequence(struct lttng_msgpack_writer *writer,
194 struct lttng_interpreter_output *output)
195{
196 const struct lttng_integer_type *integer_type = NULL;
197 const struct lttng_type *nested_type;
198 uint8_t *ptr;
199 bool signedness;
200 int ret, i;
201
202 ret = lttng_msgpack_begin_array(writer, output->u.sequence.nr_elem);
203 if (ret) {
204 WARN_ON_ONCE(1);
205 goto end;
206 }
207
208 ptr = (uint8_t *) output->u.sequence.ptr;
209 nested_type = output->u.sequence.nested_type;
210 switch (nested_type->atype) {
211 case atype_integer:
212 integer_type = &nested_type->u.integer;
213 break;
214 case atype_enum_nestable:
215 /* Treat enumeration as an integer. */
216 integer_type = &nested_type->u.enum_nestable.container_type->u.integer;
217 break;
218 default:
219 /* Capture of array of non-integer are not supported. */
220 WARN_ON(1);
221 }
222 signedness = integer_type->signedness;
223 for (i = 0; i < output->u.sequence.nr_elem; i++) {
224 if (signedness) {
225 ret = lttng_msgpack_write_signed_integer(writer,
226 capture_sequence_element_signed(ptr, integer_type));
227 if (ret) {
228 WARN_ON_ONCE(1);
229 goto end;
230 }
231 } else {
232 ret = lttng_msgpack_write_unsigned_integer(writer,
233 capture_sequence_element_unsigned(ptr, integer_type));
234 if (ret) {
235 WARN_ON_ONCE(1);
236 goto end;
237 }
238 }
239
240 /*
241 * We assume that alignment is smaller or equal to the size.
242 * This currently holds true but if it changes in the future,
243 * we will want to change the pointer arithmetics below to
244 * take into account that the next element might be further
245 * away.
246 */
247 WARN_ON(integer_type->alignment > integer_type->size);
248
249 /* Size is in number of bits. */
250 ptr += (integer_type->size / CHAR_BIT) ;
251 }
252
253 ret = lttng_msgpack_end_array(writer);
254 if (ret)
255 WARN_ON_ONCE(1);
256end:
257 return ret;
258}
259
99d223ad
FD
260static
261int notification_append_capture(
262 struct lttng_event_notifier_notification *notif,
263 struct lttng_interpreter_output *output)
264{
265 struct lttng_msgpack_writer *writer = &notif->writer;
266 int ret = 0;
267
268 switch (output->type) {
269 case LTTNG_INTERPRETER_TYPE_S64:
270 ret = lttng_msgpack_write_signed_integer(writer, output->u.s);
271 if (ret) {
272 WARN_ON_ONCE(1);
273 goto end;
274 }
275 break;
276 case LTTNG_INTERPRETER_TYPE_U64:
277 ret = lttng_msgpack_write_unsigned_integer(writer, output->u.u);
278 if (ret) {
279 WARN_ON_ONCE(1);
280 goto end;
281 }
282 break;
283 case LTTNG_INTERPRETER_TYPE_STRING:
284 ret = lttng_msgpack_write_str(writer, output->u.str.str);
285 if (ret) {
286 WARN_ON_ONCE(1);
287 goto end;
288 }
289 break;
290 case LTTNG_INTERPRETER_TYPE_SEQUENCE:
291 ret = capture_sequence(writer, output);
292 if (ret) {
293 WARN_ON_ONCE(1);
294 goto end;
295 }
296 break;
297 case LTTNG_INTERPRETER_TYPE_SIGNED_ENUM:
298 case LTTNG_INTERPRETER_TYPE_UNSIGNED_ENUM:
299 ret = capture_enum(writer, output);
300 if (ret) {
301 WARN_ON_ONCE(1);
302 goto end;
303 }
304 break;
305 default:
306 ret = -1;
307 WARN_ON(1);
308 }
309end:
310 return ret;
311}
312
313static
314int notification_append_empty_capture(
315 struct lttng_event_notifier_notification *notif)
316{
317 int ret = lttng_msgpack_write_nil(&notif->writer);
318 if (ret)
319 WARN_ON_ONCE(1);
320
321 return ret;
322}
323
324static
325int notification_init(struct lttng_event_notifier_notification *notif,
326 struct lttng_event_notifier *event_notifier)
327{
328 struct lttng_msgpack_writer *writer = &notif->writer;
329 int ret = 0;
330
331 notif->has_captures = false;
332
333 if (event_notifier->num_captures > 0) {
334 lttng_msgpack_writer_init(writer, notif->capture_buf,
335 CAPTURE_BUFFER_SIZE);
336
337 ret = lttng_msgpack_begin_array(writer, event_notifier->num_captures);
338 if (ret) {
339 WARN_ON_ONCE(1);
340 goto end;
341 }
342
343 notif->has_captures = true;
344 }
345
346end:
347 return ret;
348}
349
99f52fcc
FD
350static
351void record_error(struct lttng_event_notifier *event_notifier)
352{
353
354 struct lttng_event_notifier_group *event_notifier_group = event_notifier->group;
355 size_t dimension_index[1];
356 int ret;
357
358 dimension_index[0] = event_notifier->error_counter_index;
359
360 ret = event_notifier_group->error_counter->ops->counter_add(
361 event_notifier_group->error_counter->counter,
362 dimension_index, 1);
363 if (ret)
364 WARN_ON_ONCE(1);
365}
366
99d223ad
FD
367static
368void notification_send(struct lttng_event_notifier_notification *notif,
369 struct lttng_event_notifier *event_notifier)
21f58fb7
FD
370{
371 struct lttng_event_notifier_group *event_notifier_group = event_notifier->group;
372 struct lib_ring_buffer_ctx ctx;
99d223ad
FD
373 struct lttng_kernel_event_notifier_notification kernel_notif;
374 size_t capture_buffer_content_len, reserve_size;
21f58fb7
FD
375 int ret;
376
99d223ad
FD
377 reserve_size = sizeof(kernel_notif);
378 kernel_notif.token = event_notifier->user_token;
21f58fb7 379
99d223ad
FD
380 if (notif->has_captures) {
381 capture_buffer_content_len = notif->writer.write_pos - notif->writer.buffer;
382 } else {
383 capture_buffer_content_len = 0;
384 }
385
386 WARN_ON_ONCE(capture_buffer_content_len > CAPTURE_BUFFER_SIZE);
387
388 reserve_size += capture_buffer_content_len;
389 kernel_notif.capture_buf_size = capture_buffer_content_len;
390
391 lib_ring_buffer_ctx_init(&ctx, event_notifier_group->chan, NULL, reserve_size,
392 lttng_alignof(kernel_notif), -1);
21f58fb7
FD
393 ret = event_notifier_group->ops->event_reserve(&ctx, 0);
394 if (ret < 0) {
99f52fcc 395 record_error(event_notifier);
21f58fb7
FD
396 return;
397 }
99d223ad
FD
398
399 lib_ring_buffer_align_ctx(&ctx, lttng_alignof(kernel_notif));
400
401 /* Write the notif structure. */
402 event_notifier_group->ops->event_write(&ctx, &kernel_notif,
403 sizeof(kernel_notif));
404
405 /*
406 * Write the capture buffer. No need to realigned as the below is a raw
407 * char* buffer.
408 */
409 event_notifier_group->ops->event_write(&ctx, &notif->capture_buf,
410 capture_buffer_content_len);
411
21f58fb7
FD
412 event_notifier_group->ops->event_commit(&ctx);
413 irq_work_queue(&event_notifier_group->wakeup_pending);
414}
99d223ad
FD
415
416void lttng_event_notifier_notification_send(struct lttng_event_notifier *event_notifier,
417 struct lttng_probe_ctx *lttng_probe_ctx,
418 const char *stack_data)
419{
420 struct lttng_event_notifier_notification notif = { 0 };
421 int ret;
422
423 if (unlikely(!READ_ONCE(event_notifier->enabled)))
424 return;
425
426 ret = notification_init(&notif, event_notifier);
427 if (ret) {
428 WARN_ON_ONCE(1);
429 goto end;
430 }
431
432 if (unlikely(!list_empty(&event_notifier->capture_bytecode_runtime_head))) {
433 struct lttng_bytecode_runtime *capture_bc_runtime;
434
435 /*
436 * Iterate over all the capture bytecodes. If the interpreter
437 * functions returns successfully, append the value of the
438 * `output` parameter to the capture buffer. If the interpreter
439 * fails, append an empty capture to the buffer.
440 */
441 list_for_each_entry(capture_bc_runtime,
442 &event_notifier->capture_bytecode_runtime_head, node) {
443 struct lttng_interpreter_output output;
444
445 if (capture_bc_runtime->interpreter_funcs.capture(capture_bc_runtime,
446 lttng_probe_ctx, stack_data, &output) & LTTNG_INTERPRETER_RECORD_FLAG)
447 ret = notification_append_capture(&notif, &output);
448 else
449 ret = notification_append_empty_capture(&notif);
450
451 if (ret)
452 printk(KERN_WARNING "Error appending capture to notification");
453 }
454 }
455
456 /*
457 * Send the notification (including the capture buffer) to the
458 * sessiond.
459 */
460 notification_send(&notif, event_notifier);
461end:
462 return;
463}
This page took 0.040947 seconds and 4 git commands to generate.