if (ua_chan->obj != NULL) {
/* Remove channel from application UST object descriptor. */
iter.iter.node = &ua_chan->ust_objd_node.node;
- lttng_ht_del(app->ust_objd, &iter);
+ ret = lttng_ht_del(app->ust_objd, &iter);
+ assert(!ret);
ret = ustctl_release_object(sock, ua_chan->obj);
if (ret < 0 && ret != -EPIPE && ret != -LTTNG_UST_ERR_EXITING) {
ERR("UST app sock %d release channel obj failed with ret %d",
ret = consumer_push_metadata(socket, registry->metadata_key,
metadata_str, len, offset);
if (ret < 0) {
+ /*
+ * There is an acceptable race here between the registry metadata key
+ * assignment and the creation on the consumer. The session daemon can
+ * concurrently push metadata for this registry while being created on
+ * the consumer since the metadata key of the registry is assigned
+ * *before* it is setup to avoid the consumer to ask for metadata that
+ * could possibly be not found in the session daemon.
+ *
+ * The metadata will get pushed either by the session being stopped or
+ * the consumer requesting metadata if that race is triggered.
+ */
+ if (ret == -LTTCOMM_CONSUMERD_CHANNEL_FAIL) {
+ ret = 0;
+ }
+
+ /* Update back the actual metadata len sent since it failed here. */
+ pthread_mutex_lock(®istry->lock);
+ registry->metadata_len_sent -= len;
+ pthread_mutex_unlock(®istry->lock);
ret_val = ret;
goto error_push;
}
/* Handle ustctl error. */
if (ret < 0) {
free(tmp_event);
- if (ret != -LTTNG_UST_ERR_EXITING || ret != -EPIPE) {
+ if (ret != -LTTNG_UST_ERR_EXITING && ret != -EPIPE) {
ERR("UST app tp list get failed for app %d with ret %d",
app->sock, ret);
} else {
/* Handle ustctl error. */
if (ret < 0) {
free(tmp_event);
- if (ret != -LTTNG_UST_ERR_EXITING || ret != -EPIPE) {
+ if (ret != -LTTNG_UST_ERR_EXITING && ret != -EPIPE) {
ERR("UST app tp list field failed for app %d with ret %d",
app->sock, ret);
} else {