X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fkernel.cpp;h=f7d232ffc01aadb346b5fdf6d8c4928ea5163727;hp=e27de2436c1cd994aed3bfbf6c1cd39a48cf3370;hb=HEAD;hpb=66cefebdc240cbae0bc79594305f509b0779fa98 diff --git a/src/bin/lttng-sessiond/kernel.cpp b/src/bin/lttng-sessiond/kernel.cpp index e27de2436..4cc51a279 100644 --- a/src/bin/lttng-sessiond/kernel.cpp +++ b/src/bin/lttng-sessiond/kernel.cpp @@ -16,7 +16,6 @@ #include "lttng-syscall.hpp" #include "modprobe.hpp" #include "notification-thread-commands.hpp" -#include "rotate.hpp" #include "sessiond-config.hpp" #include "tracker.hpp" #include "utils.hpp" @@ -25,9 +24,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -49,18 +50,71 @@ #include #include +namespace { /* * 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; +uint64_t next_kernel_channel_key; -static const char *module_proc_lttng = "/proc/lttng"; +const char *module_proc_lttng = "/proc/lttng"; -static int kernel_tracer_fd = -1; -static int kernel_tracer_event_notifier_group_fd = -1; -static int kernel_tracer_event_notifier_group_notification_fd = -1; -static struct cds_lfht *kernel_token_to_event_notifier_rule_ht; +int kernel_tracer_fd = -1; +nonstd::optional kernel_tracer_status = nonstd::nullopt; +int kernel_tracer_event_notifier_group_fd = -1; +int kernel_tracer_event_notifier_group_notification_fd = -1; +struct cds_lfht *kernel_token_to_event_notifier_rule_ht; + +const char *kernel_tracer_status_to_str(lttng_kernel_tracer_status status) +{ + switch (status) { + case LTTNG_KERNEL_TRACER_STATUS_INITIALIZED: + return "LTTNG_KERNEL_TRACER_STATUS_INITIALIZED"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_UNKNOWN: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_UNKNOWN"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_NEED_ROOT: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_NEED_ROOT"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_OPEN_PROC_LTTNG: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_OPEN_PROC_LTTNG"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_VERSION_MISMATCH: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_VERSION_MISMATCH"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_UNKNOWN: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_UNKNOWN"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_MISSING: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_MISSING"; + case LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_SIGNATURE: + return "LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_SIGNATURE"; + } + + abort(); +} + +/* + * On some architectures, calling convention details are embedded in the symbol + * addresses. Uprobe requires a "clean" symbol offset (or at least, an address + * where an instruction boundary would be legal) to add + * instrumentation. sanitize_uprobe_offset implements that sanitization logic on + * a per-architecture basis. + */ +#if defined(__arm__) || defined(__aarch64__) +static inline uint64_t sanitize_uprobe_offset(uint64_t raw_offset) +{ + /* + * The least significant bit is used when branching to switch to thumb + * ISA. However, it's an invalid address for us; mask the least + * significant bit. + */ + return raw_offset &= ~0b1; +} +#else /* defined(__arm__) || defined(__aarch64__) */ +static inline uint64_t sanitize_uprobe_offset(uint64_t raw_offset) +{ + return raw_offset; +} +#endif +} /* namespace */ /* * Add context on a kernel channel. @@ -451,7 +505,7 @@ static int userspace_probe_add_callsite(const struct lttng_userspace_probe_locat goto end; } - callsite.u.uprobe.offset = offset; + callsite.u.uprobe.offset = sanitize_uprobe_offset(offset); ret = kernctl_add_callsite(fd, &callsite); if (ret) { WARN("Failed to add callsite to ELF userspace probe."); @@ -478,7 +532,7 @@ static int userspace_probe_add_callsite(const struct lttng_userspace_probe_locat goto end; } for (i = 0; i < offsets_count; i++) { - callsite.u.uprobe.offset = offsets[i]; + callsite.u.uprobe.offset = sanitize_uprobe_offset(offsets[i]); ret = kernctl_add_callsite(fd, &callsite); if (ret) { WARN("Failed to add callsite to SDT userspace probe"); @@ -796,9 +850,8 @@ static int kernel_disable_event_notifier_rule(struct ltt_kernel_event_notifier_r LTTNG_ASSERT(event); - rcu_read_lock(); + lttng::urcu::read_lock_guard read_lock; cds_lfht_del(kernel_token_to_event_notifier_rule_ht, &event->ht_node); - rcu_read_unlock(); ret = kernctl_disable(event->fd); if (ret < 0) { @@ -1590,7 +1643,8 @@ void kernel_destroy_session(struct ltt_kernel_session *ksess) struct lttng_ht_iter iter; /* For each consumer socket. */ - rcu_read_lock(); + lttng::urcu::read_lock_guard read_lock; + cds_lfht_for_each_entry ( ksess->consumer->socks->ht, &iter.iter, socket, node.node) { struct ltt_kernel_channel *chan; @@ -1604,7 +1658,6 @@ void kernel_destroy_session(struct ltt_kernel_session *ksess) } } } - rcu_read_unlock(); } /* Close any relayd session */ @@ -1680,8 +1733,6 @@ enum lttng_error_code kernel_snapshot_record(struct ltt_kernel_session *ksess, saved_metadata = ksess->metadata; saved_metadata_fd = ksess->metadata_stream_fd; - rcu_read_lock(); - ret = kernel_open_metadata(ksess); if (ret < 0) { status = LTTNG_ERR_KERN_META_FAIL; @@ -1699,49 +1750,56 @@ enum lttng_error_code kernel_snapshot_record(struct ltt_kernel_session *ksess, status = LTTNG_ERR_INVALID; goto error; } - /* Send metadata to consumer and snapshot everything. */ - cds_lfht_for_each_entry (output->socks->ht, &iter.iter, socket, node.node) { - struct ltt_kernel_channel *chan; - 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); - if (ret < 0) { - status = LTTNG_ERR_KERN_META_FAIL; - goto error_consumer; - } + { + /* Send metadata to consumer and snapshot everything. */ + lttng::urcu::read_lock_guard read_lock; + + cds_lfht_for_each_entry (output->socks->ht, &iter.iter, socket, node.node) { + struct ltt_kernel_channel *chan; + + 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); + if (ret < 0) { + status = LTTNG_ERR_KERN_META_FAIL; + goto error_consumer; + } - /* For each channel, ask the consumer to snapshot it. */ - cds_list_for_each_entry (chan, &ksess->channel_list.head, list) { + /* For each channel, ask the consumer to snapshot it. */ + cds_list_for_each_entry (chan, &ksess->channel_list.head, list) { + status = + consumer_snapshot_channel(socket, + chan->key, + output, + 0, + &trace_path[consumer_path_offset], + nb_packets_per_stream); + if (status != LTTNG_OK) { + (void) kernel_consumer_destroy_metadata(socket, + ksess->metadata); + goto error_consumer; + } + } + + /* Snapshot metadata, */ status = consumer_snapshot_channel(socket, - chan->key, + ksess->metadata->key, output, - 0, + 1, &trace_path[consumer_path_offset], - nb_packets_per_stream); + 0); if (status != LTTNG_OK) { - (void) kernel_consumer_destroy_metadata(socket, ksess->metadata); goto error_consumer; } - } - /* Snapshot metadata, */ - status = consumer_snapshot_channel(socket, - ksess->metadata->key, - output, - 1, - &trace_path[consumer_path_offset], - 0); - if (status != LTTNG_OK) { - 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); } - - /* - * 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: @@ -1757,7 +1815,6 @@ error: /* Restore metadata state.*/ ksess->metadata = saved_metadata; ksess->metadata_stream_fd = saved_metadata_fd; - rcu_read_unlock(); free(trace_path); return status; } @@ -1854,45 +1911,47 @@ enum lttng_error_code kernel_rotate_session(struct ltt_session *session) 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. + */ + lttng::urcu::read_lock_guard read_lock; + + cds_lfht_for_each_entry ( + ksess->consumer->socks->ht, &iter.iter, socket, node.node) { + struct ltt_kernel_channel *chan; - /* - * 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; - - /* For each channel, ask the consumer to rotate it. */ - cds_list_for_each_entry (chan, &ksess->channel_list.head, list) { - DBG("Rotate kernel channel %" PRIu64 ", session %s", - chan->key, - session->name); + /* For each channel, ask the consumer to rotate it. */ + cds_list_for_each_entry (chan, &ksess->channel_list.head, list) { + DBG("Rotate kernel channel %" PRIu64 ", session %s", + chan->key, + session->name); + ret = consumer_rotate_channel(socket, + chan->key, + ksess->consumer, + /* is_metadata_channel */ false); + if (ret < 0) { + status = LTTNG_ERR_ROTATION_FAIL_CONSUMER; + goto error; + } + } + + /* + * Rotate the metadata channel. + */ ret = consumer_rotate_channel(socket, - chan->key, + ksess->metadata->key, ksess->consumer, - /* is_metadata_channel */ false); + /* is_metadata_channel */ true); if (ret < 0) { status = LTTNG_ERR_ROTATION_FAIL_CONSUMER; goto error; } } - - /* - * Rotate the metadata channel. - */ - ret = consumer_rotate_channel(socket, - ksess->metadata->key, - ksess->consumer, - /* is_metadata_channel */ true); - if (ret < 0) { - status = LTTNG_ERR_ROTATION_FAIL_CONSUMER; - goto error; - } } error: - rcu_read_unlock(); return status; } @@ -1901,7 +1960,7 @@ enum lttng_error_code kernel_create_channel_subdirectories(const struct ltt_kern enum lttng_error_code ret = LTTNG_OK; enum lttng_trace_chunk_status chunk_status; - rcu_read_lock(); + lttng::urcu::read_lock_guard read_lock; LTTNG_ASSERT(ksess->current_trace_chunk); /* @@ -1915,10 +1974,51 @@ enum lttng_error_code kernel_create_channel_subdirectories(const struct ltt_kern goto error; } error: - rcu_read_unlock(); return ret; } +/* + * Get current kernel tracer status + */ +enum lttng_kernel_tracer_status get_kernel_tracer_status() +{ + if (!kernel_tracer_status) { + return LTTNG_KERNEL_TRACER_STATUS_ERR_UNKNOWN; + } + + return *kernel_tracer_status; +} + +/* + * Sets the kernel tracer status based on the positive errno code + */ +void set_kernel_tracer_status_from_modules_ret(int code) +{ + switch (code) { + case ENOENT: + { + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_MISSING); + break; + } + case ENOKEY: + case EKEYEXPIRED: + case EKEYREVOKED: + case EKEYREJECTED: + { + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_SIGNATURE); + break; + } + default: + { + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_UNKNOWN); + break; + } + } +} + /* * Setup necessary data for kernel tracer action. */ @@ -1927,9 +2027,15 @@ int init_kernel_tracer() int ret; bool is_root = !getuid(); + const auto log_status_on_exit = lttng::make_scope_exit([]() noexcept { + DBG_FMT("Kernel tracer status set to `{}`", + kernel_tracer_status_to_str(*kernel_tracer_status)); + }); + /* Modprobe lttng kernel modules */ ret = modprobe_lttng_control(); if (ret < 0) { + set_kernel_tracer_status_from_modules_ret(-ret); goto error; } @@ -1937,17 +2043,22 @@ int init_kernel_tracer() kernel_tracer_fd = open(module_proc_lttng, O_RDWR); if (kernel_tracer_fd < 0) { DBG("Failed to open %s", module_proc_lttng); + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_OPEN_PROC_LTTNG); goto error_open; } /* Validate kernel version */ ret = kernel_validate_version(&the_kernel_tracer_version, &the_kernel_tracer_abi_version); if (ret < 0) { + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_VERSION_MISMATCH); goto error_version; } ret = modprobe_lttng_data(); if (ret < 0) { + set_kernel_tracer_status_from_modules_ret(-ret); goto error_modules; } @@ -1964,6 +2075,8 @@ int init_kernel_tracer() ret = kernel_supports_event_notifiers(); if (ret < 0) { ERR("Failed to check for kernel tracer event notifier support"); + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER); goto error_modules; } ret = kernel_create_event_notifier_group(&kernel_tracer_event_notifier_group_fd); @@ -1978,6 +2091,8 @@ int init_kernel_tracer() &kernel_tracer_event_notifier_group_notification_fd); if (error_code_ret != LTTNG_OK) { + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER); goto error_modules; } @@ -1986,12 +2101,16 @@ int init_kernel_tracer() if (error_accounting_status != EVENT_NOTIFIER_ERROR_ACCOUNTING_STATUS_OK) { ERR("Failed to initialize event notifier error accounting for kernel tracer"); error_code_ret = LTTNG_ERR_EVENT_NOTIFIER_ERROR_ACCOUNTING; + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER); goto error_modules; } kernel_token_to_event_notifier_rule_ht = cds_lfht_new( DEFAULT_HT_SIZE, 1, 0, CDS_LFHT_AUTO_RESIZE | CDS_LFHT_ACCOUNTING, nullptr); if (!kernel_token_to_event_notifier_rule_ht) { + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER); goto error_token_ht; } } @@ -2007,6 +2126,8 @@ int init_kernel_tracer() "work for this session daemon."); } + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_INITIALIZED); return 0; error_version: @@ -2051,6 +2172,8 @@ error: WARN("No kernel tracer available"); kernel_tracer_fd = -1; if (!is_root) { + kernel_tracer_status = nonstd::optional( + LTTNG_KERNEL_TRACER_STATUS_ERR_NEED_ROOT); return LTTNG_ERR_NEED_ROOT_SESSIOND; } else { return LTTNG_ERR_KERN_NA; @@ -2106,6 +2229,7 @@ void cleanup_kernel_tracer() kernel_tracer_fd = -1; } + kernel_tracer_status = nonstd::nullopt; free(syscall_table); } @@ -2132,49 +2256,52 @@ enum lttng_error_code kernel_clear_session(struct ltt_session *session) DBG("Clear kernel session %s (session %" PRIu64 ")", session->name, session->id); - rcu_read_lock(); - if (ksess->active) { ERR("Expecting inactive session %s (%" PRIu64 ")", session->name, session->id); status = LTTNG_ERR_FATAL; goto end; } - /* - * 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; - - /* For each channel, ask the consumer to clear it. */ - cds_list_for_each_entry (chan, &ksess->channel_list.head, list) { - DBG("Clear kernel channel %" PRIu64 ", session %s", - chan->key, - session->name); - ret = consumer_clear_channel(socket, chan->key); - if (ret < 0) { - goto error; + { + /* + * Note that this loop will end after one iteration given that there is + * only one kernel consumer. + */ + lttng::urcu::read_lock_guard read_lock; + + 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 clear it. */ + cds_list_for_each_entry (chan, &ksess->channel_list.head, list) { + DBG("Clear kernel channel %" PRIu64 ", session %s", + chan->key, + session->name); + ret = consumer_clear_channel(socket, chan->key); + if (ret < 0) { + goto error; + } + } + + if (!ksess->metadata) { + /* + * Nothing to do for the metadata. + * This is a snapshot session. + * The metadata is genererated on the fly. + */ + continue; } - } - if (!ksess->metadata) { /* - * Nothing to do for the metadata. - * This is a snapshot session. - * The metadata is genererated on the fly. + * Clear the metadata channel. + * Metadata channel is not cleared per se but we still need to + * perform a rotation operation on it behind the scene. */ - continue; - } - - /* - * Clear the metadata channel. - * Metadata channel is not cleared per se but we still need to - * perform a rotation operation on it behind the scene. - */ - ret = consumer_clear_channel(socket, ksess->metadata->key); - if (ret < 0) { - goto error; + ret = consumer_clear_channel(socket, ksess->metadata->key); + if (ret < 0) { + goto error; + } } } @@ -2189,7 +2316,6 @@ error: break; } end: - rcu_read_unlock(); return status; } @@ -2422,11 +2548,12 @@ static enum lttng_error_code kernel_create_event_notifier_rule( } /* Add trigger to kernel token mapping in the hash table. */ - rcu_read_lock(); - cds_lfht_add(kernel_token_to_event_notifier_rule_ht, - hash_trigger(trigger), - &event_notifier_rule->ht_node); - rcu_read_unlock(); + { + lttng::urcu::read_lock_guard read_lock; + cds_lfht_add(kernel_token_to_event_notifier_rule_ht, + hash_trigger(trigger), + &event_notifier_rule->ht_node); + } DBG("Created kernel event notifier: name = '%s', fd = %d", kernel_event_notifier.event.name, @@ -2488,7 +2615,7 @@ enum lttng_error_code kernel_unregister_event_notifier(const struct lttng_trigge enum lttng_error_code error_code_ret; int ret; - rcu_read_lock(); + lttng::urcu::read_lock_guard read_lock; cds_lfht_lookup(kernel_token_to_event_notifier_rule_ht, hash_trigger(trigger), @@ -2515,7 +2642,6 @@ enum lttng_error_code kernel_unregister_event_notifier(const struct lttng_trigge error_code_ret = LTTNG_OK; error: - rcu_read_unlock(); return error_code_ret; }