From d4c19cdeeb2f1e474bc426a6da261f1d7346eb5b Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Mon, 19 Sep 2016 14:28:05 +0100 Subject: [PATCH] virtio-serial: add missing virtio_detach_element() call Ports enter a "throttled" state when writing to the chardev would block. The current output VirtQueueElement is kept around until the chardev becomes writable again. There are several places in the virtio-serial lifecycle where the VirtQueueElement should be thrown away. For example, if the virtio device is reset then virtqueue elements are no longer valid. This patch adds the discard_throttle_data() function to unmap the scatter-gather list and decrement vq->inuse. This ensures that the VirtQueueElement is freed properly. Cc: amit.shah@redhat.com Signed-off-by: Stefan Hajnoczi Tested-by: Ladi Prosek Reviewed-by: Ladi Prosek Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/char/virtio-serial-bus.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index db2a9f19bc..3955f0f741 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -145,6 +145,15 @@ static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev) virtio_notify(vdev, vq); } +static void discard_throttle_data(VirtIOSerialPort *port) +{ + if (port->elem) { + virtqueue_detach_element(port->ovq, port->elem, 0); + g_free(port->elem); + port->elem = NULL; + } +} + static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq, VirtIODevice *vdev) { @@ -267,6 +276,7 @@ int virtio_serial_close(VirtIOSerialPort *port) * consume, reset the throttling flag and discard the data. */ port->throttled = false; + discard_throttle_data(port); discard_vq_data(port->ovq, VIRTIO_DEVICE(port->vser)); send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 0); @@ -591,6 +601,9 @@ static void guest_reset(VirtIOSerial *vser) QTAILQ_FOREACH(port, &vser->ports, next) { vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); + + discard_throttle_data(port); + if (port->guest_connected) { port->guest_connected = false; if (vsc->set_guest_connected) { @@ -901,6 +914,7 @@ static void remove_port(VirtIOSerial *vser, uint32_t port_id) assert(port); /* Flush out any unconsumed buffers first */ + discard_throttle_data(port); discard_vq_data(port->ovq, VIRTIO_DEVICE(port->vser)); send_control_event(vser, port->id, VIRTIO_CONSOLE_PORT_REMOVE, 1); -- 2.11.4.GIT