diff options
author | Amit Shah <amit.shah@redhat.com> | 2009-12-21 22:15:30 +0530 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2010-02-24 14:22:57 +1030 |
commit | 88f251ac58b2460ed16ff619a020ad3ef365e607 (patch) | |
tree | c44ba54bfc42897e554399ca66f19ca720f8a751 /drivers/char | |
parent | 431edb8a8bca71008fefceadf53b9315ef7196ec (diff) |
virtio: console: Remove cached data on port close
Remove any data that we might have in a port's inbuf when closing a port
or when any data is received when a port is closed.
Signed-off-by: Amit Shah <amit.shah@redhat.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/virtio_console.c | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 99d182b132c4..5506ff8bdf03 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -316,6 +316,31 @@ static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf) return ret; } +/* Discard any unread data this port has. Callers lockers. */ +static void discard_port_data(struct port *port) +{ + struct port_buffer *buf; + struct virtqueue *vq; + unsigned int len; + + vq = port->in_vq; + if (port->inbuf) + buf = port->inbuf; + else + buf = vq->vq_ops->get_buf(vq, &len); + + if (!buf) + return; + + if (add_inbuf(vq, buf) < 0) { + buf->len = buf->offset = 0; + dev_warn(port->dev, "Error adding buffer back to vq\n"); + return; + } + + port->inbuf = NULL; +} + static bool port_has_data(struct port *port) { unsigned long flags; @@ -534,8 +559,13 @@ static int port_fops_release(struct inode *inode, struct file *filp) /* Notify host of port being closed */ send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0); + spin_lock_irq(&port->inbuf_lock); port->guest_connected = false; + discard_port_data(port); + + spin_unlock_irq(&port->inbuf_lock); + return 0; } @@ -872,6 +902,16 @@ static void in_intr(struct virtqueue *vq) spin_lock_irqsave(&port->inbuf_lock, flags); port->inbuf = get_inbuf(port); + /* + * Don't queue up data when port is closed. This condition + * can be reached when a console port is not yet connected (no + * tty is spawned) and the host sends out data to console + * ports. For generic serial ports, the host won't + * (shouldn't) send data till the guest is connected. + */ + if (!port->guest_connected) + discard_port_data(port); + spin_unlock_irqrestore(&port->inbuf_lock, flags); wake_up_interruptible(&port->waitqueue); |