aboutsummaryrefslogtreecommitdiffstats
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
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>
-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);