+
+/*
+ * Clear a kernel session.
+ *
+ * Return LTTNG_OK on success or else an LTTng error code.
+ */
+enum lttng_error_code kernel_clear_session(struct ltt_session *session)
+{
+ int ret;
+ enum lttng_error_code status = LTTNG_OK;
+ struct consumer_socket *socket;
+ struct lttng_ht_iter iter;
+ struct ltt_kernel_session *ksess = session->kernel_session;
+
+ assert(ksess);
+ assert(ksess->consumer);
+
+ DBG("Clear kernel session %s (session %" PRIu64 ")",
+ session->name, session->id);
+
+ rcu_read_lock();
+
+ if (ksess->active) {
+ ERR("Expecting inactive session %s (%" PRIu64 ")", session->name, session->id);
+ status = LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ /*
+ * Note that this loop will end after one iteration given that there is
+ * only one kernel consumer.
+ */
+ cds_lfht_for_each_entry(ksess->consumer->socks->ht, &iter.iter,
+ socket, node.node) {
+ struct ltt_kernel_channel *chan;
+
+ /* For each channel, ask the consumer to clear it. */
+ cds_list_for_each_entry(chan, &ksess->channel_list.head, list) {
+ DBG("Clear kernel channel %" PRIu64 ", session %s",
+ chan->key, session->name);
+ ret = consumer_clear_channel(socket, chan->key);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ if (!ksess->metadata) {
+ /*
+ * Nothing to do for the metadata.
+ * This is a snapshot session.
+ * The metadata is genererated on the fly.
+ */
+ continue;
+ }
+
+ /*
+ * Clear the metadata channel.
+ * Metadata channel is not cleared per se but we still need to
+ * perform a rotation operation on it behind the scene.
+ */
+ ret = consumer_clear_channel(socket, ksess->metadata->key);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ goto end;
+error:
+ switch (-ret) {
+ case LTTCOMM_CONSUMERD_RELAYD_CLEAR_DISALLOWED:
+ status = LTTNG_ERR_CLEAR_RELAY_DISALLOWED;
+ break;
+ default:
+ status = LTTNG_ERR_CLEAR_FAIL_CONSUMER;
+ break;
+ }
+end:
+ rcu_read_unlock();
+ return status;
+}
+
+enum lttng_error_code kernel_create_trigger_group_notification_fd(
+ int *trigger_group_notification_fd)
+{
+ enum lttng_error_code ret = LTTNG_OK;
+ int local_fd = -1;
+
+ assert(trigger_group_notification_fd);
+
+ ret = kernctl_create_trigger_group_notification_fd(kernel_tracer_trigger_group_fd);
+ if (ret < 0) {
+ PERROR("ioctl kernel create trigger group");
+ ret = -1;
+ goto error;
+ }
+
+ /* Store locally */
+ local_fd = ret;
+
+ /* Prevent fd duplication after execlp() */
+ ret = fcntl(local_fd, F_SETFD, FD_CLOEXEC);
+ if (ret < 0) {
+ PERROR("fcntl session fd");
+ }
+
+ DBG("Kernel trigger group notification created (fd: %d)",
+ local_fd);
+ ret = 0;
+
+error:
+ *trigger_group_notification_fd = local_fd;
+ return ret;
+}
+
+enum lttng_error_code kernel_destroy_trigger_group_notification_fd(
+ int trigger_group_notification_fd)
+{
+ enum lttng_error_code ret = LTTNG_OK;
+ DBG("Closing trigger group notification fd %d", trigger_group_notification_fd);
+ if (trigger_group_notification_fd >= 0) {
+ ret = close(trigger_group_notification_fd);
+ if (ret) {
+ PERROR("close");
+ }
+ }
+ return ret;
+}
+
+static int kernel_create_token_event_rule(struct lttng_event_rule *rule,
+ const struct lttng_credentials *creds, uint64_t token)
+{
+ int err, fd;
+ enum lttng_error_code ret;
+ struct ltt_kernel_token_event_rule *event;
+ struct lttng_kernel_trigger trigger;
+
+ assert(rule);
+
+ ret = trace_kernel_create_token_event_rule(rule, token, &event);
+ if (ret != LTTNG_OK) {
+ goto error;
+ }
+
+ trace_kernel_init_trigger_from_event_rule(event->event_rule, &trigger);
+ trigger.id = event->token;
+
+ fd = kernctl_create_trigger(kernel_tracer_trigger_group_fd, &trigger);
+ if (fd < 0) {
+ switch (-fd) {
+ case EEXIST:
+ ret = LTTNG_ERR_KERN_EVENT_EXIST;
+ break;
+ case ENOSYS:
+ WARN("Trigger type not implemented");
+ ret = LTTNG_ERR_KERN_EVENT_ENOSYS;
+ break;
+ case ENOENT:
+ WARN("Event %s not found!", trigger.name);
+ ret = LTTNG_ERR_KERN_ENABLE_FAIL;
+ break;
+ default:
+ ret = LTTNG_ERR_KERN_ENABLE_FAIL;
+ PERROR("create trigger ioctl");
+ }
+ goto free_event;
+ }
+
+ event->fd = fd;
+ /* Prevent fd duplication after execlp() */
+ err = fcntl(event->fd, F_SETFD, FD_CLOEXEC);
+ if (err < 0) {
+ PERROR("fcntl session fd");
+ }
+
+ if (event->filter) {
+ err = kernctl_filter(event->fd, event->filter);
+ if (err < 0) {
+ switch (-err) {
+ case ENOMEM:
+ ret = LTTNG_ERR_FILTER_NOMEM;
+ break;
+ default:
+ ret = LTTNG_ERR_FILTER_INVAL;
+ break;
+ }
+ goto filter_error;
+ }
+ }
+
+ if (lttng_event_rule_get_type(event->event_rule) ==
+ LTTNG_EVENT_RULE_TYPE_UPROBE) {
+ ret = userspace_probe_event_rule_add_callsites(
+ rule, creds, event->fd);
+ if (ret) {
+ goto add_callsite_error;
+ }
+ }
+
+ err = kernctl_enable(event->fd);
+ if (err < 0) {
+ switch (-err) {
+ case EEXIST:
+ ret = LTTNG_ERR_KERN_EVENT_EXIST;
+ break;
+ default:
+ PERROR("enable kernel trigger");
+ ret = LTTNG_ERR_KERN_ENABLE_FAIL;
+ break;
+ }
+ goto enable_error;
+ }
+
+ /* Add event to event list */
+ cds_list_add(&event->list, &kernel_tracer_token_list.head);
+
+ DBG("Trigger %s created (fd: %d)", trigger.name, event->fd);
+
+ return 0;
+
+add_callsite_error:
+enable_error:
+filter_error:
+ {
+ int closeret;
+
+ closeret = close(event->fd);
+ if (closeret) {
+ PERROR("close event fd");
+ }
+ }
+free_event:
+ free(event);
+error:
+ return ret;
+}
+
+enum lttng_error_code kernel_update_tokens(void)
+{
+ enum lttng_error_code ret = LTTNG_OK;
+ enum lttng_trigger_status t_status;
+ struct ltt_kernel_token_event_rule *token_event_rule_element;
+ struct lttng_triggers *triggers;
+ unsigned int count;
+
+ /* TODO error handling */
+
+ /* Get list of token trigger from the notification thread here */
+ rcu_read_lock();
+ pthread_mutex_lock(¬ification_trigger_tokens_ht_lock);
+ ret = notification_thread_command_get_tokens(notification_thread_handle, &triggers);
+ if (ret != LTTNG_OK) {
+ ret = -1;
+ goto end;
+ }
+
+ assert(triggers);
+
+ t_status = lttng_triggers_get_count(triggers, &count);
+ if (t_status != LTTNG_TRIGGER_STATUS_OK) {
+ ret = -1;
+ goto end;
+ }
+
+ for (unsigned int i = 0; i < count; i++) {
+ struct lttng_condition *condition;
+ struct lttng_event_rule *event_rule;
+ struct lttng_trigger *trigger;
+ struct ltt_kernel_token_event_rule *k_token;
+ const struct lttng_credentials *creds;
+ uint64_t token;
+
+ trigger = lttng_triggers_get_pointer_of_index(triggers, i);
+ assert(trigger);
+
+ /* TODO: error checking and type checking */
+ token = lttng_trigger_get_key(trigger);
+ condition = lttng_trigger_get_condition(trigger);
+ (void) lttng_condition_event_rule_get_rule_no_const(condition, &event_rule);
+
+ if (lttng_event_rule_get_domain_type(event_rule) != LTTNG_DOMAIN_KERNEL) {
+ /* Skip ust related trigger */
+ continue;
+ }
+
+ creds = lttng_trigger_get_credentials(trigger);
+ /* Iterate over all known token trigger */
+ k_token = trace_kernel_find_trigger_by_token(&kernel_tracer_token_list, token);
+ if (!k_token) {
+ ret = kernel_create_token_event_rule(event_rule, creds, token);
+ if (ret < 0) {
+ goto end;
+ }
+ }
+ }
+
+ /* Remove all unknown trigger from the app
+ * TODO find a way better way then this, do it on the unregister command
+ * and be specific on the token to remove instead of going over all
+ * trigger known to the app. This is sub optimal.
+ */
+ cds_list_for_each_entry (token_event_rule_element, &kernel_tracer_token_list.head,
+ list) {
+ uint64_t token;
+ bool found = false;
+
+ token = token_event_rule_element->token;
+
+ /*
+ * Check if the app event trigger still exists on the
+ * notification side.
+ * TODO: might want to change the backing data struct of the
+ * lttng_triggers object to allow quick lookup?
+ * For kernel mostly all of this can be removed once we delete
+ * on a per trigger basis.
+ */
+
+ for (unsigned int i = 0; i < count; i++) {
+ struct lttng_trigger *trigger;
+ uint64_t inner_token;
+
+ trigger = lttng_triggers_get_pointer_of_index(
+ triggers, i);
+ assert(trigger);
+
+ inner_token = lttng_trigger_get_key(trigger);
+
+ if (inner_token == token) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ /* Still valid */
+ continue;
+ }
+
+ kernel_disable_token_event_rule(token_event_rule_element);
+ trace_kernel_destroy_token_event_rule(token_event_rule_element);
+ }
+end:
+ rcu_read_unlock();
+ pthread_mutex_unlock(¬ification_trigger_tokens_ht_lock);
+ return ret;
+
+}
+
+int kernel_get_notification_fd(void)
+{
+ return kernel_tracer_trigger_group_notification_fd;
+}