From: Sjur Brændeland sjur.brandel...@stericsson.com
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.brandel...@stericsson.com
---
drivers/char/virtio_console.c | 131 +
1 files changed, 55 insertions(+), 76 deletions(-)
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 301d17e..917cc830 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -111,6 +111,12 @@ struct port_buffer {
size_t len;
/* offset in the buf from which to consume data */
size_t offset;
+
+ /* If sgpages == 0 then buf is used */
+ unsigned int sgpages;
+
+ /* sg is used if spages 0. sg must be the last in is struct */
+ struct scatterlist sg[0];
};
/*
@@ -338,17 +344,39 @@ static inline bool use_multiport(struct ports_device
*portdev)
static void free_buf(struct port_buffer *buf)
{
+ unsigned int i;
+
kfree(buf-buf);
+ for (i = 0; i buf-sgpages; i++) {
+ struct page *page = sg_page(buf-sg[i]);
+ if (!page)
+ break;
+ put_page(page);
+ }
+
kfree(buf);
}
-static struct port_buffer *alloc_buf(size_t buf_size)
+static struct port_buffer *alloc_buf(struct virtqueue *vq, size_t buf_size,
+int pages)
{
struct port_buffer *buf;
- buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+ /*
+* Allocate buffer and the sg list. The sg list array is allocated
+* directly after the port_buffer struct.
+*/
+ buf = kmalloc(sizeof(*buf) + sizeof(struct scatterlist) * pages,
+ GFP_KERNEL);
if (!buf)
goto fail;
+
+ buf-sgpages = pages;
+ if (pages 0) {
+ buf-buf = NULL;
+ return buf;
+ }
+
buf-buf = kmalloc(buf_size, GFP_KERNEL);
if (!buf-buf)
goto free_buf;
@@ -476,52 +504,26 @@ static ssize_t send_control_msg(struct port *port,
unsigned int event,
return 0;
}
-struct buffer_token {
- union {
- void *buf;
- struct scatterlist *sg;
- } u;
- /* If sgpages == 0 then buf is used, else sg is used */
- unsigned int sgpages;
-};
-
-static void reclaim_sg_pages(struct scatterlist *sg, unsigned int nrpages)
-{
- int i;
- struct page *page;
-
- for (i = 0; i nrpages; i++) {
- page = sg_page(sg[i]);
- if (!page)
- break;
- put_page(page);
- }
- kfree(sg);
-}
/* Callers must take the port-outvq_lock */
static void reclaim_consumed_buffers(struct port *port)
{
- struct buffer_token *tok;
+ struct port_buffer *buf;
unsigned int len;
if (!port-portdev) {
/* Device has been unplugged. vqs are already gone. */
return;
}
- while ((tok = virtqueue_get_buf(port-out_vq, len))) {
- if (tok-sgpages)
- reclaim_sg_pages(tok-u.sg, tok-sgpages);
- else
- kfree(tok-u.buf);
- kfree(tok);
+ while ((buf = virtqueue_get_buf(port-out_vq, len))) {
+ free_buf(buf);
port-outvq_full = false;
}
}
static ssize_t __send_to_port(struct port *port, struct scatterlist *sg,
int nents, size_t in_count,
- struct buffer_token *tok, bool nonblock)
+ void *data, bool nonblock)
{
struct virtqueue *out_vq;
ssize_t ret;
@@ -534,7 +536,7 @@ static ssize_t __send_to_port(struct port *port, struct
scatterlist *sg,
reclaim_consumed_buffers(port);
- ret = virtqueue_add_buf(out_vq, sg, nents, 0, tok, GFP_ATOMIC);
+ ret = virtqueue_add_buf(out_vq, sg, nents, 0, data, GFP_ATOMIC);
/* Tell Host to go! */
virtqueue_kick(out_vq);
@@ -572,37 +574,6 @@ done:
return in_count;
}
-static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
- bool nonblock)
-{
- struct scatterlist sg[1];
- struct buffer_token *tok;
-
- tok = kmalloc(sizeof(*tok), GFP_ATOMIC);
- if (!tok)
- return -ENOMEM;
- tok-sgpages = 0;
- tok-u.buf = in_buf;
-
- sg_init_one(sg, in_buf, in_count);
-
- return __send_to_port(port, sg, 1, in_count, tok, nonblock);
-}
-
-static ssize_t send_pages(struct port *port, struct scatterlist *sg, int nents,
- size_t in_count, bool nonblock)
-{
- struct