aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/virtio_console.c
diff options
context:
space:
mode:
authorSjur Brændeland <sjur.brandeland@stericsson.com>2012-12-13 22:16:42 -0500
committerRusty Russell <rusty@rustcorp.com.au>2012-12-17 23:50:44 -0500
commit276a3e954cfe4da7c492c9063741f99290d2973e (patch)
treeb2f697bcb414219a157f837c7183fedfd0eb7daa /drivers/char/virtio_console.c
parent9a2bdcc85d28506d4e5d4a9618fb133a3f40945d (diff)
virtio_console: Merge struct buffer_token into struct port_buffer
Refactoring the splice functionality by unifying the approach for sending scatter-lists and regular buffers. This simplifies buffer handling and reduces code size. Splice will now allocate a port_buffer and send_buf() and free_buf() can always be used for any buffer. Signed-off-by: Sjur Brændeland <sjur.brandeland@stericsson.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.c129
1 files changed, 53 insertions, 76 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index db244b5b6c8a..548224686963 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -111,6 +111,12 @@ struct port_buffer {
111 size_t len; 111 size_t len;
112 /* offset in the buf from which to consume data */ 112 /* offset in the buf from which to consume data */
113 size_t offset; 113 size_t offset;
114
115 /* If sgpages == 0 then buf is used */
116 unsigned int sgpages;
117
118 /* sg is used if spages > 0. sg must be the last in is struct */
119 struct scatterlist sg[0];
114}; 120};
115 121
116/* 122/*
@@ -338,17 +344,39 @@ static inline bool use_multiport(struct ports_device *portdev)
338 344
339static void free_buf(struct port_buffer *buf) 345static void free_buf(struct port_buffer *buf)
340{ 346{
347 unsigned int i;
348
341 kfree(buf->buf); 349 kfree(buf->buf);
350 for (i = 0; i < buf->sgpages; i++) {
351 struct page *page = sg_page(&buf->sg[i]);
352 if (!page)
353 break;
354 put_page(page);
355 }
356
342 kfree(buf); 357 kfree(buf);
343} 358}
344 359
345static struct port_buffer *alloc_buf(size_t buf_size) 360static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size,
361 int pages)
346{ 362{
347 struct port_buffer *buf; 363 struct port_buffer *buf;
348 364
349 buf = kmalloc(sizeof(*buf), GFP_KERNEL); 365 /*
366 * Allocate buffer and the sg list. The sg list array is allocated
367 * directly after the port_buffer struct.
368 */
369 buf = kmalloc(sizeof(*buf) + sizeof(struct scatterlist) * pages,
370 GFP_KERNEL);
350 if (!buf) 371 if (!buf)
351 goto fail; 372 goto fail;
373
374 buf->sgpages = pages;
375 if (pages > 0) {
376 buf->buf = NULL;
377 return buf;
378 }
379
352 buf->buf = kmalloc(buf_size, GFP_KERNEL); 380 buf->buf = kmalloc(buf_size, GFP_KERNEL);
353 if (!buf->buf) 381 if (!buf->buf)
354 goto free_buf; 382 goto free_buf;
@@ -478,52 +506,26 @@ static ssize_t send_control_msg(struct port *port, unsigned int event,
478 return 0; 506 return 0;
479} 507}
480 508
481struct buffer_token {
482 union {
483 void *buf;
484 struct scatterlist *sg;
485 } u;
486 /* If sgpages == 0 then buf is used, else sg is used */
487 unsigned int sgpages;
488};
489
490static void reclaim_sg_pages(struct scatterlist *sg, unsigned int nrpages)
491{
492 int i;
493 struct page *page;
494
495 for (i = 0; i < nrpages; i++) {
496 page = sg_page(&sg[i]);
497 if (!page)
498 break;
499 put_page(page);
500 }
501 kfree(sg);
502}
503 509
504/* Callers must take the port->outvq_lock */ 510/* Callers must take the port->outvq_lock */
505static void reclaim_consumed_buffers(struct port *port) 511static void reclaim_consumed_buffers(struct port *port)
506{ 512{
507 struct buffer_token *tok; 513 struct port_buffer *buf;
508 unsigned int len; 514 unsigned int len;
509 515
510 if (!port->portdev) { 516 if (!port->portdev) {
511 /* Device has been unplugged. vqs are already gone. */ 517 /* Device has been unplugged. vqs are already gone. */
512 return; 518 return;
513 } 519 }
514 while ((tok = virtqueue_get_buf(port->out_vq, &len))) { 520 while ((buf = virtqueue_get_buf(port->out_vq, &len))) {
515 if (tok->sgpages) 521 free_buf(buf);
516 reclaim_sg_pages(tok->u.sg, tok->sgpages);
517 else
518 kfree(tok->u.buf);
519 kfree(tok);
520 port->outvq_full = false; 522 port->outvq_full = false;
521 } 523 }
522} 524}
523 525
524static ssize_t __send_to_port(struct port *port, struct scatterlist *sg, 526static ssize_t __send_to_port(struct port *port, struct scatterlist *sg,
525 int nents, size_t in_count, 527 int nents, size_t in_count,
526 struct buffer_token *tok, bool nonblock) 528 void *data, bool nonblock)
527{ 529{
528 struct virtqueue *out_vq; 530 struct virtqueue *out_vq;
529 int err; 531 int err;
@@ -536,7 +538,7 @@ static ssize_t __send_to_port(struct port *port, struct scatterlist *sg,
536 538
537 reclaim_consumed_buffers(port); 539 reclaim_consumed_buffers(port);
538 540
539 err = virtqueue_add_buf(out_vq, sg, nents, 0, tok, GFP_ATOMIC); 541 err = virtqueue_add_buf(out_vq, sg, nents, 0, data, GFP_ATOMIC);
540 542
541 /* Tell Host to go! */ 543 /* Tell Host to go! */
542 virtqueue_kick(out_vq); 544 virtqueue_kick(out_vq);
@@ -574,37 +576,6 @@ done:
574 return in_count; 576 return in_count;
575} 577}
576 578
577static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
578 bool nonblock)
579{
580 struct scatterlist sg[1];
581 struct buffer_token *tok;
582
583 tok = kmalloc(sizeof(*tok), GFP_ATOMIC);
584 if (!tok)
585 return -ENOMEM;
586 tok->sgpages = 0;
587 tok->u.buf = in_buf;
588
589 sg_init_one(sg, in_buf, in_count);
590
591 return __send_to_port(port, sg, 1, in_count, tok, nonblock);
592}
593
594static ssize_t send_pages(struct port *port, struct scatterlist *sg, int nents,
595 size_t in_count, bool nonblock)
596{
597 struct buffer_token *tok;
598
599 tok = kmalloc(sizeof(*tok), GFP_ATOMIC);
600 if (!tok)
601 return -ENOMEM;
602 tok->sgpages = nents;
603 tok->u.sg = sg;
604
605 return __send_to_port(port, sg, nents, in_count, tok, nonblock);
606}
607
608/* 579/*
609 * Give out the data that's requested from the buffer that we have 580 * Give out the data that's requested from the buffer that we have
610 * queued up. 581 * queued up.
@@ -750,9 +721,10 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
750 size_t count, loff_t *offp) 721 size_t count, loff_t *offp)
751{ 722{
752 struct port *port; 723 struct port *port;
753 char *buf; 724 struct port_buffer *buf;
754 ssize_t ret; 725 ssize_t ret;
755 bool nonblock; 726 bool nonblock;
727 struct scatterlist sg[1];
756 728
757 /* Userspace could be out to fool us */ 729 /* Userspace could be out to fool us */
758 if (!count) 730 if (!count)
@@ -768,11 +740,11 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
768 740
769 count = min((size_t)(32 * 1024), count); 741 count = min((size_t)(32 * 1024), count);
770 742
771 buf = kmalloc(count, GFP_KERNEL); 743 buf = alloc_buf(port->out_vq, count, 0);
772 if (!buf) 744 if (!buf)
773 return -ENOMEM; 745 return -ENOMEM;
774 746
775 ret = copy_from_user(buf, ubuf, count); 747 ret = copy_from_user(buf->buf, ubuf, count);
776 if (ret) { 748 if (ret) {
777 ret = -EFAULT; 749 ret = -EFAULT;
778 goto free_buf; 750 goto free_buf;
@@ -786,13 +758,14 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
786 * through to the host. 758 * through to the host.
787 */ 759 */
788 nonblock = true; 760 nonblock = true;
789 ret = send_buf(port, buf, count, nonblock); 761 sg_init_one(sg, buf->buf, count);
762 ret = __send_to_port(port, sg, 1, count, buf, nonblock);
790 763
791 if (nonblock && ret > 0) 764 if (nonblock && ret > 0)
792 goto out; 765 goto out;
793 766
794free_buf: 767free_buf:
795 kfree(buf); 768 free_buf(buf);
796out: 769out:
797 return ret; 770 return ret;
798} 771}
@@ -858,6 +831,7 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
858 struct port *port = filp->private_data; 831 struct port *port = filp->private_data;
859 struct sg_list sgl; 832 struct sg_list sgl;
860 ssize_t ret; 833 ssize_t ret;
834 struct port_buffer *buf;
861 struct splice_desc sd = { 835 struct splice_desc sd = {
862 .total_len = len, 836 .total_len = len,
863 .flags = flags, 837 .flags = flags,
@@ -869,17 +843,18 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
869 if (ret < 0) 843 if (ret < 0)
870 return ret; 844 return ret;
871 845
846 buf = alloc_buf(port->out_vq, 0, pipe->nrbufs);
847 if (!buf)
848 return -ENOMEM;
849
872 sgl.n = 0; 850 sgl.n = 0;
873 sgl.len = 0; 851 sgl.len = 0;
874 sgl.size = pipe->nrbufs; 852 sgl.size = pipe->nrbufs;
875 sgl.sg = kmalloc(sizeof(struct scatterlist) * sgl.size, GFP_KERNEL); 853 sgl.sg = buf->sg;
876 if (unlikely(!sgl.sg))
877 return -ENOMEM;
878
879 sg_init_table(sgl.sg, sgl.size); 854 sg_init_table(sgl.sg, sgl.size);
880 ret = __splice_from_pipe(pipe, &sd, pipe_to_sg); 855 ret = __splice_from_pipe(pipe, &sd, pipe_to_sg);
881 if (likely(ret > 0)) 856 if (likely(ret > 0))
882 ret = send_pages(port, sgl.sg, sgl.n, sgl.len, true); 857 ret = __send_to_port(port, buf->sg, sgl.n, sgl.len, buf, true);
883 858
884 if (unlikely(ret <= 0)) 859 if (unlikely(ret <= 0))
885 kfree(sgl.sg); 860 kfree(sgl.sg);
@@ -1035,6 +1010,7 @@ static const struct file_operations port_fops = {
1035static int put_chars(u32 vtermno, const char *buf, int count) 1010static int put_chars(u32 vtermno, const char *buf, int count)
1036{ 1011{
1037 struct port *port; 1012 struct port *port;
1013 struct scatterlist sg[1];
1038 1014
1039 if (unlikely(early_put_chars)) 1015 if (unlikely(early_put_chars))
1040 return early_put_chars(vtermno, buf, count); 1016 return early_put_chars(vtermno, buf, count);
@@ -1043,7 +1019,8 @@ static int put_chars(u32 vtermno, const char *buf, int count)
1043 if (!port) 1019 if (!port)
1044 return -EPIPE; 1020 return -EPIPE;
1045 1021
1046 return send_buf(port, (void *)buf, count, false); 1022 sg_init_one(sg, buf, count);
1023 return __send_to_port(port, sg, 1, count, (void *)buf, false);
1047} 1024}
1048 1025
1049/* 1026/*
@@ -1264,7 +1241,7 @@ static unsigned int fill_queue(struct virtqueue *vq, spinlock_t *lock)
1264 1241
1265 nr_added_bufs = 0; 1242 nr_added_bufs = 0;
1266 do { 1243 do {
1267 buf = alloc_buf(PAGE_SIZE); 1244 buf = alloc_buf(vq, PAGE_SIZE, 0);
1268 if (!buf) 1245 if (!buf)
1269 break; 1246 break;
1270 1247