From: Amit Shah <amit.shah@redhat.com>
To: Virtualization List <virtualization@lists.linux-foundation.org>
Cc: Amit Shah <amit.shah@redhat.com>, "Michael S. Tsirkin" <mst@redhat.com>
Subject: [PATCH 10/10] virtio: console: Add support for nonblocking write()s
Date: Mon, 5 Apr 2010 19:24:14 +0530 [thread overview]
Message-ID: <1270475654-399-11-git-send-email-amit.shah@redhat.com> (raw)
In-Reply-To: <1270475654-399-10-git-send-email-amit.shah@redhat.com>
If the host port is not open, a write() should either just return if the
file is opened in non-blocking mode, or block till the host port is
opened.
Also, don't spin till host consumes data for nonblocking ports. For
non-blocking ports, we can do away with the spinning and reclaim the
buffers consumed by the host on the next write call or on the condition
that'll make poll return.
Signed-off-by: Amit Shah <amit.shah@redhat.com>
---
drivers/char/virtio_console.c | 82 +++++++++++++++++++++++++++++++++++++++--
1 files changed, 78 insertions(+), 4 deletions(-)
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 680ea25..d70efda 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -183,6 +183,8 @@ struct port {
/* The 'id' to identify the port with the Host */
u32 id;
+ bool outvq_full;
+
/* Is the host device open */
bool host_connected;
@@ -404,7 +406,19 @@ static ssize_t send_control_msg(struct port *port, unsigned int event,
return __send_control_msg(port->portdev, port->id, event, value);
}
-static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count)
+static void reclaim_consumed_buffers(struct port *port)
+{
+ void *buf;
+ unsigned int len;
+
+ while ((buf = port->out_vq->vq_ops->get_buf(port->out_vq, &len))) {
+ kfree(buf);
+ port->outvq_full = false;
+ }
+}
+
+static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
+ bool nonblock)
{
struct scatterlist sg[1];
struct virtqueue *out_vq;
@@ -413,6 +427,8 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count)
out_vq = port->out_vq;
+ reclaim_consumed_buffers(port);
+
sg_init_one(sg, in_buf, in_count);
ret = out_vq->vq_ops->add_buf(out_vq, sg, 1, 0, in_buf);
@@ -424,6 +440,12 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count)
goto fail;
}
+ if (ret == 0)
+ port->outvq_full = true;
+
+ if (nonblock)
+ return in_count;
+
/*
* Wait till the host acknowledges it pushed out the data we
* sent. This is done for ports in blocking mode or for data
@@ -491,6 +513,20 @@ static bool will_read_block(struct port *port)
return !port_has_data(port) && port->host_connected;
}
+static bool will_write_block(struct port *port)
+{
+ if (!port->host_connected)
+ return true;
+
+ /*
+ * Check if the Host has consumed any buffers since we last
+ * sent data (this is only applicable for nonblocking ports).
+ */
+ reclaim_consumed_buffers(port);
+
+ return port->outvq_full;
+}
+
static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
size_t count, loff_t *offp)
{
@@ -537,9 +573,22 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
struct port *port;
char *buf;
ssize_t ret;
+ bool nonblock;
port = filp->private_data;
+ nonblock = filp->f_flags & O_NONBLOCK;
+
+ if (will_write_block(port)) {
+ if (nonblock)
+ return -EAGAIN;
+
+ ret = wait_event_interruptible(port->waitqueue,
+ !will_write_block(port));
+ if (ret < 0)
+ return ret;
+ }
+
count = min((size_t)(32 * 1024), count);
buf = kmalloc(count, GFP_KERNEL);
@@ -552,9 +601,14 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
goto free_buf;
}
- ret = send_buf(port, buf, count);
+ ret = send_buf(port, buf, count, nonblock);
+
+ if (nonblock && ret > 0)
+ goto out;
+
free_buf:
kfree(buf);
+out:
return ret;
}
@@ -569,7 +623,7 @@ static unsigned int port_fops_poll(struct file *filp, poll_table *wait)
ret = 0;
if (port->inbuf)
ret |= POLLIN | POLLRDNORM;
- if (port->host_connected)
+ if (!will_write_block(port))
ret |= POLLOUT;
if (!port->host_connected)
ret |= POLLHUP;
@@ -592,6 +646,7 @@ static int port_fops_release(struct inode *inode, struct file *filp)
discard_port_data(port);
spin_unlock_irq(&port->inbuf_lock);
+ reclaim_consumed_buffers(port);
return 0;
}
@@ -621,6 +676,13 @@ static int port_fops_open(struct inode *inode, struct file *filp)
port->guest_connected = true;
spin_unlock_irq(&port->inbuf_lock);
+ /*
+ * There might be a chance that we missed reclaiming a few
+ * buffers in the window of the port getting previously closed
+ * and opening now.
+ */
+ reclaim_consumed_buffers(port);
+
/* Notify host of port being opened */
send_control_msg(filp->private_data, VIRTIO_CONSOLE_PORT_OPEN, 1);
@@ -661,7 +723,7 @@ static int put_chars(u32 vtermno, const char *buf, int count)
if (!port)
return -EPIPE;
- return send_buf(port, (void *)buf, count);
+ return send_buf(port, (void *)buf, count, false);
}
/*
@@ -853,6 +915,8 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
out_offset += snprintf(buf + out_offset, out_count - out_offset,
"host_connected: %d\n", port->host_connected);
out_offset += snprintf(buf + out_offset, out_count - out_offset,
+ "outvq_full: %d\n", port->outvq_full);
+ out_offset += snprintf(buf + out_offset, out_count - out_offset,
"is_console: %s\n",
is_console_port(port) ? "yes" : "no");
out_offset += snprintf(buf + out_offset, out_count - out_offset,
@@ -919,6 +983,8 @@ static int add_port(struct ports_device *portdev, u32 id)
port->host_connected = port->guest_connected = false;
+ port->outvq_full = false;
+
port->in_vq = portdev->in_vqs[port->id];
port->out_vq = portdev->out_vqs[port->id];
@@ -1036,6 +1102,8 @@ static int remove_port(struct port *port)
/* Remove unused data this port might have received. */
discard_port_data(port);
+ reclaim_consumed_buffers(port);
+
/* Remove buffers we queued up for the Host to send us data in. */
while ((buf = port->in_vq->vq_ops->detach_unused_buf(port->in_vq)))
free_buf(buf);
@@ -1107,6 +1175,12 @@ static void handle_control_message(struct ports_device *portdev,
case VIRTIO_CONSOLE_PORT_OPEN:
port->host_connected = cpkt->value;
wake_up_interruptible(&port->waitqueue);
+ /*
+ * If the host port got closed and the host had any
+ * unconsumed buffers, we'll be able to reclaim them
+ * now.
+ */
+ reclaim_unconsumed_buffers(port);
break;
case VIRTIO_CONSOLE_PORT_NAME:
/*
--
1.6.2.5
next prev parent reply other threads:[~2010-04-05 13:54 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-04-05 13:54 [PATCH 00/10] (v5) virtio: console: Fixes, new way of discovering ports Amit Shah
2010-04-05 13:54 ` [PATCH 01/10] virtio: console: Add a __send_control_msg() that can send messages without a valid port Amit Shah
2010-04-05 13:54 ` [PATCH 02/10] virtio: console: Let host know of port or device add failures Amit Shah
2010-04-05 13:54 ` [PATCH 03/10] virtio: console: Return -EPIPE to hvc_console if we lost the connection Amit Shah
2010-04-05 13:54 ` [PATCH 04/10] virtio: console: Don't call hvc_remove() on unplugging console ports Amit Shah
2010-04-05 13:54 ` [PATCH 05/10] virtio: console: Remove config work handler Amit Shah
2010-04-05 13:54 ` [PATCH 06/10] virtio: console: Move code around for future patches Amit Shah
2010-04-05 13:54 ` [PATCH 07/10] virtio: console: Use a control message to add ports Amit Shah
2010-04-05 13:54 ` [PATCH 08/10] virtio: console: Don't always create a port 0 if using multiport Amit Shah
2010-04-05 13:54 ` [PATCH 09/10] virtio: console: Rename wait_is_over() to will_read_block() Amit Shah
2010-04-05 13:54 ` Amit Shah [this message]
2010-04-06 3:12 ` [PATCH 10/10] virtio: console: Add support for nonblocking write()s Rusty Russell
2010-04-06 3:54 ` Amit Shah
2010-04-06 14:54 ` Amit Shah
2010-04-06 3:09 ` [PATCH 07/10] virtio: console: Use a control message to add ports Rusty Russell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1270475654-399-11-git-send-email-amit.shah@redhat.com \
--to=amit.shah@redhat.com \
--cc=mst@redhat.com \
--cc=virtualization@lists.linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).