#include <common/hashtable/utils.hpp>
#include <common/kernel-ctl/kernel-ctl.hpp>
#include <common/kernel-ctl/kernel-ioctl.hpp>
+#include <common/scope-exit.hpp>
#include <common/sessiond-comm/sessiond-comm.hpp>
#include <common/trace-chunk.hpp>
#include <common/tracker.hpp>
#include <sys/types.h>
#include <unistd.h>
+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<enum lttng_kernel_tracer_status> 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();
+}
-namespace {
/*
* On some architectures, calling convention details are embedded in the symbol
* addresses. Uprobe requires a "clean" symbol offset (or at least, an address
return raw_offset &= ~0b1;
}
#else /* defined(__arm__) || defined(__aarch64__) */
-static inline uint64_t sanitize_uprobe_offset(uint64_t raw_offset)
+inline uint64_t sanitize_uprobe_offset(uint64_t raw_offset)
{
return raw_offset;
}
#endif
-}
+} /* namespace */
/*
* Add context on a kernel channel.
* Create a new kernel session, register it to the kernel tracer and add it to
* the session daemon session.
*/
-int kernel_create_session(struct ltt_session *session)
+int kernel_create_session(const ltt_session::locked_ref& session)
{
int ret;
struct ltt_kernel_session *lks;
- LTTNG_ASSERT(session);
-
/* Allocate data structure */
lks = trace_kernel_create_session();
if (lks == nullptr) {
LTTNG_ASSERT(event);
- lttng::urcu::read_lock_guard read_lock;
+ const lttng::urcu::read_lock_guard read_lock;
cds_lfht_del(kernel_token_to_event_notifier_rule_ht, &event->ht_node);
ret = kernctl_disable(event->fd);
void kernel_wait_quiescent()
{
int ret;
- int fd = kernel_tracer_fd;
+ const int fd = kernel_tracer_fd;
DBG("Kernel quiescent wait on %d", fd);
* have to send a command to clean them up or else they leaked.
*/
if (!ksess->output_traces && ksess->consumer_fds_sent) {
- int ret;
- struct consumer_socket *socket;
- struct lttng_ht_iter iter;
-
- /* For each consumer socket. */
- lttng::urcu::read_lock_guard read_lock;
-
- cds_lfht_for_each_entry (
- ksess->consumer->socks->ht, &iter.iter, socket, node.node) {
+ for (auto *socket :
+ lttng::urcu::lfht_iteration_adapter<consumer_socket,
+ decltype(consumer_socket::node),
+ &consumer_socket::node>(
+ *ksess->consumer->socks->ht)) {
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);
+ const auto ret = kernel_consumer_destroy_channel(socket, chan);
if (ret < 0) {
/* Consumer is probably dead. Use next socket. */
continue;
{
int err, ret, saved_metadata_fd;
enum lttng_error_code status = LTTNG_OK;
- struct consumer_socket *socket;
- struct lttng_ht_iter iter;
struct ltt_kernel_metadata *saved_metadata;
char *trace_path = nullptr;
size_t consumer_path_offset = 0;
goto error;
}
- {
- /* 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;
+ for (auto *socket :
+ lttng::urcu::lfht_iteration_adapter<consumer_socket,
+ decltype(consumer_socket::node),
+ &consumer_socket::node>(*output->socks->ht)) {
+ 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) {
- 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;
- }
- }
+ 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;
+ }
- /* Snapshot metadata, */
+ /* 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,
- ksess->metadata->key,
+ chan->key,
output,
- 1,
+ 0,
&trace_path[consumer_path_offset],
- 0);
+ nb_packets_per_stream);
if (status != LTTNG_OK) {
+ (void) kernel_consumer_destroy_metadata(socket, ksess->metadata);
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);
+ /* 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);
}
error_consumer:
*
* Return LTTNG_OK on success or else an LTTng error code.
*/
-enum lttng_error_code kernel_rotate_session(struct ltt_session *session)
+enum lttng_error_code kernel_rotate_session(const ltt_session::locked_ref& session)
{
int ret;
enum lttng_error_code status = LTTNG_OK;
- struct consumer_socket *socket;
- struct lttng_ht_iter iter;
struct ltt_kernel_session *ksess = session->kernel_session;
LTTNG_ASSERT(ksess);
DBG("Rotate kernel session %s started (session %" PRIu64 ")", session->name, session->id);
- {
- /*
- * 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 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.
- */
+ /*
+ * Note that this loop will end after one iteration given that there is
+ * only one kernel consumer.
+ */
+ for (auto *socket : lttng::urcu::lfht_iteration_adapter<consumer_socket,
+ decltype(consumer_socket::node),
+ &consumer_socket::node>(
+ *ksess->consumer->socks->ht)) {
+ 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);
ret = consumer_rotate_channel(socket,
- ksess->metadata->key,
+ chan->key,
ksess->consumer,
- /* is_metadata_channel */ true);
+ /* is_metadata_channel */ false);
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:
enum lttng_error_code ret = LTTNG_OK;
enum lttng_trace_chunk_status chunk_status;
- lttng::urcu::read_lock_guard read_lock;
+ const lttng::urcu::read_lock_guard read_lock;
LTTNG_ASSERT(ksess->current_trace_chunk);
/*
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<enum lttng_kernel_tracer_status>(
+ LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_MISSING);
+ break;
+ }
+ case ENOKEY:
+ case EKEYEXPIRED:
+ case EKEYREVOKED:
+ case EKEYREJECTED:
+ {
+ kernel_tracer_status = nonstd::optional<enum lttng_kernel_tracer_status>(
+ LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_SIGNATURE);
+ break;
+ }
+ default:
+ {
+ kernel_tracer_status = nonstd::optional<enum lttng_kernel_tracer_status>(
+ LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_UNKNOWN);
+ break;
+ }
+ }
+}
+
/*
* Setup necessary data for kernel tracer action.
*/
int init_kernel_tracer()
{
int ret;
- bool is_root = !getuid();
+ const 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;
}
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<enum lttng_kernel_tracer_status>(
+ 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<enum lttng_kernel_tracer_status>(
+ 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;
}
ret = kernel_supports_event_notifiers();
if (ret < 0) {
ERR("Failed to check for kernel tracer event notifier support");
+ kernel_tracer_status = nonstd::optional<enum lttng_kernel_tracer_status>(
+ LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER);
goto error_modules;
}
ret = kernel_create_event_notifier_group(&kernel_tracer_event_notifier_group_fd);
&kernel_tracer_event_notifier_group_notification_fd);
if (error_code_ret != LTTNG_OK) {
+ kernel_tracer_status = nonstd::optional<enum lttng_kernel_tracer_status>(
+ LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER);
goto error_modules;
}
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<enum lttng_kernel_tracer_status>(
+ 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<enum lttng_kernel_tracer_status>(
+ LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER);
goto error_token_ht;
}
}
"work for this session daemon.");
}
+ kernel_tracer_status = nonstd::optional<enum lttng_kernel_tracer_status>(
+ LTTNG_KERNEL_TRACER_STATUS_INITIALIZED);
return 0;
error_version:
WARN("No kernel tracer available");
kernel_tracer_fd = -1;
if (!is_root) {
+ kernel_tracer_status = nonstd::optional<enum lttng_kernel_tracer_status>(
+ LTTNG_KERNEL_TRACER_STATUS_ERR_NEED_ROOT);
return LTTNG_ERR_NEED_ROOT_SESSIOND;
} else {
return LTTNG_ERR_KERN_NA;
kernel_tracer_fd = -1;
}
- free(syscall_table);
+ kernel_tracer_status = nonstd::nullopt;
}
bool kernel_tracer_is_initialized()
*
* Return LTTNG_OK on success or else an LTTng error code.
*/
-enum lttng_error_code kernel_clear_session(struct ltt_session *session)
+enum lttng_error_code kernel_clear_session(const ltt_session::locked_ref& session)
{
int ret;
enum lttng_error_code status = LTTNG_OK;
- struct consumer_socket *socket;
- struct lttng_ht_iter iter;
struct ltt_kernel_session *ksess = session->kernel_session;
LTTNG_ASSERT(ksess);
goto end;
}
- {
- /*
- * 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;
+ /*
+ * Note that this loop will end after one iteration given that there is
+ * only one kernel consumer.
+ */
+ for (auto *socket : lttng::urcu::lfht_iteration_adapter<consumer_socket,
+ decltype(consumer_socket::node),
+ &consumer_socket::node>(
+ *ksess->consumer->socks->ht)) {
+ 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) {
/*
- * 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.
+ * Nothing to do for the metadata.
+ * This is a snapshot session.
+ * The metadata is genererated on the fly.
*/
- ret = consumer_clear_channel(socket, ksess->metadata->key);
- if (ret < 0) {
- goto error;
- }
+ 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;
}
}
enum lttng_error_code
kernel_destroy_event_notifier_group_notification_fd(int event_notifier_group_notification_fd)
{
- enum lttng_error_code ret_code = LTTNG_OK;
+ const lttng_error_code ret_code = LTTNG_OK;
DBG("Closing event notifier group notification file descriptor: fd = %d",
event_notifier_group_notification_fd);
/* Add trigger to kernel token mapping in the hash table. */
{
- lttng::urcu::read_lock_guard read_lock;
+ const 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);
enum lttng_error_code error_code_ret;
int ret;
- lttng::urcu::read_lock_guard read_lock;
+ const lttng::urcu::read_lock_guard read_lock;
cds_lfht_lookup(kernel_token_to_event_notifier_rule_ht,
hash_trigger(trigger),