Fix RCU-related hangs: incorrect lttng_ht_destroy use
[lttng-tools.git] / src / common / consumer.c
index a9070b1c9bc3f976ef26a2fbbc183c7fd4b75343..c47c0ff08239f9c80ccb9a8fae286034def197fc 100644 (file)
@@ -319,9 +319,9 @@ static void cleanup_relayd_ht(void)
                destroy_relayd(relayd);
        }
 
-       lttng_ht_destroy(consumer_data.relayd_ht);
-
        rcu_read_unlock();
+
+       lttng_ht_destroy(consumer_data.relayd_ht);
 }
 
 /*
@@ -516,8 +516,7 @@ void consumer_del_stream(struct lttng_consumer_stream *stream,
        }
        rcu_read_unlock();
 
-       uatomic_dec(&stream->chan->refcount);
-       if (!uatomic_read(&stream->chan->refcount)
+       if (!uatomic_sub_return(&stream->chan->refcount, 1)
                        && !uatomic_read(&stream->chan->nb_init_stream_left)) {
                free_chan = stream->chan;
        }
@@ -659,6 +658,8 @@ static int add_stream(struct lttng_consumer_stream *stream,
         * stream.
         */
        if (uatomic_read(&stream->chan->nb_init_stream_left) > 0) {
+               /* Increment refcount before decrementing nb_init_stream_left */
+               cmm_smp_wmb();
                uatomic_dec(&stream->chan->nb_init_stream_left);
        }
 
@@ -1287,99 +1288,6 @@ end:
        return ret;
 }
 
-/*
- * Create the tracefile on disk.
- *
- * Return 0 on success or else a negative value.
- */
-int lttng_create_output_file(struct lttng_consumer_stream *stream)
-{
-       int ret;
-       char full_path[PATH_MAX];
-       char *path_name_id = NULL;
-       char *path;
-
-       assert(stream);
-
-       /* Don't create anything if this is set for streaming. */
-       if (stream->net_seq_idx != (uint64_t) -1ULL) {
-               ret = 0;
-               goto end;
-       }
-
-       ret = snprintf(full_path, sizeof(full_path), "%s/%s",
-                       stream->chan->pathname, stream->name);
-       if (ret < 0) {
-               PERROR("snprintf create output file");
-               goto error;
-       }
-
-       /*
-        * If we split the trace in multiple files, we have to add the tracefile
-        * current count at the end of the tracefile name
-        */
-       if (stream->chan->tracefile_size > 0) {
-               ret = asprintf(&path_name_id, "%s_%" PRIu64, full_path,
-                               stream->tracefile_count_current);
-               if (ret < 0) {
-                       PERROR("Allocating path name ID");
-                       goto error;
-               }
-               path = path_name_id;
-       } else {
-               path = full_path;
-       }
-
-       ret = run_as_open(path, O_WRONLY | O_CREAT | O_TRUNC,
-                       S_IRWXU | S_IRWXG | S_IRWXO, stream->uid, stream->gid);
-       if (ret < 0) {
-               PERROR("open stream path %s", path);
-               goto error_open;
-       }
-       stream->out_fd = ret;
-       stream->tracefile_size_current = 0;
-
-error_open:
-       free(path_name_id);
-error:
-end:
-       return ret;
-}
-
-/*
- * Change the output tracefile according to the tracefile_size and
- * tracefile_count parameters. The stream lock MUST be held before calling this
- * function because we are modifying the stream status.
- *
- * Return 0 on success or else a negative value.
- */
-static int rotate_output_file(struct lttng_consumer_stream *stream)
-{
-       int ret;
-
-       assert(stream);
-       assert(stream->tracefile_size_current);
-
-       ret = close(stream->out_fd);
-       if (ret < 0) {
-               PERROR("Closing tracefile");
-               goto end;
-       }
-
-       if (stream->chan->tracefile_count > 0) {
-               stream->tracefile_count_current =
-                       (stream->tracefile_count_current + 1) %
-                       stream->chan->tracefile_count;
-       } else {
-               stream->tracefile_count_current++;
-       }
-
-       return lttng_create_output_file(stream);
-
-end:
-       return ret;
-}
-
 /*
  * Mmap the ring buffer, read it and write the data to the tracefile. This is a
  * core function for writing trace buffers to either the local filesystem or
@@ -1494,12 +1402,15 @@ ssize_t lttng_consumer_on_read_subbuffer_mmap(
                if (stream->chan->tracefile_size > 0 &&
                                (stream->tracefile_size_current + len) >
                                stream->chan->tracefile_size) {
-                       ret = rotate_output_file(stream);
+                       ret = utils_rotate_stream_file(stream->chan->pathname,
+                                       stream->name, stream->chan->tracefile_size,
+                                       stream->chan->tracefile_count, stream->uid, stream->gid,
+                                       stream->out_fd, &(stream->tracefile_count_current));
                        if (ret < 0) {
                                ERR("Rotating output file");
                                goto end;
                        }
-                       outfd = stream->out_fd;
+                       outfd = stream->out_fd = ret;
                }
                stream->tracefile_size_current += len;
        }
@@ -1671,12 +1582,15 @@ ssize_t lttng_consumer_on_read_subbuffer_splice(
                if (stream->chan->tracefile_size > 0 &&
                                (stream->tracefile_size_current + len) >
                                stream->chan->tracefile_size) {
-                       ret = rotate_output_file(stream);
+                       ret = utils_rotate_stream_file(stream->chan->pathname,
+                                       stream->name, stream->chan->tracefile_size,
+                                       stream->chan->tracefile_count, stream->uid, stream->gid,
+                                       stream->out_fd, &(stream->tracefile_count_current));
                        if (ret < 0) {
                                ERR("Rotating output file");
                                goto end;
                        }
-                       outfd = stream->out_fd;
+                       outfd = stream->out_fd = ret;
                }
                stream->tracefile_size_current += len;
        }
@@ -2024,8 +1938,7 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
        rcu_read_unlock();
 
        /* Atomically decrement channel refcount since other threads can use it. */
