+ struct lttng_kernel_tracer_version v;
+
+ v.version = LTTNG_VERSION;
+ v.patchlevel = LTTNG_PATCHLEVEL;
+ v.sublevel = LTTNG_SUBLEVEL;
+
+ if (copy_to_user(uversion_param, &v, sizeof(v)))
+ return -EFAULT;
+ return 0;
+}
+
+static
+long lttng_abi_add_context(struct file *file,
+ struct lttng_kernel_context __user *ucontext_param,
+ struct lttng_ctx **ctx, struct ltt_session *session)
+{
+ struct lttng_kernel_context context_param;
+
+ if (session->been_active)
+ return -EPERM;
+
+ if (copy_from_user(&context_param, ucontext_param, sizeof(context_param)))
+ return -EFAULT;
+
+ switch (context_param.ctx) {
+ case LTTNG_KERNEL_CONTEXT_PID:
+ return lttng_add_pid_to_ctx(ctx);
+ case LTTNG_KERNEL_CONTEXT_PRIO:
+ return lttng_add_prio_to_ctx(ctx);
+ case LTTNG_KERNEL_CONTEXT_NICE:
+ return lttng_add_nice_to_ctx(ctx);
+ case LTTNG_KERNEL_CONTEXT_PERF_COUNTER:
+ return -ENOSYS;
+ case LTTNG_KERNEL_CONTEXT_COMM:
+ return lttng_add_comm_to_ctx(ctx);
+ default:
+ return -EINVAL;
+ }
+}
+
+/**
+ * lttng_ioctl - lttng syscall through ioctl
+ *
+ * @file: the file
+ * @cmd: the command
+ * @arg: command arg
+ *
+ * This ioctl implements lttng commands:
+ * LTTNG_KERNEL_SESSION
+ * Returns a LTTng trace session file descriptor
+ * LTTNG_KERNEL_TRACER_VERSION
+ * Returns the LTTng kernel tracer version
+ * LTTNG_KERNEL_TRACEPOINT_LIST
+ * Returns a file descriptor listing available tracepoints
+ *
+ * The returned session will be deleted when its file descriptor is closed.
+ */
+static
+long lttng_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case LTTNG_KERNEL_SESSION:
+ return lttng_abi_create_session();
+ case LTTNG_KERNEL_TRACER_VERSION:
+ return lttng_abi_tracer_version(file,
+ (struct lttng_kernel_tracer_version __user *) arg);
+ case LTTNG_KERNEL_TRACEPOINT_LIST:
+ return lttng_abi_tracepoint_list();
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static const struct file_operations lttng_fops = {
+ .unlocked_ioctl = lttng_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = lttng_ioctl,
+#endif
+};
+
+/*
+ * We tolerate no failure in this function (if one happens, we print a dmesg
+ * error, but cannot return any error, because the channel information is
+ * invariant.
+ */
+static
+void lttng_metadata_create_events(struct file *channel_file)
+{
+ struct ltt_channel *channel = channel_file->private_data;
+ static struct lttng_kernel_event metadata_params = {
+ .instrumentation = LTTNG_KERNEL_TRACEPOINT,
+ .name = "lttng_metadata",
+ };
+ struct ltt_event *event;
+ int ret;
+
+ /*
+ * We tolerate no failure path after event creation. It will stay
+ * invariant for the rest of the session.
+ */
+ event = ltt_event_create(channel, &metadata_params, NULL);
+ if (!event) {
+ ret = -EINVAL;
+ goto create_error;
+ }
+ return;
+
+create_error:
+ WARN_ON(1);
+ return; /* not allowed to return error */
+}
+
+static
+int lttng_abi_create_channel(struct file *session_file,
+ struct lttng_kernel_channel __user *uchan_param,
+ enum channel_type channel_type)
+{
+ struct ltt_session *session = session_file->private_data;
+ const struct file_operations *fops;
+ const char *transport_name;