X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fust-app.c;h=d8c8017d83800511afa90e7223211a002e7d6481;hb=36b588eddce05ef840bd247f6a58316925b9a0a2;hp=3abdefd7d5601c898c3305f1552bd96fbb6b014d;hpb=d65d2de846d9a0360d1ac55408f06a2b55151695;p=lttng-tools.git diff --git a/src/bin/lttng-sessiond/ust-app.c b/src/bin/lttng-sessiond/ust-app.c index 3abdefd7d..d8c8017d8 100644 --- a/src/bin/lttng-sessiond/ust-app.c +++ b/src/bin/lttng-sessiond/ust-app.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -304,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. @@ -335,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, @@ -344,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); @@ -364,21 +380,87 @@ 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. + * + * On success, return the len of metadata pushed or else a negative value. + */ +ssize_t ust_app_push_metadata(struct ust_registry_session *registry, + struct consumer_socket *socket, int send_zero_data) +{ + int ret; + char *metadata_str = NULL; + size_t len, offset; + ssize_t ret_val; + + assert(registry); + assert(socket); + /* Should never be 0 which is the initial state. */ + assert(registry->metadata_key); + + pthread_mutex_lock(®istry->lock); + + offset = registry->metadata_len_sent; + len = registry->metadata_len - registry->metadata_len_sent; + if (len == 0) { + DBG3("No metadata to push for metadata key %" PRIu64, + registry->metadata_key); + ret_val = len; + if (send_zero_data) { + DBG("No metadata to push"); + goto push_data; + } + goto end; + } + + /* Allocate only what we have to send. */ + metadata_str = zmalloc(len); + if (!metadata_str) { + PERROR("zmalloc ust app metadata string"); + ret_val = -ENOMEM; + goto error; + } + /* Copy what we haven't send out. */ + memcpy(metadata_str, registry->metadata + offset, len); + registry->metadata_len_sent += len; + +push_data: + pthread_mutex_unlock(®istry->lock); + ret = consumer_push_metadata(socket, registry->metadata_key, + metadata_str, len, offset); + if (ret < 0) { + ret_val = ret; + goto error_push; + } + + free(metadata_str); + return len; + +end: +error: + pthread_mutex_unlock(®istry->lock); +error_push: + free(metadata_str); + return ret_val; } /* * For a given application and session, push metadata to consumer. The session * lock MUST be acquired here before calling this. + * Either sock or consumer is required : if sock is NULL, the default + * socket to send the metadata is retrieved from consumer, if sock + * is not NULL we use it to send the metadata. * * Return 0 on success else a negative error. */ static int push_metadata(struct ust_registry_session *registry, struct consumer_output *consumer) { - int ret; - char *metadata_str = NULL; - size_t len, offset; + int ret_val; + ssize_t ret; struct consumer_socket *socket; assert(registry); @@ -391,7 +473,7 @@ static int push_metadata(struct ust_registry_session *registry, * no start has been done previously. */ if (!registry->metadata_key) { - ret = 0; + ret_val = 0; goto error_rcu_unlock; } @@ -399,7 +481,7 @@ static int push_metadata(struct ust_registry_session *registry, socket = consumer_find_socket_by_bitness(registry->bits_per_long, consumer); if (!socket) { - ret = -1; + ret_val = -1; goto error_rcu_unlock; } @@ -414,54 +496,19 @@ static int push_metadata(struct ust_registry_session *registry, * ability to reorder the metadata it receives. */ pthread_mutex_lock(socket->lock); - pthread_mutex_lock(®istry->lock); - - offset = registry->metadata_len_sent; - len = registry->metadata_len - registry->metadata_len_sent; - if (len == 0) { - DBG3("No metadata to push for metadata key %" PRIu64, - registry->metadata_key); - ret = 0; - goto error_reg_unlock; - } - assert(len > 0); - - /* Allocate only what we have to send. */ - metadata_str = zmalloc(len); - if (!metadata_str) { - PERROR("zmalloc ust app metadata string"); - ret = -ENOMEM; - goto error_reg_unlock; - } - /* Copy what we haven't send out. */ - memcpy(metadata_str, registry->metadata + offset, len); - - pthread_mutex_unlock(®istry->lock); - - ret = consumer_push_metadata(socket, registry->metadata_key, - metadata_str, len, offset); + ret = ust_app_push_metadata(registry, socket, 0); + pthread_mutex_unlock(socket->lock); if (ret < 0) { - pthread_mutex_unlock(socket->lock); + ret_val = ret; goto error_rcu_unlock; } - /* Update len sent of the registry. */ - pthread_mutex_lock(®istry->lock); - registry->metadata_len_sent += len; - pthread_mutex_unlock(®istry->lock); - pthread_mutex_unlock(socket->lock); - rcu_read_unlock(); - free(metadata_str); return 0; -error_reg_unlock: - pthread_mutex_unlock(®istry->lock); - pthread_mutex_unlock(socket->lock); error_rcu_unlock: rcu_read_unlock(); - free(metadata_str); - return ret; + return ret_val; } /* @@ -509,6 +556,22 @@ error: 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. @@ -545,7 +608,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) { @@ -563,12 +625,14 @@ void delete_ust_app_session(int sock, struct ust_app_session *ua_sess, sock, ret); } } - free(ua_sess); + 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) @@ -576,20 +640,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); /* @@ -613,8 +677,6 @@ void delete_ust_app(struct ust_app *app) DBG2("UST app pid %d deleted", app->pid); free(app); - - rcu_read_unlock(); } /* @@ -1266,6 +1328,9 @@ static void shadow_copy_channel(struct ust_app_channel *ua_chan, 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; @@ -1346,7 +1411,7 @@ static void shadow_copy_session(struct ust_app_session *ua_sess, 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, + DEFAULT_UST_TRACE_PID_PATH "/%s-%d-%s", app->name, app->pid, datetime); break; case LTTNG_BUFFER_PER_UID: @@ -1467,7 +1532,9 @@ static int setup_buffer_reg_pid(struct ust_app_session *ua_sess, 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->uint64_t_alignment, app->long_alignment, + app->byte_order, app->version.major, + app->version.minor); if (ret < 0) { goto error; } @@ -1518,10 +1585,12 @@ static int setup_buffer_reg_uid(struct ltt_ust_session *usess, } /* Initialize registry. */ - ret = ust_registry_session_init(®_uid->registry->reg.ust, app, + 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->uint64_t_alignment, app->long_alignment, + app->byte_order, app->version.major, + app->version.minor); if (ret < 0) { goto error; } @@ -2308,7 +2377,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. */ @@ -2481,6 +2550,14 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess, goto error; } + /* + * 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; + /* * Ask the metadata channel creation to the consumer. The metadata object * will be created by the consumer and kept their. However, the stream is @@ -2514,9 +2591,6 @@ static int create_ust_app_metadata(struct ust_app_session *ua_sess, goto error_consumer; } - /* Keep metadata key so we can identify it on the consumer side. */ - registry->metadata_key = metadata->key; - DBG2("UST metadata with key %" PRIu64 " created for app pid %d", metadata->key, app->pid); @@ -3002,6 +3076,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) { @@ -3032,13 +3108,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(); } /* @@ -3506,6 +3581,7 @@ int ust_app_create_event_glb(struct ltt_ust_session *usess, /* * Start tracing for a specific UST session and app. */ +static int ust_app_start_trace(struct ltt_ust_session *usess, struct ust_app *app) { int ret = 0; @@ -3598,12 +3674,11 @@ error_unlock: /* * Stop tracing for a specific UST session and app. */ +static int ust_app_stop_trace(struct ltt_ust_session *usess, struct ust_app *app) { int ret = 0; - struct lttng_ht_iter iter; struct ust_app_session *ua_sess; - struct ust_app_channel *ua_chan; struct ust_registry_session *registry; DBG("Stopping tracing for ust app pid %d", app->pid); @@ -3656,6 +3731,52 @@ int ust_app_stop_trace(struct ltt_ust_session *usess, struct ust_app *app) health_code_update(); + registry = get_session_registry(ua_sess); + assert(registry); + /* Push metadata for application before freeing the application. */ + (void) push_metadata(registry, ua_sess->consumer); + + pthread_mutex_unlock(&ua_sess->lock); +end_no_session: + rcu_read_unlock(); + health_code_update(); + return 0; + +error_rcu_unlock: + pthread_mutex_unlock(&ua_sess->lock); + rcu_read_unlock(); + health_code_update(); + return -1; +} + +/* + * Flush buffers for a specific UST session and app. + */ +static +int ust_app_flush_trace(struct ltt_ust_session *usess, struct ust_app *app) +{ + int ret = 0; + struct lttng_ht_iter iter; + struct ust_app_session *ua_sess; + struct ust_app_channel *ua_chan; + + DBG("Flushing buffers for ust app pid %d", app->pid); + + rcu_read_lock(); + + if (!app->compatible) { + goto end_no_session; + } + + ua_sess = lookup_session_by_app(usess, app); + if (ua_sess == NULL) { + goto end_no_session; + } + + pthread_mutex_lock(&ua_sess->lock); + + health_code_update(); + /* Flushing buffers */ cds_lfht_for_each_entry(ua_sess->channels->ht, &iter.iter, ua_chan, node.node) { @@ -3679,22 +3800,11 @@ int ust_app_stop_trace(struct ltt_ust_session *usess, struct ust_app *app) health_code_update(); - registry = get_session_registry(ua_sess); - assert(registry); - /* Push metadata for application before freeing the application. */ - (void) push_metadata(registry, ua_sess->consumer); - pthread_mutex_unlock(&ua_sess->lock); end_no_session: rcu_read_unlock(); health_code_update(); return 0; - -error_rcu_unlock: - pthread_mutex_unlock(&ua_sess->lock); - rcu_read_unlock(); - health_code_update(); - return -1; } /* @@ -3779,9 +3889,21 @@ int ust_app_stop_trace_all(struct ltt_ust_session *usess) rcu_read_lock(); - /* Flush all per UID buffers associated to that session. */ - if (usess->buffer_type == LTTNG_BUFFER_PER_UID) { + cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) { + ret = ust_app_stop_trace(usess, app); + if (ret < 0) { + /* Continue to next apps even on error */ + continue; + } + } + + /* Flush buffers */ + switch (usess->buffer_type) { + case LTTNG_BUFFER_PER_UID: + { struct buffer_reg_uid *reg; + + /* Flush all per UID buffers associated to that session. */ cds_list_for_each_entry(reg, &usess->buffer_reg_uid_list, lnode) { struct buffer_reg_channel *reg_chan; struct consumer_socket *socket; @@ -3804,14 +3926,20 @@ int ust_app_stop_trace_all(struct ltt_ust_session *usess) (void) consumer_flush_channel(socket, reg_chan->consumer_key); } } + break; } - - cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) { - ret = ust_app_stop_trace(usess, app); - if (ret < 0) { - /* Continue to next apps even on error */ - continue; + case LTTNG_BUFFER_PER_PID: + cds_lfht_for_each_entry(ust_app_ht->ht, &iter.iter, app, pid_n.node) { + ret = ust_app_flush_trace(usess, app); + if (ret < 0) { + /* Continue to next apps even on error */ + continue; + } } + break; + default: + assert(0); + break; } rcu_read_unlock(); @@ -3903,6 +4031,9 @@ void ust_app_global_update(struct ltt_ust_session *usess, int sock) sizeof(ua_chan->name))) { ret = create_ust_app_metadata(ua_sess, app, usess->consumer, &ua_chan->attr); + if (ret < 0) { + goto error_unlock; + } /* Remove it from the hash table and continue!. */ ret = lttng_ht_del(ua_sess->channels, &iter); assert(!ret); @@ -3910,14 +4041,14 @@ void ust_app_global_update(struct ltt_ust_session *usess, int sock) continue; } else { ret = do_create_channel(app, usess, ua_sess, ua_chan); - } - if (ret < 0) { - /* - * Stop everything. On error, the application failed, no more - * file descriptor are available or ENOMEM so stopping here is - * the only thing we can do for now. - */ - goto error_unlock; + if (ret < 0) { + /* + * Stop everything. On error, the application failed, no more + * file descriptor are available or ENOMEM so stopping here is + * the only thing we can do for now. + */ + goto error_unlock; + } } cds_lfht_for_each_entry(ua_chan->ctx->ht, &iter_ctx.iter, ua_ctx,