pipe_to_sg() tries to steal the page of each pipe buffer and pass it to
the host as it is.  When the steal fails, it copies the data into a page
of its own.

Pages written into the pipe with write(), gifted user pages and page
cache pages can be stolen.  The ftrace ring buffer pages that
virtio-trace splices cannot, so that in-tree user always gets the copy.

Always copy.  The data that reaches the host does not change.

Preparation for removing ->try_steal() from pipe buffers.

Suggested-by: Linus Torvalds <[email protected]>
Signed-off-by: Kiryl Shutsemau (Meta) <[email protected]>
---
 drivers/char/virtio_console.c | 39 +++++++++++++----------------------
 1 file changed, 14 insertions(+), 25 deletions(-)

diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 019bcae81af5..b1b1aaf43e07 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -891,45 +891,34 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, 
struct pipe_buffer *buf,
 {
        struct sg_list *sgl = sd->u.data;
        unsigned int offset, len;
+       struct page *page;
+       char *src;
 
        if (sgl->n == sgl->size)
                return 0;
 
-       /* Try lock this page */
-       if (pipe_buf_try_steal(pipe, buf)) {
-               /* Get reference and unlock page for moving */
-               get_page(buf->page);
-               unlock_page(buf->page);
+       page = alloc_page(GFP_KERNEL);
+       if (!page)
+               return -ENOMEM;
 
-               len = min(buf->len, sd->len);
-               sg_set_page(&(sgl->sg[sgl->n]), buf->page, len, buf->offset);
-       } else {
-               /* Failback to copying a page */
-               struct page *page = alloc_page(GFP_KERNEL);
-               char *src;
+       offset = sd->pos & ~PAGE_MASK;
 
-               if (!page)
-                       return -ENOMEM;
+       len = sd->len;
+       if (len + offset > PAGE_SIZE)
+               len = PAGE_SIZE - offset;
 
-               offset = sd->pos & ~PAGE_MASK;
+       src = kmap_local_page(buf->page);
+       memcpy(page_address(page) + offset, src + buf->offset, len);
+       kunmap_local(src);
 
-               len = sd->len;
-               if (len + offset > PAGE_SIZE)
-                       len = PAGE_SIZE - offset;
-
-               src = kmap_local_page(buf->page);
-               memcpy(page_address(page) + offset, src + buf->offset, len);
-               kunmap_local(src);
-
-               sg_set_page(&(sgl->sg[sgl->n]), page, len, offset);
-       }
+       sg_set_page(&sgl->sg[sgl->n], page, len, offset);
        sgl->n++;
        sgl->len += len;
 
        return len;
 }
 
-/* Faster zero-copy write by splicing */
+/* Write by splicing, copying the data from the pipe */
 static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
                                      struct file *filp, loff_t *ppos,
                                      size_t len, unsigned int flags)
-- 
2.54.0


Reply via email to