diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2012-08-09 08:30:50 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2012-09-28 01:35:12 -0400 |
commit | ec8fc870156b2b144f55b6a5a7d135018f04b30e (patch) | |
tree | 449d9375e37f7ff938d214690f4ed72779abf522 /drivers/char/virtio_console.c | |
parent | eb5e89fc70bb3f115b3206ed0c57d3aba1fdd155 (diff) |
virtio/console: Add a failback for unstealable pipe buffer
Add a failback memcpy path for unstealable pipe buffer.
If buf->ops->steal() fails, virtio-serial tries to
copy the page contents to an allocated page, instead
of just failing splice().
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Acked-by: Amit Shah <amit.shah@redhat.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/char/virtio_console.c')
-rw-r--r-- | drivers/char/virtio_console.c | 28 |
1 files changed, 25 insertions, 3 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 730816cdeb45..22b737353017 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c | |||
@@ -794,7 +794,7 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
794 | struct splice_desc *sd) | 794 | struct splice_desc *sd) |
795 | { | 795 | { |
796 | struct sg_list *sgl = sd->u.data; | 796 | struct sg_list *sgl = sd->u.data; |
797 | unsigned int len = 0; | 797 | unsigned int offset, len; |
798 | 798 | ||
799 | if (sgl->n == MAX_SPLICE_PAGES) | 799 | if (sgl->n == MAX_SPLICE_PAGES) |
800 | return 0; | 800 | return 0; |
@@ -807,9 +807,31 @@ static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
807 | 807 | ||
808 | len = min(buf->len, sd->len); | 808 | len = min(buf->len, sd->len); |
809 | sg_set_page(&(sgl->sg[sgl->n]), buf->page, len, buf->offset); | 809 | sg_set_page(&(sgl->sg[sgl->n]), buf->page, len, buf->offset); |
810 | sgl->n++; | 810 | } else { |
811 | sgl->len += len; | 811 | /* Failback to copying a page */ |
812 | struct page *page = alloc_page(GFP_KERNEL); | ||
813 | char *src = buf->ops->map(pipe, buf, 1); | ||
814 | char *dst; | ||
815 | |||
816 | if (!page) | ||
817 | return -ENOMEM; | ||
818 | dst = kmap(page); | ||
819 | |||
820 | offset = sd->pos & ~PAGE_MASK; | ||
821 | |||
822 | len = sd->len; | ||
823 | if (len + offset > PAGE_SIZE) | ||
824 | len = PAGE_SIZE - offset; | ||
825 | |||
826 | memcpy(dst + offset, src + buf->offset, len); | ||
827 | |||
828 | kunmap(page); | ||
829 | buf->ops->unmap(pipe, buf, src); | ||
830 | |||
831 | sg_set_page(&(sgl->sg[sgl->n]), page, len, offset); | ||
812 | } | 832 | } |
833 | sgl->n++; | ||
834 | sgl->len += len; | ||
813 | 835 | ||
814 | return len; | 836 | return len; |
815 | } | 837 | } |