+unsigned int lttng_metadata_ring_buffer_poll(struct file *filp,
+ poll_table *wait)
+{
+ struct lttng_metadata_stream *stream = filp->private_data;
+ struct lib_ring_buffer *buf = stream->priv;
+ int finalized;
+ unsigned int mask = 0;
+
+ if (filp->f_mode & FMODE_READ) {
+ poll_wait_set_exclusive(wait);
+ poll_wait(filp, &stream->read_wait, wait);
+
+ finalized = stream->finalized;
+
+ /*
+ * lib_ring_buffer_is_finalized() contains a smp_rmb()
+ * ordering finalized load before offsets loads.
+ */
+ WARN_ON(atomic_long_read(&buf->active_readers) != 1);
+
+ if (finalized)
+ mask |= POLLHUP;
+
+ mutex_lock(&stream->metadata_cache->lock);
+ if (stream->metadata_cache->metadata_written >
+ stream->metadata_out)
+ mask |= POLLIN;
+ mutex_unlock(&stream->metadata_cache->lock);
+ }
+
+ return mask;
+}
+
+static
+void lttng_metadata_ring_buffer_ioctl_put_next_subbuf(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct lttng_metadata_stream *stream = filp->private_data;
+
+ stream->metadata_out = stream->metadata_in;
+}
+
+static
+long lttng_metadata_ring_buffer_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret;
+ struct lttng_metadata_stream *stream = filp->private_data;
+ struct lib_ring_buffer *buf = stream->priv;
+
+ switch (cmd) {
+ case RING_BUFFER_GET_NEXT_SUBBUF:
+ {
+ struct lttng_metadata_stream *stream = filp->private_data;
+ struct lib_ring_buffer *buf = stream->priv;
+ struct channel *chan = buf->backend.chan;
+
+ ret = lttng_metadata_output_channel(stream, chan);
+ if (ret > 0) {
+ lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE);
+ ret = 0;
+ } else if (ret < 0)
+ goto err;
+ break;
+ }
+ case RING_BUFFER_GET_SUBBUF:
+ {
+ /*
+ * Random access is not allowed for metadata channel.
+ */
+ return -ENOSYS;
+ }
+ case RING_BUFFER_FLUSH:
+ {
+ struct lttng_metadata_stream *stream = filp->private_data;
+ struct lib_ring_buffer *buf = stream->priv;
+ struct channel *chan = buf->backend.chan;
+
+ /*
+ * Before doing the actual ring buffer flush, write up to one
+ * packet of metadata in the ring buffer.
+ */
+ ret = lttng_metadata_output_channel(stream, chan);
+ if (ret < 0)
+ goto err;
+ break;
+ }
+ default:
+ break;
+ }
+ /* PUT_SUBBUF is the one from lib ring buffer, unmodified. */
+
+ /* Performing lib ring buffer ioctl after our own. */
+ ret = lib_ring_buffer_ioctl(filp, cmd, arg, buf);
+ if (ret < 0)
+ goto err;
+
+ switch (cmd) {
+ case RING_BUFFER_PUT_NEXT_SUBBUF:
+ {
+ lttng_metadata_ring_buffer_ioctl_put_next_subbuf(filp,
+ cmd, arg);
+ break;
+ }
+ default:
+ break;
+ }
+err:
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+static
+long lttng_metadata_ring_buffer_compat_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret;
+ struct lttng_metadata_stream *stream = filp->private_data;
+ struct lib_ring_buffer *buf = stream->priv;
+
+ switch (cmd) {
+ case RING_BUFFER_GET_NEXT_SUBBUF:
+ {
+ struct lttng_metadata_stream *stream = filp->private_data;
+ struct lib_ring_buffer *buf = stream->priv;
+ struct channel *chan = buf->backend.chan;
+
+ ret = lttng_metadata_output_channel(stream, chan);
+ if (ret > 0) {
+ lib_ring_buffer_switch_slow(buf, SWITCH_ACTIVE);
+ ret = 0;
+ } else if (ret < 0)
+ goto err;
+ break;
+ }
+ case RING_BUFFER_GET_SUBBUF:
+ {
+ /*
+ * Random access is not allowed for metadata channel.
+ */
+ return -ENOSYS;
+ }
+ default:
+ break;
+ }
+ /* PUT_SUBBUF is the one from lib ring buffer, unmodified. */
+
+ /* Performing lib ring buffer ioctl after our own. */
+ ret = lib_ring_buffer_compat_ioctl(filp, cmd, arg, buf);
+ if (ret < 0)
+ goto err;
+
+ switch (cmd) {
+ case RING_BUFFER_PUT_NEXT_SUBBUF:
+ {
+ lttng_metadata_ring_buffer_ioctl_put_next_subbuf(filp,
+ cmd, arg);
+ break;
+ }
+ default:
+ break;
+ }
+err:
+ return ret;
+}
+#endif
+
+/*
+ * This is not used by anonymous file descriptors. This code is left
+ * there if we ever want to implement an inode with open() operation.
+ */
+static
+int lttng_metadata_ring_buffer_open(struct inode *inode, struct file *file)
+{
+ struct lttng_metadata_stream *stream = inode->i_private;
+ struct lib_ring_buffer *buf = stream->priv;
+
+ file->private_data = buf;
+ /*
+ * Since life-time of metadata cache differs from that of
+ * session, we need to keep our own reference on the transport.
+ */
+ if (!try_module_get(stream->transport->owner)) {
+ printk(KERN_WARNING "LTT : Can't lock transport module.\n");
+ return -EBUSY;
+ }
+ return lib_ring_buffer_open(inode, file, buf);
+}
+
+static
+int lttng_metadata_ring_buffer_release(struct inode *inode, struct file *file)
+{
+ struct lttng_metadata_stream *stream = file->private_data;
+ struct lib_ring_buffer *buf = stream->priv;
+
+ kref_put(&stream->metadata_cache->refcount, metadata_cache_destroy);
+ module_put(stream->transport->owner);
+ return lib_ring_buffer_release(inode, file, buf);
+}
+
+static
+ssize_t lttng_metadata_ring_buffer_splice_read(struct file *in, loff_t *ppos,
+ struct pipe_inode_info *pipe, size_t len,
+ unsigned int flags)
+{
+ struct lttng_metadata_stream *stream = in->private_data;
+ struct lib_ring_buffer *buf = stream->priv;
+
+ return lib_ring_buffer_splice_read(in, ppos, pipe, len,
+ flags, buf);
+}
+
+static
+int lttng_metadata_ring_buffer_mmap(struct file *filp,
+ struct vm_area_struct *vma)
+{
+ struct lttng_metadata_stream *stream = filp->private_data;
+ struct lib_ring_buffer *buf = stream->priv;
+
+ return lib_ring_buffer_mmap(filp, vma, buf);
+}
+
+static
+const struct file_operations lttng_metadata_ring_buffer_file_operations = {
+ .owner = THIS_MODULE,
+ .open = lttng_metadata_ring_buffer_open,
+ .release = lttng_metadata_ring_buffer_release,
+ .poll = lttng_metadata_ring_buffer_poll,
+ .splice_read = lttng_metadata_ring_buffer_splice_read,
+ .mmap = lttng_metadata_ring_buffer_mmap,
+ .unlocked_ioctl = lttng_metadata_ring_buffer_ioctl,
+ .llseek = vfs_lib_ring_buffer_no_llseek,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = lttng_metadata_ring_buffer_compat_ioctl,
+#endif
+};
+
+static
+int lttng_abi_create_stream_fd(struct file *channel_file, void *stream_priv,
+ const struct file_operations *fops)