Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[sfrench/cifs-2.6.git] / fs / pipe.c
index 51d5fd8840abd895b7d39c8ca0c22770615bfa7b..070aad543382a4e30aa0bd5eef94b5dabba7219d 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -225,8 +225,15 @@ void generic_pipe_buf_release(struct pipe_inode_info *pipe,
 }
 EXPORT_SYMBOL(generic_pipe_buf_release);
 
+/* New data written to a pipe may be appended to a buffer with this type. */
 static const struct pipe_buf_operations anon_pipe_buf_ops = {
-       .can_merge = 1,
+       .confirm = generic_pipe_buf_confirm,
+       .release = anon_pipe_buf_release,
+       .steal = anon_pipe_buf_steal,
+       .get = generic_pipe_buf_get,
+};
+
+static const struct pipe_buf_operations anon_pipe_buf_nomerge_ops = {
        .confirm = generic_pipe_buf_confirm,
        .release = anon_pipe_buf_release,
        .steal = anon_pipe_buf_steal,
@@ -234,13 +241,32 @@ static const struct pipe_buf_operations anon_pipe_buf_ops = {
 };
 
 static const struct pipe_buf_operations packet_pipe_buf_ops = {
-       .can_merge = 0,
        .confirm = generic_pipe_buf_confirm,
        .release = anon_pipe_buf_release,
        .steal = anon_pipe_buf_steal,
        .get = generic_pipe_buf_get,
 };
 
+/**
+ * pipe_buf_mark_unmergeable - mark a &struct pipe_buffer as unmergeable
+ * @buf:       the buffer to mark
+ *
+ * Description:
+ *     This function ensures that no future writes will be merged into the
+ *     given &struct pipe_buffer. This is necessary when multiple pipe buffers
+ *     share the same backing page.
+ */
+void pipe_buf_mark_unmergeable(struct pipe_buffer *buf)
+{
+       if (buf->ops == &anon_pipe_buf_ops)
+               buf->ops = &anon_pipe_buf_nomerge_ops;
+}
+
+static bool pipe_buf_can_merge(struct pipe_buffer *buf)
+{
+       return buf->ops == &anon_pipe_buf_ops;
+}
+
 static ssize_t
 pipe_read(struct kiocb *iocb, struct iov_iter *to)
 {
@@ -378,7 +404,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
                struct pipe_buffer *buf = pipe->bufs + lastbuf;
                int offset = buf->offset + buf->len;
 
-               if (buf->ops->can_merge && offset + chars <= PAGE_SIZE) {
+               if (pipe_buf_can_merge(buf) && offset + chars <= PAGE_SIZE) {
                        ret = pipe_buf_confirm(pipe, buf);
                        if (ret)
                                goto out;