-       uatomic_dec(&stream->chan->refcount);
-       if (!uatomic_read(&stream->chan->refcount)
+       if (!uatomic_sub_return(&stream->chan->refcount, 1)
                        && !uatomic_read(&stream->chan->nb_init_stream_left)) {
                /* Go for channel deletion! */
                free_chan = stream->chan;
@@ -2095,6 +2008,8 @@ static int add_metadata_stream(struct lttng_consumer_stream *stream,
         * stream.
         */
        if (uatomic_read(&stream->chan->nb_init_stream_left) > 0) {
+               /* Increment refcount before decrementing nb_init_stream_left */
+               cmm_smp_wmb();
                uatomic_dec(&stream->chan->nb_init_stream_left);
        }
 
@@ -2644,6 +2559,13 @@ void consumer_close_channel_streams(struct lttng_consumer_channel *channel)
                        ht->hash_fct(&channel->key, lttng_ht_seed),
                        ht->match_fct, &channel->key,
                        &iter.iter, stream, node_channel_id.node) {
+               /*
+                * Protect against teardown with mutex.
+                */
+               pthread_mutex_lock(&stream->lock);
+               if (cds_lfht_is_node_deleted(&stream->node.node)) {
+                       goto next;
+               }
                switch (consumer_data.type) {
                case LTTNG_CONSUMER_KERNEL:
                        break;
@@ -2660,6 +2582,8 @@ void consumer_close_channel_streams(struct lttng_consumer_channel *channel)
                        ERR("Unknown consumer_data type");
                        assert(0);
                }
+       next:
+               pthread_mutex_unlock(&stream->lock);
        }
        rcu_read_unlock();
 }
@@ -2824,6 +2748,12 @@ restart:
                                ret = lttng_ht_del(channel_ht, &iter);
                                assert(ret == 0);
                                consumer_close_channel_streams(chan);
+
+                               /* Release our own refcount */
+                               if (!uatomic_sub_return(&chan->refcount, 1)
+                                               && !uatomic_read(&chan->nb_init_stream_left)) {
+                                       consumer_del_channel(chan);
+                               }
                        }
 
                        /* Release RCU lock for the channel looked up */
@@ -3086,7 +3016,7 @@ int consumer_add_relayd_socket(int net_seq_idx, int sock_type,
 {
        int fd = -1, ret = -1, relayd_created = 0;
        enum lttng_error_code ret_code = LTTNG_OK;
-       struct consumer_relayd_sock_pair *relayd;
+       struct consumer_relayd_sock_pair *relayd = NULL;
 
        assert(ctx);
        assert(relayd_sock);
This page took 0.025739 seconds and 4 git commands to generate.