Fix: FD leak on consumer add relayd socket error
[lttng-tools.git] / src / common / consumer.c
index f69f0081a9cd77a38798c3dd745cd842cd4f4329..5766860a89823bf40c4ebd98448fc233e54c06f2 100644 (file)
@@ -127,6 +127,12 @@ void consumer_steal_stream_key(int key, struct lttng_ht *ht)
        rcu_read_unlock();
 }
 
+/*
+ * Return a channel object for the given key.
+ *
+ * RCU read side lock MUST be acquired before calling this function and
+ * protects the channel ptr.
+ */
 static struct lttng_consumer_channel *consumer_find_channel(int key)
 {
        struct lttng_ht_iter iter;
@@ -138,8 +144,6 @@ static struct lttng_consumer_channel *consumer_find_channel(int key)
                return NULL;
        }
 
-       rcu_read_lock();
-
        lttng_ht_lookup(consumer_data.channel_ht, (void *)((unsigned long) key),
                        &iter);
        node = lttng_ht_iter_get_node_ulong(&iter);
@@ -147,8 +151,6 @@ static struct lttng_consumer_channel *consumer_find_channel(int key)
                channel = caa_container_of(node, struct lttng_consumer_channel, node);
        }
 
-       rcu_read_unlock();
-
        return channel;
 }
 
@@ -348,8 +350,8 @@ void consumer_del_stream(struct lttng_consumer_stream *stream,
                goto free_stream;
        }
 
-       pthread_mutex_lock(&stream->lock);
        pthread_mutex_lock(&consumer_data.lock);
