+
+/*
+ * Teardown of a kernel session, keeping data required by destroy notifiers.
+ */
+void kernel_destroy_session(struct ltt_kernel_session *ksess)
+{
+ struct lttng_trace_chunk *trace_chunk;
+
+ if (ksess == NULL) {
+ DBG3("No kernel session when tearing down session");
+ return;
+ }
+
+ DBG("Tearing down kernel session");
+ trace_chunk = ksess->current_trace_chunk;
+
+ /*
+ * Destroy channels on the consumer if at least one FD has been sent and we
+ * are 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 && ksess->consumer_fds_sent) {
+ int ret;
+ struct consumer_socket *socket;
+ struct lttng_ht_iter iter;
+
+ /* For each consumer socket. */
+ rcu_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 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;
+ }
+ }
+ }
+ rcu_read_unlock();
+ }
+
+ /* Close any relayd session */
+ consumer_output_send_destroy_relayd(ksess->consumer);
+
+ trace_kernel_destroy_session(ksess);
+ lttng_trace_chunk_put(trace_chunk);
+}
+
+/* Teardown of data required by destroy notifiers. */
+void kernel_free_session(struct ltt_kernel_session *ksess)
+{
+ if (ksess == NULL) {
+ return;
+ }
+ trace_kernel_free_session(ksess);
+}
+
+/*
+ * Destroy a kernel channel object. It does not do anything on the tracer side.
+ */
+void kernel_destroy_channel(struct ltt_kernel_channel *kchan)
+{
+ struct ltt_kernel_session *ksess = NULL;
+
+ assert(kchan);
+ assert(kchan->channel);
+
+ DBG3("Kernel destroy channel %s", kchan->channel->name);
+
+ /* Update channel count of associated session. */
+ if (kchan->session) {
+ /* Keep pointer reference so we can update it after the destroy. */
+ ksess = kchan->session;
+ }
+
+ trace_kernel_destroy_channel(kchan);
+
+ /*
+ * At this point the kernel channel is not visible anymore. This is safe
+ * since in order to work on a visible kernel session, the tracing session
+ * lock (ltt_session.lock) MUST be acquired.
+ */
+ if (ksess) {
+ ksess->channel_count--;
+ }
+}
+
+/*
+ * Take a snapshot for a given kernel session.
+ *
+ * Return LTTNG_OK on success or else return a LTTNG_ERR code.
+ */
+enum lttng_error_code kernel_snapshot_record(
+ struct ltt_kernel_session *ksess,
+ const struct consumer_output *output, int wait,
+ uint64_t nb_packets_per_stream)
+{
+ 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 = NULL;
+
+ 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) {
+ status = LTTNG_ERR_KERN_META_FAIL;
+ goto error;
+ }
+
+ ret = kernel_open_metadata_stream(ksess);
+ if (ret < 0) {
+ status = LTTNG_ERR_KERN_META_FAIL;
+ goto error_open_stream;
+ }
+
+ trace_path = setup_channel_trace_path(ksess->consumer,
+ DEFAULT_KERNEL_TRACE_DIR);
+ if (!trace_path) {
+ 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;
+ }
+
+ /* 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,
+ ksess->uid, ksess->gid,
+ trace_path, wait,
+ 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, ksess->metadata->key, output,
+ 1, ksess->uid, ksess->gid, trace_path, wait, 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:
+ /* Close newly opened metadata stream. It's now on the consumer side. */
+ err = close(ksess->metadata_stream_fd);
+ if (err < 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();
+ free(trace_path);
+ return status;
+}
+
+/*
+ * Get the syscall mask array from the kernel tracer.
+ *
+ * Return 0 on success else a negative value. In both case, syscall_mask should
+ * be freed.
+ */
+int kernel_syscall_mask(int chan_fd, char **syscall_mask, uint32_t *nr_bits)
+{
+ assert(syscall_mask);
+ assert(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(void)
+{
+ int ret = 0; // Not supported by default
+ struct lttng_kernel_tracer_abi_version abi;
+
+ ret = kernctl_tracer_abi_version(kernel_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;
+}
+
+/*
+ * Check for the support of the packet sequence number 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_packet_sequence_number(void)
+{
+ int ret = 0; // Not supported by default
+ struct lttng_kernel_tracer_abi_version abi;
+
+ ret = kernctl_tracer_abi_version(kernel_tracer_fd, &abi);
+ if (ret < 0) {
+ ERR("Failed to retrieve lttng-modules ABI version");
+ goto error;
+ }
+
+ /*
+ * Packet sequence number was introduced in 2.8
+ */
+ if (abi.major >= 2 && abi.minor >= 8) {
+ /* Supported */
+ ret = 1;
+ } else {
+ /* Not supported */
+ ret = 0;
+ }
+error:
+ return ret;
+}
+
+/*
+ * Rotate a kernel session.
+ *
+ * Return LTTNG_OK on success or else an LTTng error code.
+ */
+enum lttng_error_code kernel_rotate_session(struct ltt_session *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;
+
+ 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;
+
+ /* 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->uid, ksess->gid, ksess->consumer,
+ /* is_metadata_channel */ false);
+ if (ret < 0) {
+ status = 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,
+ /* is_metadata_channel */ true);
+ if (ret < 0) {
+ status = LTTNG_ERR_KERN_CONSUMER_FAIL;
+ goto error;
+ }
+ }
+
+error:
+ rcu_read_unlock();
+ return status;
+}
+
+enum lttng_error_code kernel_create_channel_subdirectories(
+ const struct ltt_kernel_session *ksess)
+{
+ enum lttng_error_code ret = LTTNG_OK;
+ enum lttng_trace_chunk_status chunk_status;
+
+ rcu_read_lock();
+ assert(ksess->current_trace_chunk);
+
+ /*
+ * Create the index subdirectory which will take care
+ * of implicitly creating the channel's path.
+ */
+ chunk_status = lttng_trace_chunk_create_subdirectory(
+ ksess->current_trace_chunk,
+ DEFAULT_KERNEL_TRACE_DIR "/" DEFAULT_INDEX_DIR);
+ if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+ ret = LTTNG_ERR_CREATE_DIR_FAIL;
+ goto error;
+ }
+error:
+ rcu_read_unlock();
+ return ret;
+}
+
+/*
+ * Setup necessary data for kernel tracer action.
+ */
+LTTNG_HIDDEN
+int init_kernel_tracer(void)
+{
+ int ret;
+ bool is_root = !getuid();
+
+ /* Modprobe lttng kernel modules */
+ ret = modprobe_lttng_control();
+ if (ret < 0) {
+ goto error;
+ }
+
+ /* Open debugfs lttng */
+ kernel_tracer_fd = open(module_proc_lttng, O_RDWR);
+ if (kernel_tracer_fd < 0) {
+ DBG("Failed to open %s", module_proc_lttng);
+ goto error_open;
+ }
+
+ /* Validate kernel version */
+ ret = kernel_validate_version(&kernel_tracer_version,
+ &kernel_tracer_abi_version);
+ if (ret < 0) {
+ goto error_version;
+ }
+
+ ret = modprobe_lttng_data();
+ if (ret < 0) {
+ goto error_modules;
+ }
+
+ ret = kernel_supports_ring_buffer_snapshot_sample_positions();
+ if (ret < 0) {
+ goto error_modules;
+ }
+
+ if (ret < 1) {
+ WARN("Kernel tracer does not support buffer monitoring. "
+ "The monitoring timer of channels in the kernel domain "
+ "will be set to 0 (disabled).");
+ }
+
+ DBG("Kernel tracer fd %d", kernel_tracer_fd);
+
+ ret = syscall_init_table(kernel_tracer_fd);
+ if (ret < 0) {
+ ERR("Unable to populate syscall table. Syscall tracing won't "
+ "work for this session daemon.");
+ }
+ return 0;
+
+error_version:
+ modprobe_remove_lttng_control();
+ ret = close(kernel_tracer_fd);
+ if (ret) {
+ PERROR("close");
+ }
+ kernel_tracer_fd = -1;
+ return LTTNG_ERR_KERN_VERSION;
+
+error_modules:
+ ret = close(kernel_tracer_fd);
+ if (ret) {
+ PERROR("close");
+ }
+
+error_open:
+ modprobe_remove_lttng_control();
+
+error:
+ WARN("No kernel tracer available");
+ kernel_tracer_fd = -1;
+ if (!is_root) {
+ return LTTNG_ERR_NEED_ROOT_SESSIOND;
+ } else {
+ return LTTNG_ERR_KERN_NA;
+ }
+}
+
+LTTNG_HIDDEN
+void cleanup_kernel_tracer(void)
+{
+ int ret;
+
+ DBG2("Closing kernel fd");
+ if (kernel_tracer_fd >= 0) {
+ ret = close(kernel_tracer_fd);
+ if (ret) {
+ PERROR("close");
+ }
+ kernel_tracer_fd = -1;
+ }
+ DBG("Unloading kernel modules");
+ modprobe_remove_lttng_all();
+ free(syscall_table);
+}
+
+LTTNG_HIDDEN
+bool kernel_tracer_is_initialized(void)
+{
+ return kernel_tracer_fd >= 0;
+}