On Mon, Sep 28, 2026 at 07:26:48PM +0400, [email protected] wrote:
> From: Marc-André Lureau <[email protected]>
>
> When the host chardev disconnects while the output queue is throttled,
> virtio_serial_close() calls discard_throttle_data() which detaches the
> in-flight element with virtqueue_detach_element(). This silently removes
> the descriptor without placing it on the used ring, so the guest never
> sees the write complete and the descriptor leaks.
>
> Add return_throttle_data(), which pushes the element back via
> virtqueue_push() instead of detaching it, and call it from
> virtio_serial_close().
Thanks for fixing this!
>
> Fixes: d4c19cdeeb2f ("virtio-serial: add missing virtio_detach_element()
> call")
> Signed-off-by: Marc-André Lureau <[email protected]>
> ---
> hw/char/virtio-serial-bus.c | 16 +++++++++++++++-
> 1 file changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
> index 623e9f17a83e..008cad1b625c 100644
> --- a/hw/char/virtio-serial-bus.c
> +++ b/hw/char/virtio-serial-bus.c
> @@ -158,6 +158,20 @@ static void discard_throttle_data(VirtIOSerialPort *port)
> }
> }
>
> +/*
> + * Return a partial element held back by throttling to the guest via
> + * the used ring, so the guest driver can reclaim the descriptor.
> + * Unlike discard_throttle_data() this must be used when the virtqueue
> + * stays live (port close) rather than being reset.
> + */
> +static void return_throttle_data(VirtIOSerialPort *port)
> +{
> + if (port->elem) {
> + virtqueue_push(port->ovq, port->elem, 0);
virtio_notify() is missing here. discard_vq_data() calls virtio_notify()
as long as the vq is set up, so in practice the guest will receive a
notification. However, this is a latent bug and the code isn't
performance-critical, so I suggest adding an explicit virtio_notify()
call to prevent future issues.
Reviewed-by: Stefan Hajnoczi <[email protected]>