+ assert(app);
+ assert(ua_sess);
+ assert(ua_chan);
+
+ health_code_update();
+
+ DBG("UST app sending channel %s to UST app sock %d", ua_chan->name,
+ app->sock);
+
+ /* Send channel to the application. */
+ ret = ust_consumer_send_channel_to_ust(app, ua_sess, ua_chan);
+ if (ret == -EPIPE || ret == -LTTNG_UST_ERR_EXITING) {
+ ret = -ENOTCONN; /* Caused by app exiting. */
+ goto error;
+ } else if (ret < 0) {
+ goto error;
+ }
+
+ health_code_update();
+
+ /* Send all streams to application. */
+ cds_list_for_each_entry_safe(stream, stmp, &ua_chan->streams.head, list) {
+ ret = ust_consumer_send_stream_to_ust(app, ua_chan, stream);
+ if (ret == -EPIPE || ret == -LTTNG_UST_ERR_EXITING) {
+ ret = -ENOTCONN; /* Caused by app exiting. */
+ goto error;
+ } else if (ret < 0) {
+ goto error;
+ }
+ /* We don't need the stream anymore once sent to the tracer. */
+ cds_list_del(&stream->list);
+ delete_ust_app_stream(-1, stream, app);
+ }
+ /* Flag the channel that it is sent to the application. */
+ ua_chan->is_sent = 1;
+
+error:
+ health_code_update();
+ return ret;
+}
+
+/*
+ * Create the specified event onto the UST tracer for a UST session.
+ *
+ * Should be called with session mutex held.
+ */
+static
+int create_ust_event(struct ust_app *app, struct ust_app_session *ua_sess,
+ struct ust_app_channel *ua_chan, struct ust_app_event *ua_event)
+{
+ int ret = 0;
+
+ health_code_update();
+
+ /* Create UST event on tracer */
+ pthread_mutex_lock(&app->sock_lock);
+ ret = ustctl_create_event(app->sock, &ua_event->attr, ua_chan->obj,
+ &ua_event->obj);
+ pthread_mutex_unlock(&app->sock_lock);
+ if (ret < 0) {
+ if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+ abort();
+ ERR("Error ustctl create event %s for app pid: %d with ret %d",
+ ua_event->attr.name, app->pid, ret);
+ } else {
+ /*
+ * This is normal behavior, an application can die during the
+ * creation process. Don't report an error so the execution can
+ * continue normally.
+ */
+ ret = 0;
+ DBG3("UST app create event failed. Application is dead.");
+ }
+ goto error;
+ }
+
+ ua_event->handle = ua_event->obj->handle;
+
+ DBG2("UST app event %s created successfully for pid:%d object: %p",
+ ua_event->attr.name, app->pid, ua_event->obj);
+
+ health_code_update();
+
+ /* Set filter if one is present. */
+ if (ua_event->filter) {
+ ret = set_ust_object_filter(app, ua_event->filter, ua_event->obj);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ /* Set exclusions for the event */
+ if (ua_event->exclusion) {
+ ret = set_ust_object_exclusions(app, ua_event->exclusion, ua_event->obj);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ /* If event not enabled, disable it on the tracer */
+ if (ua_event->enabled) {
+ /*
+ * We now need to explicitly enable the event, since it
+ * is now disabled at creation.
+ */
+ ret = enable_ust_object(app, ua_event->obj);
+ if (ret < 0) {
+ /*
+ * If we hit an EPERM, something is wrong with our enable call. If
+ * we get an EEXIST, there is a problem on the tracer side since we
+ * just created it.
+ */
+ switch (ret) {
+ case -LTTNG_UST_ERR_PERM:
+ /* Code flow problem */
+ assert(0);
+ case -LTTNG_UST_ERR_EXIST:
+ /* It's OK for our use case. */
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+ goto error;
+ }
+ }
+
+error:
+ health_code_update();
+ return ret;
+}
+
+static int init_ust_event_notifier_from_event_rule(
+ const struct lttng_event_rule *rule,
+ struct lttng_ust_event_notifier *event_notifier)
+{
+ enum lttng_event_rule_status status;
+ enum lttng_loglevel_type loglevel_type;
+ enum lttng_ust_loglevel_type ust_loglevel_type = LTTNG_UST_LOGLEVEL_ALL;
+ int loglevel = -1, ret = 0;
+ const char *pattern;
+
+ /* For now only LTTNG_EVENT_RULE_TYPE_TRACEPOINT are supported. */
+ assert(lttng_event_rule_get_type(rule) ==
+ LTTNG_EVENT_RULE_TYPE_TRACEPOINT);
+
+ memset(event_notifier, 0, sizeof(*event_notifier));
+
+ status = lttng_event_rule_tracepoint_get_pattern(rule, &pattern);
+ if (status != LTTNG_EVENT_RULE_STATUS_OK) {
+ /* At this point, this is a fatal error. */
+ abort();
+ }
+
+ status = lttng_event_rule_tracepoint_get_log_level_type(
+ rule, &loglevel_type);
+ if (status != LTTNG_EVENT_RULE_STATUS_OK) {
+ /* At this point, this is a fatal error. */
+ abort();
+ }
+
+ switch (loglevel_type) {
+ case LTTNG_EVENT_LOGLEVEL_ALL:
+ ust_loglevel_type = LTTNG_UST_LOGLEVEL_ALL;
+ break;
+ case LTTNG_EVENT_LOGLEVEL_RANGE:
+ ust_loglevel_type = LTTNG_UST_LOGLEVEL_RANGE;
+ break;
+ case LTTNG_EVENT_LOGLEVEL_SINGLE:
+ ust_loglevel_type = LTTNG_UST_LOGLEVEL_SINGLE;
+ break;
+ default:
+ /* Unknown log level specification type. */
+ abort();
+ }
+
+ if (loglevel_type != LTTNG_EVENT_LOGLEVEL_ALL) {
+ status = lttng_event_rule_tracepoint_get_log_level(
+ rule, &loglevel);
+ assert(status == LTTNG_EVENT_RULE_STATUS_OK);
+ }
+
+ event_notifier->event.instrumentation = LTTNG_UST_TRACEPOINT;
+ ret = lttng_strncpy(event_notifier->event.name, pattern,
+ LTTNG_UST_SYM_NAME_LEN - 1);
+ if (ret) {
+ ERR("Failed to copy event rule pattern to notifier: pattern = '%s' ",
+ pattern);
+ goto end;
+ }
+
+ event_notifier->event.loglevel_type = ust_loglevel_type;
+ event_notifier->event.loglevel = loglevel;
+end:
+ return ret;
+}
+
+/*
+ * Create the specified event notifier against the user space tracer of a
+ * given application.
+ */
+static int create_ust_event_notifier(struct ust_app *app,
+ struct ust_app_event_notifier_rule *ua_event_notifier_rule)
+{
+ int ret = 0;
+ struct lttng_ust_event_notifier event_notifier;
+
+ health_code_update();
+ assert(app->event_notifier_group.object);
+
+ ret = init_ust_event_notifier_from_event_rule(
+ ua_event_notifier_rule->event_rule, &event_notifier);
+ if (ret) {
+ ERR("Failed to initialize UST event notifier from event rule: app = '%s' (ppid: %d)",
+ app->name, app->ppid);
+ goto error;
+ }
+
+ event_notifier.event.token = ua_event_notifier_rule->token;
+
+ /* Create UST event notifier against the tracer. */
+ pthread_mutex_lock(&app->sock_lock);
+ ret = ustctl_create_event_notifier(app->sock, &event_notifier,
+ app->event_notifier_group.object,
+ &ua_event_notifier_rule->obj);
+ pthread_mutex_unlock(&app->sock_lock);
+ if (ret < 0) {
+ if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+ ERR("Error ustctl create event notifier: name = '%s', app = '%s' (ppid: %d), ret = %d",
+ event_notifier.event.name, app->name,
+ app->ppid, ret);
+ } else {
+ /*
+ * This is normal behavior, an application can die
+ * during the creation process. Don't report an error so
+ * the execution can continue normally.
+ */
+ ret = 0;
+ DBG3("UST app create event notifier failed (application is dead): app = '%s' (ppid = %d)",
+ app->name, app->ppid);
+ }
+
+ goto error;
+ }
+
+ ua_event_notifier_rule->handle = ua_event_notifier_rule->obj->handle;
+
+ DBG2("UST app event notifier %s created successfully: app = '%s' (ppid: %d), object: %p",
+ event_notifier.event.name, app->name, app->ppid,
+ ua_event_notifier_rule->obj);
+
+ health_code_update();
+
+ /* Set filter if one is present. */
+ if (ua_event_notifier_rule->filter) {
+ ret = set_ust_object_filter(app, ua_event_notifier_rule->filter,
+ ua_event_notifier_rule->obj);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ /* Set exclusions for the event. */
+ if (ua_event_notifier_rule->exclusion) {
+ ret = set_ust_object_exclusions(app,
+ ua_event_notifier_rule->exclusion,
+ ua_event_notifier_rule->obj);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+ /*
+ * We now need to explicitly enable the event, since it
+ * is disabled at creation.
+ */
+ ret = enable_ust_object(app, ua_event_notifier_rule->obj);
+ if (ret < 0) {
+ /*
+ * If we hit an EPERM, something is wrong with our enable call.
+ * If we get an EEXIST, there is a problem on the tracer side
+ * since we just created it.
+ */
+ switch (ret) {
+ case -LTTNG_UST_ERR_PERM:
+ /* Code flow problem. */
+ abort();
+ case -LTTNG_UST_ERR_EXIST:
+ /* It's OK for our use case. */
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+
+ goto error;
+ }
+
+ ua_event_notifier_rule->enabled = true;
+
+error:
+ health_code_update();
+ return ret;
+}
+
+/*
+ * Copy data between an UST app event and a LTT event.
+ */
+static void shadow_copy_event(struct ust_app_event *ua_event,
+ struct ltt_ust_event *uevent)
+{
+ size_t exclusion_alloc_size;
+
+ strncpy(ua_event->name, uevent->attr.name, sizeof(ua_event->name));
+ ua_event->name[sizeof(ua_event->name) - 1] = '\0';
+
+ ua_event->enabled = uevent->enabled;
+
+ /* Copy event attributes */
+ memcpy(&ua_event->attr, &uevent->attr, sizeof(ua_event->attr));
+
+ /* Copy filter bytecode */
+ if (uevent->filter) {
+ ua_event->filter = copy_filter_bytecode(uevent->filter);
+ /* Filter might be NULL here in case of ENONEM. */
+ }
+
+ /* Copy exclusion data */
+ if (uevent->exclusion) {
+ exclusion_alloc_size = sizeof(struct lttng_event_exclusion) +
+ LTTNG_UST_SYM_NAME_LEN * uevent->exclusion->count;
+ ua_event->exclusion = zmalloc(exclusion_alloc_size);
+ if (ua_event->exclusion == NULL) {
+ PERROR("malloc");
+ } else {
+ memcpy(ua_event->exclusion, uevent->exclusion,
+ exclusion_alloc_size);
+ }
+ }
+}
+
+/*
+ * Copy data between an UST app channel and a LTT channel.
+ */
+static void shadow_copy_channel(struct ust_app_channel *ua_chan,
+ struct ltt_ust_channel *uchan)
+{
+ DBG2("UST app shadow copy of channel %s started", ua_chan->name);
+
+ strncpy(ua_chan->name, uchan->name, sizeof(ua_chan->name));
+ ua_chan->name[sizeof(ua_chan->name) - 1] = '\0';
+
+ ua_chan->tracefile_size = uchan->tracefile_size;
+ ua_chan->tracefile_count = uchan->tracefile_count;
+
+ /* Copy event attributes since the layout is different. */
+ ua_chan->attr.subbuf_size = uchan->attr.subbuf_size;
+ ua_chan->attr.num_subbuf = uchan->attr.num_subbuf;
+ ua_chan->attr.overwrite = uchan->attr.overwrite;
+ ua_chan->attr.switch_timer_interval = uchan->attr.switch_timer_interval;
+ ua_chan->attr.read_timer_interval = uchan->attr.read_timer_interval;
+ ua_chan->monitor_timer_interval = uchan->monitor_timer_interval;
+ ua_chan->attr.output = uchan->attr.output;
+ ua_chan->attr.blocking_timeout = uchan->attr.u.s.blocking_timeout;
+
+ /*
+ * Note that the attribute channel type is not set since the channel on the
+ * tracing registry side does not have this information.
+ */
+
+ ua_chan->enabled = uchan->enabled;
+ ua_chan->tracing_channel_id = uchan->id;
+
+ DBG3("UST app shadow copy of channel %s done", ua_chan->name);
+}
+
+/*
+ * Copy data between a UST app session and a regular LTT session.
+ */
+static void shadow_copy_session(struct ust_app_session *ua_sess,
+ struct ltt_ust_session *usess, struct ust_app *app)
+{
+ struct tm *timeinfo;
+ char datetime[16];
+ int ret;
+ char tmp_shm_path[PATH_MAX];
+
+ timeinfo = localtime(&app->registration_time);
+ strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo);
+
+ DBG2("Shadow copy of session handle %d", ua_sess->handle);
+
+ ua_sess->tracing_id = usess->id;
+ ua_sess->id = get_next_session_id();
+ LTTNG_OPTIONAL_SET(&ua_sess->real_credentials.uid, app->uid);
+ LTTNG_OPTIONAL_SET(&ua_sess->real_credentials.gid, app->gid);
+ LTTNG_OPTIONAL_SET(&ua_sess->effective_credentials.uid, usess->uid);
+ LTTNG_OPTIONAL_SET(&ua_sess->effective_credentials.gid, usess->gid);
+ ua_sess->buffer_type = usess->buffer_type;
+ ua_sess->bits_per_long = app->bits_per_long;
+
+ /* There is only one consumer object per session possible. */
+ consumer_output_get(usess->consumer);
+ ua_sess->consumer = usess->consumer;
+
+ ua_sess->output_traces = usess->output_traces;
+ ua_sess->live_timer_interval = usess->live_timer_interval;
+ copy_channel_attr_to_ustctl(&ua_sess->metadata_attr,
+ &usess->metadata_attr);
+
+ switch (ua_sess->buffer_type) {
+ case LTTNG_BUFFER_PER_PID:
+ ret = snprintf(ua_sess->path, sizeof(ua_sess->path),
+ DEFAULT_UST_TRACE_PID_PATH "/%s-%d-%s", app->name, app->pid,
+ datetime);
+ break;
+ case LTTNG_BUFFER_PER_UID:
+ ret = snprintf(ua_sess->path, sizeof(ua_sess->path),
+ DEFAULT_UST_TRACE_UID_PATH,
+ lttng_credentials_get_uid(&ua_sess->real_credentials),
+ app->bits_per_long);
+ break;
+ default:
+ assert(0);
+ goto error;
+ }
+ if (ret < 0) {
+ PERROR("asprintf UST shadow copy session");
+ assert(0);
+ goto error;
+ }
+
+ strncpy(ua_sess->root_shm_path, usess->root_shm_path,
+ sizeof(ua_sess->root_shm_path));
+ ua_sess->root_shm_path[sizeof(ua_sess->root_shm_path) - 1] = '\0';
+ strncpy(ua_sess->shm_path, usess->shm_path,
+ sizeof(ua_sess->shm_path));
+ ua_sess->shm_path[sizeof(ua_sess->shm_path) - 1] = '\0';
+ if (ua_sess->shm_path[0]) {
+ switch (ua_sess->buffer_type) {
+ case LTTNG_BUFFER_PER_PID:
+ ret = snprintf(tmp_shm_path, sizeof(tmp_shm_path),
+ "/" DEFAULT_UST_TRACE_PID_PATH "/%s-%d-%s",
+ app->name, app->pid, datetime);
+ break;
+ case LTTNG_BUFFER_PER_UID:
+ ret = snprintf(tmp_shm_path, sizeof(tmp_shm_path),
+ "/" DEFAULT_UST_TRACE_UID_PATH,
+ app->uid, app->bits_per_long);
+ break;
+ default:
+ assert(0);
+ goto error;
+ }
+ if (ret < 0) {
+ PERROR("sprintf UST shadow copy session");
+ assert(0);
+ goto error;
+ }
+ strncat(ua_sess->shm_path, tmp_shm_path,
+ sizeof(ua_sess->shm_path) - strlen(ua_sess->shm_path) - 1);
+ ua_sess->shm_path[sizeof(ua_sess->shm_path) - 1] = '\0';
+ }
+ return;
+
+error:
+ consumer_output_put(ua_sess->consumer);
+}
+
+/*
+ * Lookup sesison wrapper.
+ */
+static
+void __lookup_session_by_app(const struct ltt_ust_session *usess,
+ struct ust_app *app, struct lttng_ht_iter *iter)
+{
+ /* Get right UST app session from app */
+ lttng_ht_lookup(app->sessions, &usess->id, iter);
+}
+
+/*
+ * Return ust app session from the app session hashtable using the UST session
+ * id.
+ */
+static struct ust_app_session *lookup_session_by_app(
+ const struct ltt_ust_session *usess, struct ust_app *app)
+{
+ struct lttng_ht_iter iter;
+ struct lttng_ht_node_u64 *node;
+
+ __lookup_session_by_app(usess, app, &iter);
+ node = lttng_ht_iter_get_node_u64(&iter);
+ if (node == NULL) {
+ goto error;
+ }
+
+ return caa_container_of(node, struct ust_app_session, node);
+
+error:
+ return NULL;
+}
+
+/*
+ * Setup buffer registry per PID for the given session and application. If none
+ * is found, a new one is created, added to the global registry and
+ * initialized. If regp is valid, it's set with the newly created object.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int setup_buffer_reg_pid(struct ust_app_session *ua_sess,
+ struct ust_app *app, struct buffer_reg_pid **regp)
+{
+ int ret = 0;
+ struct buffer_reg_pid *reg_pid;
+
+ assert(ua_sess);
+ assert(app);
+
+ rcu_read_lock();
+
+ reg_pid = buffer_reg_pid_find(ua_sess->id);
+ if (!reg_pid) {
+ /*
+ * This is the create channel path meaning that if there is NO
+ * registry available, we have to create one for this session.
+ */
+ ret = buffer_reg_pid_create(ua_sess->id, ®_pid,
+ ua_sess->root_shm_path, ua_sess->shm_path);
+ if (ret < 0) {
+ goto error;
+ }
+ } else {
+ goto end;
+ }
+
+ /* Initialize registry. */
+ ret = ust_registry_session_init(®_pid->registry->reg.ust, app,
+ app->bits_per_long, app->uint8_t_alignment,
+ app->uint16_t_alignment, app->uint32_t_alignment,
+ app->uint64_t_alignment, app->long_alignment,
+ app->byte_order, app->version.major, app->version.minor,
+ reg_pid->root_shm_path, reg_pid->shm_path,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
+ ua_sess->tracing_id,
+ app->uid);
+ if (ret < 0) {
+ /*
+ * reg_pid->registry->reg.ust is NULL upon error, so we need to
+ * destroy the buffer registry, because it is always expected
+ * that if the buffer registry can be found, its ust registry is
+ * non-NULL.
+ */
+ buffer_reg_pid_destroy(reg_pid);
+ goto error;
+ }
+
+ buffer_reg_pid_add(reg_pid);
+
+ DBG3("UST app buffer registry per PID created successfully");
+
+end:
+ if (regp) {
+ *regp = reg_pid;
+ }
+error:
+ rcu_read_unlock();
+ return ret;
+}
+
+/*
+ * Setup buffer registry per UID for the given session and application. If none
+ * is found, a new one is created, added to the global registry and
+ * initialized. If regp is valid, it's set with the newly created object.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int setup_buffer_reg_uid(struct ltt_ust_session *usess,
+ struct ust_app_session *ua_sess,
+ struct ust_app *app, struct buffer_reg_uid **regp)
+{
+ int ret = 0;
+ struct buffer_reg_uid *reg_uid;
+
+ assert(usess);
+ assert(app);
+
+ rcu_read_lock();
+
+ reg_uid = buffer_reg_uid_find(usess->id, app->bits_per_long, app->uid);
+ if (!reg_uid) {
+ /*
+ * This is the create channel path meaning that if there is NO
+ * registry available, we have to create one for this session.
+ */
+ ret = buffer_reg_uid_create(usess->id, app->bits_per_long, app->uid,
+ LTTNG_DOMAIN_UST, ®_uid,
+ ua_sess->root_shm_path, ua_sess->shm_path);
+ if (ret < 0) {
+ goto error;
+ }
+ } else {
+ goto end;
+ }
+
+ /* Initialize registry. */
+ ret = ust_registry_session_init(®_uid->registry->reg.ust, NULL,
+ app->bits_per_long, app->uint8_t_alignment,
+ app->uint16_t_alignment, app->uint32_t_alignment,
+ app->uint64_t_alignment, app->long_alignment,
+ app->byte_order, app->version.major,
+ app->version.minor, reg_uid->root_shm_path,
+ reg_uid->shm_path, usess->uid, usess->gid,
+ ua_sess->tracing_id, app->uid);
+ if (ret < 0) {
+ /*
+ * reg_uid->registry->reg.ust is NULL upon error, so we need to
+ * destroy the buffer registry, because it is always expected
+ * that if the buffer registry can be found, its ust registry is
+ * non-NULL.
+ */
+ buffer_reg_uid_destroy(reg_uid, NULL);
+ goto error;
+ }
+ /* Add node to teardown list of the session. */
+ cds_list_add(®_uid->lnode, &usess->buffer_reg_uid_list);
+
+ buffer_reg_uid_add(reg_uid);
+
+ DBG3("UST app buffer registry per UID created successfully");
+end:
+ if (regp) {
+ *regp = reg_uid;
+ }
+error:
+ rcu_read_unlock();
+ return ret;
+}
+
+/*
+ * Create a session on the tracer side for the given app.
+ *
+ * On success, ua_sess_ptr is populated with the session pointer or else left
+ * untouched. If the session was created, is_created is set to 1. On error,
+ * it's left untouched. Note that ua_sess_ptr is mandatory but is_created can
+ * be NULL.
+ *
+ * Returns 0 on success or else a negative code which is either -ENOMEM or
+ * -ENOTCONN which is the default code if the ustctl_create_session fails.
+ */
+static int find_or_create_ust_app_session(struct ltt_ust_session *usess,
+ struct ust_app *app, struct ust_app_session **ua_sess_ptr,
+ int *is_created)
+{
+ int ret, created = 0;
+ struct ust_app_session *ua_sess;
+
+ assert(usess);
+ assert(app);
+ assert(ua_sess_ptr);
+
+ health_code_update();
+
+ ua_sess = lookup_session_by_app(usess, app);
+ if (ua_sess == NULL) {
+ DBG2("UST app pid: %d session id %" PRIu64 " not found, creating it",
+ app->pid, usess->id);
+ ua_sess = alloc_ust_app_session();
+ if (ua_sess == NULL) {
+ /* Only malloc can failed so something is really wrong */
+ ret = -ENOMEM;
+ goto error;
+ }
+ shadow_copy_session(ua_sess, usess, app);
+ created = 1;
+ }
+
+ switch (usess->buffer_type) {
+ case LTTNG_BUFFER_PER_PID:
+ /* Init local registry. */
+ ret = setup_buffer_reg_pid(ua_sess, app, NULL);
+ if (ret < 0) {
+ delete_ust_app_session(-1, ua_sess, app);
+ goto error;
+ }
+ break;
+ case LTTNG_BUFFER_PER_UID:
+ /* Look for a global registry. If none exists, create one. */
+ ret = setup_buffer_reg_uid(usess, ua_sess, app, NULL);
+ if (ret < 0) {
+ delete_ust_app_session(-1, ua_sess, app);
+ goto error;
+ }
+ break;
+ default:
+ assert(0);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ health_code_update();
+
+ if (ua_sess->handle == -1) {
+ pthread_mutex_lock(&app->sock_lock);
+ ret = ustctl_create_session(app->sock);
+ pthread_mutex_unlock(&app->sock_lock);
+ if (ret < 0) {
+ if (ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
+ ERR("Creating session for app pid %d with ret %d",
+ app->pid, ret);
+ } else {
+ DBG("UST app creating session failed. Application is dead");
+ /*
+ * This is normal behavior, an application can die during the
+ * creation process. Don't report an error so the execution can
+ * continue normally. This will get flagged ENOTCONN and the
+ * caller will handle it.
+ */
+ ret = 0;
+ }
+ delete_ust_app_session(-1, ua_sess, app);
+ if (ret != -ENOMEM) {
+ /*
+ * Tracer is probably gone or got an internal error so let's
+ * behave like it will soon unregister or not usable.
+ */
+ ret = -ENOTCONN;
+ }
+ goto error;
+ }
+
+ ua_sess->handle = ret;
+
+ /* Add ust app session to app's HT */
+ lttng_ht_node_init_u64(&ua_sess->node,
+ ua_sess->tracing_id);
+ lttng_ht_add_unique_u64(app->sessions, &ua_sess->node);
+ lttng_ht_node_init_ulong(&ua_sess->ust_objd_node, ua_sess->handle);
+ lttng_ht_add_unique_ulong(app->ust_sessions_objd,
+ &ua_sess->ust_objd_node);
+
+ DBG2("UST app session created successfully with handle %d", ret);
+ }
+
+ *ua_sess_ptr = ua_sess;
+ if (is_created) {
+ *is_created = created;
+ }
+
+ /* Everything went well. */
+ ret = 0;
+
+error:
+ health_code_update();
+ return ret;
+}
+
+/*
+ * Match function for a hash table lookup of ust_app_ctx.
+ *
+ * It matches an ust app context based on the context type and, in the case
+ * of perf counters, their name.
+ */
+static int ht_match_ust_app_ctx(struct cds_lfht_node *node, const void *_key)
+{
+ struct ust_app_ctx *ctx;
+ const struct lttng_ust_context_attr *key;
+
+ assert(node);
+ assert(_key);
+
+ ctx = caa_container_of(node, struct ust_app_ctx, node.node);
+ key = _key;
+
+ /* Context type */
+ if (ctx->ctx.ctx != key->ctx) {
+ goto no_match;
+ }
+
+ switch(key->ctx) {
+ case LTTNG_UST_CONTEXT_PERF_THREAD_COUNTER:
+ if (strncmp(key->u.perf_counter.name,
+ ctx->ctx.u.perf_counter.name,
+ sizeof(key->u.perf_counter.name))) {
+ goto no_match;
+ }
+ break;
+ case LTTNG_UST_CONTEXT_APP_CONTEXT:
+ if (strcmp(key->u.app_ctx.provider_name,
+ ctx->ctx.u.app_ctx.provider_name) ||
+ strcmp(key->u.app_ctx.ctx_name,
+ ctx->ctx.u.app_ctx.ctx_name)) {
+ goto no_match;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* Match. */
+ return 1;
+
+no_match:
+ return 0;
+}
+
+/*
+ * Lookup for an ust app context from an lttng_ust_context.
+ *
+ * Must be called while holding RCU read side lock.
+ * Return an ust_app_ctx object or NULL on error.
+ */
+static
+struct ust_app_ctx *find_ust_app_context(struct lttng_ht *ht,
+ struct lttng_ust_context_attr *uctx)
+{
+ struct lttng_ht_iter iter;
+ struct lttng_ht_node_ulong *node;
+ struct ust_app_ctx *app_ctx = NULL;
+
+ assert(uctx);
+ assert(ht);
+
+ /* Lookup using the lttng_ust_context_type and a custom match fct. */
+ cds_lfht_lookup(ht->ht, ht->hash_fct((void *) uctx->ctx, lttng_ht_seed),
+ ht_match_ust_app_ctx, uctx, &iter.iter);
+ node = lttng_ht_iter_get_node_ulong(&iter);
+ if (!node) {
+ goto end;
+ }
+
+ app_ctx = caa_container_of(node, struct ust_app_ctx, node);
+
+end:
+ return app_ctx;
+}
+
+/*
+ * Create a context for the channel on the tracer.
+ *
+ * Called with UST app session lock held and a RCU read side lock.
+ */
+static
+int create_ust_app_channel_context(struct ust_app_channel *ua_chan,
+ struct lttng_ust_context_attr *uctx,
+ struct ust_app *app)
+{
+ int ret = 0;
+ struct ust_app_ctx *ua_ctx;
+
+ DBG2("UST app adding context to channel %s", ua_chan->name);
+
+ ua_ctx = find_ust_app_context(ua_chan->ctx, uctx);
+ if (ua_ctx) {
+ ret = -EEXIST;
+ goto error;
+ }
+
+ ua_ctx = alloc_ust_app_ctx(uctx);
+ if (ua_ctx == NULL) {
+ /* malloc failed */
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ lttng_ht_node_init_ulong(&ua_ctx->node, (unsigned long) ua_ctx->ctx.ctx);
+ lttng_ht_add_ulong(ua_chan->ctx, &ua_ctx->node);
+ cds_list_add_tail(&ua_ctx->list, &ua_chan->ctx_list);
+
+ ret = create_ust_channel_context(ua_chan, ua_ctx, app);
+ if (ret < 0) {
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * Enable on the tracer side a ust app event for the session and channel.
+ *
+ * Called with UST app session lock held.
+ */
+static
+int enable_ust_app_event(struct ust_app_session *ua_sess,
+ struct ust_app_event *ua_event, struct ust_app *app)
+{
+ int ret;
+
+ ret = enable_ust_object(app, ua_event->obj);
+ if (ret < 0) {
+ goto error;
+ }
+
+ ua_event->enabled = 1;
+
+error:
+ return ret;
+}
+
+/*
+ * Disable on the tracer side a ust app event for the session and channel.
+ */
+static int disable_ust_app_event(struct ust_app_session *ua_sess,
+ struct ust_app_event *ua_event, struct ust_app *app)
+{
+ int ret;
+
+ ret = disable_ust_object(app, ua_event->obj);
+ if (ret < 0) {
+ goto error;
+ }
+
+ ua_event->enabled = 0;
+
+error:
+ return ret;
+}
+
+/*
+ * Lookup ust app channel for session and disable it on the tracer side.
+ */
+static
+int disable_ust_app_channel(struct ust_app_session *ua_sess,
+ struct ust_app_channel *ua_chan, struct ust_app *app)
+{
+ int ret;
+
+ ret = disable_ust_channel(app, ua_sess, ua_chan);
+ if (ret < 0) {
+ goto error;
+ }
+
+ ua_chan->enabled = 0;
+
+error:
+ return ret;
+}
+
+/*
+ * Lookup ust app channel for session and enable it on the tracer side. This
+ * MUST be called with a RCU read side lock acquired.
+ */
+static int enable_ust_app_channel(struct ust_app_session *ua_sess,
+ struct ltt_ust_channel *uchan, struct ust_app *app)
+{
+ int ret = 0;
+ struct lttng_ht_iter iter;
+ struct lttng_ht_node_str *ua_chan_node;
+ struct ust_app_channel *ua_chan;
+
+ lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &iter);
+ ua_chan_node = lttng_ht_iter_get_node_str(&iter);
+ if (ua_chan_node == NULL) {
+ DBG2("Unable to find channel %s in ust session id %" PRIu64,
+ uchan->name, ua_sess->tracing_id);
+ goto error;
+ }
+
+ ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
+
+ ret = enable_ust_channel(app, ua_sess, ua_chan);
+ if (ret < 0) {
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * Ask the consumer to create a channel and get it if successful.
+ *
+ * Called with UST app session lock held.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int do_consumer_create_channel(struct ltt_ust_session *usess,
+ struct ust_app_session *ua_sess, struct ust_app_channel *ua_chan,
+ int bitness, struct ust_registry_session *registry,
+ uint64_t trace_archive_id)
+{
+ int ret;
+ unsigned int nb_fd = 0;
+ struct consumer_socket *socket;
+
+ assert(usess);
+ assert(ua_sess);
+ assert(ua_chan);
+ assert(registry);
+
+ rcu_read_lock();
+ health_code_update();
+
+ /* Get the right consumer socket for the application. */
+ socket = consumer_find_socket_by_bitness(bitness, usess->consumer);
+ if (!socket) {
+ ret = -EINVAL;
+ goto error;
+ }
+
+ health_code_update();
+
+ /* Need one fd for the channel. */
+ ret = lttng_fd_get(LTTNG_FD_APPS, 1);
+ if (ret < 0) {
+ ERR("Exhausted number of available FD upon create channel");
+ goto error;
+ }
+
+ /*
+ * Ask consumer to create channel. The consumer will return the number of
+ * stream we have to expect.
+ */
+ ret = ust_consumer_ask_channel(ua_sess, ua_chan, usess->consumer, socket,
+ registry, usess->current_trace_chunk);
+ if (ret < 0) {
+ goto error_ask;
+ }
+
+ /*
+ * Compute the number of fd needed before receiving them. It must be 2 per
+ * stream (2 being the default value here).
+ */
+ nb_fd = DEFAULT_UST_STREAM_FD_NUM * ua_chan->expected_stream_count;
+
+ /* Reserve the amount of file descriptor we need. */
+ ret = lttng_fd_get(LTTNG_FD_APPS, nb_fd);
+ if (ret < 0) {
+ ERR("Exhausted number of available FD upon create channel");
+ goto error_fd_get_stream;
+ }
+
+ health_code_update();
+
+ /*
+ * Now get the channel from the consumer. This call wil populate the stream
+ * list of that channel and set the ust objects.
+ */
+ if (usess->consumer->enabled) {
+ ret = ust_consumer_get_channel(socket, ua_chan);
+ if (ret < 0) {
+ goto error_destroy;
+ }
+ }
+
+ rcu_read_unlock();
+ return 0;
+
+error_destroy:
+ lttng_fd_put(LTTNG_FD_APPS, nb_fd);
+error_fd_get_stream:
+ /*
+ * Initiate a destroy channel on the consumer since we had an error
+ * handling it on our side. The return value is of no importance since we
+ * already have a ret value set by the previous error that we need to
+ * return.
+ */
+ (void) ust_consumer_destroy_channel(socket, ua_chan);
+error_ask:
+ lttng_fd_put(LTTNG_FD_APPS, 1);
+error:
+ health_code_update();
+ rcu_read_unlock();
+ return ret;
+}
+
+/*
+ * Duplicate the ust data object of the ust app stream and save it in the
+ * buffer registry stream.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int duplicate_stream_object(struct buffer_reg_stream *reg_stream,
+ struct ust_app_stream *stream)
+{
+ int ret;
+
+ assert(reg_stream);
+ assert(stream);
+
+ /* Reserve the amount of file descriptor we need. */
+ ret = lttng_fd_get(LTTNG_FD_APPS, 2);
+ if (ret < 0) {
+ ERR("Exhausted number of available FD upon duplicate stream");
+ goto error;
+ }
+
+ /* Duplicate object for stream once the original is in the registry. */
+ ret = ustctl_duplicate_ust_object_data(&stream->obj,
+ reg_stream->obj.ust);
+ if (ret < 0) {
+ ERR("Duplicate stream obj from %p to %p failed with ret %d",
+ reg_stream->obj.ust, stream->obj, ret);
+ lttng_fd_put(LTTNG_FD_APPS, 2);
+ goto error;
+ }
+ stream->handle = stream->obj->handle;
+
+error:
+ return ret;
+}
+
+/*
+ * Duplicate the ust data object of the ust app. channel and save it in the
+ * buffer registry channel.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int duplicate_channel_object(struct buffer_reg_channel *reg_chan,
+ struct ust_app_channel *ua_chan)
+{
+ int ret;
+
+ assert(reg_chan);
+ assert(ua_chan);
+
+ /* Need two fds for the channel. */
+ ret = lttng_fd_get(LTTNG_FD_APPS, 1);
+ if (ret < 0) {
+ ERR("Exhausted number of available FD upon duplicate channel");
+ goto error_fd_get;
+ }
+
+ /* Duplicate object for stream once the original is in the registry. */
+ ret = ustctl_duplicate_ust_object_data(&ua_chan->obj, reg_chan->obj.ust);
+ if (ret < 0) {
+ ERR("Duplicate channel obj from %p to %p failed with ret: %d",
+ reg_chan->obj.ust, ua_chan->obj, ret);
+ goto error;
+ }
+ ua_chan->handle = ua_chan->obj->handle;
+
+ return 0;
+
+error:
+ lttng_fd_put(LTTNG_FD_APPS, 1);
+error_fd_get:
+ return ret;
+}
+
+/*
+ * For a given channel buffer registry, setup all streams of the given ust
+ * application channel.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int setup_buffer_reg_streams(struct buffer_reg_channel *reg_chan,
+ struct ust_app_channel *ua_chan,
+ struct ust_app *app)
+{
+ int ret = 0;
+ struct ust_app_stream *stream, *stmp;
+
+ assert(reg_chan);
+ assert(ua_chan);
+
+ DBG2("UST app setup buffer registry stream");
+
+ /* Send all streams to application. */
+ cds_list_for_each_entry_safe(stream, stmp, &ua_chan->streams.head, list) {
+ struct buffer_reg_stream *reg_stream;
+
+ ret = buffer_reg_stream_create(®_stream);
+ if (ret < 0) {
+ goto error;
+ }
+
+ /*
+ * Keep original pointer and nullify it in the stream so the delete
+ * stream call does not release the object.
+ */
+ reg_stream->obj.ust = stream->obj;
+ stream->obj = NULL;
+ buffer_reg_stream_add(reg_stream, reg_chan);
+
+ /* We don't need the streams anymore. */
+ cds_list_del(&stream->list);
+ delete_ust_app_stream(-1, stream, app);
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * Create a buffer registry channel for the given session registry and
+ * application channel object. If regp pointer is valid, it's set with the
+ * created object. Important, the created object is NOT added to the session
+ * registry hash table.
+ *
+ * Return 0 on success else a negative value.
+ */
+static int create_buffer_reg_channel(struct buffer_reg_session *reg_sess,
+ struct ust_app_channel *ua_chan, struct buffer_reg_channel **regp)
+{
+ int ret;
+ struct buffer_reg_channel *reg_chan = NULL;
+
+ assert(reg_sess);
+ assert(ua_chan);
+
+ DBG2("UST app creating buffer registry channel for %s", ua_chan->name);
+
+ /* Create buffer registry channel. */
+ ret = buffer_reg_channel_create(ua_chan->tracing_channel_id, ®_chan);
+ if (ret < 0) {
+ goto error_create;
+ }
+ assert(reg_chan);
+ reg_chan->consumer_key = ua_chan->key;
+ reg_chan->subbuf_size = ua_chan->attr.subbuf_size;
+ reg_chan->num_subbuf = ua_chan->attr.num_subbuf;
+
+ /* Create and add a channel registry to session. */
+ ret = ust_registry_channel_add(reg_sess->reg.ust,
+ ua_chan->tracing_channel_id);
+ if (ret < 0) {
+ goto error;
+ }
+ buffer_reg_channel_add(reg_sess, reg_chan);
+
+ if (regp) {
+ *regp = reg_chan;
+ }
+
+ return 0;
+
+error:
+ /* Safe because the registry channel object was not added to any HT. */
+ buffer_reg_channel_destroy(reg_chan, LTTNG_DOMAIN_UST);
+error_create:
+ return ret;
+}
+
+/*
+ * Setup buffer registry channel for the given session registry and application
+ * channel object. If regp pointer is valid, it's set with the created object.
+ *
+ * Return 0 on success else a negative value.
+ */
+static int setup_buffer_reg_channel(struct buffer_reg_session *reg_sess,
+ struct ust_app_channel *ua_chan, struct buffer_reg_channel *reg_chan,
+ struct ust_app *app)
+{
+ int ret;
+
+ assert(reg_sess);
+ assert(reg_chan);
+ assert(ua_chan);
+ assert(ua_chan->obj);
+
+ DBG2("UST app setup buffer registry channel for %s", ua_chan->name);
+
+ /* Setup all streams for the registry. */
+ ret = setup_buffer_reg_streams(reg_chan, ua_chan, app);
+ if (ret < 0) {
+ goto error;
+ }
+
+ reg_chan->obj.ust = ua_chan->obj;
+ ua_chan->obj = NULL;
+
+ return 0;
+
+error:
+ buffer_reg_channel_remove(reg_sess, reg_chan);
+ buffer_reg_channel_destroy(reg_chan, LTTNG_DOMAIN_UST);
+ return ret;
+}
+
+/*
+ * Send buffer registry channel to the application.
+ *
+ * Return 0 on success else a negative value.
+ */
+static int send_channel_uid_to_ust(struct buffer_reg_channel *reg_chan,
+ struct ust_app *app, struct ust_app_session *ua_sess,
+ struct ust_app_channel *ua_chan)
+{
+ int ret;
+ struct buffer_reg_stream *reg_stream;
+
+ assert(reg_chan);
+ assert(app);
+ assert(ua_sess);
+ assert(ua_chan);
+
+ DBG("UST app sending buffer registry channel to ust sock %d", app->sock);
+
+ ret = duplicate_channel_object(reg_chan, ua_chan);
+ if (ret < 0) {
+ goto error;
+ }
+
+ /* Send channel to the application. */
+ ret = ust_consumer_send_channel_to_ust(app, ua_sess, ua_chan);
+ if (ret == -EPIPE || ret == -LTTNG_UST_ERR_EXITING) {
+ ret = -ENOTCONN; /* Caused by app exiting. */
+ goto error;
+ } else if (ret < 0) {
+ goto error;
+ }
+
+ health_code_update();
+
+ /* Send all streams to application. */
+ pthread_mutex_lock(®_chan->stream_list_lock);
+ cds_list_for_each_entry(reg_stream, ®_chan->streams, lnode) {
+ struct ust_app_stream stream;
+
+ ret = duplicate_stream_object(reg_stream, &stream);
+ if (ret < 0) {
+ goto error_stream_unlock;
+ }
+
+ ret = ust_consumer_send_stream_to_ust(app, ua_chan, &stream);
+ if (ret < 0) {
+ (void) release_ust_app_stream(-1, &stream, app);
+ if (ret == -EPIPE || ret == -LTTNG_UST_ERR_EXITING) {
+ ret = -ENOTCONN; /* Caused by app exiting. */
+ }
+ goto error_stream_unlock;
+ }
+
+ /*
+ * The return value is not important here. This function will output an
+ * error if needed.
+ */
+ (void) release_ust_app_stream(-1, &stream, app);
+ }
+ ua_chan->is_sent = 1;
+
+error_stream_unlock:
+ pthread_mutex_unlock(®_chan->stream_list_lock);
+error:
+ return ret;
+}
+
+/*
+ * Create and send to the application the created buffers with per UID buffers.
+ *
+ * This MUST be called with a RCU read side lock acquired.
+ * The session list lock and the session's lock must be acquired.
+ *
+ * Return 0 on success else a negative value.
+ */
+static int create_channel_per_uid(struct ust_app *app,
+ struct ltt_ust_session *usess, struct ust_app_session *ua_sess,
+ struct ust_app_channel *ua_chan)
+{
+ int ret;
+ struct buffer_reg_uid *reg_uid;
+ struct buffer_reg_channel *reg_chan;
+ struct ltt_session *session = NULL;
+ enum lttng_error_code notification_ret;
+ struct ust_registry_channel *chan_reg;
+
+ assert(app);
+ assert(usess);
+ assert(ua_sess);
+ assert(ua_chan);
+
+ DBG("UST app creating channel %s with per UID buffers", ua_chan->name);
+
+ reg_uid = buffer_reg_uid_find(usess->id, app->bits_per_long, app->uid);
+ /*
+ * The session creation handles the creation of this global registry
+ * object. If none can be find, there is a code flow problem or a
+ * teardown race.
+ */
+ assert(reg_uid);
+
+ reg_chan = buffer_reg_channel_find(ua_chan->tracing_channel_id,
+ reg_uid);
+ if (reg_chan) {
+ goto send_channel;
+ }
+
+ /* Create the buffer registry channel object. */
+ ret = create_buffer_reg_channel(reg_uid->registry, ua_chan, ®_chan);
+ if (ret < 0) {
+ ERR("Error creating the UST channel \"%s\" registry instance",
+ ua_chan->name);
+ goto error;
+ }
+
+ session = session_find_by_id(ua_sess->tracing_id);
+ assert(session);
+ assert(pthread_mutex_trylock(&session->lock));
+ assert(session_trylock_list());
+
+ /*
+ * Create the buffers on the consumer side. This call populates the
+ * ust app channel object with all streams and data object.
+ */
+ ret = do_consumer_create_channel(usess, ua_sess, ua_chan,
+ app->bits_per_long, reg_uid->registry->reg.ust,
+ session->most_recent_chunk_id.value);
+ if (ret < 0) {
+ ERR("Error creating UST channel \"%s\" on the consumer daemon",
+ ua_chan->name);
+
+ /*
+ * Let's remove the previously created buffer registry channel so
+ * it's not visible anymore in the session registry.
+ */
+ ust_registry_channel_del_free(reg_uid->registry->reg.ust,
+ ua_chan->tracing_channel_id, false);
+ buffer_reg_channel_remove(reg_uid->registry, reg_chan);
+ buffer_reg_channel_destroy(reg_chan, LTTNG_DOMAIN_UST);
+ goto error;
+ }
+
+ /*
+ * Setup the streams and add it to the session registry.
+ */
+ ret = setup_buffer_reg_channel(reg_uid->registry,
+ ua_chan, reg_chan, app);
+ if (ret < 0) {
+ ERR("Error setting up UST channel \"%s\"", ua_chan->name);
+ goto error;
+ }
+
+ /* Notify the notification subsystem of the channel's creation. */
+ pthread_mutex_lock(®_uid->registry->reg.ust->lock);
+ chan_reg = ust_registry_channel_find(reg_uid->registry->reg.ust,
+ ua_chan->tracing_channel_id);
+ assert(chan_reg);
+ chan_reg->consumer_key = ua_chan->key;
+ chan_reg = NULL;
+ pthread_mutex_unlock(®_uid->registry->reg.ust->lock);
+
+ notification_ret = notification_thread_command_add_channel(
+ notification_thread_handle, session->name,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
+ ua_chan->name,
+ ua_chan->key, LTTNG_DOMAIN_UST,
+ ua_chan->attr.subbuf_size * ua_chan->attr.num_subbuf);
+ if (notification_ret != LTTNG_OK) {
+ ret = - (int) notification_ret;
+ ERR("Failed to add channel to notification thread");
+ goto error;
+ }
+
+send_channel:
+ /* Send buffers to the application. */
+ ret = send_channel_uid_to_ust(reg_chan, app, ua_sess, ua_chan);
+ if (ret < 0) {
+ if (ret != -ENOTCONN) {
+ ERR("Error sending channel to application");
+ }
+ goto error;
+ }
+
+error:
+ if (session) {
+ session_put(session);
+ }
+ return ret;
+}
+
+/*
+ * Create and send to the application the created buffers with per PID buffers.
+ *
+ * Called with UST app session lock held.
+ * The session list lock and the session's lock must be acquired.
+ *
+ * Return 0 on success else a negative value.
+ */
+static int create_channel_per_pid(struct ust_app *app,
+ struct ltt_ust_session *usess, struct ust_app_session *ua_sess,
+ struct ust_app_channel *ua_chan)
+{
+ int ret;
+ struct ust_registry_session *registry;
+ enum lttng_error_code cmd_ret;
+ struct ltt_session *session = NULL;
+ uint64_t chan_reg_key;
+ struct ust_registry_channel *chan_reg;
+
+ assert(app);
+ assert(usess);
+ assert(ua_sess);
+ assert(ua_chan);
+
+ DBG("UST app creating channel %s with per PID buffers", ua_chan->name);
+
+ rcu_read_lock();
+
+ registry = get_session_registry(ua_sess);
+ /* The UST app session lock is held, registry shall not be null. */
+ assert(registry);
+
+ /* Create and add a new channel registry to session. */
+ ret = ust_registry_channel_add(registry, ua_chan->key);
+ if (ret < 0) {
+ ERR("Error creating the UST channel \"%s\" registry instance",
+ ua_chan->name);
+ goto error;
+ }
+
+ session = session_find_by_id(ua_sess->tracing_id);
+ assert(session);
+
+ assert(pthread_mutex_trylock(&session->lock));
+ assert(session_trylock_list());
+
+ /* Create and get channel on the consumer side. */
+ ret = do_consumer_create_channel(usess, ua_sess, ua_chan,
+ app->bits_per_long, registry,
+ session->most_recent_chunk_id.value);
+ if (ret < 0) {
+ ERR("Error creating UST channel \"%s\" on the consumer daemon",
+ ua_chan->name);
+ goto error_remove_from_registry;
+ }
+
+ ret = send_channel_pid_to_ust(app, ua_sess, ua_chan);
+ if (ret < 0) {
+ if (ret != -ENOTCONN) {
+ ERR("Error sending channel to application");
+ }
+ goto error_remove_from_registry;
+ }
+
+ chan_reg_key = ua_chan->key;
+ pthread_mutex_lock(®istry->lock);
+ chan_reg = ust_registry_channel_find(registry, chan_reg_key);
+ assert(chan_reg);
+ chan_reg->consumer_key = ua_chan->key;
+ pthread_mutex_unlock(®istry->lock);
+
+ cmd_ret = notification_thread_command_add_channel(
+ notification_thread_handle, session->name,
+ lttng_credentials_get_uid(&ua_sess->effective_credentials),
+ lttng_credentials_get_gid(&ua_sess->effective_credentials),
+ ua_chan->name,
+ ua_chan->key, LTTNG_DOMAIN_UST,
+ ua_chan->attr.subbuf_size * ua_chan->attr.num_subbuf);
+ if (cmd_ret != LTTNG_OK) {
+ ret = - (int) cmd_ret;
+ ERR("Failed to add channel to notification thread");
+ goto error_remove_from_registry;
+ }
+
+error_remove_from_registry:
+ if (ret) {
+ ust_registry_channel_del_free(registry, ua_chan->key, false);
+ }
+error:
+ rcu_read_unlock();
+ if (session) {
+ session_put(session);
+ }
+ return ret;
+}
+
+/*
+ * From an already allocated ust app channel, create the channel buffers if
+ * needed and send them to the application. This MUST be called with a RCU read
+ * side lock acquired.
+ *
+ * Called with UST app session lock held.
+ *
+ * Return 0 on success or else a negative value. Returns -ENOTCONN if
+ * the application exited concurrently.
+ */
+static int ust_app_channel_send(struct ust_app *app,
+ struct ltt_ust_session *usess, struct ust_app_session *ua_sess,
+ struct ust_app_channel *ua_chan)
+{
+ int ret;
+
+ assert(app);
+ assert(usess);
+ assert(usess->active);
+ assert(ua_sess);
+ assert(ua_chan);
+
+ /* Handle buffer type before sending the channel to the application. */
+ switch (usess->buffer_type) {
+ case LTTNG_BUFFER_PER_UID:
+ {
+ ret = create_channel_per_uid(app, usess, ua_sess, ua_chan);
+ if (ret < 0) {
+ goto error;
+ }
+ break;
+ }
+ case LTTNG_BUFFER_PER_PID:
+ {
+ ret = create_channel_per_pid(app, usess, ua_sess, ua_chan);
+ if (ret < 0) {
+ goto error;
+ }
+ break;
+ }
+ default:
+ assert(0);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* Initialize ust objd object using the received handle and add it. */
+ lttng_ht_node_init_ulong(&ua_chan->ust_objd_node, ua_chan->handle);
+ lttng_ht_add_unique_ulong(app->ust_objd, &ua_chan->ust_objd_node);
+
+ /* If channel is not enabled, disable it on the tracer */
+ if (!ua_chan->enabled) {
+ ret = disable_ust_channel(app, ua_sess, ua_chan);
+ if (ret < 0) {
+ goto error;
+ }
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * Create UST app channel and return it through ua_chanp if not NULL.
+ *
+ * Called with UST app session lock and RCU read-side lock held.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int ust_app_channel_allocate(struct ust_app_session *ua_sess,
+ struct ltt_ust_channel *uchan,
+ enum lttng_ust_chan_type type, struct ltt_ust_session *usess,
+ struct ust_app_channel **ua_chanp)
+{
+ int ret = 0;
+ struct lttng_ht_iter iter;
+ struct lttng_ht_node_str *ua_chan_node;
+ struct ust_app_channel *ua_chan;
+
+ /* Lookup channel in the ust app session */
+ lttng_ht_lookup(ua_sess->channels, (void *)uchan->name, &iter);
+ ua_chan_node = lttng_ht_iter_get_node_str(&iter);
+ if (ua_chan_node != NULL) {
+ ua_chan = caa_container_of(ua_chan_node, struct ust_app_channel, node);
+ goto end;
+ }
+
+ ua_chan = alloc_ust_app_channel(uchan->name, ua_sess, &uchan->attr);
+ if (ua_chan == NULL) {
+ /* Only malloc can fail here */
+ ret = -ENOMEM;
+ goto error;
+ }
+ shadow_copy_channel(ua_chan, uchan);
+
+ /* Set channel type. */
+ ua_chan->attr.type = type;
+
+ /* Only add the channel if successful on the tracer side. */
+ lttng_ht_add_unique_str(ua_sess->channels, &ua_chan->node);
+end:
+ if (ua_chanp) {
+ *ua_chanp = ua_chan;
+ }
+
+ /* Everything went well. */
+ return 0;
+
+error:
+ return ret;
+}
+
+/*
+ * Create UST app event and create it on the tracer side.
+ *
+ * Must be called with the RCU read side lock held.
+ * Called with ust app session mutex held.
+ */
+static
+int create_ust_app_event(struct ust_app_session *ua_sess,
+ struct ust_app_channel *ua_chan, struct ltt_ust_event *uevent,
+ struct ust_app *app)
+{
+ int ret = 0;
+ struct ust_app_event *ua_event;
+
+ ua_event = alloc_ust_app_event(uevent->attr.name, &uevent->attr);
+ if (ua_event == NULL) {
+ /* Only failure mode of alloc_ust_app_event(). */
+ ret = -ENOMEM;
+ goto end;
+ }
+ shadow_copy_event(ua_event, uevent);
+
+ /* Create it on the tracer side */
+ ret = create_ust_event(app, ua_sess, ua_chan, ua_event);
+ if (ret < 0) {
+ /*
+ * Not found previously means that it does not exist on the
+ * tracer. If the application reports that the event existed,
+ * it means there is a bug in the sessiond or lttng-ust
+ * (or corruption, etc.)
+ */
+ if (ret == -LTTNG_UST_ERR_EXIST) {
+ ERR("Tracer for application reported that an event being created already existed: "
+ "event_name = \"%s\", pid = %d, ppid = %d, uid = %d, gid = %d",
+ uevent->attr.name,
+ app->pid, app->ppid, app->uid,
+ app->gid);
+ }
+ goto error;
+ }
+
+ add_unique_ust_app_event(ua_chan, ua_event);
+
+ DBG2("UST app create event completed: app = '%s' (ppid: %d)",
+ app->name, app->ppid);
+
+end:
+ return ret;
+
+error:
+ /* Valid. Calling here is already in a read side lock */
+ delete_ust_app_event(-1, ua_event, app);
+ return ret;
+}
+
+/*
+ * Create UST app event notifier rule and create it on the tracer side.
+ *
+ * Must be called with the RCU read side lock held.
+ * Called with ust app session mutex held.
+ */
+static
+int create_ust_app_event_notifier_rule(struct lttng_event_rule *rule,
+ struct ust_app *app, uint64_t token)
+{
+ int ret = 0;
+ struct ust_app_event_notifier_rule *ua_event_notifier_rule;
+
+ ua_event_notifier_rule = alloc_ust_app_event_notifier_rule(rule, token);
+ if (ua_event_notifier_rule == NULL) {
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ /* Create it on the tracer side. */
+ ret = create_ust_event_notifier(app, ua_event_notifier_rule);
+ if (ret < 0) {
+ /*
+ * Not found previously means that it does not exist on the
+ * tracer. If the application reports that the event existed,
+ * it means there is a bug in the sessiond or lttng-ust
+ * (or corruption, etc.)
+ */
+ if (ret == -LTTNG_UST_ERR_EXIST) {
+ ERR("Tracer for application reported that an event notifier being created already exists: "
+ "token = \"%" PRIu64 "\", pid = %d, ppid = %d, uid = %d, gid = %d",
+ token,
+ app->pid, app->ppid, app->uid,
+ app->gid);
+ }
+ goto error;
+ }
+
+ lttng_ht_add_unique_u64(app->token_to_event_notifier_rule_ht,
+ &ua_event_notifier_rule->node);
+
+ DBG2("UST app create token event rule completed: app = '%s' (ppid: %d), token = %" PRIu64,
+ app->name, app->ppid, token);
+
+end:
+ return ret;
+
+error:
+ /* The RCU read side lock is already being held by the caller. */
+ delete_ust_app_event_notifier_rule(-1, ua_event_notifier_rule, app);
+ return ret;
+}
+
+/*
+ * Create UST metadata and open it on the tracer side.
+ *
+ * Called with UST app session lock held and RCU read side lock.
+ */
+static int create_ust_app_metadata(struct ust_app_session *ua_sess,
+ struct ust_app *app, struct consumer_output *consumer)
+{
+ int ret = 0;
+ struct ust_app_channel *metadata;
+ struct consumer_socket *socket;
+ struct ust_registry_session *registry;
+ struct ltt_session *session = NULL;
+
+ assert(ua_sess);
+ assert(app);
+ assert(consumer);
+
+ registry = get_session_registry(ua_sess);
+ /* The UST app session is held registry shall not be null. */
+ assert(registry);
+
+ pthread_mutex_lock(®istry->lock);
+
+ /* Metadata already exists for this registry or it was closed previously */
+ if (registry->metadata_key || registry->metadata_closed) {
+ ret = 0;
+ goto error;
+ }
+
+ /* Allocate UST metadata */
+ metadata = alloc_ust_app_channel(DEFAULT_METADATA_NAME, ua_sess, NULL);
+ if (!metadata) {
+ /* malloc() failed */
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ memcpy(&metadata->attr, &ua_sess->metadata_attr, sizeof(metadata->attr));
+
+ /* Need one fd for the channel. */
+ ret = lttng_fd_get(LTTNG_FD_APPS, 1);
+ if (ret < 0) {
+ ERR("Exhausted number of available FD upon create metadata");
+ goto error;
+ }
+
+ /* Get the right consumer socket for the application. */
+ socket = consumer_find_socket_by_bitness(app->bits_per_long, consumer);
+ if (!socket) {
+ ret = -EINVAL;
+ goto error_consumer;
+ }
+
+ /*
+ * Keep metadata key so we can identify it on the consumer side. Assign it
+ * to the registry *before* we ask the consumer so we avoid the race of the
+ * consumer requesting the metadata and the ask_channel call on our side
+ * did not returned yet.
+ */
+ registry->metadata_key = metadata->key;
+
+ session = session_find_by_id(ua_sess->tracing_id);
+ assert(session);
+
+ assert(pthread_mutex_trylock(&session->lock));
+ assert(session_trylock_list());
+
+ /*
+ * Ask the metadata channel creation to the consumer. The metadata object
+ * will be created by the consumer and kept their. However, the stream is
+ * never added or monitored until we do a first push metadata to the
+ * consumer.
+ */
+ ret = ust_consumer_ask_channel(ua_sess, metadata, consumer, socket,
+ registry, session->current_trace_chunk);
+ if (ret < 0) {
+ /* Nullify the metadata key so we don't try to close it later on. */
+ registry->metadata_key = 0;
+ goto error_consumer;
+ }
+
+ /*
+ * The setup command will make the metadata stream be sent to the relayd,
+ * if applicable, and the thread managing the metadatas. This is important
+ * because after this point, if an error occurs, the only way the stream
+ * can be deleted is to be monitored in the consumer.
+ */
+ ret = consumer_setup_metadata(socket, metadata->key);
+ if (ret < 0) {
+ /* Nullify the metadata key so we don't try to close it later on. */
+ registry->metadata_key = 0;
+ goto error_consumer;
+ }
+
+ DBG2("UST metadata with key %" PRIu64 " created for app pid %d",
+ metadata->key, app->pid);
+
+error_consumer:
+ lttng_fd_put(LTTNG_FD_APPS, 1);
+ delete_ust_app_channel(-1, metadata, app);
+error:
+ pthread_mutex_unlock(®istry->lock);
+ if (session) {
+ session_put(session);
+ }
+ return ret;
+}
+
+/*
+ * Return ust app pointer or NULL if not found. RCU read side lock MUST be
+ * acquired before calling this function.
+ */
+struct ust_app *ust_app_find_by_pid(pid_t pid)
+{
+ struct ust_app *app = NULL;
+ struct lttng_ht_node_ulong *node;
+ struct lttng_ht_iter iter;
+
+ lttng_ht_lookup(ust_app_ht, (void *)((unsigned long) pid), &iter);
+ node = lttng_ht_iter_get_node_ulong(&iter);
+ if (node == NULL) {
+ DBG2("UST app no found with pid %d", pid);
+ goto error;
+ }
+
+ DBG2("Found UST app by pid %d", pid);
+
+ app = caa_container_of(node, struct ust_app, pid_n);
+
+error:
+ return app;
+}
+
+/*
+ * Allocate and init an UST app object using the registration information and
+ * the command socket. This is called when the command socket connects to the
+ * session daemon.
+ *
+ * The object is returned on success or else NULL.
+ */
+struct ust_app *ust_app_create(struct ust_register_msg *msg, int sock)
+{
+ int ret;
+ struct ust_app *lta = NULL;
+ struct lttng_pipe *event_notifier_event_source_pipe = NULL;
+
+ assert(msg);
+ assert(sock >= 0);
+
+ DBG3("UST app creating application for socket %d", sock);
+
+ if ((msg->bits_per_long == 64 &&
+ (uatomic_read(&ust_consumerd64_fd) == -EINVAL))
+ || (msg->bits_per_long == 32 &&
+ (uatomic_read(&ust_consumerd32_fd) == -EINVAL))) {
+ ERR("Registration failed: application \"%s\" (pid: %d) has "
+ "%d-bit long, but no consumerd for this size is available.\n",
+ msg->name, msg->pid, msg->bits_per_long);
+ goto error;
+ }
+
+ /*
+ * Reserve the two file descriptors of the event source pipe. The write
+ * end will be closed once it is passed to the application, at which
+ * point a single 'put' will be performed.
+ */
+ ret = lttng_fd_get(LTTNG_FD_APPS, 2);
+ if (ret) {
+ ERR("Failed to reserve two file descriptors for the event source pipe while creating a new application instance: app = '%s' (ppid: %d)",
+ msg->name, (int) msg->ppid);
+ goto error;
+ }
+
+ event_notifier_event_source_pipe = lttng_pipe_open(FD_CLOEXEC);
+ if (!event_notifier_event_source_pipe) {
+ PERROR("Failed to open application event source pipe: '%s' (ppid = %d)",
+ msg->name, msg->ppid);
+ goto error;
+ }
+
+ lta = zmalloc(sizeof(struct ust_app));
+ if (lta == NULL) {