+ *
+ * The returned channel will be deleted when its file descriptor is closed.
+ */
+static
+long lttng_session_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case LTTNG_CHANNEL:
+ return lttng_abi_create_channel(filp, (struct lttng_channel __user *)arg);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static
+long lttng_session_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case LTTNG_CHANNEL:
+ return lttng_abi_create_channel(filp, (struct lttng_channel __user *)arg);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+#endif
+
+static const struct file_operations lttng_session_fops = {
+ .unlocked_ioctl = lttng_session_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = lttng_session_compat_ioctl,
+#endif
+}
+
+static
+int lttng_abi_open_stream(struct file *channel_filp)
+{
+ struct ltt_channel *channel = channel_filp->private_data;
+ struct lib_ring_buffer *buf;
+ int stream_fd, ret;
+
+ buf = ltt_buffer_read_open(channel->chan);
+ if (!buf)
+ return -ENOENT;
+
+ stream_fd = get_unused_fd_flags(O_RDWR);
+ if (stream_fd < 0) {
+ ret = stream_fd;
+ goto fd_error;
+ }
+ stream_filp = anon_inode_getfile("[lttng_stream]",
+ <tng_stream_fops,
+ buf, O_RDWR);
+ if (IS_ERR(stream_filp)) {
+ ret = PTR_ERR(stream_filp);
+ goto file_error;
+ }
+
+ /* The stream holds a reference on the channel */
+ atomic_inc(&channel_filp->f_count);
+ return stream_fd;
+
+file_error:
+ put_unused_fd(stream_fd);
+fd_error:
+ ltt_buffer_read_close(buf);
+ return ret;
+}
+
+
+/**
+ * lttng_channel_ioctl - lttng syscall through ioctl
+ *
+ * @filp: the file
+ * @cmd: the command
+ * @arg: command arg
+ *
+ * This ioctl implements lttng commands:
+ * LTTNG_STREAM
+ * Returns an event stream file descriptor or failure.
+ * (typically, one event stream records events from one CPU)
+ * LTTNG_STREAM_NOTIFIER
+ * Returns a file descriptor that can be used to monitor
+ * addition/removal of streams to/from a channel. (e.g. notifier
+ * called on CPU hotplug).