diff options
author | Stefan Hajnoczi <stefanha@redhat.com> | 2016-09-19 14:28:05 +0100 |
---|---|---|
committer | Michael S. Tsirkin <mst@redhat.com> | 2016-10-10 01:16:58 +0300 |
commit | d4c19cdeeb2f1e474bc426a6da261f1d7346eb5b (patch) | |
tree | ca6257b6196dbfa2857984b4c87646ece6553f2f /hw/char | |
parent | 97b93c8ad2242c5a5f89ac50f9e696289c5b4947 (diff) |
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 <stefanha@redhat.com>
Tested-by: Ladi Prosek <lprosek@redhat.com>
Reviewed-by: Ladi Prosek <lprosek@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/char')
-rw-r--r-- | hw/char/virtio-serial-bus.c | 14 |
1 files changed, 14 insertions, 0 deletions
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); |