SoW-2019-0002: Dynamic Snapshot
[lttng-tools.git] / src / common / trigger.c
1 /*
2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <lttng/trigger/trigger-internal.h>
9 #include <lttng/condition/condition-internal.h>
10 #include <lttng/condition/event-rule.h>
11 #include <lttng/condition/buffer-usage.h>
12 #include <lttng/event-rule/event-rule-internal.h>
13 #include <lttng/action/action-internal.h>
14 #include <lttng/domain.h>
15 #include <common/error.h>
16 #include <common/dynamic-array.h>
17 #include <assert.h>
18 #include <inttypes.h>
19
20 static void lttng_trigger_set_internal_object_ownership(
21 struct lttng_trigger *trigger)
22 {
23 /*
24 * This is necessary to faciliate the object destroy phase. A trigger
25 * created by a client does not OWN the internal objects (condition and
26 * action) but when a trigger object is created on the sessiond side or
27 * for listing triggers (mostly via create_from_buffer) the object is
28 * the owner of the internal objects. Hence, we set the ownership bool
29 * to true, in such case, to facilitate object lifetime management and
30 * internal ownership.
31 *
32 * TODO: I'm open to any other solution
33 */
34 assert(trigger);
35 trigger->owns_internal_objects = true;
36 }
37
38 LTTNG_HIDDEN
39 bool lttng_trigger_validate(const struct lttng_trigger *trigger)
40 {
41 bool valid;
42
43 if (!trigger) {
44 valid = false;
45 goto end;
46 }
47
48 valid = lttng_condition_validate(trigger->condition) &&
49 lttng_action_validate(trigger->action);
50 end:
51 return valid;
52 }
53
54 struct lttng_trigger *lttng_trigger_create(
55 struct lttng_condition *condition,
56 struct lttng_action *action)
57 {
58 struct lttng_trigger *trigger = NULL;
59
60 if (!condition || !action) {
61 goto end;
62 }
63
64 trigger = zmalloc(sizeof(struct lttng_trigger));
65 if (!trigger) {
66 goto end;
67 }
68
69 urcu_ref_init(&trigger->ref);
70 trigger->owns_internal_objects = false;
71 trigger->firing_policy.type = LTTNG_TRIGGER_FIRE_EVERY_N;
72 trigger->firing_policy.threshold = 1;
73 trigger->condition = condition;
74 trigger->action = action;
75
76 trigger->creds.set = false;
77
78 end:
79 return trigger;
80 }
81
82 struct lttng_condition *lttng_trigger_get_condition(
83 struct lttng_trigger *trigger)
84 {
85 return trigger ? trigger->condition : NULL;
86 }
87
88 const struct lttng_condition *lttng_trigger_get_const_condition(
89 const struct lttng_trigger *trigger)
90 {
91 return trigger ? trigger->condition : NULL;
92 }
93
94 struct lttng_action *lttng_trigger_get_action(
95 struct lttng_trigger *trigger)
96 {
97 return trigger ? trigger->action : NULL;
98 }
99
100 const struct lttng_action *lttng_trigger_get_const_action(
101 const struct lttng_trigger *trigger)
102 {
103 return trigger ? trigger->action : NULL;
104 }
105
106 static void trigger_destroy_ref(struct urcu_ref *ref)
107 {
108 struct lttng_trigger *trigger =
109 container_of(ref, struct lttng_trigger, ref);
110
111 if (trigger->owns_internal_objects) {
112 struct lttng_action *action = lttng_trigger_get_action(trigger);
113 struct lttng_condition *condition =
114 lttng_trigger_get_condition(trigger);
115
116 assert(action);
117 assert(condition);
118 lttng_action_destroy(action);
119 lttng_condition_destroy(condition);
120 }
121
122 free(trigger->name);
123 free(trigger);
124 }
125
126 void lttng_trigger_destroy(struct lttng_trigger *trigger)
127 {
128 lttng_trigger_put(trigger);
129 }
130
131 LTTNG_HIDDEN
132 ssize_t lttng_trigger_create_from_buffer(
133 const struct lttng_buffer_view *src_view,
134 struct lttng_trigger **trigger)
135 {
136 ssize_t ret, offset = 0, condition_size, action_size, name_size = 0;
137 enum lttng_trigger_status status;
138 struct lttng_condition *condition = NULL;
139 struct lttng_action *action = NULL;
140 const struct lttng_trigger_comm *trigger_comm;
141 struct lttng_buffer_view condition_view;
142 struct lttng_buffer_view action_view;
143 struct lttng_buffer_view name_view;
144 const char *name = NULL;
145 unsigned long long firing_threshold;
146 enum lttng_trigger_firing_policy_type firing_policy;
147
148 if (!src_view || !trigger) {
149 ret = -1;
150 goto end;
151 }
152
153 /* lttng_trigger_comm header */
154 trigger_comm = (const struct lttng_trigger_comm *) src_view->data;
155 offset += sizeof(*trigger_comm);
156
157 firing_policy = trigger_comm->policy_type;
158 firing_threshold = trigger_comm->policy_threshold;
159 if (trigger_comm->name_length != 0) {
160 name_view = lttng_buffer_view_from_view(
161 src_view, offset, trigger_comm->name_length);
162 name = name_view.data;
163 if (trigger_comm->name_length == 1 ||
164 name[trigger_comm->name_length - 1] != '\0' ||
165 strlen(name) != trigger_comm->name_length - 1) {
166 ret = -1;
167 goto end;
168 }
169 offset += trigger_comm->name_length;
170 name_size = trigger_comm->name_length;
171 }
172
173 condition_view = lttng_buffer_view_from_view(src_view, offset, -1);
174
175 /* struct lttng_condition */
176 condition_size = lttng_condition_create_from_buffer(&condition_view,
177 &condition);
178 if (condition_size < 0) {
179 ret = condition_size;
180 goto end;
181 }
182 offset += condition_size;
183
184 /* struct lttng_action */
185 action_view = lttng_buffer_view_from_view(src_view, offset, -1);
186 action_size = lttng_action_create_from_buffer(&action_view, &action);
187 if (action_size < 0) {
188 ret = action_size;
189 goto end;
190 }
191 offset += action_size;
192
193 /* Unexpected size of inner-elements; the buffer is corrupted. */
194 if ((ssize_t) trigger_comm->length != condition_size + action_size + name_size) {
195 ret = -1;
196 goto error;
197 }
198
199 *trigger = lttng_trigger_create(condition, action);
200 if (!*trigger) {
201 ret = -1;
202 goto error;
203 }
204
205 /* Take ownership of the internal object from there */
206 lttng_trigger_set_internal_object_ownership(*trigger);
207 condition = NULL;
208 action = NULL;
209
210 if (name) {
211 status = lttng_trigger_set_name(*trigger, name);
212 if (status != LTTNG_TRIGGER_STATUS_OK) {
213 ret = -1;
214 goto end;
215 }
216 }
217
218 status = lttng_trigger_set_firing_policy(*trigger, firing_policy, firing_threshold);
219 if (status != LTTNG_TRIGGER_STATUS_OK) {
220 ret = -1;
221 goto end;
222 }
223
224 ret = offset;
225 end:
226 return ret;
227 error:
228 lttng_condition_destroy(condition);
229 lttng_action_destroy(action);
230 return ret;
231 }
232
233 /*
234 * Both elements are stored contiguously, see their "*_comm" structure
235 * for the detailed format.
236 */
237 LTTNG_HIDDEN
238 int lttng_trigger_serialize(const struct lttng_trigger *trigger,
239 struct lttng_dynamic_buffer *buf,
240 int *fd_to_send)
241 {
242 int ret;
243 size_t header_offset, size_before_payload, size_name;
244 struct lttng_trigger_comm trigger_comm = { 0 };
245 struct lttng_trigger_comm *header;
246
247 header_offset = buf->size;
248
249 if (trigger->name != NULL) {
250 size_name = strlen(trigger->name) + 1;
251 } else {
252 size_name = 0;
253 }
254
255 trigger_comm.name_length = size_name;
256 trigger_comm.policy_type = (uint8_t) trigger->firing_policy.type;
257 trigger_comm.policy_threshold = (uint64_t) trigger->firing_policy.threshold;
258
259 ret = lttng_dynamic_buffer_append(buf, &trigger_comm,
260 sizeof(trigger_comm));
261 if (ret) {
262 goto end;
263 }
264
265 size_before_payload = buf->size;
266
267 /* Trigger name */
268 ret = lttng_dynamic_buffer_append(buf, trigger->name, size_name);
269 if (ret) {
270 goto end;
271 }
272
273 ret = lttng_condition_serialize(trigger->condition, buf, fd_to_send);
274 if (ret) {
275 goto end;
276 }
277
278 ret = lttng_action_serialize(trigger->action, buf);
279 if (ret) {
280 goto end;
281 }
282
283 /* Update payload size. */
284 header = (struct lttng_trigger_comm *) ((char *) buf->data + header_offset);
285 header->length = buf->size - size_before_payload;
286 end:
287 return ret;
288 }
289
290 enum lttng_trigger_status lttng_trigger_set_name(struct lttng_trigger *trigger, const char* name)
291 {
292 char *name_copy = NULL;
293 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
294
295 if (!trigger || !name ||
296 strlen(name) == 0) {
297 status = LTTNG_TRIGGER_STATUS_INVALID;
298 goto end;
299 }
300
301 name_copy = strdup(name);
302 if (!name_copy) {
303 status = LTTNG_TRIGGER_STATUS_ERROR;
304 goto end;
305 }
306
307 if (trigger->name) {
308 free(trigger->name);
309 }
310
311 trigger->name = name_copy;
312 name_copy = NULL;
313 end:
314 return status;
315 }
316
317 enum lttng_trigger_status lttng_trigger_get_name(const struct lttng_trigger *trigger, const char **name)
318 {
319 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
320
321 if (!trigger || !name) {
322 status = LTTNG_TRIGGER_STATUS_INVALID;
323 goto end;
324 }
325
326 if (!trigger->name) {
327 status = LTTNG_TRIGGER_STATUS_UNSET;
328 }
329
330 *name = trigger->name;
331 end:
332 return status;
333 }
334
335 LTTNG_HIDDEN
336 int lttng_trigger_assign(struct lttng_trigger *dst,
337 const struct lttng_trigger *src)
338 {
339 int ret = 0;
340 enum lttng_trigger_status status;
341 /* todo some validation */
342
343 status = lttng_trigger_set_name(dst, src->name);
344 if (status != LTTNG_TRIGGER_STATUS_OK) {
345 ret = -1;
346 ERR("Failed to set name for trigger");
347 goto end;
348 }
349 end:
350 return ret;
351 }
352
353 LTTNG_HIDDEN
354 void lttng_trigger_set_key(struct lttng_trigger *trigger, uint64_t key)
355 {
356 assert(trigger);
357 trigger->key.value = key;
358 trigger->key.set = true;
359 }
360
361 LTTNG_HIDDEN
362 uint64_t lttng_trigger_get_key(const struct lttng_trigger *trigger)
363 {
364 assert(trigger);
365
366 assert(trigger->key.set == true);
367 return trigger->key.value;
368 }
369
370 LTTNG_HIDDEN
371 int lttng_trigger_generate_name(struct lttng_trigger *trigger, uint64_t offset)
372 {
373 int ret = 0;
374 char *generated_name = NULL;
375 assert(trigger->key.set);
376
377 ret = asprintf(&generated_name, "T%" PRIu64 "", trigger->key.value + offset);
378 if (ret < 0) {
379 ERR("Failed to generate trigger name");
380 ret = -1;
381 goto end;
382 }
383
384 if (trigger->name) {
385 free(trigger->name);
386 }
387 trigger->name = generated_name;
388 end:
389 return ret;
390 }
391
392 LTTNG_HIDDEN
393 bool lttng_trigger_is_equal(
394 const struct lttng_trigger *a, const struct lttng_trigger *b)
395 {
396 /* TODO: Optimization: for now a trigger with a firing policy that is
397 * not the same even if the conditions and actions is the same is
398 * treated as a "completely" different trigger. In a perfect world we
399 * would simply add a supplemental counter internally (sessiond side) to
400 * remove overhead on the tracer side.
401 */
402 if (a->firing_policy.type != b->firing_policy.type) {
403 return false;
404 }
405
406 if (a->firing_policy.threshold != b->firing_policy.threshold) {
407 return false;
408 }
409
410 /*
411 * Name is not taken into account since it is cosmetic only
412 */
413 if (!lttng_condition_is_equal(a->condition, b->condition)) {
414 return false;
415 }
416 if (!lttng_action_is_equal(a->action, b->action)) {
417 return false;
418 }
419
420 return true;
421 }
422
423 static void delete_trigger_array_element(void *ptr)
424 {
425 struct lttng_trigger *trigger = ptr;
426 lttng_trigger_destroy(trigger);
427 }
428
429 LTTNG_HIDDEN
430 struct lttng_triggers *lttng_triggers_create(void)
431 {
432 struct lttng_triggers *triggers = NULL;
433
434 triggers = zmalloc(sizeof(*triggers));
435 if (!triggers) {
436 goto error;
437 }
438
439 lttng_dynamic_pointer_array_init(&triggers->array, delete_trigger_array_element);
440
441 return triggers;
442 error:
443 free(triggers);
444 return NULL;
445 }
446
447 LTTNG_HIDDEN
448 struct lttng_trigger *lttng_triggers_get_pointer_of_index(
449 const struct lttng_triggers *triggers, unsigned int index)
450 {
451 assert(triggers);
452 if (index >= lttng_dynamic_pointer_array_get_count(&triggers->array)) {
453 return NULL;
454 }
455 return lttng_dynamic_pointer_array_get_pointer(&triggers->array, index);
456 }
457
458 LTTNG_HIDDEN
459 int lttng_triggers_add(
460 struct lttng_triggers *triggers, struct lttng_trigger *trigger)
461 {
462 assert(triggers);
463 assert(trigger);
464
465 return lttng_dynamic_pointer_array_add_pointer(&triggers->array, trigger);
466 }
467
468 const struct lttng_trigger *lttng_triggers_get_at_index(
469 const struct lttng_triggers *triggers, unsigned int index)
470 {
471 assert(triggers);
472 return lttng_triggers_get_pointer_of_index(triggers, index);
473 }
474
475 enum lttng_trigger_status lttng_triggers_get_count(const struct lttng_triggers *triggers, unsigned int *count)
476 {
477 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
478
479 if (!triggers || !count) {
480 status = LTTNG_TRIGGER_STATUS_INVALID;
481 goto end;
482 }
483
484 *count = lttng_dynamic_pointer_array_get_count(&triggers->array);
485 end:
486 return status;
487 }
488
489 void lttng_triggers_destroy(struct lttng_triggers *triggers)
490 {
491 if (!triggers) {
492 return;
493 }
494
495 lttng_dynamic_pointer_array_reset(&triggers->array);
496 free(triggers);
497 }
498
499 int lttng_triggers_serialize(const struct lttng_triggers *triggers,
500 struct lttng_dynamic_buffer *buffer)
501 {
502 int ret;
503 unsigned int count;
504 size_t header_offset, size_before_payload;
505 struct lttng_triggers_comm triggers_comm = { 0 };
506 struct lttng_triggers_comm *header;
507 struct lttng_trigger *trigger;
508 enum lttng_trigger_status status;
509
510 header_offset = buffer->size;
511
512 status = lttng_triggers_get_count(triggers, &count);
513 if (status != LTTNG_TRIGGER_STATUS_OK) {
514 ret = LTTNG_ERR_INVALID;
515 goto end;
516 }
517
518 triggers_comm.count = count;
519
520 ret = lttng_dynamic_buffer_append(buffer, &triggers_comm,
521 sizeof(triggers_comm));
522 if (ret) {
523 goto end;
524 }
525
526 size_before_payload = buffer->size;
527
528 for (int i = 0; i < count; i++) {
529 trigger = lttng_triggers_get_pointer_of_index(triggers, i);
530 if (!trigger) {
531 assert(0);
532 }
533
534 ret = lttng_trigger_serialize(trigger, buffer, NULL);
535 if (ret) {
536 goto end;
537 }
538 }
539
540 /* Update payload size. */
541 header = (struct lttng_triggers_comm *) ((char *) buffer->data + header_offset);
542 header->length = buffer->size - size_before_payload;
543 end:
544 return ret;
545 }
546
547 LTTNG_HIDDEN
548 ssize_t lttng_triggers_create_from_buffer(
549 const struct lttng_buffer_view *src_view,
550 struct lttng_triggers **triggers)
551 {
552 ssize_t ret, offset = 0, trigger_size, triggers_size = 0;
553 const struct lttng_triggers_comm *triggers_comm;
554 struct lttng_buffer_view trigger_view;
555 struct lttng_triggers *local_triggers = NULL;
556
557 if (!src_view || !triggers) {
558 ret = -1;
559 goto error;
560 }
561
562 /* lttng_trigger_comms header */
563 triggers_comm = (const struct lttng_triggers_comm *) src_view->data;
564 offset += sizeof(*triggers_comm);
565
566 local_triggers = lttng_triggers_create();
567 if (!local_triggers) {
568 ret = -1;
569 goto error;
570 }
571
572 for (int i = 0; i < triggers_comm->count; i++) {
573 struct lttng_trigger *trigger = NULL;
574 trigger_view = lttng_buffer_view_from_view(src_view, offset, -1);
575 trigger_size = lttng_trigger_create_from_buffer(&trigger_view,
576 &trigger);
577 if (trigger_size < 0) {
578 ret = trigger_size;
579 goto error;
580 }
581
582 /* Pass ownership of the trigger to the collection */
583 ret = lttng_triggers_add(local_triggers, trigger);
584 if (ret < 0) {
585 assert(0);
586 }
587 trigger = NULL;
588
589 offset += trigger_size;
590 triggers_size += trigger_size;
591 }
592
593 /* Unexpected size of inner-elements; the buffer is corrupted. */
594 if ((ssize_t) triggers_comm->length != triggers_size) {
595 ret = -1;
596 goto error;
597 }
598
599 /* Pass ownership to caller */
600 *triggers = local_triggers;
601 local_triggers = NULL;
602
603 ret = offset;
604 error:
605
606 lttng_triggers_destroy(local_triggers);
607 return ret;
608 }
609
610 LTTNG_HIDDEN
611 const struct lttng_credentials *lttng_trigger_get_credentials(
612 const struct lttng_trigger *trigger)
613 {
614 assert(trigger->creds.set);
615 return &(trigger->creds.credentials);
616 }
617
618 LTTNG_HIDDEN
619 void lttng_trigger_set_credentials(
620 struct lttng_trigger *trigger, uid_t uid, gid_t gid)
621 {
622 trigger->creds.credentials.uid = uid;
623 trigger->creds.credentials.gid = gid;
624 trigger->creds.set = true;
625 }
626
627 enum lttng_trigger_status lttng_trigger_set_firing_policy(
628 struct lttng_trigger *trigger,
629 enum lttng_trigger_firing_policy_type policy_type,
630 unsigned long long threshold)
631 {
632 enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
633 assert(trigger);
634
635 if (threshold < 1) {
636 ret = LTTNG_TRIGGER_STATUS_INVALID;
637 goto end;
638 }
639
640 trigger->firing_policy.type = policy_type;
641 trigger->firing_policy.threshold = threshold;
642
643 end:
644 return ret;
645 }
646
647 enum lttng_trigger_status lttng_trigger_get_firing_policy(
648 const struct lttng_trigger *trigger,
649 enum lttng_trigger_firing_policy_type *policy_type,
650 unsigned long long *threshold)
651 {
652 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
653
654 if (!trigger || !policy_type || !threshold) {
655 status = LTTNG_TRIGGER_STATUS_INVALID;
656 goto end;
657 }
658
659 *policy_type = trigger->firing_policy.type;
660 *threshold = trigger->firing_policy.threshold;
661
662 end:
663 return status;
664 }
665
666 LTTNG_HIDDEN
667 bool lttng_trigger_is_ready_to_fire(struct lttng_trigger *trigger)
668 {
669 assert(trigger);
670 bool ready_to_fire = false;
671
672 trigger->firing_policy.current_count++;
673
674 switch (trigger->firing_policy.type) {
675 case LTTNG_TRIGGER_FIRE_EVERY_N:
676 if (trigger->firing_policy.current_count == trigger->firing_policy.threshold) {
677 trigger->firing_policy.current_count = 0;
678 ready_to_fire = true;
679 }
680 break;
681 case LTTNG_TRIGGER_FIRE_ONCE_AFTER_N:
682 if (trigger->firing_policy.current_count == trigger->firing_policy.threshold) {
683 /* TODO: remove the trigger of at least deactivate it on
684 * the tracers side to remove any work overhead on the
685 * traced application or kernel since the trigger will
686 * never fire again.
687 * Still this branch should be left here since event
688 * could still be in the pipe. These will be discarded.
689 */
690 ready_to_fire = true;
691 }
692 break;
693 default:
694 assert(0);
695 };
696
697 return ready_to_fire;
698 }
699
700 LTTNG_HIDDEN
701 void lttng_trigger_get(struct lttng_trigger *trigger)
702 {
703 urcu_ref_get(&trigger->ref);
704 }
705
706 LTTNG_HIDDEN
707 void lttng_trigger_put(struct lttng_trigger *trigger)
708 {
709 if (!trigger) {
710 return;
711 }
712
713 urcu_ref_put(&trigger->ref , trigger_destroy_ref);
714 }
715
716 LTTNG_HIDDEN
717 enum lttng_domain_type lttng_trigger_get_underlying_domain_type_restriction(
718 const struct lttng_trigger *trigger)
719 {
720 enum lttng_domain_type type = LTTNG_DOMAIN_NONE;
721 const struct lttng_event_rule *event_rule;
722 enum lttng_condition_status c_status;
723 enum lttng_condition_type c_type;
724
725 assert(trigger);
726 assert(trigger->condition);
727 c_type = lttng_condition_get_type(trigger->condition);
728 if (c_type == LTTNG_CONDITION_TYPE_UNKNOWN) {
729 assert(0);
730 }
731
732 switch (c_type) {
733 case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
734 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
735 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
736 type = LTTNG_DOMAIN_NONE;
737 break;
738 case LTTNG_CONDITION_TYPE_EVENT_RULE_HIT:
739 c_status = lttng_condition_event_rule_get_rule(
740 trigger->condition, &event_rule);
741 if (c_status != LTTNG_CONDITION_STATUS_OK) {
742 /* The condition object is invalid */
743 assert(0);
744 }
745
746 type = lttng_event_rule_get_domain_type(event_rule);
747 break;
748 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
749 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
750 c_status = lttng_condition_buffer_usage_get_domain_type(
751 trigger->condition, &type);
752 if (c_status != LTTNG_CONDITION_STATUS_OK) {
753 /* The condition object is invalid */
754 assert(0);
755 }
756 break;
757 default:
758 type = LTTNG_DOMAIN_NONE;
759 break;
760 }
761
762 return type;
763 }
This page took 0.071689 seconds and 5 git commands to generate.