X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fust-app.c;h=396ca936e004d751633fb6a8fce41cfd9c0b61cd;hb=1b532a6039fbcdb02f698c23e79ee3f607a9790c;hp=9bd4e69a2e031be166da7cac0e81edba38d44147;hpb=b34cbebfc8e60a678782bcffdf4ff8fc12de037e;p=lttng-tools.git diff --git a/src/bin/lttng-sessiond/ust-app.c b/src/bin/lttng-sessiond/ust-app.c index 9bd4e69a2..396ca936e 100644 --- a/src/bin/lttng-sessiond/ust-app.c +++ b/src/bin/lttng-sessiond/ust-app.c @@ -305,6 +305,23 @@ void delete_ust_app_stream(int sock, struct ust_app_stream *stream) free(stream); } +/* + * We need to execute ht_destroy outside of RCU read-side critical + * section, so we postpone its execution using call_rcu. It is simpler + * than to change the semantic of the many callers of + * delete_ust_app_channel(). + */ +static +void delete_ust_app_channel_rcu(struct rcu_head *head) +{ + struct ust_app_channel *ua_chan = + caa_container_of(head, struct ust_app_channel, rcu_head); + + lttng_ht_destroy(ua_chan->ctx); + lttng_ht_destroy(ua_chan->events); + free(ua_chan); +} + /* * Delete ust app channel safely. RCU read lock must be held before calling * this function. @@ -336,7 +353,6 @@ void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan, assert(!ret); delete_ust_app_ctx(sock, ua_ctx); } - lttng_ht_destroy(ua_chan->ctx); /* Wipe events */ cds_lfht_for_each_entry(ua_chan->events->ht, &iter.iter, ua_event, @@ -345,7 +361,6 @@ void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan, assert(!ret); delete_ust_app_event(sock, ua_event); } - lttng_ht_destroy(ua_chan->events); /* Wipe and free registry from session registry. */ registry = get_session_registry(ua_chan->session); @@ -365,11 +380,14 @@ void delete_ust_app_channel(int sock, struct ust_app_channel *ua_chan, lttng_fd_put(LTTNG_FD_APPS, 1); free(ua_chan->obj); } - free(ua_chan); + call_rcu(&ua_chan->rcu_head, delete_ust_app_channel_rcu); } /* - * Push metadata to consumer socket. The socket lock MUST be acquired. + * Push metadata to consumer socket. + * + * The socket lock MUST be acquired. + * The ust app session lock MUST be acquired. * * On success, return the len of metadata pushed or else a negative value. */ @@ -383,8 +401,19 @@ ssize_t ust_app_push_metadata(struct ust_registry_session *registry, assert(registry); assert(socket); - /* Should never be 0 which is the initial state. */ - assert(registry->metadata_key); + + /* + * On a push metadata error either the consumer is dead or the metadata + * channel has been destroyed because its endpoint might have died (e.g: + * relayd). If so, the metadata closed flag is set to 1 so we deny pushing + * metadata again which is not valid anymore on the consumer side. + * + * The ust app session mutex locked allows us to make this check without + * the registry lock. + */ + if (registry->metadata_closed) { + return -EPIPE; + } pthread_mutex_lock(®istry->lock); @@ -459,7 +488,7 @@ static int push_metadata(struct ust_registry_session *registry, */ if (!registry->metadata_key) { ret_val = 0; - goto error_rcu_unlock; + goto end_rcu_unlock; } /* Get consumer socket to use to push the metadata.*/ @@ -492,6 +521,13 @@ static int push_metadata(struct ust_registry_session *registry, return 0; error_rcu_unlock: + /* + * On error, flag the registry that the metadata is closed. We were unable + * to push anything and this means that either the consumer is not + * responding or the metadata cache has been destroyed on the consumer. + */ + registry->metadata_closed = 1; +end_rcu_unlock: rcu_read_unlock(); return ret_val; } @@ -517,7 +553,7 @@ static int close_metadata(struct ust_registry_session *registry, if (!registry->metadata_key || registry->metadata_closed) { ret = 0; - goto error; + goto end; } /* Get consumer socket to use to push the metadata.*/ @@ -533,14 +569,34 @@ static int close_metadata(struct ust_registry_session *registry, goto error; } - /* Metadata successfully closed. Flag the registry. */ - registry->metadata_closed = 1; - error: + /* + * Metadata closed. Even on error this means that the consumer is not + * responding or not found so either way a second close should NOT be emit + * for this registry. + */ + registry->metadata_closed = 1; +end: rcu_read_unlock(); return ret; } +/* + * We need to execute ht_destroy outside of RCU read-side critical + * section, so we postpone its execution using call_rcu. It is simpler + * than to change the semantic of the many callers of + * delete_ust_app_session(). + */ +static +void delete_ust_app_session_rcu(struct rcu_head *head) +{ + struct ust_app_session *ua_sess = + caa_container_of(head, struct ust_app_session, rcu_head); + + lttng_ht_destroy(ua_sess->channels); + free(ua_sess); +} + /* * Delete ust app session safely. RCU read lock must be held before calling * this function. @@ -556,16 +612,21 @@ void delete_ust_app_session(int sock, struct ust_app_session *ua_sess, assert(ua_sess); + pthread_mutex_lock(&ua_sess->lock); + registry = get_session_registry(ua_sess); - if (registry) { + if (registry && !registry->metadata_closed) { /* Push metadata for application before freeing the application. */ (void) push_metadata(registry, ua_sess->consumer); /* * Don't ask to close metadata for global per UID buffers. Close - * metadata only on destroy trace session in this case. + * metadata only on destroy trace session in this case. Also, the + * previous push metadata could have flag the metadata registry to + * close so don't send a close command if closed. */ - if (ua_sess->buffer_type != LTTNG_BUFFER_PER_UID) { + if (ua_sess->buffer_type != LTTNG_BUFFER_PER_UID && + !registry->metadata_closed) { /* And ask to close it for this session registry. */ (void) close_metadata(registry, ua_sess->consumer); } @@ -577,7 +638,6 @@ void delete_ust_app_session(int sock, struct ust_app_session *ua_sess, assert(!ret); delete_ust_app_channel(sock, ua_chan, app); } - lttng_ht_destroy(ua_sess->channels); /* In case of per PID, the registry is kept in the session. */ if (ua_sess->buffer_type == LTTNG_BUFFER_PER_PID) { @@ -595,12 +655,16 @@ void delete_ust_app_session(int sock, struct ust_app_session *ua_sess, sock, ret); } } - free(ua_sess); + pthread_mutex_unlock(&ua_sess->lock); + + call_rcu(&ua_sess->rcu_head, delete_ust_app_session_rcu); } /* * Delete a traceable application structure from the global list. Never call * this function outside of a call_rcu call. + * + * RCU read side lock should _NOT_ be held when calling this function. */ static void delete_ust_app(struct ust_app *app) @@ -608,20 +672,20 @@ void delete_ust_app(struct ust_app *app) int ret, sock; struct ust_app_session *ua_sess, *tmp_ua_sess; - rcu_read_lock(); - /* Delete ust app sessions info */ sock = app->sock; app->sock = -1; - lttng_ht_destroy(app->sessions); - /* Wipe sessions */ cds_list_for_each_entry_safe(ua_sess, tmp_ua_sess, &app->teardown_head, teardown_node) { /* Free every object in the session and the session. */ + rcu_read_lock(); delete_ust_app_session(sock, ua_sess, app); + rcu_read_unlock(); } + + lttng_ht_destroy(app->sessions); lttng_ht_destroy(app->ust_objd); /* @@ -645,8 +709,6 @@ void delete_ust_app(struct ust_app *app) DBG2("UST app pid %d deleted", app->pid); free(app); - - rcu_read_unlock(); } /* @@ -2153,6 +2215,7 @@ static int send_channel_uid_to_ust(struct buffer_reg_channel *reg_chan, 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; } @@ -2215,6 +2278,14 @@ static int create_channel_per_uid(struct ust_app *app, 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; } @@ -2347,7 +2418,7 @@ error: * Create UST app channel and create it on the tracer. Set ua_chanp of the * newly created channel if not NULL. * - * Called with UST app session lock held. + * Called with UST app session lock and RCU read-side lock held. * * Return 0 on success or else a negative value. */ @@ -2373,7 +2444,7 @@ static int create_ust_app_channel(struct ust_app_session *ua_sess, if (ua_chan == NULL) { /* Only malloc can fail here */ ret = -ENOMEM; - goto error; + goto error_alloc; } shadow_copy_channel(ua_chan, uchan); @@ -2401,6 +2472,7 @@ end: error: delete_ust_app_channel(ua_chan->is_sent ? app->sock : -1, ua_chan, app); +error_alloc: return ret; } @@ -2477,8 +2549,8 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess, registry = get_session_registry(ua_sess); assert(registry); - /* Metadata already exists for this registry. */ - if (registry->metadata_key) { + /* Metadata already exists for this registry or it was closed previously */ + if (registry->metadata_key || registry->metadata_closed) { ret = 0; goto error; } @@ -2496,8 +2568,8 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess, metadata->attr.overwrite = DEFAULT_CHANNEL_OVERWRITE; metadata->attr.subbuf_size = default_get_metadata_subbuf_size(); metadata->attr.num_subbuf = DEFAULT_METADATA_SUBBUF_NUM; - metadata->attr.switch_timer_interval = DEFAULT_UST_CHANNEL_SWITCH_TIMER; - metadata->attr.read_timer_interval = DEFAULT_UST_CHANNEL_READ_TIMER; + metadata->attr.switch_timer_interval = DEFAULT_METADATA_SWITCH_TIMER; + metadata->attr.read_timer_interval = DEFAULT_METADATA_READ_TIMER; metadata->attr.output = LTTNG_UST_MMAP; metadata->attr.type = LTTNG_UST_CHAN_METADATA; } else { @@ -2506,13 +2578,6 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess, metadata->attr.type = LTTNG_UST_CHAN_METADATA; } - /* 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; - } - /* Need one fd for the channel. */ ret = lttng_fd_get(LTTNG_FD_APPS, 1); if (ret < 0) { @@ -2520,6 +2585,13 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess, 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 @@ -2541,7 +2613,6 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess, * Safe because the metadata obj pointer is not set so the delete below * will not put a FD back again. */ - lttng_fd_put(LTTNG_FD_APPS, 1); goto error_consumer; } @@ -2557,7 +2628,6 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess, * Safe because the metadata obj pointer is not set so the delete below * will not put a FD back again. */ - lttng_fd_put(LTTNG_FD_APPS, 1); goto error_consumer; } @@ -2565,6 +2635,7 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess, metadata->key, app->pid); error_consumer: + lttng_fd_put(LTTNG_FD_APPS, 1); delete_ust_app_channel(-1, metadata, app); error: return ret; @@ -2812,15 +2883,18 @@ void ust_app_unregister(int sock) * session so the delete session will NOT push/close a second time. */ registry = get_session_registry(ua_sess); - if (registry) { + if (registry && !registry->metadata_closed) { /* Push metadata for application before freeing the application. */ (void) push_metadata(registry, ua_sess->consumer); /* * Don't ask to close metadata for global per UID buffers. Close - * metadata only on destroy trace session in this case. + * metadata only on destroy trace session in this case. Also, the + * previous push metadata could have flag the metadata registry to + * close so don't send a close command if closed. */ - if (ua_sess->buffer_type != LTTNG_BUFFER_PER_UID) { + if (ua_sess->buffer_type != LTTNG_BUFFER_PER_UID && + !registry->metadata_closed) { /* And ask to close it for this session registry. */ (void) close_metadata(registry, ua_sess->consumer); } @@ -3046,6 +3120,8 @@ error: /* * Free and clean all traceable apps of the global list. + * + * Should _NOT_ be called with RCU read-side lock held. */ void ust_app_clean_list(void) { @@ -3076,13 +3152,12 @@ void ust_app_clean_list(void) ret = lttng_ht_del(ust_app_ht_by_notify_sock, &iter); assert(!ret); } + rcu_read_unlock(); /* Destroy is done only when the ht is empty */ lttng_ht_destroy(ust_app_ht); lttng_ht_destroy(ust_app_ht_by_sock); lttng_ht_destroy(ust_app_ht_by_notify_sock); - - rcu_read_unlock(); } /* @@ -3702,8 +3777,11 @@ int ust_app_stop_trace(struct ltt_ust_session *usess, struct ust_app *app) registry = get_session_registry(ua_sess); assert(registry); - /* Push metadata for application before freeing the application. */ - (void) push_metadata(registry, ua_sess->consumer); + + if (!registry->metadata_closed) { + /* Push metadata for application before freeing the application. */ + (void) push_metadata(registry, ua_sess->consumer); + } pthread_mutex_unlock(&ua_sess->lock); end_no_session: