X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fkernel.c;h=ddf01044c816f179b668525c5463c60a6f3483c2;hp=95194113243dcf4dbf426e0dfaac19b192cd46ba;hb=bd722d76b035766511f0b329f9bbaa2f4180c4ed;hpb=1624d5b7ba86633d36f3a5c86ea1df5d308c4360 diff --git a/src/bin/lttng-sessiond/kernel.c b/src/bin/lttng-sessiond/kernel.c index 951941132..ddf01044c 100644 --- a/src/bin/lttng-sessiond/kernel.c +++ b/src/bin/lttng-sessiond/kernel.c @@ -30,6 +30,7 @@ #include "consumer.h" #include "kernel.h" +#include "kernel-consumer.h" #include "kern-modules.h" /* @@ -81,7 +82,7 @@ int kernel_create_session(struct ltt_session *session, int tracer_fd) assert(session); /* Allocate data structure */ - lks = trace_kernel_create_session(session->path); + lks = trace_kernel_create_session(); if (lks == NULL) { ret = -1; goto error; @@ -110,6 +111,9 @@ int kernel_create_session(struct ltt_session *session, int tracer_fd) return 0; error: + if (lks) { + trace_kernel_destroy_session(lks); + } return ret; } @@ -163,6 +167,10 @@ int kernel_create_channel(struct ltt_kernel_session *session, return 0; error: + if (lkc) { + free(lkc->channel); + free(lkc); + } return -1; } @@ -353,7 +361,7 @@ error: int kernel_open_metadata(struct ltt_kernel_session *session) { int ret; - struct ltt_kernel_metadata *lkm; + struct ltt_kernel_metadata *lkm = NULL; assert(session); @@ -366,7 +374,7 @@ int kernel_open_metadata(struct ltt_kernel_session *session) /* Kernel tracer metadata creation */ ret = kernctl_open_metadata(session->fd, &lkm->conf->attr); if (ret < 0) { - goto error; + goto error_open; } lkm->fd = ret; @@ -382,6 +390,8 @@ int kernel_open_metadata(struct ltt_kernel_session *session) return 0; +error_open: + trace_kernel_destroy_metadata(lkm); error: return -1; } @@ -451,6 +461,8 @@ int kernel_metadata_flush_buffer(int fd) { int ret; + DBG("Kernel flushing metadata buffer on fd %d", fd); + ret = kernctl_buffer_flush(fd); if (ret < 0) { ERR("Fail to flush metadata buffers %d (ret: %d)", fd, ret); @@ -742,6 +754,32 @@ void kernel_destroy_session(struct ltt_kernel_session *ksess) DBG("Tearing down kernel session"); + /* + * Destroy channels on the consumer if in no output mode because the + * streams are in *no* monitor mode so we have to send a command to clean + * them up or else they leaked. + */ + if (!ksess->output_traces) { + int ret; + struct consumer_socket *socket; + struct lttng_ht_iter iter; + + /* For each consumer socket. */ + cds_lfht_for_each_entry(ksess->consumer->socks->ht, &iter.iter, + socket, node.node) { + struct ltt_kernel_channel *chan; + + /* For each channel, ask the consumer to destroy it. */ + cds_list_for_each_entry(chan, &ksess->channel_list.head, list) { + ret = kernel_consumer_destroy_channel(socket, chan); + if (ret < 0) { + /* Consumer is probably dead. Use next socket. */ + continue; + } + } + } + } + /* Close any relayd session */ consumer_output_send_destroy_relayd(ksess->consumer); @@ -777,3 +815,130 @@ void kernel_destroy_channel(struct ltt_kernel_channel *kchan) ksess->channel_count--; } } + +/* + * Take a snapshot for a given kernel session. + * + * Return 0 on success or else a negative value. + */ +int kernel_snapshot_record(struct ltt_kernel_session *ksess, + struct snapshot_output *output, int wait, unsigned int nb_streams) +{ + int ret, saved_metadata_fd; + struct consumer_socket *socket; + struct lttng_ht_iter iter; + struct ltt_kernel_metadata *saved_metadata; + uint64_t max_size_per_stream = 0; + + assert(ksess); + assert(ksess->consumer); + assert(output); + + DBG("Kernel snapshot record started"); + + /* Save current metadata since the following calls will change it. */ + saved_metadata = ksess->metadata; + saved_metadata_fd = ksess->metadata_stream_fd; + + rcu_read_lock(); + + ret = kernel_open_metadata(ksess); + if (ret < 0) { + ret = LTTNG_ERR_KERN_META_FAIL; + goto error; + } + + ret = kernel_open_metadata_stream(ksess); + if (ret < 0) { + ret = LTTNG_ERR_KERN_META_FAIL; + goto error_open_stream; + } + + if (output->max_size > 0 && nb_streams > 0) { + max_size_per_stream = output->max_size / nb_streams; + } + + /* Send metadata to consumer and snapshot everything. */ + cds_lfht_for_each_entry(ksess->consumer->socks->ht, &iter.iter, + socket, node.node) { + struct consumer_output *saved_output; + struct ltt_kernel_channel *chan; + /* Code flow error */ + assert(socket->fd >= 0); + + /* + * Temporarly switch consumer output for our snapshot output. As long + * as the session lock is taken, this is safe. + */ + saved_output = ksess->consumer; + ksess->consumer = output->consumer; + + pthread_mutex_lock(socket->lock); + /* This stream must not be monitored by the consumer. */ + ret = kernel_consumer_add_metadata(socket, ksess, 0); + pthread_mutex_unlock(socket->lock); + /* Put back the saved consumer output into the session. */ + ksess->consumer = saved_output; + if (ret < 0) { + ret = LTTNG_ERR_KERN_CONSUMER_FAIL; + goto error_consumer; + } + + /* For each channel, ask the consumer to snapshot it. */ + cds_list_for_each_entry(chan, &ksess->channel_list.head, list) { + if (max_size_per_stream && + chan->channel->attr.subbuf_size > max_size_per_stream) { + ret = LTTNG_ERR_INVALID; + DBG3("Kernel snapshot record maximum stream size %" PRIu64 + " is smaller than subbuffer size of %" PRIu64, + max_size_per_stream, chan->channel->attr.subbuf_size); + goto error_consumer; + } + + pthread_mutex_lock(socket->lock); + ret = consumer_snapshot_channel(socket, chan->fd, output, 0, + ksess->uid, ksess->gid, + DEFAULT_KERNEL_TRACE_DIR, wait, + max_size_per_stream); + pthread_mutex_unlock(socket->lock); + if (ret < 0) { + ret = LTTNG_ERR_KERN_CONSUMER_FAIL; + goto error_consumer; + } + } + + /* Snapshot metadata, */ + pthread_mutex_lock(socket->lock); + ret = consumer_snapshot_channel(socket, ksess->metadata->fd, output, + 1, ksess->uid, ksess->gid, + DEFAULT_KERNEL_TRACE_DIR, wait, max_size_per_stream); + pthread_mutex_unlock(socket->lock); + if (ret < 0) { + ret = LTTNG_ERR_KERN_CONSUMER_FAIL; + goto error_consumer; + } + + /* + * The metadata snapshot is done, ask the consumer to destroy it since + * it's not monitored on the consumer side. + */ + (void) kernel_consumer_destroy_metadata(socket, ksess->metadata); + } + +error_consumer: + /* Close newly opened metadata stream. It's now on the consumer side. */ + ret = close(ksess->metadata_stream_fd); + if (ret < 0) { + PERROR("close snapshot kernel"); + } + +error_open_stream: + trace_kernel_destroy_metadata(ksess->metadata); +error: + /* Restore metadata state.*/ + ksess->metadata = saved_metadata; + ksess->metadata_stream_fd = saved_metadata_fd; + + rcu_read_unlock(); + return ret; +}