+ 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);
+ }
+
+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;
+
+ /* 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)
+{
+ 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);
+ 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 < 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);
+ 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);
+ }
+ 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.
+ *
+ * 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;
+
+ 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) {
+ /* Create the buffer registry channel object. */
+ ret = create_buffer_reg_channel(reg_uid->registry, ua_chan, ®_chan);
+ if (ret < 0) {
+ goto error;
+ }
+ assert(reg_chan);
+
+ /*
+ * 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);
+ if (ret < 0) {
+ /*
+ * 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);
+ 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);
+ if (ret < 0) {
+ goto error;
+ }
+
+ }
+
+ /* Send buffers to the application. */
+ ret = send_channel_uid_to_ust(reg_chan, app, ua_sess, ua_chan);
+ if (ret < 0) {
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/*
+ * Create and send to the application the created buffers with per PID buffers.
+ *
+ * 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;
+
+ 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);
+ assert(registry);
+
+ /* Create and add a new channel registry to session. */
+ ret = ust_registry_channel_add(registry, ua_chan->key);
+ if (ret < 0) {
+ goto error;
+ }
+
+ /* Create and get channel on the consumer side. */
+ ret = do_consumer_create_channel(usess, ua_sess, ua_chan,
+ app->bits_per_long, registry);
+ if (ret < 0) {
+ goto error;
+ }
+
+ ret = send_channel_pid_to_ust(app, ua_sess, ua_chan);
+ if (ret < 0) {
+ goto error;
+ }
+
+error:
+ rcu_read_unlock();
+ return ret;
+}
+
+/*
+ * From an already allocated ust app channel, create the channel buffers if
+ * need and send it to the application. This MUST be called with a RCU read
+ * side lock acquired.
+ *
+ * Return 0 on success or else a negative value.
+ */
+static int do_create_channel(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(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;
+}