+       pthread_mutex_lock(&stream->lock);
 
        switch (consumer_data.type) {
        case LTTNG_CONSUMER_KERNEL:
@@ -441,8 +443,8 @@ void consumer_del_stream(struct lttng_consumer_stream *stream,
 
 end:
        consumer_data.need_update = 1;
-       pthread_mutex_unlock(&consumer_data.lock);
        pthread_mutex_unlock(&stream->lock);
+       pthread_mutex_unlock(&consumer_data.lock);
 
        if (free_chan) {
                consumer_del_channel(free_chan);
@@ -475,6 +477,8 @@ struct lttng_consumer_stream *consumer_allocate_stream(
                goto end;
        }
 
+       rcu_read_lock();
+
        /*
         * Get stream's channel reference. Needed when adding the stream to the
         * global hash table.
@@ -531,9 +535,12 @@ struct lttng_consumer_stream *consumer_allocate_stream(
                        stream->path_name, stream->key, stream->shm_fd, stream->wait_fd,
                        (unsigned long long) stream->mmap_len, stream->out_fd,
                        stream->net_seq_idx, stream->session_id);
+
+       rcu_read_unlock();
        return stream;
 
 error:
+       rcu_read_unlock();
        free(stream);
 end:
        return NULL;
@@ -910,7 +917,7 @@ static int consumer_update_poll_array(
                 * changed where this function will be called back again.
                 */
                if (stream->state != LTTNG_CONSUMER_ACTIVE_STREAM ||
-                               stream->endpoint_status) {
+                               stream->endpoint_status == CONSUMER_ENDPOINT_INACTIVE) {
                        continue;
                }
                DBG("Active FD %d", stream->wait_fd);
@@ -1260,6 +1267,8 @@ end:
  * core function for writing trace buffers to either the local filesystem or
  * the network.
  *
+ * It must be called with the stream lock held.
+ *
  * Careful review MUST be put if any changes occur!
  *
  * Returns the number of bytes written
@@ -1280,8 +1289,6 @@ ssize_t lttng_consumer_on_read_subbuffer_mmap(
        /* RCU lock for the relayd pointer */
        rcu_read_lock();
 
-       pthread_mutex_lock(&stream->lock);
-
        /* Flag that the current stream if set for network streaming. */
        if (stream->net_seq_idx != -1) {
                relayd = consumer_find_relayd(stream->net_seq_idx);
@@ -1406,7 +1413,6 @@ end:
        if (relayd && stream->metadata_flag) {
                pthread_mutex_unlock(&relayd->ctrl_sock_mutex);
        }
-       pthread_mutex_unlock(&stream->lock);
 
        rcu_read_unlock();
        return written;
@@ -1415,6 +1421,8 @@ end:
 /*
  * Splice the data from the ring buffer to the tracefile.
  *
+ * It must be called with the stream lock held.
+ *
  * Returns the number of bytes spliced.
  */
 ssize_t lttng_consumer_on_read_subbuffer_splice(
@@ -1447,8 +1455,6 @@ ssize_t lttng_consumer_on_read_subbuffer_splice(
        /* RCU lock for the relayd pointer */
        rcu_read_lock();
 
-       pthread_mutex_lock(&stream->lock);
-
        /* Flag that the current stream if set for network streaming. */
        if (stream->net_seq_idx != -1) {
                relayd = consumer_find_relayd(stream->net_seq_idx);
@@ -1616,7 +1622,6 @@ end:
        if (relayd && stream->metadata_flag) {
                pthread_mutex_unlock(&relayd->ctrl_sock_mutex);
        }
-       pthread_mutex_unlock(&stream->lock);
 
        rcu_read_unlock();
        return written;
@@ -1762,9 +1767,9 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
                goto free_stream;
        }
 
+       pthread_mutex_lock(&consumer_data.lock);
        pthread_mutex_lock(&stream->lock);
 
-       pthread_mutex_lock(&consumer_data.lock);
        switch (consumer_data.type) {
        case LTTNG_CONSUMER_KERNEL:
                if (stream->mmap_base != NULL) {
@@ -1854,8 +1859,8 @@ void consumer_del_metadata_stream(struct lttng_consumer_stream *stream,
        }
 
 end:
-       pthread_mutex_unlock(&consumer_data.lock);
        pthread_mutex_unlock(&stream->lock);
+       pthread_mutex_unlock(&consumer_data.lock);
 
        if (free_chan) {
                consumer_del_channel(free_chan);
@@ -1874,6 +1879,8 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
 {
        int ret = 0;
        struct consumer_relayd_sock_pair *relayd;
+       struct lttng_ht_iter iter;
+       struct lttng_ht_node_ulong *node;
 
        assert(stream);
        assert(ht);
@@ -1889,6 +1896,15 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
         */
 
        rcu_read_lock();
+
+       /*
+        * Lookup the stream just to make sure it does not exist in our internal
+        * state. This should NEVER happen.
+        */
+       lttng_ht_lookup(ht, (void *)((unsigned long) stream->wait_fd), &iter);
+       node = lttng_ht_iter_get_node_ulong(&iter);
+       assert(!node);
+
        /* Find relayd and, if one is found, increment refcount. */
        relayd = consumer_find_relayd(stream->net_seq_idx);
        if (relayd != NULL) {
@@ -1909,9 +1925,6 @@ static int consumer_add_metadata_stream(struct lttng_consumer_stream *stream,
                uatomic_dec(&stream->chan->nb_init_streams);
        }
 
-       /* Steal stream identifier to avoid having streams with the same key */
-       consumer_steal_stream_key(stream->key, ht);
-
        lttng_ht_add_unique_ulong(ht, &stream->node);
 
        /*
@@ -1941,7 +1954,7 @@ static void validate_endpoint_status_data_stream(void)
        rcu_read_lock();
        cds_lfht_for_each_entry(data_ht->ht, &iter.iter, stream, node.node) {
                /* Validate delete flag of the stream */
-               if (stream->endpoint_status != CONSUMER_ENDPOINT_INACTIVE) {
+               if (stream->endpoint_status == CONSUMER_ENDPOINT_ACTIVE) {
                        continue;
                }
                /* Delete it right now */
@@ -1966,7 +1979,7 @@ static void validate_endpoint_status_metadata_stream(
        rcu_read_lock();
        cds_lfht_for_each_entry(metadata_ht->ht, &iter.iter, stream, node.node) {
                /* Validate delete flag of the stream */
-               if (!stream->endpoint_status) {
+               if (stream->endpoint_status == CONSUMER_ENDPOINT_ACTIVE) {
                        continue;
                }
                /*
@@ -2441,7 +2454,7 @@ end:
  */
 void *consumer_thread_sessiond_poll(void *data)
 {
-       int sock, client_socket, ret;
+       int sock = -1, client_socket, ret;
        /*
         * structure to poll for incoming data on communication socket avoids
         * making blocking sockets.
@@ -2501,6 +2514,13 @@ void *consumer_thread_sessiond_poll(void *data)
                goto end;
        }
 
+       /* This socket is not useful anymore. */
+       ret = close(client_socket);
+       if (ret < 0) {
+               PERROR("close client_socket");
+       }
+       client_socket = -1;
+
        /* update the polling structure to poll on the established socket */
        consumer_sockpoll[1].fd = sock;
        consumer_sockpoll[1].events = POLLIN | POLLPRI;
@@ -2544,6 +2564,20 @@ end:
         */
        notify_thread_pipe(ctx->consumer_data_pipe[1]);
 
+       /* Cleaning up possibly open sockets. */
+       if (sock >= 0) {
+               ret = close(sock);
+               if (ret < 0) {
+                       PERROR("close sock sessiond poll");
+               }
+       }
+       if (client_socket >= 0) {
+               ret = close(sock);
+               if (ret < 0) {
+                       PERROR("close client_socket sessiond poll");
+               }
+       }
+
        rcu_unregister_thread();
        return NULL;
 }
@@ -2551,17 +2585,27 @@ end:
 ssize_t lttng_consumer_read_subbuffer(struct lttng_consumer_stream *stream,
                struct lttng_consumer_local_data *ctx)
 {
+       ssize_t ret;
+
+       pthread_mutex_lock(&stream->lock);
+
        switch (consumer_data.type) {
        case LTTNG_CONSUMER_KERNEL:
-               return lttng_kconsumer_read_subbuffer(stream, ctx);
+               ret = lttng_kconsumer_read_subbuffer(stream, ctx);
+               break;
        case LTTNG_CONSUMER32_UST:
        case LTTNG_CONSUMER64_UST:
-               return lttng_ustconsumer_read_subbuffer(stream, ctx);
+               ret = lttng_ustconsumer_read_subbuffer(stream, ctx);
+               break;
        default:
                ERR("Unknown consumer_data type");
                assert(0);
-               return -ENOSYS;
+               ret = -ENOSYS;
+               break;
        }
+
+       pthread_mutex_unlock(&stream->lock);
+       return ret;
 }
 
 int lttng_consumer_on_recv_stream(struct lttng_consumer_stream *stream)
@@ -2604,7 +2648,7 @@ int consumer_add_relayd_socket(int net_seq_idx, int sock_type,
                struct lttng_consumer_local_data *ctx, int sock,
                struct pollfd *consumer_sockpoll, struct lttcomm_sock *relayd_sock)
 {
-       int fd, ret = -1;
+       int fd = -1, ret = -1;
        struct consumer_relayd_sock_pair *relayd;
 
        DBG("Consumer adding relayd socket (idx: %d)", net_seq_idx);
@@ -2631,6 +2675,7 @@ int consumer_add_relayd_socket(int net_seq_idx, int sock_type,
        if (ret != sizeof(fd)) {
                lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_ERROR_RECV_FD);
                ret = -1;
+               fd = -1;        /* Just in case it gets set with an invalid value. */
                goto error;
        }
 
@@ -2640,14 +2685,15 @@ int consumer_add_relayd_socket(int net_seq_idx, int sock_type,
                /* Copy received lttcomm socket */
                lttcomm_copy_sock(&relayd->control_sock, relayd_sock);
                ret = lttcomm_create_sock(&relayd->control_sock);
-               if (ret < 0) {
-                       goto error;
+               /* Immediately try to close the created socket if valid. */
+               if (relayd->control_sock.fd >= 0) {
+                       if (close(relayd->control_sock.fd)) {
+                               PERROR("close relayd control socket");
+                       }
                }
-
-               /* Close the created socket fd which is useless */
-               ret = close(relayd->control_sock.fd);
+               /* Handle create_sock error. */
                if (ret < 0) {
-                       PERROR("close relayd control socket");
+                       goto error;
                }
 
                /* Assign new file descriptor */
@@ -2657,14 +2703,15 @@ int consumer_add_relayd_socket(int net_seq_idx, int sock_type,
                /* Copy received lttcomm socket */
                lttcomm_copy_sock(&relayd->data_sock, relayd_sock);
                ret = lttcomm_create_sock(&relayd->data_sock);
-               if (ret < 0) {
-                       goto error;
+               /* Immediately try to close the created socket if valid. */
+               if (relayd->data_sock.fd >= 0) {
+                       if (close(relayd->data_sock.fd)) {
+                               PERROR("close relayd data socket");
+                       }
                }
-
-               /* Close the created socket fd which is useless */
-               ret = close(relayd->data_sock.fd);
+               /* Handle create_sock error. */
                if (ret < 0) {
-                       PERROR("close relayd control socket");
+                       goto error;
                }
 
                /* Assign new file descriptor */
@@ -2686,9 +2733,15 @@ int consumer_add_relayd_socket(int net_seq_idx, int sock_type,
        add_relayd(relayd);
 
        /* All good! */
-       ret = 0;
+       return 0;
 
 error:
+       /* Close received socket if valid. */
+       if (fd >= 0) {
+               if (close(fd)) {
+                       PERROR("close received socket");
+               }
+       }
        return ret;
 }
 
This page took 0.027511 seconds and 4 git commands to generate.