+
+/*
+ * Get kernel version and validate it.
+ */
+int kernel_validate_version(int tracer_fd)
+{
+ int ret;
+ struct lttng_kernel_tracer_version version;
+
+ ret = kernctl_tracer_version(tracer_fd, &version);
+ if (ret < 0) {
+ ERR("Failed at getting the lttng-modules version");
+ goto error;
+ }
+
+ /* Validate version */
+ if (version.major != KERN_MODULES_PRE_MAJOR
+ && version.major != KERN_MODULES_MAJOR) {
+ goto error_version;
+ }
+
+ DBG2("Kernel tracer version validated (major version %d)", version.major);
+ return 0;
+
+error_version:
+ ERR("Kernel major version %d is not compatible (supporting <= %d)",
+ version.major, KERN_MODULES_MAJOR)
+ ret = -1;
+
+error:
+ 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");
+
+ /* 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--;
+ }
+}