+ ERR("Kernel tracer version check failed; kernel tracing will not be available");
+ return ret;
+}
+
+/*
+ * Kernel work-arounds called at the start of sessiond main().
+ */
+int init_kernel_workarounds(void)
+{
+ int ret;
+ FILE *fp;
+
+ /*
+ * boot_id needs to be read once before being used concurrently
+ * to deal with a Linux kernel race. A fix is proposed for
+ * upstream, but the work-around is needed for older kernels.
+ */
+ fp = fopen("/proc/sys/kernel/random/boot_id", "r");
+ if (!fp) {
+ goto end_boot_id;
+ }
+ while (!feof(fp)) {
+ char buf[37] = "";
+
+ ret = fread(buf, 1, sizeof(buf), fp);
+ if (ret < 0) {
+ /* Ignore error, we don't really care */
+ }
+ }
+ ret = fclose(fp);
+ if (ret) {
+ PERROR("fclose");
+ }
+end_boot_id:
+ return 0;
+}
+
+/*
+ * Complete teardown of a kernel session.
+ */
+void kernel_destroy_session(struct ltt_kernel_session *ksess)
+{
+ if (ksess == NULL) {
+ DBG3("No kernel session when tearing down session");
+ return;
+ }
+
+ DBG("Tearing down kernel session");
+
+ /*
+ * 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);
+}
+
+/*
+ * 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 0 on success or else return a LTTNG_ERR code.
+ */
+int kernel_snapshot_record(struct ltt_kernel_session *ksess,
+ struct snapshot_output *output, int wait,
+ uint64_t nb_packets_per_stream)
+{
+ int err, ret, saved_metadata_fd;
+ struct consumer_socket *socket;
+ struct lttng_ht_iter iter;
+ struct ltt_kernel_metadata *saved_metadata;
+
+ 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) {
+ ret = LTTNG_ERR_KERN_META_FAIL;
+ goto error;
+ }
+
+ ret = kernel_open_metadata_stream(ksess);
+ if (ret < 0) {
+ ret = LTTNG_ERR_KERN_META_FAIL;
+ goto error_open_stream;
+ }
+
+ /* Send metadata to consumer and snapshot everything. */
+ cds_lfht_for_each_entry(ksess->consumer->socks->ht, &iter.iter,
+ socket, node.node) {
+ struct consumer_output *saved_output;
+ struct ltt_kernel_channel *chan;
+
+ /*
+ * Temporarly switch consumer output for our snapshot output. As long
+ * as the session lock is taken, this is safe.
+ */
+ saved_output = ksess->consumer;
+ ksess->consumer = output->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);
+ /* Put back the saved consumer output into the session. */
+ ksess->consumer = saved_output;
+ if (ret < 0) {
+ ret = LTTNG_ERR_KERN_CONSUMER_FAIL;
+ goto error_consumer;
+ }
+
+ /* For each channel, ask the consumer to snapshot it. */
+ cds_list_for_each_entry(chan, &ksess->channel_list.head, list) {
+ ret = consumer_snapshot_channel(socket, chan->key, output, 0,
+ ksess->uid, ksess->gid,
+ DEFAULT_KERNEL_TRACE_DIR, wait,
+ nb_packets_per_stream);
+ if (ret < 0) {
+ ret = LTTNG_ERR_KERN_CONSUMER_FAIL;
+ (void) kernel_consumer_destroy_metadata(socket,
+ ksess->metadata);
+ goto error_consumer;
+ }
+ }
+
+ /* Snapshot metadata, */
+ ret = consumer_snapshot_channel(socket, ksess->metadata->key, output,
+ 1, ksess->uid, ksess->gid,
+ DEFAULT_KERNEL_TRACE_DIR, wait, 0);
+ if (ret < 0) {
+ ret = LTTNG_ERR_KERN_CONSUMER_FAIL;
+ 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);
+ }
+
+ ret = LTTNG_OK;
+
+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();
+ return ret;
+}
+
+/*
+ * 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(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->current_archive_id,
+ &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->current_archive_id,
+ &session->rotate_pending_relay);
+ if (ret < 0) {
+ ret = LTTNG_ERR_KERN_CONSUMER_FAIL;
+ goto error;
+ }
+ }
+
+ ret = LTTNG_OK;
+
+error:
+ rcu_read_unlock();