Issue observed
--------------
When `lttng enable-channel --kernel` fails, little feedback is
available to user to help them to understand the cause.
Eg.
```
Error: Channel asdf: Kernel tracer not available (session auto-
20231123-092621)
```
Solution
--------
The semantic status of the kernel tracer is tracked and persisted in
the session daemon (through `init_kernel_tracer` and
`cleanup_tracer_tracer`.
A new client command `lttng_kernel_tracer_status` is added to request
the current value of the `kernel_tracer_status`. The `lttng` client
uses this command after enabling a kernel-domain channel fails to
provide the user with a more specific cause of the failure.
Eg.
```
Error: Channel asdf: Kernel tracer not available (session auto-
20231123-092621)
Missing one or more required kernel modules
Consult lttng-sessiond logs for more information
```
The kernel tracer status is tracked with an enum defined in
`include/lttng/kernel.h` to avoid passing potentially different errno values
or locale-dependant strings between the LTTng client and session
daemon.
Loading modules and checking signatures can fail with a number of
different errno values. For example:
C.f. https://gitlab.com/linux-kernel/stable/-/blob/master/kernel/module/signing.c#L70
* `EKEYREJECTED`
* Any other error code
C.f. https://gitlab.com/linux-kernel/stable/-/blob/master/Documentation/security/keys/core.rst
* `EKEYREVOKED`
* `EKEYEXPIRED`
* `ENOKEY`
* Others, such as `ENOMEM`
Known drawbacks
---------------
None.
Signed-off-by: Kienan Stewart <kstewart@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: I2ae4b188f0110a472200c2511439b9e3e600527d
lttng/event.h \
lttng/handle.h \
lttng/health.h \
+ lttng/kernel.h \
lttng/kernel-probe.h \
lttng/load.h \
lttng/location.h \
--- /dev/null
+/*
+ * kernel.h
+ *
+ * Linux Trace Toolkit Control Library Header File
+ *
+ * Copyright (C) 2023 Kienan Stewart <kstewart@efficios.com>
+ *
+ * SPDX-License-Identifier; LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_KERNEL_H
+#define LTTNG_KERNEL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum lttng_kernel_tracer_status {
+ /* Loaded without error. */
+ LTTNG_KERNEL_TRACER_STATUS_INITIALIZED = 0,
+ /* Unknown error. */
+ LTTNG_KERNEL_TRACER_STATUS_ERR_UNKNOWN = -1,
+ /* lttng-sessiond isn't running as root. */
+ LTTNG_KERNEL_TRACER_STATUS_ERR_NEED_ROOT = -2,
+ /* Notifier setup failed. */
+ LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER = -3,
+ /* Failed to open /proc/lttng. */
+ LTTNG_KERNEL_TRACER_STATUS_ERR_OPEN_PROC_LTTNG = -4,
+ /* Version mismatch between kernel tracer and kernel tracer ABI. */
+ LTTNG_KERNEL_TRACER_STATUS_ERR_VERSION_MISMATCH = -5,
+ /* Kernel module loading failed. */
+ LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_UNKNOWN = -6,
+ /* Kernel modules missing. */
+ LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_MISSING = -7,
+ /* Kernel module signature error. */
+ LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_SIGNATURE = -8,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_KERNEL_H */
#include <lttng/event.h>
#include <lttng/handle.h>
#include <lttng/health.h>
+#include <lttng/kernel.h>
#include <lttng/kernel-probe.h>
#include <lttng/load.h>
#include <lttng/location.h>
*/
LTTNG_EXPORT extern int lttng_data_pending(const char *session_name);
+/*
+ * Gets the status of the kernel tracer.
+ *
+ * Sets the value of the argument, which must not be null.
+ */
+LTTNG_EXPORT extern enum lttng_error_code lttng_get_kernel_tracer_status(enum lttng_kernel_tracer_status *status);
+
/*
* Deprecated, replaced by lttng_regenerate_metadata.
*/
case LTTCOMM_SESSIOND_COMMAND_CLEAR_SESSION:
case LTTCOMM_SESSIOND_COMMAND_LIST_TRIGGERS:
case LTTCOMM_SESSIOND_COMMAND_EXECUTE_ERROR_QUERY:
+ case LTTCOMM_SESSIOND_COMMAND_KERNEL_TRACER_STATUS:
need_domain = false;
break;
default:
case LTTCOMM_SESSIOND_COMMAND_UNREGISTER_TRIGGER:
case LTTCOMM_SESSIOND_COMMAND_LIST_TRIGGERS:
case LTTCOMM_SESSIOND_COMMAND_EXECUTE_ERROR_QUERY:
+ case LTTCOMM_SESSIOND_COMMAND_KERNEL_TRACER_STATUS:
need_tracing_session = false;
break;
default:
cmd_ctx->session, cmd_ctx->lsm.domain.type, cmd_ctx->lsm.u.reg.path, cdata);
break;
}
+ case LTTCOMM_SESSIOND_COMMAND_KERNEL_TRACER_STATUS:
+ {
+ uint32_t u_status;
+ enum lttng_kernel_tracer_status status;
+
+ ret = cmd_kernel_tracer_status(&status);
+ if (ret != LTTNG_OK) {
+ goto error;
+ }
+
+ u_status = (uint32_t) status;
+ ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &u_status, 4);
+ if (ret < 0) {
+ goto error;
+ }
+
+ ret = LTTNG_OK;
+ break;
+ }
case LTTCOMM_SESSIOND_COMMAND_DATA_PENDING:
{
int pending_ret;
#include <lttng/event-internal.hpp>
#include <lttng/event-rule/event-rule-internal.hpp>
#include <lttng/event-rule/event-rule.h>
+#include <lttng/kernel.h>
#include <lttng/location-internal.hpp>
#include <lttng/lttng-error.h>
#include <lttng/rotate-internal.hpp>
}
}
+/*
+ * Command LTTCOMM_SESSIOND_COMMAND_KERNEL_TRACER_STATUS
+ */
+enum lttng_error_code cmd_kernel_tracer_status(enum lttng_kernel_tracer_status *status)
+{
+ if (status == nullptr) {
+ return LTTNG_ERR_INVALID;
+ }
+
+ *status = get_kernel_tracer_status();
+ return LTTNG_OK;
+}
+
/*
* Command LTTNG_DATA_PENDING returning 0 if the data is NOT pending meaning
* ready for trace analysis (or any kind of reader) or else 1 for pending data.
#include "session.hpp"
#include <common/tracker.hpp>
+#include <lttng/kernel.h>
struct notification_thread_handle;
struct lttng_dynamic_buffer;
enum lttng_error_code cmd_list_syscalls(struct lttng_payload *reply_payload);
int cmd_data_pending(struct ltt_session *session);
+enum lttng_error_code cmd_kernel_tracer_status(enum lttng_kernel_tracer_status *status);
/* Snapshot */
int cmd_snapshot_add_output(struct ltt_session *session,
static const char *module_proc_lttng = "/proc/lttng";
static int kernel_tracer_fd = -1;
+static nonstd::optional<enum lttng_kernel_tracer_status> kernel_tracer_status = nonstd::nullopt;
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;
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.
*/
/* 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;
}
+ kernel_tracer_status = nonstd::nullopt;
free(syscall_table);
}
int kernel_supports_ring_buffer_snapshot_sample_positions(void);
int kernel_supports_ring_buffer_packet_sequence_number(void);
int kernel_supports_event_notifiers(void);
+enum lttng_kernel_tracer_status get_kernel_tracer_status(void);
+void set_kernel_tracer_status_from_modules_ret(int);
int init_kernel_tracer(void);
void cleanup_kernel_tracer(void);
bool kernel_tracer_is_initialized(void);
} else if (WEXITSTATUS(ret) != 0) {
if (modules[i].load_policy == KERNEL_MODULE_PROPERTY_LOAD_POLICY_REQUIRED) {
ERR("Unable to load required module %s", modules[i].name);
+ /* Force negative return code */
+ if (ret > 0) {
+ ret = -ret;
+ }
goto error;
} else {
DBG("Unable to load optional module %s; continuing",
#include <common/mi-lttng.hpp>
#include <common/sessiond-comm/sessiond-comm.hpp>
+#include <common/lttng-kernel.hpp>
#include <common/utils.hpp>
#include <lttng/domain-internal.hpp>
{
struct lttng_channel *channel = nullptr;
int ret = CMD_SUCCESS, warn = 0, error = 0, success = 0;
+ enum lttng_kernel_tracer_status kernel_tracer_status;
char *channel_name;
struct lttng_domain dom;
error = 1;
break;
}
+ /*
+ * Ask the sessiond for the more details on the status of the kernel tracer.
+ */
+ ret = lttng_get_kernel_tracer_status(&kernel_tracer_status);
+ if (ret < 0) {
+ ERR("Failed to get kernel tracer status: %s", lttng_strerror(ret));
+ } else {
+ switch (kernel_tracer_status) {
+ case LTTNG_KERNEL_TRACER_STATUS_INITIALIZED:
+ break;
+ case LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_UNKNOWN:
+ MSG("\tKernel module loading failed");
+ break;
+ case LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_MISSING:
+ MSG("\tMissing one or more required kernel modules");
+ break;
+ case LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_SIGNATURE:
+ MSG("\tKernel module signature error prevented loading of one or more required kernel modules");
+ break;
+ case LTTNG_KERNEL_TRACER_STATUS_ERR_NEED_ROOT:
+ MSG("\tlttng-sessiond isn't running as root");
+ break;
+ case LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER:
+ MSG("\tFailed to setup notifiers");
+ break;
+ case LTTNG_KERNEL_TRACER_STATUS_ERR_OPEN_PROC_LTTNG:
+ MSG("\tlttng-sessiond failed to open proc lttng");
+ break;
+ case LTTNG_KERNEL_TRACER_STATUS_ERR_VERSION_MISMATCH:
+ MSG("\tVersion mismatch between kernel tracer and kernel tracer ABI");
+ break;
+ default:
+ MSG("\tUnknown kernel tracer status (%d)", kernel_tracer_status);
+ break;
+ }
+ MSG("\tConsult lttng-sessiond logs for more information");
+ }
} else {
MSG("%s channel %s enabled for session %s",
lttng_domain_type_str(dom.type),
LTTCOMM_SESSIOND_COMMAND_CLEAR_SESSION,
LTTCOMM_SESSIOND_COMMAND_LIST_TRIGGERS,
LTTCOMM_SESSIOND_COMMAND_EXECUTE_ERROR_QUERY,
+ LTTCOMM_SESSIOND_COMMAND_KERNEL_TRACER_STATUS,
LTTCOMM_SESSIOND_COMMAND_MAX,
};
return "LIST_TRIGGERS";
case LTTCOMM_SESSIOND_COMMAND_EXECUTE_ERROR_QUERY:
return "EXECUTE_ERROR_QUERY";
+ case LTTCOMM_SESSIOND_COMMAND_KERNEL_TRACER_STATUS:
+ return "KERNEL_TRACER_STATUS";
default:
abort();
}
lttng_event_rule_user_tracepoint_set_log_level_rule
lttng_event_rule_user_tracepoint_set_name_pattern
lttng_event_set_userspace_probe_location
+lttng_get_kernel_tracer_status
lttng_health_create_consumerd
lttng_health_create_relayd
lttng_health_create_sessiond
return ret;
}
+/*
+ * Get the status of the kernel tracer
+ *
+ * Sets the value of the argument
+ */
+enum lttng_error_code lttng_get_kernel_tracer_status(enum lttng_kernel_tracer_status *status)
+{
+ enum lttng_error_code ret = LTTNG_ERR_INVALID;
+
+ if (status == nullptr) {
+ return LTTNG_ERR_INVALID;
+ }
+
+ struct lttcomm_session_msg lsm = {};
+ lsm.cmd_type = LTTCOMM_SESSIOND_COMMAND_KERNEL_TRACER_STATUS;
+
+ uint32_t *u_status = nullptr;
+ const auto ask_ret = lttng_ctl_ask_sessiond(&lsm, (void **) &u_status);
+ if (ask_ret != 4) {
+ goto end;
+ }
+
+ *status = (enum lttng_kernel_tracer_status) * u_status;
+ ret = LTTNG_OK;
+end:
+ free(u_status);
+ return ret;
+}
+
/*
* Regenerate the metadata for a session.
* Return 0 on success, a negative error code on error.