X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fkernel.c;h=2b59fe09d3b19924993b08849b5360d5d8eeac9e;hp=381b83e6366c120128d9e6a639a081a24c54b684;hb=22a1b9316f04f95a904ea724ad51aabcc389aca0;hpb=7c493d31f0a1461e0f17a3fd494fef9459d1987c diff --git a/src/bin/lttng-sessiond/kernel.c b/src/bin/lttng-sessiond/kernel.c index 381b83e63..2b59fe09d 100644 --- a/src/bin/lttng-sessiond/kernel.c +++ b/src/bin/lttng-sessiond/kernel.c @@ -15,9 +15,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#define _GNU_SOURCE #define _LGPL_SOURCE -#include #include #include #include @@ -35,9 +33,18 @@ #include "kernel-consumer.h" #include "kern-modules.h" #include "utils.h" +#include "rotate.h" + +/* + * Key used to reference a channel between the sessiond and the consumer. This + * is only read and updated with the session_list lock held. + */ +static uint64_t next_kernel_channel_key; /* * Add context on a kernel channel. + * + * Assumes the ownership of ctx. */ int kernel_add_channel_context(struct ltt_kernel_channel *chan, struct ltt_kernel_context *ctx) @@ -50,20 +57,31 @@ int kernel_add_channel_context(struct ltt_kernel_channel *chan, DBG("Adding context to channel %s", chan->channel->name); ret = kernctl_add_context(chan->fd, &ctx->ctx); if (ret < 0) { - if (errno != EEXIST) { - PERROR("add context ioctl"); - } else { + switch (-ret) { + case ENOSYS: + /* Exists but not available for this kernel */ + ret = LTTNG_ERR_KERN_CONTEXT_UNAVAILABLE; + goto error; + case EEXIST: /* If EEXIST, we just ignore the error */ ret = 0; + goto end; + default: + PERROR("add context ioctl"); + ret = LTTNG_ERR_KERN_CONTEXT_FAIL; + goto error; } - goto error; } + ret = 0; +end: cds_list_add_tail(&ctx->list, &chan->ctx_list); - - return 0; - + ctx->in_list = true; + ctx = NULL; error: + if (ctx) { + trace_kernel_destroy_context(ctx); + } return ret; } @@ -158,8 +176,10 @@ int kernel_create_channel(struct ltt_kernel_session *session, cds_list_add(&lkc->list, &session->channel_list.head); session->channel_count++; lkc->session = session; + lkc->key = ++next_kernel_channel_key; - DBG("Kernel channel %s created (fd: %d)", lkc->channel->name, lkc->fd); + DBG("Kernel channel %s created (fd: %d, key: %" PRIu64 ")", + lkc->channel->name, lkc->fd, lkc->key); return 0; @@ -197,7 +217,7 @@ int kernel_create_event(struct lttng_event *ev, ret = kernctl_create_event(channel->fd, event->event); if (ret < 0) { - switch (errno) { + switch (-ret) { case EEXIST: break; case ENOSYS: @@ -209,7 +229,6 @@ int kernel_create_event(struct lttng_event *ev, default: PERROR("create event ioctl"); } - ret = -errno; goto free_event; } @@ -230,7 +249,7 @@ int kernel_create_event(struct lttng_event *ev, ret = kernctl_enable(event->fd); if (ret < 0) { - switch (errno) { + switch (-ret) { case EEXIST: ret = LTTNG_ERR_KERN_EVENT_EXIST; break; @@ -277,12 +296,12 @@ int kernel_disable_channel(struct ltt_kernel_channel *chan) ret = kernctl_disable(chan->fd); if (ret < 0) { PERROR("disable chan ioctl"); - ret = errno; goto error; } chan->enabled = 0; - DBG("Kernel channel %s disabled (fd: %d)", chan->channel->name, chan->fd); + DBG("Kernel channel %s disabled (fd: %d, key: %" PRIu64 ")", + chan->channel->name, chan->fd, chan->key); return 0; @@ -300,13 +319,14 @@ int kernel_enable_channel(struct ltt_kernel_channel *chan) assert(chan); ret = kernctl_enable(chan->fd); - if (ret < 0 && errno != EEXIST) { + if (ret < 0 && ret != -EEXIST) { PERROR("Enable kernel chan"); goto error; } chan->enabled = 1; - DBG("Kernel channel %s enabled (fd: %d)", chan->channel->name, chan->fd); + DBG("Kernel channel %s enabled (fd: %d, key: %" PRIu64 ")", + chan->channel->name, chan->fd, chan->key); return 0; @@ -325,7 +345,7 @@ int kernel_enable_event(struct ltt_kernel_event *event) ret = kernctl_enable(event->fd); if (ret < 0) { - switch (errno) { + switch (-ret) { case EEXIST: ret = LTTNG_ERR_KERN_EVENT_EXIST; break; @@ -356,7 +376,7 @@ int kernel_disable_event(struct ltt_kernel_event *event) ret = kernctl_disable(event->fd); if (ret < 0) { - switch (errno) { + switch (-ret) { case EEXIST: ret = LTTNG_ERR_KERN_EVENT_EXIST; break; @@ -387,7 +407,7 @@ int kernel_track_pid(struct ltt_kernel_session *session, int pid) if (!ret) { return LTTNG_OK; } - switch (errno) { + switch (-ret) { case EINVAL: return LTTNG_ERR_INVALID; case ENOMEM: @@ -409,7 +429,7 @@ int kernel_untrack_pid(struct ltt_kernel_session *session, int pid) if (!ret) { return LTTNG_OK; } - switch (errno) { + switch (-ret) { case EINVAL: return LTTNG_ERR_INVALID; case ENOMEM: @@ -516,6 +536,7 @@ int kernel_open_metadata(struct ltt_kernel_session *session) } lkm->fd = ret; + lkm->key = ++next_kernel_channel_key; /* Prevent fd duplication after execlp() */ ret = fcntl(lkm->fd, F_SETFD, FD_CLOEXEC); if (ret < 0) { @@ -573,25 +594,6 @@ void kernel_wait_quiescent(int fd) } } -/* - * Kernel calibrate - */ -int kernel_calibrate(int fd, struct lttng_kernel_calibrate *calibrate) -{ - int ret; - - assert(calibrate); - - ret = kernctl_calibrate(fd, calibrate); - if (ret < 0) { - PERROR("calibrate ioctl"); - return -1; - } - - return 0; -} - - /* * Force flush buffer of metadata. */ @@ -660,17 +662,22 @@ error: * Open stream of channel, register it to the kernel tracer and add it * to the stream list of the channel. * + * Note: given that the streams may appear in random order wrt CPU + * number (e.g. cpu hotplug), the index value of the stream number in + * the stream name is not necessarily linked to the CPU number. + * * Return the number of created stream. Else, a negative value. */ int kernel_open_channel_stream(struct ltt_kernel_channel *channel) { - int ret, count = 0; + int ret; struct ltt_kernel_stream *lks; assert(channel); while ((ret = kernctl_create_stream(channel->fd)) >= 0) { - lks = trace_kernel_create_stream(channel->channel->name, count); + lks = trace_kernel_create_stream(channel->channel->name, + channel->stream_count); if (lks == NULL) { ret = close(ret); if (ret) { @@ -689,13 +696,10 @@ int kernel_open_channel_stream(struct ltt_kernel_channel *channel) lks->tracefile_size = channel->channel->attr.tracefile_size; lks->tracefile_count = channel->channel->attr.tracefile_count; - /* Add stream to channe stream list */ + /* Add stream to channel stream list */ cds_list_add(&lks->list, &channel->stream_list.head); channel->stream_count++; - /* Increment counter which represent CPU number. */ - count++; - DBG("Kernel stream %s created (fd: %d, state: %d)", lks->name, lks->fd, lks->state); } @@ -822,44 +826,45 @@ error: /* * Get kernel version and validate it. */ -int kernel_validate_version(int tracer_fd) +int kernel_validate_version(int tracer_fd, + struct lttng_kernel_tracer_version *version, + struct lttng_kernel_tracer_abi_version *abi_version) { int ret; - struct lttng_kernel_tracer_version version; - struct lttng_kernel_tracer_abi_version abi_version; - ret = kernctl_tracer_version(tracer_fd, &version); + ret = kernctl_tracer_version(tracer_fd, version); if (ret < 0) { - ERR("Failed at getting the lttng-modules version"); + ERR("Failed to retrieve the lttng-modules version"); goto error; } /* Validate version */ - if (version.major != VERSION_MAJOR) { + if (version->major != VERSION_MAJOR) { ERR("Kernel tracer major version (%d) is not compatible with lttng-tools major version (%d)", - version.major, VERSION_MAJOR); + version->major, VERSION_MAJOR); goto error_version; } - ret = kernctl_tracer_abi_version(tracer_fd, &abi_version); + ret = kernctl_tracer_abi_version(tracer_fd, abi_version); if (ret < 0) { - ERR("Failed at getting lttng-modules ABI version"); + ERR("Failed to retrieve lttng-modules ABI version"); goto error; } - if (abi_version.major != LTTNG_MODULES_ABI_MAJOR_VERSION) { - ERR("Kernel tracer ABI version (%d.%d) is not compatible with expected ABI major version (%d.*)", - abi_version.major, abi_version.minor, + if (abi_version->major != LTTNG_MODULES_ABI_MAJOR_VERSION) { + ERR("Kernel tracer ABI version (%d.%d) does not match the expected ABI major version (%d.*)", + abi_version->major, abi_version->minor, LTTNG_MODULES_ABI_MAJOR_VERSION); goto error; } DBG2("Kernel tracer version validated (%d.%d, ABI %d.%d)", - version.major, version.minor, - abi_version.major, abi_version.minor); + version->major, version->minor, + abi_version->major, abi_version->minor); return 0; error_version: ret = -1; error: + ERR("Kernel tracer version check failed; kernel tracing will not be available"); return ret; } @@ -1036,12 +1041,10 @@ int kernel_snapshot_record(struct ltt_kernel_session *ksess, /* For each channel, ask the consumer to snapshot it. */ cds_list_for_each_entry(chan, &ksess->channel_list.head, list) { - pthread_mutex_lock(socket->lock); - ret = consumer_snapshot_channel(socket, chan->fd, output, 0, + ret = consumer_snapshot_channel(socket, chan->key, output, 0, ksess->uid, ksess->gid, DEFAULT_KERNEL_TRACE_DIR, wait, nb_packets_per_stream); - pthread_mutex_unlock(socket->lock); if (ret < 0) { ret = LTTNG_ERR_KERN_CONSUMER_FAIL; (void) kernel_consumer_destroy_metadata(socket, @@ -1051,11 +1054,9 @@ int kernel_snapshot_record(struct ltt_kernel_session *ksess, } /* Snapshot metadata, */ - pthread_mutex_lock(socket->lock); - ret = consumer_snapshot_channel(socket, ksess->metadata->fd, output, + ret = consumer_snapshot_channel(socket, ksess->metadata->key, output, 1, ksess->uid, ksess->gid, DEFAULT_KERNEL_TRACE_DIR, wait, 0); - pthread_mutex_unlock(socket->lock); if (ret < 0) { ret = LTTNG_ERR_KERN_CONSUMER_FAIL; goto error_consumer; @@ -1101,3 +1102,120 @@ int kernel_syscall_mask(int chan_fd, char **syscall_mask, uint32_t *nr_bits) return kernctl_syscall_mask(chan_fd, syscall_mask, nr_bits); } + +/* + * Check for the support of the RING_BUFFER_SNAPSHOT_SAMPLE_POSITIONS via abi + * version number. + * + * Return 1 on success, 0 when feature is not supported, negative value in case + * of errors. + */ +int kernel_supports_ring_buffer_snapshot_sample_positions(int tracer_fd) +{ + int ret = 0; // Not supported by default + struct lttng_kernel_tracer_abi_version abi; + + ret = kernctl_tracer_abi_version(tracer_fd, &abi); + if (ret < 0) { + ERR("Failed to retrieve lttng-modules ABI version"); + goto error; + } + + /* + * RING_BUFFER_SNAPSHOT_SAMPLE_POSITIONS was introduced in 2.3 + */ + if (abi.major >= 2 && abi.minor >= 3) { + /* Supported */ + ret = 1; + } else { + /* Not supported */ + ret = 0; + } +error: + return ret; +} + +/* + * Rotate a kernel session. + * + * Return 0 on success or else return a LTTNG_ERR code. + */ +int kernel_rotate_session(struct ltt_session *session) +{ + int ret; + struct consumer_socket *socket; + struct lttng_ht_iter iter; + struct ltt_kernel_session *ksess = session->kernel_session; + + assert(ksess); + assert(ksess->consumer); + + DBG("Rotate kernel session %s started (session %" PRIu64 ")", + session->name, session->id); + + rcu_read_lock(); + + /* + * Note that this loop will end after one iteration given that there is + * only one kernel consumer. + */ + cds_lfht_for_each_entry(ksess->consumer->socks->ht, &iter.iter, + socket, node.node) { + struct ltt_kernel_channel *chan; + + /* + * Account the metadata channel first to make sure the + * number of channels waiting for a rotation cannot + * reach 0 before we complete the iteration over all + * the channels. + */ + ret = rotate_add_channel_pending(ksess->metadata->key, + LTTNG_DOMAIN_KERNEL, session); + if (ret < 0) { + ret = LTTNG_ERR_KERN_CONSUMER_FAIL; + goto error; + } + + /* For each channel, ask the consumer to rotate it. */ + cds_list_for_each_entry(chan, &ksess->channel_list.head, list) { + ret = rotate_add_channel_pending(chan->key, + LTTNG_DOMAIN_KERNEL, session); + if (ret < 0) { + ret = LTTNG_ERR_KERN_CONSUMER_FAIL; + goto error; + } + + DBG("Rotate channel %" PRIu64 ", session %s", chan->key, session->name); + ret = consumer_rotate_channel(socket, chan->key, + ksess->uid, ksess->gid, ksess->consumer, + ksess->consumer->subdir, + /* is_metadata_channel */ false, + session->rotate_count, + &session->rotate_pending_relay); + if (ret < 0) { + ret = LTTNG_ERR_KERN_CONSUMER_FAIL; + goto error; + } + } + + /* + * Rotate the metadata channel. + */ + ret = consumer_rotate_channel(socket, ksess->metadata->key, + ksess->uid, ksess->gid, ksess->consumer, + ksess->consumer->subdir, + /* is_metadata_channel */ true, + session->rotate_count, + &session->rotate_pending_relay); + if (ret < 0) { + ret = LTTNG_ERR_KERN_CONSUMER_FAIL; + goto error; + } + } + + ret = LTTNG_OK; + +error: + rcu_read_unlock(); + return ret; +}