Fix: session info reference is not put on unhandled condition type
[lttng-tools.git] / src / bin / lttng-sessiond / notification-thread-events.c
... / ...
CommitLineData
1/*
2 * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18#define _LGPL_SOURCE
19#include <urcu.h>
20#include <urcu/rculfhash.h>
21
22#include <common/defaults.h>
23#include <common/error.h>
24#include <common/futex.h>
25#include <common/unix.h>
26#include <common/dynamic-buffer.h>
27#include <common/hashtable/utils.h>
28#include <common/sessiond-comm/sessiond-comm.h>
29#include <common/macros.h>
30#include <lttng/condition/condition.h>
31#include <lttng/action/action-internal.h>
32#include <lttng/notification/notification-internal.h>
33#include <lttng/condition/condition-internal.h>
34#include <lttng/condition/buffer-usage-internal.h>
35#include <lttng/condition/session-consumed-size-internal.h>
36#include <lttng/condition/session-rotation-internal.h>
37#include <lttng/notification/channel-internal.h>
38
39#include <time.h>
40#include <unistd.h>
41#include <assert.h>
42#include <inttypes.h>
43#include <fcntl.h>
44
45#include "notification-thread.h"
46#include "notification-thread-events.h"
47#include "notification-thread-commands.h"
48#include "lttng-sessiond.h"
49#include "kernel.h"
50
51#define CLIENT_POLL_MASK_IN (LPOLLIN | LPOLLERR | LPOLLHUP | LPOLLRDHUP)
52#define CLIENT_POLL_MASK_IN_OUT (CLIENT_POLL_MASK_IN | LPOLLOUT)
53
54enum lttng_object_type {
55 LTTNG_OBJECT_TYPE_UNKNOWN,
56 LTTNG_OBJECT_TYPE_NONE,
57 LTTNG_OBJECT_TYPE_CHANNEL,
58 LTTNG_OBJECT_TYPE_SESSION,
59};
60
61struct lttng_trigger_list_element {
62 /* No ownership of the trigger object is assumed. */
63 const struct lttng_trigger *trigger;
64 struct cds_list_head node;
65};
66
67struct lttng_channel_trigger_list {
68 struct channel_key channel_key;
69 /* List of struct lttng_trigger_list_element. */
70 struct cds_list_head list;
71 /* Node in the channel_triggers_ht */
72 struct cds_lfht_node channel_triggers_ht_node;
73};
74
75/*
76 * List of triggers applying to a given session.
77 *
78 * See:
79 * - lttng_session_trigger_list_create()
80 * - lttng_session_trigger_list_build()
81 * - lttng_session_trigger_list_destroy()
82 * - lttng_session_trigger_list_add()
83 */
84struct lttng_session_trigger_list {
85 /*
86 * Not owned by this; points to the session_info structure's
87 * session name.
88 */
89 const char *session_name;
90 /* List of struct lttng_trigger_list_element. */
91 struct cds_list_head list;
92 /* Node in the session_triggers_ht */
93 struct cds_lfht_node session_triggers_ht_node;
94 /*
95 * Weak reference to the notification system's session triggers
96 * hashtable.
97 *
98 * The session trigger list structure structure is owned by
99 * the session's session_info.
100 *
101 * The session_info is kept alive the the channel_infos holding a
102 * reference to it (reference counting). When those channels are
103 * destroyed (at runtime or on teardown), the reference they hold
104 * to the session_info are released. On destruction of session_info,
105 * session_info_destroy() will remove the list of triggers applying
106 * to this session from the notification system's state.
107 *
108 * This implies that the session_triggers_ht must be destroyed
109 * after the channels.
110 */
111 struct cds_lfht *session_triggers_ht;
112 /* Used for delayed RCU reclaim. */
113 struct rcu_head rcu_node;
114};
115
116struct lttng_trigger_ht_element {
117 struct lttng_trigger *trigger;
118 struct cds_lfht_node node;
119};
120
121struct lttng_condition_list_element {
122 struct lttng_condition *condition;
123 struct cds_list_head node;
124};
125
126struct notification_client_list_element {
127 struct notification_client *client;
128 struct cds_list_head node;
129};
130
131struct notification_client_list {
132 const struct lttng_trigger *trigger;
133 struct cds_list_head list;
134 struct cds_lfht_node notification_trigger_ht_node;
135};
136
137struct notification_client {
138 int socket;
139 /* Client protocol version. */
140 uint8_t major, minor;
141 uid_t uid;
142 gid_t gid;
143 /*
144 * Indicates if the credentials and versions of the client have been
145 * checked.
146 */
147 bool validated;
148 /*
149 * Conditions to which the client's notification channel is subscribed.
150 * List of struct lttng_condition_list_node. The condition member is
151 * owned by the client.
152 */
153 struct cds_list_head condition_list;
154 struct cds_lfht_node client_socket_ht_node;
155 struct {
156 struct {
157 /*
158 * During the reception of a message, the reception
159 * buffers' "size" is set to contain the current
160 * message's complete payload.
161 */
162 struct lttng_dynamic_buffer buffer;
163 /* Bytes left to receive for the current message. */
164 size_t bytes_to_receive;
165 /* Type of the message being received. */
166 enum lttng_notification_channel_message_type msg_type;
167 /*
168 * Indicates whether or not credentials are expected
169 * from the client.
170 */
171 bool expect_creds;
172 /*
173 * Indicates whether or not credentials were received
174 * from the client.
175 */
176 bool creds_received;
177 /* Only used during credentials reception. */
178 lttng_sock_cred creds;
179 } inbound;
180 struct {
181 /*
182 * Indicates whether or not a notification addressed to
183 * this client was dropped because a command reply was
184 * already buffered.
185 *
186 * A notification is dropped whenever the buffer is not
187 * empty.
188 */
189 bool dropped_notification;
190 /*
191 * Indicates whether or not a command reply is already
192 * buffered. In this case, it means that the client is
193 * not consuming command replies before emitting a new
194 * one. This could be caused by a protocol error or a
195 * misbehaving/malicious client.
196 */
197 bool queued_command_reply;
198 struct lttng_dynamic_buffer buffer;
199 } outbound;
200 } communication;
201};
202
203struct channel_state_sample {
204 struct channel_key key;
205 struct cds_lfht_node channel_state_ht_node;
206 uint64_t highest_usage;
207 uint64_t lowest_usage;
208 uint64_t channel_total_consumed;
209};
210
211static unsigned long hash_channel_key(struct channel_key *key);
212static int evaluate_buffer_condition(const struct lttng_condition *condition,
213 struct lttng_evaluation **evaluation,
214 const struct notification_thread_state *state,
215 const struct channel_state_sample *previous_sample,
216 const struct channel_state_sample *latest_sample,
217 uint64_t previous_session_consumed_total,
218 uint64_t latest_session_consumed_total,
219 struct channel_info *channel_info);
220static
221int send_evaluation_to_clients(const struct lttng_trigger *trigger,
222 const struct lttng_evaluation *evaluation,
223 struct notification_client_list *client_list,
224 struct notification_thread_state *state,
225 uid_t channel_uid, gid_t channel_gid);
226
227
228/* session_info API */
229static
230void session_info_destroy(void *_data);
231static
232void session_info_get(struct session_info *session_info);
233static
234void session_info_put(struct session_info *session_info);
235static
236struct session_info *session_info_create(const char *name,
237 uid_t uid, gid_t gid,
238 struct lttng_session_trigger_list *trigger_list,
239 struct cds_lfht *sessions_ht);
240static
241void session_info_add_channel(struct session_info *session_info,
242 struct channel_info *channel_info);
243static
244void session_info_remove_channel(struct session_info *session_info,
245 struct channel_info *channel_info);
246
247/* lttng_session_trigger_list API */
248static
249struct lttng_session_trigger_list *lttng_session_trigger_list_create(
250 const char *session_name,
251 struct cds_lfht *session_triggers_ht);
252static
253struct lttng_session_trigger_list *lttng_session_trigger_list_build(
254 const struct notification_thread_state *state,
255 const char *session_name);
256static
257void lttng_session_trigger_list_destroy(
258 struct lttng_session_trigger_list *list);
259static
260int lttng_session_trigger_list_add(struct lttng_session_trigger_list *list,
261 const struct lttng_trigger *trigger);
262
263
264static
265int match_client(struct cds_lfht_node *node, const void *key)
266{
267 /* This double-cast is intended to supress pointer-to-cast warning. */
268 int socket = (int) (intptr_t) key;
269 struct notification_client *client;
270
271 client = caa_container_of(node, struct notification_client,
272 client_socket_ht_node);
273
274 return !!(client->socket == socket);
275}
276
277static
278int match_channel_trigger_list(struct cds_lfht_node *node, const void *key)
279{
280 struct channel_key *channel_key = (struct channel_key *) key;
281 struct lttng_channel_trigger_list *trigger_list;
282
283 trigger_list = caa_container_of(node, struct lttng_channel_trigger_list,
284 channel_triggers_ht_node);
285
286 return !!((channel_key->key == trigger_list->channel_key.key) &&
287 (channel_key->domain == trigger_list->channel_key.domain));
288}
289
290static
291int match_session_trigger_list(struct cds_lfht_node *node, const void *key)
292{
293 const char *session_name = (const char *) key;
294 struct lttng_session_trigger_list *trigger_list;
295
296 trigger_list = caa_container_of(node, struct lttng_session_trigger_list,
297 session_triggers_ht_node);
298
299 return !!(strcmp(trigger_list->session_name, session_name) == 0);
300}
301
302static
303int match_channel_state_sample(struct cds_lfht_node *node, const void *key)
304{
305 struct channel_key *channel_key = (struct channel_key *) key;
306 struct channel_state_sample *sample;
307
308 sample = caa_container_of(node, struct channel_state_sample,
309 channel_state_ht_node);
310
311 return !!((channel_key->key == sample->key.key) &&
312 (channel_key->domain == sample->key.domain));
313}
314
315static
316int match_channel_info(struct cds_lfht_node *node, const void *key)
317{
318 struct channel_key *channel_key = (struct channel_key *) key;
319 struct channel_info *channel_info;
320
321 channel_info = caa_container_of(node, struct channel_info,
322 channels_ht_node);
323
324 return !!((channel_key->key == channel_info->key.key) &&
325 (channel_key->domain == channel_info->key.domain));
326}
327
328static
329int match_condition(struct cds_lfht_node *node, const void *key)
330{
331 struct lttng_condition *condition_key = (struct lttng_condition *) key;
332 struct lttng_trigger_ht_element *trigger;
333 struct lttng_condition *condition;
334
335 trigger = caa_container_of(node, struct lttng_trigger_ht_element,
336 node);
337 condition = lttng_trigger_get_condition(trigger->trigger);
338 assert(condition);
339
340 return !!lttng_condition_is_equal(condition_key, condition);
341}
342
343static
344int match_client_list_condition(struct cds_lfht_node *node, const void *key)
345{
346 struct lttng_condition *condition_key = (struct lttng_condition *) key;
347 struct notification_client_list *client_list;
348 const struct lttng_condition *condition;
349
350 assert(condition_key);
351
352 client_list = caa_container_of(node, struct notification_client_list,
353 notification_trigger_ht_node);
354 condition = lttng_trigger_get_const_condition(client_list->trigger);
355
356 return !!lttng_condition_is_equal(condition_key, condition);
357}
358
359static
360int match_session(struct cds_lfht_node *node, const void *key)
361{
362 const char *name = key;
363 struct session_info *session_info = caa_container_of(
364 node, struct session_info, sessions_ht_node);
365
366 return !strcmp(session_info->name, name);
367}
368
369static
370unsigned long lttng_condition_buffer_usage_hash(
371 const struct lttng_condition *_condition)
372{
373 unsigned long hash;
374 unsigned long condition_type;
375 struct lttng_condition_buffer_usage *condition;
376
377 condition = container_of(_condition,
378 struct lttng_condition_buffer_usage, parent);
379
380 condition_type = (unsigned long) condition->parent.type;
381 hash = hash_key_ulong((void *) condition_type, lttng_ht_seed);
382 if (condition->session_name) {
383 hash ^= hash_key_str(condition->session_name, lttng_ht_seed);
384 }
385 if (condition->channel_name) {
386 hash ^= hash_key_str(condition->channel_name, lttng_ht_seed);
387 }
388 if (condition->domain.set) {
389 hash ^= hash_key_ulong(
390 (void *) condition->domain.type,
391 lttng_ht_seed);
392 }
393 if (condition->threshold_ratio.set) {
394 uint64_t val;
395
396 val = condition->threshold_ratio.value * (double) UINT32_MAX;
397 hash ^= hash_key_u64(&val, lttng_ht_seed);
398 } else if (condition->threshold_bytes.set) {
399 uint64_t val;
400
401 val = condition->threshold_bytes.value;
402 hash ^= hash_key_u64(&val, lttng_ht_seed);
403 }
404 return hash;
405}
406
407static
408unsigned long lttng_condition_session_consumed_size_hash(
409 const struct lttng_condition *_condition)
410{
411 unsigned long hash;
412 unsigned long condition_type =
413 (unsigned long) LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE;
414 struct lttng_condition_session_consumed_size *condition;
415 uint64_t val;
416
417 condition = container_of(_condition,
418 struct lttng_condition_session_consumed_size, parent);
419
420 hash = hash_key_ulong((void *) condition_type, lttng_ht_seed);
421 if (condition->session_name) {
422 hash ^= hash_key_str(condition->session_name, lttng_ht_seed);
423 }
424 val = condition->consumed_threshold_bytes.value;
425 hash ^= hash_key_u64(&val, lttng_ht_seed);
426 return hash;
427}
428
429static
430unsigned long lttng_condition_session_rotation_hash(
431 const struct lttng_condition *_condition)
432{
433 unsigned long hash, condition_type;
434 struct lttng_condition_session_rotation *condition;
435
436 condition = container_of(_condition,
437 struct lttng_condition_session_rotation, parent);
438 condition_type = (unsigned long) condition->parent.type;
439 hash = hash_key_ulong((void *) condition_type, lttng_ht_seed);
440 assert(condition->session_name);
441 hash ^= hash_key_str(condition->session_name, lttng_ht_seed);
442 return hash;
443}
444
445/*
446 * The lttng_condition hashing code is kept in this file (rather than
447 * condition.c) since it makes use of GPLv2 code (hashtable utils), which we
448 * don't want to link in liblttng-ctl.
449 */
450static
451unsigned long lttng_condition_hash(const struct lttng_condition *condition)
452{
453 switch (condition->type) {
454 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
455 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
456 return lttng_condition_buffer_usage_hash(condition);
457 case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
458 return lttng_condition_session_consumed_size_hash(condition);
459 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
460 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
461 return lttng_condition_session_rotation_hash(condition);
462 default:
463 ERR("[notification-thread] Unexpected condition type caught");
464 abort();
465 }
466}
467
468static
469unsigned long hash_channel_key(struct channel_key *key)
470{
471 unsigned long key_hash = hash_key_u64(&key->key, lttng_ht_seed);
472 unsigned long domain_hash = hash_key_ulong(
473 (void *) (unsigned long) key->domain, lttng_ht_seed);
474
475 return key_hash ^ domain_hash;
476}
477
478/*
479 * Get the type of object to which a given condition applies. Bindings let
480 * the notification system evaluate a trigger's condition when a given
481 * object's state is updated.
482 *
483 * For instance, a condition bound to a channel will be evaluated everytime
484 * the channel's state is changed by a channel monitoring sample.
485 */
486static
487enum lttng_object_type get_condition_binding_object(
488 const struct lttng_condition *condition)
489{
490 switch (lttng_condition_get_type(condition)) {
491 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
492 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
493 case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
494 return LTTNG_OBJECT_TYPE_CHANNEL;
495 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
496 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
497 return LTTNG_OBJECT_TYPE_SESSION;
498 default:
499 return LTTNG_OBJECT_TYPE_UNKNOWN;
500 }
501}
502
503static
504void channel_info_destroy(struct channel_info *channel_info)
505{
506 if (!channel_info) {
507 return;
508 }
509
510 if (channel_info->session_info) {
511 session_info_remove_channel(channel_info->session_info,
512 channel_info);
513 session_info_put(channel_info->session_info);
514 }
515 if (channel_info->name) {
516 free(channel_info->name);
517 }
518 free(channel_info);
519}
520
521/* Don't call directly, use the ref-counting mechanism. */
522static
523void session_info_destroy(void *_data)
524{
525 struct session_info *session_info = _data;
526 int ret;
527
528 assert(session_info);
529 if (session_info->channel_infos_ht) {
530 ret = cds_lfht_destroy(session_info->channel_infos_ht, NULL);
531 if (ret) {
532 ERR("[notification-thread] Failed to destroy channel information hash table");
533 }
534 }
535 lttng_session_trigger_list_destroy(session_info->trigger_list);
536
537 rcu_read_lock();
538 cds_lfht_del(session_info->sessions_ht,
539 &session_info->sessions_ht_node);
540 rcu_read_unlock();
541 free(session_info->name);
542 free(session_info);
543}
544
545static
546void session_info_get(struct session_info *session_info)
547{
548 if (!session_info) {
549 return;
550 }
551 lttng_ref_get(&session_info->ref);
552}
553
554static
555void session_info_put(struct session_info *session_info)
556{
557 if (!session_info) {
558 return;
559 }
560 lttng_ref_put(&session_info->ref);
561}
562
563static
564struct session_info *session_info_create(const char *name, uid_t uid, gid_t gid,
565 struct lttng_session_trigger_list *trigger_list,
566 struct cds_lfht *sessions_ht)
567{
568 struct session_info *session_info;
569
570 assert(name);
571
572 session_info = zmalloc(sizeof(*session_info));
573 if (!session_info) {
574 goto end;
575 }
576 lttng_ref_init(&session_info->ref, session_info_destroy);
577
578 session_info->channel_infos_ht = cds_lfht_new(DEFAULT_HT_SIZE,
579 1, 0, CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, NULL);
580 if (!session_info->channel_infos_ht) {
581 goto error;
582 }
583
584 cds_lfht_node_init(&session_info->sessions_ht_node);
585 session_info->name = strdup(name);
586 if (!session_info->name) {
587 goto error;
588 }
589 session_info->uid = uid;
590 session_info->gid = gid;
591 session_info->trigger_list = trigger_list;
592 session_info->sessions_ht = sessions_ht;
593end:
594 return session_info;
595error:
596 session_info_put(session_info);
597 return NULL;
598}
599
600static
601void session_info_add_channel(struct session_info *session_info,
602 struct channel_info *channel_info)
603{
604 rcu_read_lock();
605 cds_lfht_add(session_info->channel_infos_ht,
606 hash_channel_key(&channel_info->key),
607 &channel_info->session_info_channels_ht_node);
608 rcu_read_unlock();
609}
610
611static
612void session_info_remove_channel(struct session_info *session_info,
613 struct channel_info *channel_info)
614{
615 rcu_read_lock();
616 cds_lfht_del(session_info->channel_infos_ht,
617 &channel_info->session_info_channels_ht_node);
618 rcu_read_unlock();
619}
620
621static
622struct channel_info *channel_info_create(const char *channel_name,
623 struct channel_key *channel_key, uint64_t channel_capacity,
624 struct session_info *session_info)
625{
626 struct channel_info *channel_info = zmalloc(sizeof(*channel_info));
627
628 if (!channel_info) {
629 goto end;
630 }
631
632 cds_lfht_node_init(&channel_info->channels_ht_node);
633 cds_lfht_node_init(&channel_info->session_info_channels_ht_node);
634 memcpy(&channel_info->key, channel_key, sizeof(*channel_key));
635 channel_info->capacity = channel_capacity;
636
637 channel_info->name = strdup(channel_name);
638 if (!channel_info->name) {
639 goto error;
640 }
641
642 /*
643 * Set the references between session and channel infos:
644 * - channel_info holds a strong reference to session_info
645 * - session_info holds a weak reference to channel_info
646 */
647 session_info_get(session_info);
648 session_info_add_channel(session_info, channel_info);
649 channel_info->session_info = session_info;
650end:
651 return channel_info;
652error:
653 channel_info_destroy(channel_info);
654 return NULL;
655}
656
657/* RCU read lock must be held by the caller. */
658static
659struct notification_client_list *get_client_list_from_condition(
660 struct notification_thread_state *state,
661 const struct lttng_condition *condition)
662{
663 struct cds_lfht_node *node;
664 struct cds_lfht_iter iter;
665
666 cds_lfht_lookup(state->notification_trigger_clients_ht,
667 lttng_condition_hash(condition),
668 match_client_list_condition,
669 condition,
670 &iter);
671 node = cds_lfht_iter_get_node(&iter);
672
673 return node ? caa_container_of(node,
674 struct notification_client_list,
675 notification_trigger_ht_node) : NULL;
676}
677
678/* This function must be called with the RCU read lock held. */
679static
680int evaluate_channel_condition_for_client(
681 const struct lttng_condition *condition,
682 struct notification_thread_state *state,
683 struct lttng_evaluation **evaluation,
684 uid_t *session_uid, gid_t *session_gid)
685{
686 int ret;
687 struct cds_lfht_iter iter;
688 struct cds_lfht_node *node;
689 struct channel_info *channel_info = NULL;
690 struct channel_key *channel_key = NULL;
691 struct channel_state_sample *last_sample = NULL;
692 struct lttng_channel_trigger_list *channel_trigger_list = NULL;
693
694 /* Find the channel associated with the condition. */
695 cds_lfht_for_each_entry(state->channel_triggers_ht, &iter,
696 channel_trigger_list, channel_triggers_ht_node) {
697 struct lttng_trigger_list_element *element;
698
699 cds_list_for_each_entry(element, &channel_trigger_list->list, node) {
700 const struct lttng_condition *current_condition =
701 lttng_trigger_get_const_condition(
702 element->trigger);
703
704 assert(current_condition);
705 if (!lttng_condition_is_equal(condition,
706 current_condition)) {
707 continue;
708 }
709
710 /* Found the trigger, save the channel key. */
711 channel_key = &channel_trigger_list->channel_key;
712 break;
713 }
714 if (channel_key) {
715 /* The channel key was found stop iteration. */
716 break;
717 }
718 }
719
720 if (!channel_key){
721 /* No channel found; normal exit. */
722 DBG("[notification-thread] No known channel associated with newly subscribed-to condition");
723 ret = 0;
724 goto end;
725 }
726
727 /* Fetch channel info for the matching channel. */
728 cds_lfht_lookup(state->channels_ht,
729 hash_channel_key(channel_key),
730 match_channel_info,
731 channel_key,
732 &iter);
733 node = cds_lfht_iter_get_node(&iter);
734 assert(node);
735 channel_info = caa_container_of(node, struct channel_info,
736 channels_ht_node);
737
738 /* Retrieve the channel's last sample, if it exists. */
739 cds_lfht_lookup(state->channel_state_ht,
740 hash_channel_key(channel_key),
741 match_channel_state_sample,
742 channel_key,
743 &iter);
744 node = cds_lfht_iter_get_node(&iter);
745 if (node) {
746 last_sample = caa_container_of(node,
747 struct channel_state_sample,
748 channel_state_ht_node);
749 } else {
750 /* Nothing to evaluate, no sample was ever taken. Normal exit */
751 DBG("[notification-thread] No channel sample associated with newly subscribed-to condition");
752 ret = 0;
753 goto end;
754 }
755
756 ret = evaluate_buffer_condition(condition, evaluation, state,
757 NULL, last_sample,
758 0, channel_info->session_info->consumed_data_size,
759 channel_info);
760 if (ret) {
761 WARN("[notification-thread] Fatal error occurred while evaluating a newly subscribed-to condition");
762 goto end;
763 }
764
765 *session_uid = channel_info->session_info->uid;
766 *session_gid = channel_info->session_info->gid;
767end:
768 return ret;
769}
770
771static
772const char *get_condition_session_name(const struct lttng_condition *condition)
773{
774 const char *session_name = NULL;
775 enum lttng_condition_status status;
776
777 switch (lttng_condition_get_type(condition)) {
778 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
779 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
780 status = lttng_condition_buffer_usage_get_session_name(
781 condition, &session_name);
782 break;
783 case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
784 status = lttng_condition_session_consumed_size_get_session_name(
785 condition, &session_name);
786 break;
787 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
788 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
789 status = lttng_condition_session_rotation_get_session_name(
790 condition, &session_name);
791 break;
792 default:
793 abort();
794 }
795 if (status != LTTNG_CONDITION_STATUS_OK) {
796 ERR("[notification-thread] Failed to retrieve session rotation condition's session name");
797 goto end;
798 }
799end:
800 return session_name;
801}
802
803/* This function must be called with the RCU read lock held. */
804static
805int evaluate_session_condition_for_client(
806 const struct lttng_condition *condition,
807 struct notification_thread_state *state,
808 struct lttng_evaluation **evaluation,
809 uid_t *session_uid, gid_t *session_gid)
810{
811 int ret;
812 struct cds_lfht_iter iter;
813 struct cds_lfht_node *node;
814 const char *session_name;
815 struct session_info *session_info = NULL;
816
817 session_name = get_condition_session_name(condition);
818
819 /* Find the session associated with the trigger. */
820 cds_lfht_lookup(state->sessions_ht,
821 hash_key_str(session_name, lttng_ht_seed),
822 match_session,
823 session_name,
824 &iter);
825 node = cds_lfht_iter_get_node(&iter);
826 if (!node) {
827 DBG("[notification-thread] No known session matching name \"%s\"",
828 session_name);
829 ret = 0;
830 goto end;
831 }
832
833 session_info = caa_container_of(node, struct session_info,
834 sessions_ht_node);
835 session_info_get(session_info);
836
837 /*
838 * Evaluation is performed in-line here since only one type of
839 * session-bound condition is handled for the moment.
840 */
841 switch (lttng_condition_get_type(condition)) {
842 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
843 if (!session_info->rotation.ongoing) {
844 goto end_session_put;
845 }
846
847 *evaluation = lttng_evaluation_session_rotation_ongoing_create(
848 session_info->rotation.id);
849 if (!*evaluation) {
850 /* Fatal error. */
851 ERR("[notification-thread] Failed to create session rotation ongoing evaluation for session \"%s\"",
852 session_info->name);
853 ret = -1;
854 goto end_session_put;
855 }
856 ret = 0;
857 break;
858 default:
859 ret = 0;
860 goto end_session_put;
861 }
862
863 *session_uid = session_info->uid;
864 *session_gid = session_info->gid;
865
866end_session_put:
867 session_info_put(session_info);
868end:
869 return ret;
870}
871
872/* This function must be called with the RCU read lock held. */
873static
874int evaluate_condition_for_client(const struct lttng_trigger *trigger,
875 const struct lttng_condition *condition,
876 struct notification_client *client,
877 struct notification_thread_state *state)
878{
879 int ret;
880 struct lttng_evaluation *evaluation = NULL;
881 struct notification_client_list client_list = { 0 };
882 struct notification_client_list_element client_list_element = { 0 };
883 uid_t object_uid = 0;
884 gid_t object_gid = 0;
885
886 assert(trigger);
887 assert(condition);
888 assert(client);
889 assert(state);
890
891 switch (get_condition_binding_object(condition)) {
892 case LTTNG_OBJECT_TYPE_SESSION:
893 ret = evaluate_session_condition_for_client(condition, state,
894 &evaluation, &object_uid, &object_gid);
895 break;
896 case LTTNG_OBJECT_TYPE_CHANNEL:
897 ret = evaluate_channel_condition_for_client(condition, state,
898 &evaluation, &object_uid, &object_gid);
899 break;
900 case LTTNG_OBJECT_TYPE_NONE:
901 ret = 0;
902 goto end;
903 case LTTNG_OBJECT_TYPE_UNKNOWN:
904 default:
905 ret = -1;
906 goto end;
907 }
908
909 if (!evaluation) {
910 /* Evaluation yielded nothing. Normal exit. */
911 DBG("[notification-thread] Newly subscribed-to condition evaluated to false, nothing to report to client");
912 ret = 0;
913 goto end;
914 }
915
916 /*
917 * Create a temporary client list with the client currently
918 * subscribing.
919 */
920 cds_lfht_node_init(&client_list.notification_trigger_ht_node);
921 CDS_INIT_LIST_HEAD(&client_list.list);
922 client_list.trigger = trigger;
923
924 CDS_INIT_LIST_HEAD(&client_list_element.node);
925 client_list_element.client = client;
926 cds_list_add(&client_list_element.node, &client_list.list);
927
928 /* Send evaluation result to the newly-subscribed client. */
929 DBG("[notification-thread] Newly subscribed-to condition evaluated to true, notifying client");
930 ret = send_evaluation_to_clients(trigger, evaluation, &client_list,
931 state, object_uid, object_gid);
932
933end:
934 return ret;
935}
936
937static
938int notification_thread_client_subscribe(struct notification_client *client,
939 struct lttng_condition *condition,
940 struct notification_thread_state *state,
941 enum lttng_notification_channel_status *_status)
942{
943 int ret = 0;
944 struct notification_client_list *client_list;
945 struct lttng_condition_list_element *condition_list_element = NULL;
946 struct notification_client_list_element *client_list_element = NULL;
947 enum lttng_notification_channel_status status =
948 LTTNG_NOTIFICATION_CHANNEL_STATUS_OK;
949
950 /*
951 * Ensure that the client has not already subscribed to this condition
952 * before.
953 */
954 cds_list_for_each_entry(condition_list_element, &client->condition_list, node) {
955 if (lttng_condition_is_equal(condition_list_element->condition,
956 condition)) {
957 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_ALREADY_SUBSCRIBED;
958 goto end;
959 }
960 }
961
962 condition_list_element = zmalloc(sizeof(*condition_list_element));
963 if (!condition_list_element) {
964 ret = -1;
965 goto error;
966 }
967 client_list_element = zmalloc(sizeof(*client_list_element));
968 if (!client_list_element) {
969 ret = -1;
970 goto error;
971 }
972
973 rcu_read_lock();
974
975 /*
976 * Add the newly-subscribed condition to the client's subscription list.
977 */
978 CDS_INIT_LIST_HEAD(&condition_list_element->node);
979 condition_list_element->condition = condition;
980 cds_list_add(&condition_list_element->node, &client->condition_list);
981
982 client_list = get_client_list_from_condition(state, condition);
983 if (!client_list) {
984 /*
985 * No notification-emiting trigger registered with this
986 * condition. We don't evaluate the condition right away
987 * since this trigger is not registered yet.
988 */
989 free(client_list_element);
990 goto end_unlock;
991 }
992
993 /*
994 * The condition to which the client just subscribed is evaluated
995 * at this point so that conditions that are already TRUE result
996 * in a notification being sent out.
997 */
998 if (evaluate_condition_for_client(client_list->trigger, condition,
999 client, state)) {
1000 WARN("[notification-thread] Evaluation of a condition on client subscription failed, aborting.");
1001 ret = -1;
1002 free(client_list_element);
1003 goto end_unlock;
1004 }
1005
1006 /*
1007 * Add the client to the list of clients interested in a given trigger
1008 * if a "notification" trigger with a corresponding condition was
1009 * added prior.
1010 */
1011 client_list_element->client = client;
1012 CDS_INIT_LIST_HEAD(&client_list_element->node);
1013 cds_list_add(&client_list_element->node, &client_list->list);
1014end_unlock:
1015 rcu_read_unlock();
1016end:
1017 if (_status) {
1018 *_status = status;
1019 }
1020 return ret;
1021error:
1022 free(condition_list_element);
1023 free(client_list_element);
1024 return ret;
1025}
1026
1027static
1028int notification_thread_client_unsubscribe(
1029 struct notification_client *client,
1030 struct lttng_condition *condition,
1031 struct notification_thread_state *state,
1032 enum lttng_notification_channel_status *_status)
1033{
1034 struct notification_client_list *client_list;
1035 struct lttng_condition_list_element *condition_list_element,
1036 *condition_tmp;
1037 struct notification_client_list_element *client_list_element,
1038 *client_tmp;
1039 bool condition_found = false;
1040 enum lttng_notification_channel_status status =
1041 LTTNG_NOTIFICATION_CHANNEL_STATUS_OK;
1042
1043 /* Remove the condition from the client's condition list. */
1044 cds_list_for_each_entry_safe(condition_list_element, condition_tmp,
1045 &client->condition_list, node) {
1046 if (!lttng_condition_is_equal(condition_list_element->condition,
1047 condition)) {
1048 continue;
1049 }
1050
1051 cds_list_del(&condition_list_element->node);
1052 /*
1053 * The caller may be iterating on the client's conditions to
1054 * tear down a client's connection. In this case, the condition
1055 * will be destroyed at the end.
1056 */
1057 if (condition != condition_list_element->condition) {
1058 lttng_condition_destroy(
1059 condition_list_element->condition);
1060 }
1061 free(condition_list_element);
1062 condition_found = true;
1063 break;
1064 }
1065
1066 if (!condition_found) {
1067 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_UNKNOWN_CONDITION;
1068 goto end;
1069 }
1070
1071 /*
1072 * Remove the client from the list of clients interested the trigger
1073 * matching the condition.
1074 */
1075 rcu_read_lock();
1076 client_list = get_client_list_from_condition(state, condition);
1077 if (!client_list) {
1078 goto end_unlock;
1079 }
1080
1081 cds_list_for_each_entry_safe(client_list_element, client_tmp,
1082 &client_list->list, node) {
1083 if (client_list_element->client->socket != client->socket) {
1084 continue;
1085 }
1086 cds_list_del(&client_list_element->node);
1087 free(client_list_element);
1088 break;
1089 }
1090end_unlock:
1091 rcu_read_unlock();
1092end:
1093 lttng_condition_destroy(condition);
1094 if (_status) {
1095 *_status = status;
1096 }
1097 return 0;
1098}
1099
1100static
1101void notification_client_destroy(struct notification_client *client,
1102 struct notification_thread_state *state)
1103{
1104 struct lttng_condition_list_element *condition_list_element, *tmp;
1105
1106 if (!client) {
1107 return;
1108 }
1109
1110 /* Release all conditions to which the client was subscribed. */
1111 cds_list_for_each_entry_safe(condition_list_element, tmp,
1112 &client->condition_list, node) {
1113 (void) notification_thread_client_unsubscribe(client,
1114 condition_list_element->condition, state, NULL);
1115 }
1116
1117 if (client->socket >= 0) {
1118 (void) lttcomm_close_unix_sock(client->socket);
1119 }
1120 lttng_dynamic_buffer_reset(&client->communication.inbound.buffer);
1121 lttng_dynamic_buffer_reset(&client->communication.outbound.buffer);
1122 free(client);
1123}
1124
1125/*
1126 * Call with rcu_read_lock held (and hold for the lifetime of the returned
1127 * client pointer).
1128 */
1129static
1130struct notification_client *get_client_from_socket(int socket,
1131 struct notification_thread_state *state)
1132{
1133 struct cds_lfht_iter iter;
1134 struct cds_lfht_node *node;
1135 struct notification_client *client = NULL;
1136
1137 cds_lfht_lookup(state->client_socket_ht,
1138 hash_key_ulong((void *) (unsigned long) socket, lttng_ht_seed),
1139 match_client,
1140 (void *) (unsigned long) socket,
1141 &iter);
1142 node = cds_lfht_iter_get_node(&iter);
1143 if (!node) {
1144 goto end;
1145 }
1146
1147 client = caa_container_of(node, struct notification_client,
1148 client_socket_ht_node);
1149end:
1150 return client;
1151}
1152
1153static
1154bool buffer_usage_condition_applies_to_channel(
1155 const struct lttng_condition *condition,
1156 const struct channel_info *channel_info)
1157{
1158 enum lttng_condition_status status;
1159 enum lttng_domain_type condition_domain;
1160 const char *condition_session_name = NULL;
1161 const char *condition_channel_name = NULL;
1162
1163 status = lttng_condition_buffer_usage_get_domain_type(condition,
1164 &condition_domain);
1165 assert(status == LTTNG_CONDITION_STATUS_OK);
1166 if (channel_info->key.domain != condition_domain) {
1167 goto fail;
1168 }
1169
1170 status = lttng_condition_buffer_usage_get_session_name(
1171 condition, &condition_session_name);
1172 assert((status == LTTNG_CONDITION_STATUS_OK) && condition_session_name);
1173
1174 status = lttng_condition_buffer_usage_get_channel_name(
1175 condition, &condition_channel_name);
1176 assert((status == LTTNG_CONDITION_STATUS_OK) && condition_channel_name);
1177
1178 if (strcmp(channel_info->session_info->name, condition_session_name)) {
1179 goto fail;
1180 }
1181 if (strcmp(channel_info->name, condition_channel_name)) {
1182 goto fail;
1183 }
1184
1185 return true;
1186fail:
1187 return false;
1188}
1189
1190static
1191bool session_consumed_size_condition_applies_to_channel(
1192 const struct lttng_condition *condition,
1193 const struct channel_info *channel_info)
1194{
1195 enum lttng_condition_status status;
1196 const char *condition_session_name = NULL;
1197
1198 status = lttng_condition_session_consumed_size_get_session_name(
1199 condition, &condition_session_name);
1200 assert((status == LTTNG_CONDITION_STATUS_OK) && condition_session_name);
1201
1202 if (strcmp(channel_info->session_info->name, condition_session_name)) {
1203 goto fail;
1204 }
1205
1206 return true;
1207fail:
1208 return false;
1209}
1210
1211static
1212bool trigger_applies_to_channel(const struct lttng_trigger *trigger,
1213 const struct channel_info *channel_info)
1214{
1215 const struct lttng_condition *condition;
1216 bool trigger_applies;
1217
1218 condition = lttng_trigger_get_const_condition(trigger);
1219 if (!condition) {
1220 goto fail;
1221 }
1222
1223 switch (lttng_condition_get_type(condition)) {
1224 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
1225 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
1226 trigger_applies = buffer_usage_condition_applies_to_channel(
1227 condition, channel_info);
1228 break;
1229 case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
1230 trigger_applies = session_consumed_size_condition_applies_to_channel(
1231 condition, channel_info);
1232 break;
1233 default:
1234 goto fail;
1235 }
1236
1237 return trigger_applies;
1238fail:
1239 return false;
1240}
1241
1242static
1243bool trigger_applies_to_client(struct lttng_trigger *trigger,
1244 struct notification_client *client)
1245{
1246 bool applies = false;
1247 struct lttng_condition_list_element *condition_list_element;
1248
1249 cds_list_for_each_entry(condition_list_element, &client->condition_list,
1250 node) {
1251 applies = lttng_condition_is_equal(
1252 condition_list_element->condition,
1253 lttng_trigger_get_condition(trigger));
1254 if (applies) {
1255 break;
1256 }
1257 }
1258 return applies;
1259}
1260
1261/* Must be called with RCU read lock held. */
1262static
1263struct lttng_session_trigger_list *get_session_trigger_list(
1264 struct notification_thread_state *state,
1265 const char *session_name)
1266{
1267 struct lttng_session_trigger_list *list = NULL;
1268 struct cds_lfht_node *node;
1269 struct cds_lfht_iter iter;
1270
1271 cds_lfht_lookup(state->session_triggers_ht,
1272 hash_key_str(session_name, lttng_ht_seed),
1273 match_session_trigger_list,
1274 session_name,
1275 &iter);
1276 node = cds_lfht_iter_get_node(&iter);
1277 if (!node) {
1278 /*
1279 * Not an error, the list of triggers applying to that session
1280 * will be initialized when the session is created.
1281 */
1282 DBG("[notification-thread] No trigger list found for session \"%s\" as it is not yet known to the notification system",
1283 session_name);
1284 goto end;
1285 }
1286
1287 list = caa_container_of(node,
1288 struct lttng_session_trigger_list,
1289 session_triggers_ht_node);
1290end:
1291 return list;
1292}
1293
1294/*
1295 * Allocate an empty lttng_session_trigger_list for the session named
1296 * 'session_name'.
1297 *
1298 * No ownership of 'session_name' is assumed by the session trigger list.
1299 * It is the caller's responsability to ensure the session name is alive
1300 * for as long as this list is.
1301 */
1302static
1303struct lttng_session_trigger_list *lttng_session_trigger_list_create(
1304 const char *session_name,
1305 struct cds_lfht *session_triggers_ht)
1306{
1307 struct lttng_session_trigger_list *list;
1308
1309 list = zmalloc(sizeof(*list));
1310 if (!list) {
1311 goto end;
1312 }
1313 list->session_name = session_name;
1314 CDS_INIT_LIST_HEAD(&list->list);
1315 cds_lfht_node_init(&list->session_triggers_ht_node);
1316 list->session_triggers_ht = session_triggers_ht;
1317
1318 rcu_read_lock();
1319 /* Publish the list through the session_triggers_ht. */
1320 cds_lfht_add(session_triggers_ht,
1321 hash_key_str(session_name, lttng_ht_seed),
1322 &list->session_triggers_ht_node);
1323 rcu_read_unlock();
1324end:
1325 return list;
1326}
1327
1328static
1329void free_session_trigger_list_rcu(struct rcu_head *node)
1330{
1331 free(caa_container_of(node, struct lttng_session_trigger_list,
1332 rcu_node));
1333}
1334
1335static
1336void lttng_session_trigger_list_destroy(struct lttng_session_trigger_list *list)
1337{
1338 struct lttng_trigger_list_element *trigger_list_element, *tmp;
1339
1340 /* Empty the list element by element, and then free the list itself. */
1341 cds_list_for_each_entry_safe(trigger_list_element, tmp,
1342 &list->list, node) {
1343 cds_list_del(&trigger_list_element->node);
1344 free(trigger_list_element);
1345 }
1346 rcu_read_lock();
1347 /* Unpublish the list from the session_triggers_ht. */
1348 cds_lfht_del(list->session_triggers_ht,
1349 &list->session_triggers_ht_node);
1350 rcu_read_unlock();
1351 call_rcu(&list->rcu_node, free_session_trigger_list_rcu);
1352}
1353
1354static
1355int lttng_session_trigger_list_add(struct lttng_session_trigger_list *list,
1356 const struct lttng_trigger *trigger)
1357{
1358 int ret = 0;
1359 struct lttng_trigger_list_element *new_element =
1360 zmalloc(sizeof(*new_element));
1361
1362 if (!new_element) {
1363 ret = -1;
1364 goto end;
1365 }
1366 CDS_INIT_LIST_HEAD(&new_element->node);
1367 new_element->trigger = trigger;
1368 cds_list_add(&new_element->node, &list->list);
1369end:
1370 return ret;
1371}
1372
1373static
1374bool trigger_applies_to_session(const struct lttng_trigger *trigger,
1375 const char *session_name)
1376{
1377 bool applies = false;
1378 const struct lttng_condition *condition;
1379
1380 condition = lttng_trigger_get_const_condition(trigger);
1381 switch (lttng_condition_get_type(condition)) {
1382 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
1383 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
1384 {
1385 enum lttng_condition_status condition_status;
1386 const char *condition_session_name;
1387
1388 condition_status = lttng_condition_session_rotation_get_session_name(
1389 condition, &condition_session_name);
1390 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
1391 ERR("[notification-thread] Failed to retrieve session rotation condition's session name");
1392 goto end;
1393 }
1394
1395 assert(condition_session_name);
1396 applies = !strcmp(condition_session_name, session_name);
1397 break;
1398 }
1399 default:
1400 goto end;
1401 }
1402end:
1403 return applies;
1404}
1405
1406/*
1407 * Allocate and initialize an lttng_session_trigger_list which contains
1408 * all triggers that apply to the session named 'session_name'.
1409 *
1410 * No ownership of 'session_name' is assumed by the session trigger list.
1411 * It is the caller's responsability to ensure the session name is alive
1412 * for as long as this list is.
1413 */
1414static
1415struct lttng_session_trigger_list *lttng_session_trigger_list_build(
1416 const struct notification_thread_state *state,
1417 const char *session_name)
1418{
1419 int trigger_count = 0;
1420 struct lttng_session_trigger_list *session_trigger_list = NULL;
1421 struct lttng_trigger_ht_element *trigger_ht_element = NULL;
1422 struct cds_lfht_iter iter;
1423
1424 session_trigger_list = lttng_session_trigger_list_create(session_name,
1425 state->session_triggers_ht);
1426
1427 /* Add all triggers applying to the session named 'session_name'. */
1428 cds_lfht_for_each_entry(state->triggers_ht, &iter, trigger_ht_element,
1429 node) {
1430 int ret;
1431
1432 if (!trigger_applies_to_session(trigger_ht_element->trigger,
1433 session_name)) {
1434 continue;
1435 }
1436
1437 ret = lttng_session_trigger_list_add(session_trigger_list,
1438 trigger_ht_element->trigger);
1439 if (ret) {
1440 goto error;
1441 }
1442
1443 trigger_count++;
1444 }
1445
1446 DBG("[notification-thread] Found %i triggers that apply to newly created session",
1447 trigger_count);
1448 return session_trigger_list;
1449error:
1450 lttng_session_trigger_list_destroy(session_trigger_list);
1451 return NULL;
1452}
1453
1454static
1455struct session_info *find_or_create_session_info(
1456 struct notification_thread_state *state,
1457 const char *name, uid_t uid, gid_t gid)
1458{
1459 struct session_info *session = NULL;
1460 struct cds_lfht_node *node;
1461 struct cds_lfht_iter iter;
1462 struct lttng_session_trigger_list *trigger_list;
1463
1464 rcu_read_lock();
1465 cds_lfht_lookup(state->sessions_ht,
1466 hash_key_str(name, lttng_ht_seed),
1467 match_session,
1468 name,
1469 &iter);
1470 node = cds_lfht_iter_get_node(&iter);
1471 if (node) {
1472 DBG("[notification-thread] Found session info of session \"%s\" (uid = %i, gid = %i)",
1473 name, uid, gid);
1474 session = caa_container_of(node, struct session_info,
1475 sessions_ht_node);
1476 assert(session->uid == uid);
1477 assert(session->gid == gid);
1478 session_info_get(session);
1479 goto end;
1480 }
1481
1482 trigger_list = lttng_session_trigger_list_build(state, name);
1483 if (!trigger_list) {
1484 goto error;
1485 }
1486
1487 session = session_info_create(name, uid, gid, trigger_list,
1488 state->sessions_ht);
1489 if (!session) {
1490 ERR("[notification-thread] Failed to allocation session info for session \"%s\" (uid = %i, gid = %i)",
1491 name, uid, gid);
1492 goto error;
1493 }
1494 trigger_list = NULL;
1495
1496 cds_lfht_add(state->sessions_ht, hash_key_str(name, lttng_ht_seed),
1497 &session->sessions_ht_node);
1498end:
1499 rcu_read_unlock();
1500 return session;
1501error:
1502 rcu_read_unlock();
1503 session_info_put(session);
1504 return NULL;
1505}
1506
1507static
1508int handle_notification_thread_command_add_channel(
1509 struct notification_thread_state *state,
1510 const char *session_name, uid_t session_uid, gid_t session_gid,
1511 const char *channel_name, enum lttng_domain_type channel_domain,
1512 uint64_t channel_key_int, uint64_t channel_capacity,
1513 enum lttng_error_code *cmd_result)
1514{
1515 struct cds_list_head trigger_list;
1516 struct channel_info *new_channel_info = NULL;
1517 struct channel_key channel_key = {
1518 .key = channel_key_int,
1519 .domain = channel_domain,
1520 };
1521 struct lttng_channel_trigger_list *channel_trigger_list = NULL;
1522 struct lttng_trigger_ht_element *trigger_ht_element = NULL;
1523 int trigger_count = 0;
1524 struct cds_lfht_iter iter;
1525 struct session_info *session_info = NULL;
1526
1527 DBG("[notification-thread] Adding channel %s from session %s, channel key = %" PRIu64 " in %s domain",
1528 channel_name, session_name, channel_key_int,
1529 channel_domain == LTTNG_DOMAIN_KERNEL ? "kernel" : "user space");
1530
1531 CDS_INIT_LIST_HEAD(&trigger_list);
1532
1533 session_info = find_or_create_session_info(state, session_name,
1534 session_uid, session_gid);
1535 if (!session_info) {
1536 /* Allocation error or an internal error occurred. */
1537 goto error;
1538 }
1539
1540 new_channel_info = channel_info_create(channel_name, &channel_key,
1541 channel_capacity, session_info);
1542 if (!new_channel_info) {
1543 goto error;
1544 }
1545
1546 /* Build a list of all triggers applying to the new channel. */
1547 cds_lfht_for_each_entry(state->triggers_ht, &iter, trigger_ht_element,
1548 node) {
1549 struct lttng_trigger_list_element *new_element;
1550
1551 if (!trigger_applies_to_channel(trigger_ht_element->trigger,
1552 new_channel_info)) {
1553 continue;
1554 }
1555
1556 new_element = zmalloc(sizeof(*new_element));
1557 if (!new_element) {
1558 goto error;
1559 }
1560 CDS_INIT_LIST_HEAD(&new_element->node);
1561 new_element->trigger = trigger_ht_element->trigger;
1562 cds_list_add(&new_element->node, &trigger_list);
1563 trigger_count++;
1564 }
1565
1566 DBG("[notification-thread] Found %i triggers that apply to newly added channel",
1567 trigger_count);
1568 channel_trigger_list = zmalloc(sizeof(*channel_trigger_list));
1569 if (!channel_trigger_list) {
1570 goto error;
1571 }
1572 channel_trigger_list->channel_key = new_channel_info->key;
1573 CDS_INIT_LIST_HEAD(&channel_trigger_list->list);
1574 cds_lfht_node_init(&channel_trigger_list->channel_triggers_ht_node);
1575 cds_list_splice(&trigger_list, &channel_trigger_list->list);
1576
1577 rcu_read_lock();
1578 /* Add channel to the channel_ht which owns the channel_infos. */
1579 cds_lfht_add(state->channels_ht,
1580 hash_channel_key(&new_channel_info->key),
1581 &new_channel_info->channels_ht_node);
1582 /*
1583 * Add the list of triggers associated with this channel to the
1584 * channel_triggers_ht.
1585 */
1586 cds_lfht_add(state->channel_triggers_ht,
1587 hash_channel_key(&new_channel_info->key),
1588 &channel_trigger_list->channel_triggers_ht_node);
1589 rcu_read_unlock();
1590 session_info_put(session_info);
1591 *cmd_result = LTTNG_OK;
1592 return 0;
1593error:
1594 channel_info_destroy(new_channel_info);
1595 session_info_put(session_info);
1596 return 1;
1597}
1598
1599static
1600int handle_notification_thread_command_remove_channel(
1601 struct notification_thread_state *state,
1602 uint64_t channel_key, enum lttng_domain_type domain,
1603 enum lttng_error_code *cmd_result)
1604{
1605 struct cds_lfht_node *node;
1606 struct cds_lfht_iter iter;
1607 struct lttng_channel_trigger_list *trigger_list;
1608 struct lttng_trigger_list_element *trigger_list_element, *tmp;
1609 struct channel_key key = { .key = channel_key, .domain = domain };
1610 struct channel_info *channel_info;
1611
1612 DBG("[notification-thread] Removing channel key = %" PRIu64 " in %s domain",
1613 channel_key, domain == LTTNG_DOMAIN_KERNEL ? "kernel" : "user space");
1614
1615 rcu_read_lock();
1616
1617 cds_lfht_lookup(state->channel_triggers_ht,
1618 hash_channel_key(&key),
1619 match_channel_trigger_list,
1620 &key,
1621 &iter);
1622 node = cds_lfht_iter_get_node(&iter);
1623 /*
1624 * There is a severe internal error if we are being asked to remove a
1625 * channel that doesn't exist.
1626 */
1627 if (!node) {
1628 ERR("[notification-thread] Channel being removed is unknown to the notification thread");
1629 goto end;
1630 }
1631
1632 /* Free the list of triggers associated with this channel. */
1633 trigger_list = caa_container_of(node, struct lttng_channel_trigger_list,
1634 channel_triggers_ht_node);
1635 cds_list_for_each_entry_safe(trigger_list_element, tmp,
1636 &trigger_list->list, node) {
1637 cds_list_del(&trigger_list_element->node);
1638 free(trigger_list_element);
1639 }
1640 cds_lfht_del(state->channel_triggers_ht, node);
1641 free(trigger_list);
1642
1643 /* Free sampled channel state. */
1644 cds_lfht_lookup(state->channel_state_ht,
1645 hash_channel_key(&key),
1646 match_channel_state_sample,
1647 &key,
1648 &iter);
1649 node = cds_lfht_iter_get_node(&iter);
1650 /*
1651 * This is expected to be NULL if the channel is destroyed before we
1652 * received a sample.
1653 */
1654 if (node) {
1655 struct channel_state_sample *sample = caa_container_of(node,
1656 struct channel_state_sample,
1657 channel_state_ht_node);
1658
1659 cds_lfht_del(state->channel_state_ht, node);
1660 free(sample);
1661 }
1662
1663 /* Remove the channel from the channels_ht and free it. */
1664 cds_lfht_lookup(state->channels_ht,
1665 hash_channel_key(&key),
1666 match_channel_info,
1667 &key,
1668 &iter);
1669 node = cds_lfht_iter_get_node(&iter);
1670 assert(node);
1671 channel_info = caa_container_of(node, struct channel_info,
1672 channels_ht_node);
1673 cds_lfht_del(state->channels_ht, node);
1674 channel_info_destroy(channel_info);
1675end:
1676 rcu_read_unlock();
1677 *cmd_result = LTTNG_OK;
1678 return 0;
1679}
1680
1681static
1682int handle_notification_thread_command_session_rotation(
1683 struct notification_thread_state *state,
1684 enum notification_thread_command_type cmd_type,
1685 const char *session_name, uid_t session_uid, gid_t session_gid,
1686 uint64_t trace_archive_chunk_id,
1687 struct lttng_trace_archive_location *location,
1688 enum lttng_error_code *_cmd_result)
1689{
1690 int ret = 0;
1691 enum lttng_error_code cmd_result = LTTNG_OK;
1692 struct lttng_session_trigger_list *trigger_list;
1693 struct lttng_trigger_list_element *trigger_list_element;
1694 struct session_info *session_info;
1695
1696 rcu_read_lock();
1697
1698 session_info = find_or_create_session_info(state, session_name,
1699 session_uid, session_gid);
1700 if (!session_info) {
1701 /* Allocation error or an internal error occurred. */
1702 ret = -1;
1703 cmd_result = LTTNG_ERR_NOMEM;
1704 goto end;
1705 }
1706
1707 session_info->rotation.ongoing =
1708 cmd_type == NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_ONGOING;
1709 session_info->rotation.id = trace_archive_chunk_id;
1710 trigger_list = get_session_trigger_list(state, session_name);
1711 if (!trigger_list) {
1712 DBG("[notification-thread] No triggers applying to session \"%s\" found",
1713 session_name);
1714 goto end;
1715 }
1716
1717 cds_list_for_each_entry(trigger_list_element, &trigger_list->list,
1718 node) {
1719 const struct lttng_condition *condition;
1720 const struct lttng_action *action;
1721 const struct lttng_trigger *trigger;
1722 struct notification_client_list *client_list;
1723 struct lttng_evaluation *evaluation = NULL;
1724 enum lttng_condition_type condition_type;
1725
1726 trigger = trigger_list_element->trigger;
1727 condition = lttng_trigger_get_const_condition(trigger);
1728 assert(condition);
1729 condition_type = lttng_condition_get_type(condition);
1730
1731 if (condition_type == LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING &&
1732 cmd_type != NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_ONGOING) {
1733 continue;
1734 } else if (condition_type == LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED &&
1735 cmd_type != NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_COMPLETED) {
1736 continue;
1737 }
1738
1739 action = lttng_trigger_get_const_action(trigger);
1740
1741 /* Notify actions are the only type currently supported. */
1742 assert(lttng_action_get_type_const(action) ==
1743 LTTNG_ACTION_TYPE_NOTIFY);
1744
1745 client_list = get_client_list_from_condition(state, condition);
1746 assert(client_list);
1747
1748 if (cds_list_empty(&client_list->list)) {
1749 /*
1750 * No clients interested in the evaluation's result,
1751 * skip it.
1752 */
1753 continue;
1754 }
1755
1756 if (cmd_type == NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_ONGOING) {
1757 evaluation = lttng_evaluation_session_rotation_ongoing_create(
1758 trace_archive_chunk_id);
1759 } else {
1760 evaluation = lttng_evaluation_session_rotation_completed_create(
1761 trace_archive_chunk_id, location);
1762 }
1763
1764 if (!evaluation) {
1765 /* Internal error */
1766 ret = -1;
1767 cmd_result = LTTNG_ERR_UNK;
1768 goto end;
1769 }
1770
1771 /* Dispatch evaluation result to all clients. */
1772 ret = send_evaluation_to_clients(trigger_list_element->trigger,
1773 evaluation, client_list, state,
1774 session_info->uid,
1775 session_info->gid);
1776 lttng_evaluation_destroy(evaluation);
1777 if (caa_unlikely(ret)) {
1778 goto end;
1779 }
1780 }
1781end:
1782 session_info_put(session_info);
1783 *_cmd_result = cmd_result;
1784 rcu_read_unlock();
1785 return ret;
1786}
1787
1788static
1789int condition_is_supported(struct lttng_condition *condition)
1790{
1791 int ret;
1792
1793 switch (lttng_condition_get_type(condition)) {
1794 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
1795 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
1796 {
1797 enum lttng_domain_type domain;
1798
1799 ret = lttng_condition_buffer_usage_get_domain_type(condition,
1800 &domain);
1801 if (ret) {
1802 ret = -1;
1803 goto end;
1804 }
1805
1806 if (domain != LTTNG_DOMAIN_KERNEL) {
1807 ret = 1;
1808 goto end;
1809 }
1810
1811 /*
1812 * Older kernel tracers don't expose the API to monitor their
1813 * buffers. Therefore, we reject triggers that require that
1814 * mechanism to be available to be evaluated.
1815 */
1816 ret = kernel_supports_ring_buffer_snapshot_sample_positions(
1817 kernel_tracer_fd);
1818 break;
1819 }
1820 default:
1821 ret = 1;
1822 }
1823end:
1824 return ret;
1825}
1826
1827/* Must be called with RCU read lock held. */
1828static
1829int bind_trigger_to_matching_session(const struct lttng_trigger *trigger,
1830 struct notification_thread_state *state)
1831{
1832 int ret = 0;
1833 const struct lttng_condition *condition;
1834 const char *session_name;
1835 struct lttng_session_trigger_list *trigger_list;
1836
1837 condition = lttng_trigger_get_const_condition(trigger);
1838 switch (lttng_condition_get_type(condition)) {
1839 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
1840 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
1841 {
1842 enum lttng_condition_status status;
1843
1844 status = lttng_condition_session_rotation_get_session_name(
1845 condition, &session_name);
1846 if (status != LTTNG_CONDITION_STATUS_OK) {
1847 ERR("[notification-thread] Failed to bind trigger to session: unable to get 'session_rotation' condition's session name");
1848 ret = -1;
1849 goto end;
1850 }
1851 break;
1852 }
1853 default:
1854 ret = -1;
1855 goto end;
1856 }
1857
1858 trigger_list = get_session_trigger_list(state, session_name);
1859 if (!trigger_list) {
1860 DBG("[notification-thread] Unable to bind trigger applying to session \"%s\" as it is not yet known to the notification system",
1861 session_name);
1862 goto end;
1863
1864 }
1865
1866 DBG("[notification-thread] Newly registered trigger bound to session \"%s\"",
1867 session_name);
1868 ret = lttng_session_trigger_list_add(trigger_list, trigger);
1869end:
1870 return ret;
1871}
1872
1873/* Must be called with RCU read lock held. */
1874static
1875int bind_trigger_to_matching_channels(const struct lttng_trigger *trigger,
1876 struct notification_thread_state *state)
1877{
1878 int ret = 0;
1879 struct cds_lfht_node *node;
1880 struct cds_lfht_iter iter;
1881 struct channel_info *channel;
1882
1883 cds_lfht_for_each_entry(state->channels_ht, &iter, channel,
1884 channels_ht_node) {
1885 struct lttng_trigger_list_element *trigger_list_element;
1886 struct lttng_channel_trigger_list *trigger_list;
1887
1888 if (!trigger_applies_to_channel(trigger, channel)) {
1889 continue;
1890 }
1891
1892 cds_lfht_lookup(state->channel_triggers_ht,
1893 hash_channel_key(&channel->key),
1894 match_channel_trigger_list,
1895 &channel->key,
1896 &iter);
1897 node = cds_lfht_iter_get_node(&iter);
1898 assert(node);
1899 trigger_list = caa_container_of(node,
1900 struct lttng_channel_trigger_list,
1901 channel_triggers_ht_node);
1902
1903 trigger_list_element = zmalloc(sizeof(*trigger_list_element));
1904 if (!trigger_list_element) {
1905 ret = -1;
1906 goto end;
1907 }
1908 CDS_INIT_LIST_HEAD(&trigger_list_element->node);
1909 trigger_list_element->trigger = trigger;
1910 cds_list_add(&trigger_list_element->node, &trigger_list->list);
1911 DBG("[notification-thread] Newly registered trigger bound to channel \"%s\"",
1912 channel->name);
1913 }
1914end:
1915 return ret;
1916}
1917
1918/*
1919 * FIXME A client's credentials are not checked when registering a trigger, nor
1920 * are they stored alongside with the trigger.
1921 *
1922 * The effects of this are benign since:
1923 * - The client will succeed in registering the trigger, as it is valid,
1924 * - The trigger will, internally, be bound to the channel/session,
1925 * - The notifications will not be sent since the client's credentials
1926 * are checked against the channel at that moment.
1927 *
1928 * If this function returns a non-zero value, it means something is
1929 * fundamentally broken and the whole subsystem/thread will be torn down.
1930 *
1931 * If a non-fatal error occurs, just set the cmd_result to the appropriate
1932 * error code.
1933 */
1934static
1935int handle_notification_thread_command_register_trigger(
1936 struct notification_thread_state *state,
1937 struct lttng_trigger *trigger,
1938 enum lttng_error_code *cmd_result)
1939{
1940 int ret = 0;
1941 struct lttng_condition *condition;
1942 struct notification_client *client;
1943 struct notification_client_list *client_list = NULL;
1944 struct lttng_trigger_ht_element *trigger_ht_element = NULL;
1945 struct notification_client_list_element *client_list_element, *tmp;
1946 struct cds_lfht_node *node;
1947 struct cds_lfht_iter iter;
1948 bool free_trigger = true;
1949
1950 rcu_read_lock();
1951
1952 condition = lttng_trigger_get_condition(trigger);
1953 assert(condition);
1954
1955 ret = condition_is_supported(condition);
1956 if (ret < 0) {
1957 goto error;
1958 } else if (ret == 0) {
1959 *cmd_result = LTTNG_ERR_NOT_SUPPORTED;
1960 goto error;
1961 } else {
1962 /* Feature is supported, continue. */
1963 ret = 0;
1964 }
1965
1966 trigger_ht_element = zmalloc(sizeof(*trigger_ht_element));
1967 if (!trigger_ht_element) {
1968 ret = -1;
1969 goto error;
1970 }
1971
1972 /* Add trigger to the trigger_ht. */
1973 cds_lfht_node_init(&trigger_ht_element->node);
1974 trigger_ht_element->trigger = trigger;
1975
1976 node = cds_lfht_add_unique(state->triggers_ht,
1977 lttng_condition_hash(condition),
1978 match_condition,
1979 condition,
1980 &trigger_ht_element->node);
1981 if (node != &trigger_ht_element->node) {
1982 /* Not a fatal error, simply report it to the client. */
1983 *cmd_result = LTTNG_ERR_TRIGGER_EXISTS;
1984 goto error_free_ht_element;
1985 }
1986
1987 /*
1988 * Ownership of the trigger and of its wrapper was transfered to
1989 * the triggers_ht.
1990 */
1991 trigger_ht_element = NULL;
1992 free_trigger = false;
1993
1994 /*
1995 * The rest only applies to triggers that have a "notify" action.
1996 * It is not skipped as this is the only action type currently
1997 * supported.
1998 */
1999 client_list = zmalloc(sizeof(*client_list));
2000 if (!client_list) {
2001 ret = -1;
2002 goto error_free_ht_element;
2003 }
2004 cds_lfht_node_init(&client_list->notification_trigger_ht_node);
2005 CDS_INIT_LIST_HEAD(&client_list->list);
2006 client_list->trigger = trigger;
2007
2008 /* Build a list of clients to which this new trigger applies. */
2009 cds_lfht_for_each_entry(state->client_socket_ht, &iter, client,
2010 client_socket_ht_node) {
2011 if (!trigger_applies_to_client(trigger, client)) {
2012 continue;
2013 }
2014
2015 client_list_element = zmalloc(sizeof(*client_list_element));
2016 if (!client_list_element) {
2017 ret = -1;
2018 goto error_free_client_list;
2019 }
2020 CDS_INIT_LIST_HEAD(&client_list_element->node);
2021 client_list_element->client = client;
2022 cds_list_add(&client_list_element->node, &client_list->list);
2023 }
2024
2025 cds_lfht_add(state->notification_trigger_clients_ht,
2026 lttng_condition_hash(condition),
2027 &client_list->notification_trigger_ht_node);
2028
2029 switch (get_condition_binding_object(condition)) {
2030 case LTTNG_OBJECT_TYPE_SESSION:
2031 /* Add the trigger to the list if it matches a known session. */
2032 ret = bind_trigger_to_matching_session(trigger, state);
2033 if (ret) {
2034 goto error_free_client_list;
2035 }
2036 break;
2037 case LTTNG_OBJECT_TYPE_CHANNEL:
2038 /*
2039 * Add the trigger to list of triggers bound to the channels
2040 * currently known.
2041 */
2042 ret = bind_trigger_to_matching_channels(trigger, state);
2043 if (ret) {
2044 goto error_free_client_list;
2045 }
2046 break;
2047 case LTTNG_OBJECT_TYPE_NONE:
2048 break;
2049 default:
2050 ERR("[notification-thread] Unknown object type on which to bind a newly registered trigger was encountered");
2051 ret = -1;
2052 goto error_free_client_list;
2053 }
2054
2055 /*
2056 * Since there is nothing preventing clients from subscribing to a
2057 * condition before the corresponding trigger is registered, we have
2058 * to evaluate this new condition right away.
2059 *
2060 * At some point, we were waiting for the next "evaluation" (e.g. on
2061 * reception of a channel sample) to evaluate this new condition, but
2062 * that was broken.
2063 *
2064 * The reason it was broken is that waiting for the next sample
2065 * does not allow us to properly handle transitions for edge-triggered
2066 * conditions.
2067 *
2068 * Consider this example: when we handle a new channel sample, we
2069 * evaluate each conditions twice: once with the previous state, and
2070 * again with the newest state. We then use those two results to
2071 * determine whether a state change happened: a condition was false and
2072 * became true. If a state change happened, we have to notify clients.
2073 *
2074 * Now, if a client subscribes to a given notification and registers
2075 * a trigger *after* that subscription, we have to make sure the
2076 * condition is evaluated at this point while considering only the
2077 * current state. Otherwise, the next evaluation cycle may only see
2078 * that the evaluations remain the same (true for samples n-1 and n) and
2079 * the client will never know that the condition has been met.
2080 */
2081 cds_list_for_each_entry_safe(client_list_element, tmp,
2082 &client_list->list, node) {
2083 ret = evaluate_condition_for_client(trigger, condition,
2084 client_list_element->client, state);
2085 if (ret) {
2086 goto error_free_client_list;
2087 }
2088 }
2089
2090 /*
2091 * Client list ownership transferred to the
2092 * notification_trigger_clients_ht.
2093 */
2094 client_list = NULL;
2095
2096 *cmd_result = LTTNG_OK;
2097error_free_client_list:
2098 if (client_list) {
2099 cds_list_for_each_entry_safe(client_list_element, tmp,
2100 &client_list->list, node) {
2101 free(client_list_element);
2102 }
2103 free(client_list);
2104 }
2105error_free_ht_element:
2106 free(trigger_ht_element);
2107error:
2108 if (free_trigger) {
2109 struct lttng_action *action = lttng_trigger_get_action(trigger);
2110
2111 lttng_condition_destroy(condition);
2112 lttng_action_destroy(action);
2113 lttng_trigger_destroy(trigger);
2114 }
2115 rcu_read_unlock();
2116 return ret;
2117}
2118
2119static
2120int handle_notification_thread_command_unregister_trigger(
2121 struct notification_thread_state *state,
2122 struct lttng_trigger *trigger,
2123 enum lttng_error_code *_cmd_reply)
2124{
2125 struct cds_lfht_iter iter;
2126 struct cds_lfht_node *triggers_ht_node;
2127 struct lttng_channel_trigger_list *trigger_list;
2128 struct notification_client_list *client_list;
2129 struct notification_client_list_element *client_list_element, *tmp;
2130 struct lttng_trigger_ht_element *trigger_ht_element = NULL;
2131 struct lttng_condition *condition = lttng_trigger_get_condition(
2132 trigger);
2133 struct lttng_action *action;
2134 enum lttng_error_code cmd_reply;
2135
2136 rcu_read_lock();
2137
2138 cds_lfht_lookup(state->triggers_ht,
2139 lttng_condition_hash(condition),
2140 match_condition,
2141 condition,
2142 &iter);
2143 triggers_ht_node = cds_lfht_iter_get_node(&iter);
2144 if (!triggers_ht_node) {
2145 cmd_reply = LTTNG_ERR_TRIGGER_NOT_FOUND;
2146 goto end;
2147 } else {
2148 cmd_reply = LTTNG_OK;
2149 }
2150
2151 /* Remove trigger from channel_triggers_ht. */
2152 cds_lfht_for_each_entry(state->channel_triggers_ht, &iter, trigger_list,
2153 channel_triggers_ht_node) {
2154 struct lttng_trigger_list_element *trigger_element, *tmp;
2155
2156 cds_list_for_each_entry_safe(trigger_element, tmp,
2157 &trigger_list->list, node) {
2158 const struct lttng_condition *current_condition =
2159 lttng_trigger_get_const_condition(
2160 trigger_element->trigger);
2161
2162 assert(current_condition);
2163 if (!lttng_condition_is_equal(condition,
2164 current_condition)) {
2165 continue;
2166 }
2167
2168 DBG("[notification-thread] Removed trigger from channel_triggers_ht");
2169 cds_list_del(&trigger_element->node);
2170 /* A trigger can only appear once per channel */
2171 break;
2172 }
2173 }
2174
2175 /*
2176 * Remove and release the client list from
2177 * notification_trigger_clients_ht.
2178 */
2179 client_list = get_client_list_from_condition(state, condition);
2180 assert(client_list);
2181
2182 cds_list_for_each_entry_safe(client_list_element, tmp,
2183 &client_list->list, node) {
2184 free(client_list_element);
2185 }
2186 cds_lfht_del(state->notification_trigger_clients_ht,
2187 &client_list->notification_trigger_ht_node);
2188 free(client_list);
2189
2190 /* Remove trigger from triggers_ht. */
2191 trigger_ht_element = caa_container_of(triggers_ht_node,
2192 struct lttng_trigger_ht_element, node);
2193 cds_lfht_del(state->triggers_ht, triggers_ht_node);
2194
2195 condition = lttng_trigger_get_condition(trigger_ht_element->trigger);
2196 lttng_condition_destroy(condition);
2197 action = lttng_trigger_get_action(trigger_ht_element->trigger);
2198 lttng_action_destroy(action);
2199 lttng_trigger_destroy(trigger_ht_element->trigger);
2200 free(trigger_ht_element);
2201end:
2202 rcu_read_unlock();
2203 if (_cmd_reply) {
2204 *_cmd_reply = cmd_reply;
2205 }
2206 return 0;
2207}
2208
2209/* Returns 0 on success, 1 on exit requested, negative value on error. */
2210int handle_notification_thread_command(
2211 struct notification_thread_handle *handle,
2212 struct notification_thread_state *state)
2213{
2214 int ret;
2215 uint64_t counter;
2216 struct notification_thread_command *cmd;
2217
2218 /* Read the event pipe to put it back into a quiescent state. */
2219 ret = read(lttng_pipe_get_readfd(handle->cmd_queue.event_pipe), &counter,
2220 sizeof(counter));
2221 if (ret == -1) {
2222 goto error;
2223 }
2224
2225 pthread_mutex_lock(&handle->cmd_queue.lock);
2226 cmd = cds_list_first_entry(&handle->cmd_queue.list,
2227 struct notification_thread_command, cmd_list_node);
2228 switch (cmd->type) {
2229 case NOTIFICATION_COMMAND_TYPE_REGISTER_TRIGGER:
2230 DBG("[notification-thread] Received register trigger command");
2231 ret = handle_notification_thread_command_register_trigger(
2232 state, cmd->parameters.trigger,
2233 &cmd->reply_code);
2234 break;
2235 case NOTIFICATION_COMMAND_TYPE_UNREGISTER_TRIGGER:
2236 DBG("[notification-thread] Received unregister trigger command");
2237 ret = handle_notification_thread_command_unregister_trigger(
2238 state, cmd->parameters.trigger,
2239 &cmd->reply_code);
2240 break;
2241 case NOTIFICATION_COMMAND_TYPE_ADD_CHANNEL:
2242 DBG("[notification-thread] Received add channel command");
2243 ret = handle_notification_thread_command_add_channel(
2244 state,
2245 cmd->parameters.add_channel.session.name,
2246 cmd->parameters.add_channel.session.uid,
2247 cmd->parameters.add_channel.session.gid,
2248 cmd->parameters.add_channel.channel.name,
2249 cmd->parameters.add_channel.channel.domain,
2250 cmd->parameters.add_channel.channel.key,
2251 cmd->parameters.add_channel.channel.capacity,
2252 &cmd->reply_code);
2253 break;
2254 case NOTIFICATION_COMMAND_TYPE_REMOVE_CHANNEL:
2255 DBG("[notification-thread] Received remove channel command");
2256 ret = handle_notification_thread_command_remove_channel(
2257 state, cmd->parameters.remove_channel.key,
2258 cmd->parameters.remove_channel.domain,
2259 &cmd->reply_code);
2260 break;
2261 case NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_ONGOING:
2262 case NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_COMPLETED:
2263 DBG("[notification-thread] Received session rotation %s command",
2264 cmd->type == NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_ONGOING ?
2265 "ongoing" : "completed");
2266 ret = handle_notification_thread_command_session_rotation(
2267 state,
2268 cmd->type,
2269 cmd->parameters.session_rotation.session_name,
2270 cmd->parameters.session_rotation.uid,
2271 cmd->parameters.session_rotation.gid,
2272 cmd->parameters.session_rotation.trace_archive_chunk_id,
2273 cmd->parameters.session_rotation.location,
2274 &cmd->reply_code);
2275 break;
2276 case NOTIFICATION_COMMAND_TYPE_QUIT:
2277 DBG("[notification-thread] Received quit command");
2278 cmd->reply_code = LTTNG_OK;
2279 ret = 1;
2280 goto end;
2281 default:
2282 ERR("[notification-thread] Unknown internal command received");
2283 goto error_unlock;
2284 }
2285
2286 if (ret) {
2287 goto error_unlock;
2288 }
2289end:
2290 cds_list_del(&cmd->cmd_list_node);
2291 lttng_waiter_wake_up(&cmd->reply_waiter);
2292 pthread_mutex_unlock(&handle->cmd_queue.lock);
2293 return ret;
2294error_unlock:
2295 /* Wake-up and return a fatal error to the calling thread. */
2296 lttng_waiter_wake_up(&cmd->reply_waiter);
2297 pthread_mutex_unlock(&handle->cmd_queue.lock);
2298 cmd->reply_code = LTTNG_ERR_FATAL;
2299error:
2300 /* Indicate a fatal error to the caller. */
2301 return -1;
2302}
2303
2304static
2305unsigned long hash_client_socket(int socket)
2306{
2307 return hash_key_ulong((void *) (unsigned long) socket, lttng_ht_seed);
2308}
2309
2310static
2311int socket_set_non_blocking(int socket)
2312{
2313 int ret, flags;
2314
2315 /* Set the pipe as non-blocking. */
2316 ret = fcntl(socket, F_GETFL, 0);
2317 if (ret == -1) {
2318 PERROR("fcntl get socket flags");
2319 goto end;
2320 }
2321 flags = ret;
2322
2323 ret = fcntl(socket, F_SETFL, flags | O_NONBLOCK);
2324 if (ret == -1) {
2325 PERROR("fcntl set O_NONBLOCK socket flag");
2326 goto end;
2327 }
2328 DBG("Client socket (fd = %i) set as non-blocking", socket);
2329end:
2330 return ret;
2331}
2332
2333static
2334int client_reset_inbound_state(struct notification_client *client)
2335{
2336 int ret;
2337
2338 ret = lttng_dynamic_buffer_set_size(
2339 &client->communication.inbound.buffer, 0);
2340 assert(!ret);
2341
2342 client->communication.inbound.bytes_to_receive =
2343 sizeof(struct lttng_notification_channel_message);
2344 client->communication.inbound.msg_type =
2345 LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_UNKNOWN;
2346 LTTNG_SOCK_SET_UID_CRED(&client->communication.inbound.creds, -1);
2347 LTTNG_SOCK_SET_GID_CRED(&client->communication.inbound.creds, -1);
2348 ret = lttng_dynamic_buffer_set_size(
2349 &client->communication.inbound.buffer,
2350 client->communication.inbound.bytes_to_receive);
2351 return ret;
2352}
2353
2354int handle_notification_thread_client_connect(
2355 struct notification_thread_state *state)
2356{
2357 int ret;
2358 struct notification_client *client;
2359
2360 DBG("[notification-thread] Handling new notification channel client connection");
2361
2362 client = zmalloc(sizeof(*client));
2363 if (!client) {
2364 /* Fatal error. */
2365 ret = -1;
2366 goto error;
2367 }
2368 CDS_INIT_LIST_HEAD(&client->condition_list);
2369 lttng_dynamic_buffer_init(&client->communication.inbound.buffer);
2370 lttng_dynamic_buffer_init(&client->communication.outbound.buffer);
2371 client->communication.inbound.expect_creds = true;
2372 ret = client_reset_inbound_state(client);
2373 if (ret) {
2374 ERR("[notification-thread] Failed to reset client communication's inbound state");
2375 ret = 0;
2376 goto error;
2377 }
2378
2379 ret = lttcomm_accept_unix_sock(state->notification_channel_socket);
2380 if (ret < 0) {
2381 ERR("[notification-thread] Failed to accept new notification channel client connection");
2382 ret = 0;
2383 goto error;
2384 }
2385
2386 client->socket = ret;
2387
2388 ret = socket_set_non_blocking(client->socket);
2389 if (ret) {
2390 ERR("[notification-thread] Failed to set new notification channel client connection socket as non-blocking");
2391 goto error;
2392 }
2393
2394 ret = lttcomm_setsockopt_creds_unix_sock(client->socket);
2395 if (ret < 0) {
2396 ERR("[notification-thread] Failed to set socket options on new notification channel client socket");
2397 ret = 0;
2398 goto error;
2399 }
2400
2401 ret = lttng_poll_add(&state->events, client->socket,
2402 LPOLLIN | LPOLLERR |
2403 LPOLLHUP | LPOLLRDHUP);
2404 if (ret < 0) {
2405 ERR("[notification-thread] Failed to add notification channel client socket to poll set");
2406 ret = 0;
2407 goto error;
2408 }
2409 DBG("[notification-thread] Added new notification channel client socket (%i) to poll set",
2410 client->socket);
2411
2412 rcu_read_lock();
2413 cds_lfht_add(state->client_socket_ht,
2414 hash_client_socket(client->socket),
2415 &client->client_socket_ht_node);
2416 rcu_read_unlock();
2417
2418 return ret;
2419error:
2420 notification_client_destroy(client, state);
2421 return ret;
2422}
2423
2424int handle_notification_thread_client_disconnect(
2425 int client_socket,
2426 struct notification_thread_state *state)
2427{
2428 int ret = 0;
2429 struct notification_client *client;
2430
2431 rcu_read_lock();
2432 DBG("[notification-thread] Closing client connection (socket fd = %i)",
2433 client_socket);
2434 client = get_client_from_socket(client_socket, state);
2435 if (!client) {
2436 /* Internal state corruption, fatal error. */
2437 ERR("[notification-thread] Unable to find client (socket fd = %i)",
2438 client_socket);
2439 ret = -1;
2440 goto end;
2441 }
2442
2443 ret = lttng_poll_del(&state->events, client_socket);
2444 if (ret) {
2445 ERR("[notification-thread] Failed to remove client socket from poll set");
2446 }
2447 cds_lfht_del(state->client_socket_ht,
2448 &client->client_socket_ht_node);
2449 notification_client_destroy(client, state);
2450end:
2451 rcu_read_unlock();
2452 return ret;
2453}
2454
2455int handle_notification_thread_client_disconnect_all(
2456 struct notification_thread_state *state)
2457{
2458 struct cds_lfht_iter iter;
2459 struct notification_client *client;
2460 bool error_encoutered = false;
2461
2462 rcu_read_lock();
2463 DBG("[notification-thread] Closing all client connections");
2464 cds_lfht_for_each_entry(state->client_socket_ht, &iter, client,
2465 client_socket_ht_node) {
2466 int ret;
2467
2468 ret = handle_notification_thread_client_disconnect(
2469 client->socket, state);
2470 if (ret) {
2471 error_encoutered = true;
2472 }
2473 }
2474 rcu_read_unlock();
2475 return error_encoutered ? 1 : 0;
2476}
2477
2478int handle_notification_thread_trigger_unregister_all(
2479 struct notification_thread_state *state)
2480{
2481 bool error_occurred = false;
2482 struct cds_lfht_iter iter;
2483 struct lttng_trigger_ht_element *trigger_ht_element;
2484
2485 cds_lfht_for_each_entry(state->triggers_ht, &iter, trigger_ht_element,
2486 node) {
2487 int ret = handle_notification_thread_command_unregister_trigger(
2488 state, trigger_ht_element->trigger, NULL);
2489 if (ret) {
2490 error_occurred = true;
2491 }
2492 }
2493 return error_occurred ? -1 : 0;
2494}
2495
2496static
2497int client_flush_outgoing_queue(struct notification_client *client,
2498 struct notification_thread_state *state)
2499{
2500 ssize_t ret;
2501 size_t to_send_count;
2502
2503 assert(client->communication.outbound.buffer.size != 0);
2504 to_send_count = client->communication.outbound.buffer.size;
2505 DBG("[notification-thread] Flushing client (socket fd = %i) outgoing queue",
2506 client->socket);
2507
2508 ret = lttcomm_send_unix_sock_non_block(client->socket,
2509 client->communication.outbound.buffer.data,
2510 to_send_count);
2511 if ((ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) ||
2512 (ret > 0 && ret < to_send_count)) {
2513 DBG("[notification-thread] Client (socket fd = %i) outgoing queue could not be completely flushed",
2514 client->socket);
2515 to_send_count -= max(ret, 0);
2516
2517 memcpy(client->communication.outbound.buffer.data,
2518 client->communication.outbound.buffer.data +
2519 client->communication.outbound.buffer.size - to_send_count,
2520 to_send_count);
2521 ret = lttng_dynamic_buffer_set_size(
2522 &client->communication.outbound.buffer,
2523 to_send_count);
2524 if (ret) {
2525 goto error;
2526 }
2527
2528 /*
2529 * We want to be notified whenever there is buffer space
2530 * available to send the rest of the payload.
2531 */
2532 ret = lttng_poll_mod(&state->events, client->socket,
2533 CLIENT_POLL_MASK_IN_OUT);
2534 if (ret) {
2535 goto error;
2536 }
2537 } else if (ret < 0) {
2538 /* Generic error, disconnect the client. */
2539 ERR("[notification-thread] Failed to send flush outgoing queue, disconnecting client (socket fd = %i)",
2540 client->socket);
2541 ret = handle_notification_thread_client_disconnect(
2542 client->socket, state);
2543 if (ret) {
2544 goto error;
2545 }
2546 } else {
2547 /* No error and flushed the queue completely. */
2548 ret = lttng_dynamic_buffer_set_size(
2549 &client->communication.outbound.buffer, 0);
2550 if (ret) {
2551 goto error;
2552 }
2553 ret = lttng_poll_mod(&state->events, client->socket,
2554 CLIENT_POLL_MASK_IN);
2555 if (ret) {
2556 goto error;
2557 }
2558
2559 client->communication.outbound.queued_command_reply = false;
2560 client->communication.outbound.dropped_notification = false;
2561 }
2562
2563 return 0;
2564error:
2565 return -1;
2566}
2567
2568static
2569int client_send_command_reply(struct notification_client *client,
2570 struct notification_thread_state *state,
2571 enum lttng_notification_channel_status status)
2572{
2573 int ret;
2574 struct lttng_notification_channel_command_reply reply = {
2575 .status = (int8_t) status,
2576 };
2577 struct lttng_notification_channel_message msg = {
2578 .type = (int8_t) LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_COMMAND_REPLY,
2579 .size = sizeof(reply),
2580 };
2581 char buffer[sizeof(msg) + sizeof(reply)];
2582
2583 if (client->communication.outbound.queued_command_reply) {
2584 /* Protocol error. */
2585 goto error;
2586 }
2587
2588 memcpy(buffer, &msg, sizeof(msg));
2589 memcpy(buffer + sizeof(msg), &reply, sizeof(reply));
2590 DBG("[notification-thread] Send command reply (%i)", (int) status);
2591
2592 /* Enqueue buffer to outgoing queue and flush it. */
2593 ret = lttng_dynamic_buffer_append(
2594 &client->communication.outbound.buffer,
2595 buffer, sizeof(buffer));
2596 if (ret) {
2597 goto error;
2598 }
2599
2600 ret = client_flush_outgoing_queue(client, state);
2601 if (ret) {
2602 goto error;
2603 }
2604
2605 if (client->communication.outbound.buffer.size != 0) {
2606 /* Queue could not be emptied. */
2607 client->communication.outbound.queued_command_reply = true;
2608 }
2609
2610 return 0;
2611error:
2612 return -1;
2613}
2614
2615static
2616int client_dispatch_message(struct notification_client *client,
2617 struct notification_thread_state *state)
2618{
2619 int ret = 0;
2620
2621 if (client->communication.inbound.msg_type !=
2622 LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_HANDSHAKE &&
2623 client->communication.inbound.msg_type !=
2624 LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_UNKNOWN &&
2625 !client->validated) {
2626 WARN("[notification-thread] client attempted a command before handshake");
2627 ret = -1;
2628 goto end;
2629 }
2630
2631 switch (client->communication.inbound.msg_type) {
2632 case LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_UNKNOWN:
2633 {
2634 /*
2635 * Receiving message header. The function will be called again
2636 * once the rest of the message as been received and can be
2637 * interpreted.
2638 */
2639 const struct lttng_notification_channel_message *msg;
2640
2641 assert(sizeof(*msg) ==
2642 client->communication.inbound.buffer.size);
2643 msg = (const struct lttng_notification_channel_message *)
2644 client->communication.inbound.buffer.data;
2645
2646 if (msg->size == 0 || msg->size > DEFAULT_MAX_NOTIFICATION_CLIENT_MESSAGE_PAYLOAD_SIZE) {
2647 ERR("[notification-thread] Invalid notification channel message: length = %u", msg->size);
2648 ret = -1;
2649 goto end;
2650 }
2651
2652 switch (msg->type) {
2653 case LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_SUBSCRIBE:
2654 case LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_UNSUBSCRIBE:
2655 case LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_HANDSHAKE:
2656 break;
2657 default:
2658 ret = -1;
2659 ERR("[notification-thread] Invalid notification channel message: unexpected message type");
2660 goto end;
2661 }
2662
2663 client->communication.inbound.bytes_to_receive = msg->size;
2664 client->communication.inbound.msg_type =
2665 (enum lttng_notification_channel_message_type) msg->type;
2666 ret = lttng_dynamic_buffer_set_size(
2667 &client->communication.inbound.buffer, msg->size);
2668 if (ret) {
2669 goto end;
2670 }
2671 break;
2672 }
2673 case LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_HANDSHAKE:
2674 {
2675 struct lttng_notification_channel_command_handshake *handshake_client;
2676 struct lttng_notification_channel_command_handshake handshake_reply = {
2677 .major = LTTNG_NOTIFICATION_CHANNEL_VERSION_MAJOR,
2678 .minor = LTTNG_NOTIFICATION_CHANNEL_VERSION_MINOR,
2679 };
2680 struct lttng_notification_channel_message msg_header = {
2681 .type = LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_HANDSHAKE,
2682 .size = sizeof(handshake_reply),
2683 };
2684 enum lttng_notification_channel_status status =
2685 LTTNG_NOTIFICATION_CHANNEL_STATUS_OK;
2686 char send_buffer[sizeof(msg_header) + sizeof(handshake_reply)];
2687
2688 memcpy(send_buffer, &msg_header, sizeof(msg_header));
2689 memcpy(send_buffer + sizeof(msg_header), &handshake_reply,
2690 sizeof(handshake_reply));
2691
2692 handshake_client =
2693 (struct lttng_notification_channel_command_handshake *)
2694 client->communication.inbound.buffer.data;
2695 client->major = handshake_client->major;
2696 client->minor = handshake_client->minor;
2697 if (!client->communication.inbound.creds_received) {
2698 ERR("[notification-thread] No credentials received from client");
2699 ret = -1;
2700 goto end;
2701 }
2702
2703 client->uid = LTTNG_SOCK_GET_UID_CRED(
2704 &client->communication.inbound.creds);
2705 client->gid = LTTNG_SOCK_GET_GID_CRED(
2706 &client->communication.inbound.creds);
2707 DBG("[notification-thread] Received handshake from client (uid = %u, gid = %u) with version %i.%i",
2708 client->uid, client->gid, (int) client->major,
2709 (int) client->minor);
2710
2711 if (handshake_client->major != LTTNG_NOTIFICATION_CHANNEL_VERSION_MAJOR) {
2712 status = LTTNG_NOTIFICATION_CHANNEL_STATUS_UNSUPPORTED_VERSION;
2713 }
2714
2715 ret = lttng_dynamic_buffer_append(&client->communication.outbound.buffer,
2716 send_buffer, sizeof(send_buffer));
2717 if (ret) {
2718 ERR("[notification-thread] Failed to send protocol version to notification channel client");
2719 goto end;
2720 }
2721
2722 ret = client_flush_outgoing_queue(client, state);
2723 if (ret) {
2724 goto end;
2725 }
2726
2727 ret = client_send_command_reply(client, state, status);
2728 if (ret) {
2729 ERR("[notification-thread] Failed to send reply to notification channel client");
2730 goto end;
2731 }
2732
2733 /* Set reception state to receive the next message header. */
2734 ret = client_reset_inbound_state(client);
2735 if (ret) {
2736 ERR("[notification-thread] Failed to reset client communication's inbound state");
2737 goto end;
2738 }
2739 client->validated = true;
2740 break;
2741 }
2742 case LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_SUBSCRIBE:
2743 case LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_UNSUBSCRIBE:
2744 {
2745 struct lttng_condition *condition;
2746 enum lttng_notification_channel_status status =
2747 LTTNG_NOTIFICATION_CHANNEL_STATUS_OK;
2748 const struct lttng_buffer_view condition_view =
2749 lttng_buffer_view_from_dynamic_buffer(
2750 &client->communication.inbound.buffer,
2751 0, -1);
2752 size_t expected_condition_size =
2753 client->communication.inbound.buffer.size;
2754
2755 ret = lttng_condition_create_from_buffer(&condition_view,
2756 &condition);
2757 if (ret != expected_condition_size) {
2758 ERR("[notification-thread] Malformed condition received from client");
2759 goto end;
2760 }
2761
2762 if (client->communication.inbound.msg_type ==
2763 LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_SUBSCRIBE) {
2764 ret = notification_thread_client_subscribe(client,
2765 condition, state, &status);
2766 } else {
2767 ret = notification_thread_client_unsubscribe(client,
2768 condition, state, &status);
2769 }
2770 if (ret) {
2771 goto end;
2772 }
2773
2774 ret = client_send_command_reply(client, state, status);
2775 if (ret) {
2776 ERR("[notification-thread] Failed to send reply to notification channel client");
2777 goto end;
2778 }
2779
2780 /* Set reception state to receive the next message header. */
2781 ret = client_reset_inbound_state(client);
2782 if (ret) {
2783 ERR("[notification-thread] Failed to reset client communication's inbound state");
2784 goto end;
2785 }
2786 break;
2787 }
2788 default:
2789 abort();
2790 }
2791end:
2792 return ret;
2793}
2794
2795/* Incoming data from client. */
2796int handle_notification_thread_client_in(
2797 struct notification_thread_state *state, int socket)
2798{
2799 int ret = 0;
2800 struct notification_client *client;
2801 ssize_t recv_ret;
2802 size_t offset;
2803
2804 client = get_client_from_socket(socket, state);
2805 if (!client) {
2806 /* Internal error, abort. */
2807 ret = -1;
2808 goto end;
2809 }
2810
2811 offset = client->communication.inbound.buffer.size -
2812 client->communication.inbound.bytes_to_receive;
2813 if (client->communication.inbound.expect_creds) {
2814 recv_ret = lttcomm_recv_creds_unix_sock(socket,
2815 client->communication.inbound.buffer.data + offset,
2816 client->communication.inbound.bytes_to_receive,
2817 &client->communication.inbound.creds);
2818 if (recv_ret > 0) {
2819 client->communication.inbound.expect_creds = false;
2820 client->communication.inbound.creds_received = true;
2821 }
2822 } else {
2823 recv_ret = lttcomm_recv_unix_sock_non_block(socket,
2824 client->communication.inbound.buffer.data + offset,
2825 client->communication.inbound.bytes_to_receive);
2826 }
2827 if (recv_ret < 0) {
2828 goto error_disconnect_client;
2829 }
2830
2831 client->communication.inbound.bytes_to_receive -= recv_ret;
2832 if (client->communication.inbound.bytes_to_receive == 0) {
2833 ret = client_dispatch_message(client, state);
2834 if (ret) {
2835 /*
2836 * Only returns an error if this client must be
2837 * disconnected.
2838 */
2839 goto error_disconnect_client;
2840 }
2841 } else {
2842 goto end;
2843 }
2844end:
2845 return ret;
2846error_disconnect_client:
2847 ret = handle_notification_thread_client_disconnect(socket, state);
2848 return ret;
2849}
2850
2851/* Client ready to receive outgoing data. */
2852int handle_notification_thread_client_out(
2853 struct notification_thread_state *state, int socket)
2854{
2855 int ret;
2856 struct notification_client *client;
2857
2858 client = get_client_from_socket(socket, state);
2859 if (!client) {
2860 /* Internal error, abort. */
2861 ret = -1;
2862 goto end;
2863 }
2864
2865 ret = client_flush_outgoing_queue(client, state);
2866 if (ret) {
2867 goto end;
2868 }
2869end:
2870 return ret;
2871}
2872
2873static
2874bool evaluate_buffer_usage_condition(const struct lttng_condition *condition,
2875 const struct channel_state_sample *sample,
2876 uint64_t buffer_capacity)
2877{
2878 bool result = false;
2879 uint64_t threshold;
2880 enum lttng_condition_type condition_type;
2881 const struct lttng_condition_buffer_usage *use_condition = container_of(
2882 condition, struct lttng_condition_buffer_usage,
2883 parent);
2884
2885 if (use_condition->threshold_bytes.set) {
2886 threshold = use_condition->threshold_bytes.value;
2887 } else {
2888 /*
2889 * Threshold was expressed as a ratio.
2890 *
2891 * TODO the threshold (in bytes) of conditions expressed
2892 * as a ratio of total buffer size could be cached to
2893 * forego this double-multiplication or it could be performed
2894 * as fixed-point math.
2895 *
2896 * Note that caching should accomodate the case where the
2897 * condition applies to multiple channels (i.e. don't assume
2898 * that all channels matching my_chann* have the same size...)
2899 */
2900 threshold = (uint64_t) (use_condition->threshold_ratio.value *
2901 (double) buffer_capacity);
2902 }
2903
2904 condition_type = lttng_condition_get_type(condition);
2905 if (condition_type == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW) {
2906 DBG("[notification-thread] Low buffer usage condition being evaluated: threshold = %" PRIu64 ", highest usage = %" PRIu64,
2907 threshold, sample->highest_usage);
2908
2909 /*
2910 * The low condition should only be triggered once _all_ of the
2911 * streams in a channel have gone below the "low" threshold.
2912 */
2913 if (sample->highest_usage <= threshold) {
2914 result = true;
2915 }
2916 } else {
2917 DBG("[notification-thread] High buffer usage condition being evaluated: threshold = %" PRIu64 ", highest usage = %" PRIu64,
2918 threshold, sample->highest_usage);
2919
2920 /*
2921 * For high buffer usage scenarios, we want to trigger whenever
2922 * _any_ of the streams has reached the "high" threshold.
2923 */
2924 if (sample->highest_usage >= threshold) {
2925 result = true;
2926 }
2927 }
2928
2929 return result;
2930}
2931
2932static
2933bool evaluate_session_consumed_size_condition(
2934 const struct lttng_condition *condition,
2935 uint64_t session_consumed_size)
2936{
2937 uint64_t threshold;
2938 const struct lttng_condition_session_consumed_size *size_condition =
2939 container_of(condition,
2940 struct lttng_condition_session_consumed_size,
2941 parent);
2942
2943 threshold = size_condition->consumed_threshold_bytes.value;
2944 DBG("[notification-thread] Session consumed size condition being evaluated: threshold = %" PRIu64 ", current size = %" PRIu64,
2945 threshold, session_consumed_size);
2946 return session_consumed_size >= threshold;
2947}
2948
2949static
2950int evaluate_buffer_condition(const struct lttng_condition *condition,
2951 struct lttng_evaluation **evaluation,
2952 const struct notification_thread_state *state,
2953 const struct channel_state_sample *previous_sample,
2954 const struct channel_state_sample *latest_sample,
2955 uint64_t previous_session_consumed_total,
2956 uint64_t latest_session_consumed_total,
2957 struct channel_info *channel_info)
2958{
2959 int ret = 0;
2960 enum lttng_condition_type condition_type;
2961 const bool previous_sample_available = !!previous_sample;
2962 bool previous_sample_result = false;
2963 bool latest_sample_result;
2964
2965 condition_type = lttng_condition_get_type(condition);
2966
2967 switch (condition_type) {
2968 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
2969 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
2970 if (caa_likely(previous_sample_available)) {
2971 previous_sample_result =
2972 evaluate_buffer_usage_condition(condition,
2973 previous_sample, channel_info->capacity);
2974 }
2975 latest_sample_result = evaluate_buffer_usage_condition(
2976 condition, latest_sample,
2977 channel_info->capacity);
2978 break;
2979 case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
2980 if (caa_likely(previous_sample_available)) {
2981 previous_sample_result =
2982 evaluate_session_consumed_size_condition(
2983 condition,
2984 previous_session_consumed_total);
2985 }
2986 latest_sample_result =
2987 evaluate_session_consumed_size_condition(
2988 condition,
2989 latest_session_consumed_total);
2990 break;
2991 default:
2992 /* Unknown condition type; internal error. */
2993 abort();
2994 }
2995
2996 if (!latest_sample_result ||
2997 (previous_sample_result == latest_sample_result)) {
2998 /*
2999 * Only trigger on a condition evaluation transition.
3000 *
3001 * NOTE: This edge-triggered logic may not be appropriate for
3002 * future condition types.
3003 */
3004 goto end;
3005 }
3006
3007 if (!evaluation || !latest_sample_result) {
3008 goto end;
3009 }
3010
3011 switch (condition_type) {
3012 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
3013 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
3014 *evaluation = lttng_evaluation_buffer_usage_create(
3015 condition_type,
3016 latest_sample->highest_usage,
3017 channel_info->capacity);
3018 break;
3019 case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
3020 *evaluation = lttng_evaluation_session_consumed_size_create(
3021 latest_session_consumed_total);
3022 break;
3023 default:
3024 abort();
3025 }
3026
3027 if (!*evaluation) {
3028 ret = -1;
3029 goto end;
3030 }
3031end:
3032 return ret;
3033}
3034
3035static
3036int client_enqueue_dropped_notification(struct notification_client *client,
3037 struct notification_thread_state *state)
3038{
3039 int ret;
3040 struct lttng_notification_channel_message msg = {
3041 .type = (int8_t) LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_NOTIFICATION_DROPPED,
3042 .size = 0,
3043 };
3044
3045 ret = lttng_dynamic_buffer_append(
3046 &client->communication.outbound.buffer, &msg,
3047 sizeof(msg));
3048 return ret;
3049}
3050
3051static
3052int send_evaluation_to_clients(const struct lttng_trigger *trigger,
3053 const struct lttng_evaluation *evaluation,
3054 struct notification_client_list* client_list,
3055 struct notification_thread_state *state,
3056 uid_t channel_uid, gid_t channel_gid)
3057{
3058 int ret = 0;
3059 struct lttng_dynamic_buffer msg_buffer;
3060 struct notification_client_list_element *client_list_element, *tmp;
3061 const struct lttng_notification notification = {
3062 .condition = (struct lttng_condition *) lttng_trigger_get_const_condition(trigger),
3063 .evaluation = (struct lttng_evaluation *) evaluation,
3064 };
3065 struct lttng_notification_channel_message msg_header = {
3066 .type = (int8_t) LTTNG_NOTIFICATION_CHANNEL_MESSAGE_TYPE_NOTIFICATION,
3067 };
3068
3069 lttng_dynamic_buffer_init(&msg_buffer);
3070
3071 ret = lttng_dynamic_buffer_append(&msg_buffer, &msg_header,
3072 sizeof(msg_header));
3073 if (ret) {
3074 goto end;
3075 }
3076
3077 ret = lttng_notification_serialize(&notification, &msg_buffer);
3078 if (ret) {
3079 ERR("[notification-thread] Failed to serialize notification");
3080 ret = -1;
3081 goto end;
3082 }
3083
3084 /* Update payload size. */
3085 ((struct lttng_notification_channel_message * ) msg_buffer.data)->size =
3086 (uint32_t) (msg_buffer.size - sizeof(msg_header));
3087
3088 cds_list_for_each_entry_safe(client_list_element, tmp,
3089 &client_list->list, node) {
3090 struct notification_client *client =
3091 client_list_element->client;
3092
3093 if (client->uid != channel_uid && client->gid != channel_gid &&
3094 client->uid != 0) {
3095 /* Client is not allowed to monitor this channel. */
3096 DBG("[notification-thread] Skipping client at it does not have the permission to receive notification for this channel");
3097 continue;
3098 }
3099
3100 DBG("[notification-thread] Sending notification to client (fd = %i, %zu bytes)",
3101 client->socket, msg_buffer.size);
3102 if (client->communication.outbound.buffer.size) {
3103 /*
3104 * Outgoing data is already buffered for this client;
3105 * drop the notification and enqueue a "dropped
3106 * notification" message if this is the first dropped
3107 * notification since the socket spilled-over to the
3108 * queue.
3109 */
3110 DBG("[notification-thread] Dropping notification addressed to client (socket fd = %i)",
3111 client->socket);
3112 if (!client->communication.outbound.dropped_notification) {
3113 client->communication.outbound.dropped_notification = true;
3114 ret = client_enqueue_dropped_notification(
3115 client, state);
3116 if (ret) {
3117 goto end;
3118 }
3119 }
3120 continue;
3121 }
3122
3123 ret = lttng_dynamic_buffer_append_buffer(
3124 &client->communication.outbound.buffer,
3125 &msg_buffer);
3126 if (ret) {
3127 goto end;
3128 }
3129
3130 ret = client_flush_outgoing_queue(client, state);
3131 if (ret) {
3132 goto end;
3133 }
3134 }
3135 ret = 0;
3136end:
3137 lttng_dynamic_buffer_reset(&msg_buffer);
3138 return ret;
3139}
3140
3141int handle_notification_thread_channel_sample(
3142 struct notification_thread_state *state, int pipe,
3143 enum lttng_domain_type domain)
3144{
3145 int ret = 0;
3146 struct lttcomm_consumer_channel_monitor_msg sample_msg;
3147 struct channel_info *channel_info;
3148 struct cds_lfht_node *node;
3149 struct cds_lfht_iter iter;
3150 struct lttng_channel_trigger_list *trigger_list;
3151 struct lttng_trigger_list_element *trigger_list_element;
3152 bool previous_sample_available = false;
3153 struct channel_state_sample previous_sample, latest_sample;
3154 uint64_t previous_session_consumed_total, latest_session_consumed_total;
3155
3156 /*
3157 * The monitoring pipe only holds messages smaller than PIPE_BUF,
3158 * ensuring that read/write of sampling messages are atomic.
3159 */
3160 ret = lttng_read(pipe, &sample_msg, sizeof(sample_msg));
3161 if (ret != sizeof(sample_msg)) {
3162 ERR("[notification-thread] Failed to read from monitoring pipe (fd = %i)",
3163 pipe);
3164 ret = -1;
3165 goto end;
3166 }
3167
3168 ret = 0;
3169 latest_sample.key.key = sample_msg.key;
3170 latest_sample.key.domain = domain;
3171 latest_sample.highest_usage = sample_msg.highest;
3172 latest_sample.lowest_usage = sample_msg.lowest;
3173 latest_sample.channel_total_consumed = sample_msg.total_consumed;
3174
3175 rcu_read_lock();
3176
3177 /* Retrieve the channel's informations */
3178 cds_lfht_lookup(state->channels_ht,
3179 hash_channel_key(&latest_sample.key),
3180 match_channel_info,
3181 &latest_sample.key,
3182 &iter);
3183 node = cds_lfht_iter_get_node(&iter);
3184 if (caa_unlikely(!node)) {
3185 /*
3186 * Not an error since the consumer can push a sample to the pipe
3187 * and the rest of the session daemon could notify us of the
3188 * channel's destruction before we get a chance to process that
3189 * sample.
3190 */
3191 DBG("[notification-thread] Received a sample for an unknown channel from consumerd, key = %" PRIu64 " in %s domain",
3192 latest_sample.key.key,
3193 domain == LTTNG_DOMAIN_KERNEL ? "kernel" :
3194 "user space");
3195 goto end_unlock;
3196 }
3197 channel_info = caa_container_of(node, struct channel_info,
3198 channels_ht_node);
3199 DBG("[notification-thread] Handling channel sample for channel %s (key = %" PRIu64 ") in session %s (highest usage = %" PRIu64 ", lowest usage = %" PRIu64", total consumed = %" PRIu64")",
3200 channel_info->name,
3201 latest_sample.key.key,
3202 channel_info->session_info->name,
3203 latest_sample.highest_usage,
3204 latest_sample.lowest_usage,
3205 latest_sample.channel_total_consumed);
3206
3207 previous_session_consumed_total =
3208 channel_info->session_info->consumed_data_size;
3209
3210 /* Retrieve the channel's last sample, if it exists, and update it. */
3211 cds_lfht_lookup(state->channel_state_ht,
3212 hash_channel_key(&latest_sample.key),
3213 match_channel_state_sample,
3214 &latest_sample.key,
3215 &iter);
3216 node = cds_lfht_iter_get_node(&iter);
3217 if (caa_likely(node)) {
3218 struct channel_state_sample *stored_sample;
3219
3220 /* Update the sample stored. */
3221 stored_sample = caa_container_of(node,
3222 struct channel_state_sample,
3223 channel_state_ht_node);
3224
3225 memcpy(&previous_sample, stored_sample,
3226 sizeof(previous_sample));
3227 stored_sample->highest_usage = latest_sample.highest_usage;
3228 stored_sample->lowest_usage = latest_sample.lowest_usage;
3229 stored_sample->channel_total_consumed = latest_sample.channel_total_consumed;
3230 previous_sample_available = true;
3231
3232 latest_session_consumed_total =
3233 previous_session_consumed_total +
3234 (latest_sample.channel_total_consumed - previous_sample.channel_total_consumed);
3235 } else {
3236 /*
3237 * This is the channel's first sample, allocate space for and
3238 * store the new sample.
3239 */
3240 struct channel_state_sample *stored_sample;
3241
3242 stored_sample = zmalloc(sizeof(*stored_sample));
3243 if (!stored_sample) {
3244 ret = -1;
3245 goto end_unlock;
3246 }
3247
3248 memcpy(stored_sample, &latest_sample, sizeof(*stored_sample));
3249 cds_lfht_node_init(&stored_sample->channel_state_ht_node);
3250 cds_lfht_add(state->channel_state_ht,
3251 hash_channel_key(&stored_sample->key),
3252 &stored_sample->channel_state_ht_node);
3253
3254 latest_session_consumed_total =
3255 previous_session_consumed_total +
3256 latest_sample.channel_total_consumed;
3257 }
3258
3259 channel_info->session_info->consumed_data_size =
3260 latest_session_consumed_total;
3261
3262 /* Find triggers associated with this channel. */
3263 cds_lfht_lookup(state->channel_triggers_ht,
3264 hash_channel_key(&latest_sample.key),
3265 match_channel_trigger_list,
3266 &latest_sample.key,
3267 &iter);
3268 node = cds_lfht_iter_get_node(&iter);
3269 if (caa_likely(!node)) {
3270 goto end_unlock;
3271 }
3272
3273 trigger_list = caa_container_of(node, struct lttng_channel_trigger_list,
3274 channel_triggers_ht_node);
3275 cds_list_for_each_entry(trigger_list_element, &trigger_list->list,
3276 node) {
3277 const struct lttng_condition *condition;
3278 const struct lttng_action *action;
3279 const struct lttng_trigger *trigger;
3280 struct notification_client_list *client_list;
3281 struct lttng_evaluation *evaluation = NULL;
3282
3283 trigger = trigger_list_element->trigger;
3284 condition = lttng_trigger_get_const_condition(trigger);
3285 assert(condition);
3286 action = lttng_trigger_get_const_action(trigger);
3287
3288 /* Notify actions are the only type currently supported. */
3289 assert(lttng_action_get_type_const(action) ==
3290 LTTNG_ACTION_TYPE_NOTIFY);
3291
3292 /*
3293 * Check if any client is subscribed to the result of this
3294 * evaluation.
3295 */
3296 client_list = get_client_list_from_condition(state, condition);
3297 assert(client_list);
3298 if (cds_list_empty(&client_list->list)) {
3299 /*
3300 * No clients interested in the evaluation's result,
3301 * skip it.
3302 */
3303 continue;
3304 }
3305
3306 ret = evaluate_buffer_condition(condition, &evaluation, state,
3307 previous_sample_available ? &previous_sample : NULL,
3308 &latest_sample,
3309 previous_session_consumed_total,
3310 latest_session_consumed_total,
3311 channel_info);
3312 if (caa_unlikely(ret)) {
3313 goto end_unlock;
3314 }
3315
3316 if (caa_likely(!evaluation)) {
3317 continue;
3318 }
3319
3320 /* Dispatch evaluation result to all clients. */
3321 ret = send_evaluation_to_clients(trigger_list_element->trigger,
3322 evaluation, client_list, state,
3323 channel_info->session_info->uid,
3324 channel_info->session_info->gid);
3325 lttng_evaluation_destroy(evaluation);
3326 if (caa_unlikely(ret)) {
3327 goto end_unlock;
3328 }
3329 }
3330end_unlock:
3331 rcu_read_unlock();
3332end:
3333 return ret;
3334}
This page took 0.037349 seconds and 4 git commands to generate.