Virtuozzo QEMU development (svt-core@virtuozzo.com)
 help / color / mirror / Atom feed
From: no-reply@sashiko.virtuozzo.com
To: svt-core@virtuozzo.com,
	 Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>
Cc: andrey.drobyshev@virtuozzo.com, den@openvz.org
Subject: Re: [PATCH QEMU HCI-8.0 v6 06/12] usb-host: re-issue drained URBs if CPR is aborted #VSTOR-137800
Date: Tue, 6 Oct 2026 10:46:12 +0000	[thread overview]
Message-ID: <010701a110d22f9b-2bc514aa-aa87-4f14-9f9f-3cfde3d1fe96-000000@eu-central-1.amazonses.com> (raw)
In-Reply-To: <20261006-usb-host_v3-v6-6-8688ec9576d1@virtuozzo.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] usb-host: cpr_reissue() completes failed combined IN packets with plain usb_packet_complete()
- [Medium] usb-host: cpr_vm_state() returns on NULL dh before reissue, leaving CPR state stale
- [Medium] usb-host: replay from offset 0 under cpr_replay_all duplicates OUT data and loses IN data
--

commit cf25e5a0b05e40289cd96941160f3044c5ee49c9
Author: Andrey Drobyshev <andrey.drobyshev@virtuozzo.com>

usb-host: re-issue drained URBs if CPR is aborted #VSTOR-137800

This patch records the packets suppressed during the CPR drain on a new
cpr_inflight list. If CPR is aborted, the vm-state handler's resume
branch re-issues them on the preserved fd. Control transfers are
completed with an error so that the guest driver retries them.

> diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
> --- a/hw/usb/host-libusb.c
> +++ b/hw/usb/host-libusb.c

[ ... ]

> @@ -446,6 +448,9 @@ static bool usb_host_req_cpr_replay(USBHostRequest *r,
>          xfer->status = LIBUSB_TRANSFER_COMPLETED;
>          return false;
>      }
> +    if (r->p->state == USB_PACKET_ASYNC) {
> +        r->host->cpr_inflight = g_slist_append(r->host->cpr_inflight, r->p);
> +    }
>      return true;
>  }

[Severity: Medium]
When cpr_replay_all is set by usb_host_pre_save(), a cancelled URB with
a non-zero actual_length is also suppressed and queued here:

    if (xfer->actual_length != 0 && !r->host->cpr_replay_all) {
        ...
    }

If CPR is then aborted, usb_host_cpr_reissue() restarts that packet from
offset 0:

    /* Replay from the start of the TD */
    p->actual_length = 0;

Can this duplicate data? For an OUT endpoint, the part already sent to
the device would be sent again, since usb_host_handle_data() copies the
whole payload and resubmits it. For an IN endpoint, the bytes already
read from the device would be discarded, so the guest would never see
them.

Also, cpr_inflight is filled in libusb reap order. Is that the same as
guest submission order when several URBs are pipelined on one endpoint?
I could not confirm this from the code.

The commit message does not mention this limitation.

[ ... ]

> @@ -1254,17 +1259,26 @@ static int usb_host_cpr_drain_xfers(USBHostDevice *s)
>  static void usb_host_cpr_vm_state(void *opaque, bool running, RunState state)
>  {
>      USBHostDevice *s = opaque;
>      MigMode mode;
>  
> -    if (running || !s->dh || state != RUN_STATE_FINISH_MIGRATE) {
> +    if (!s->dh) {
> +        return;
> +    }
> +    if (running) {
> +        usb_host_cpr_reissue(s);
> +        return;
> +    }
> +    if (state != RUN_STATE_FINISH_MIGRATE) {
>          return;
>      }

[Severity: Medium]
Can this early return on a NULL dh leave stale CPR state? Before this
patch the !s->dh check only guarded the drain. It now also skips
usb_host_cpr_reissue() on resume.

Consider this sequence:

usb_host_cpr_drain_xfers()
    suppresses requests and queues their packets on cpr_inflight
usb_host_nodev_bh() or unplug
    usb_host_close()
        s->dh = NULL
resume
    usb_host_cpr_vm_state(running)
        if (!s->dh) return;

Here cpr_drained and cpr_replay_all stay set. A later CPR attempt then
skips the drain, because usb_host_pre_save() tests
"s->dh && !s->cpr_drained".

In the base patch, usb_host_close() calls usb_device_detach(). The HCD
then cancels the packets through usb_host_cancel_packet(), which drops
them from cpr_inflight, so the packets are not stranded in that case.

With the later patch "usb-host: hand off the device across
cpr-transfer", usb_host_close() skips usb_host_abort_xfers() and
usb_device_detach() when cpr_handed_off is set. In cpr-transfer mode, a
device loss between the drain and the resume would then leave the guest
packets ASYNC with no request behind them and nothing to complete them.
cpr_handed_off would also stay true.

Should the resume branch run the reissue and the state reset even when
dh is NULL?

[ ... ]

> @@ -1356,6 +1370,45 @@ static libusb_device *usb_host_find_ref(int bus, int addr)
> +static void usb_host_cpr_reissue(USBHostDevice *s)
> +{
[ ... ]
> +        } else {
> +            usb_host_handle_data(udev, p);
> +            if (p->status != USB_RET_ASYNC) {
> +                /* Completed synchronously with error */
> +                usb_packet_complete(udev, p);
> +            }
> +        }

[Severity: Medium]
Does this completion handle combined packets correctly?
usb_host_handle_data() can return a non-ASYNC status synchronously:

- USB_RET_NODEV when libusb_submit_transfer() fails
- USB_RET_STALL on a halted endpoint
- USB_RET_STALL when streams are unsupported

For a bulk IN endpoint where usb_host_use_combining() is true, the
packet on cpr_inflight is the first packet of a USBCombinedPacket. A
plain usb_packet_complete() then completes only that first packet.

The normal completion path in usb_host_req_complete_data() does this
instead:

    if (usb_host_use_combining(r->p->ep)) {
        usb_combined_input_packet_complete(USB_DEVICE(s), r->p);
    } else {
        usb_packet_complete(USB_DEVICE(s), r->p);
    }

Can the other sub-packets be left in USB_PACKET_ASYNC with p->combined
still set, and combined->first pointing at an already completed packet?
That could wedge the pipelined bulk-IN endpoint.

The existing usb_host_req_complete_err() uses the same plain call, but
this reissue error path is new in this patch. The later patch "usb-host:
make CPR migration blocker conditional" does not change this code.

[ ... ]

-- 
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261006-usb-host_v3-v6-0-8688ec9576d1@virtuozzo.com?part=6

  reply	other threads:[~2026-10-06 10:46 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-06 10:34 [PATCH QEMU HCI-8.0 v6 00/12] usb-host: support CPR migration Andrey Drobyshev
2026-10-06 10:34 ` [PATCH QEMU HCI-8.0 v6 01/12] usb-host: don't leak hostdev FD on open failure #VSTOR-137800 Andrey Drobyshev
2026-10-06 10:37   ` no-reply
2026-10-06 10:34 ` [PATCH QEMU HCI-8.0 v6 02/12] usb-host: add migration blocker for CPR modes #VSTOR-137800 Andrey Drobyshev
2026-10-06 10:36   ` no-reply
2026-10-06 10:34 ` [PATCH QEMU HCI-8.0 v6 03/12] usb-host: preserve hostdev FD during CPR migration #VSTOR-137800 Andrey Drobyshev
2026-10-06 10:40   ` no-reply
2026-10-06 10:34 ` [PATCH QEMU HCI-8.0 v6 04/12] usb-host: factor out usb_host_reap_xfers() #VSTOR-137800 Andrey Drobyshev
2026-10-06 10:38   ` no-reply
2026-10-06 10:34 ` [PATCH QEMU HCI-8.0 v6 05/12] usb-host: drain in-flight URBs across CPR #VSTOR-137800 Andrey Drobyshev
2026-10-06 10:48   ` no-reply
2026-10-06 10:34 ` [PATCH QEMU HCI-8.0 v6 06/12] usb-host: re-issue drained URBs if CPR is aborted #VSTOR-137800 Andrey Drobyshev
2026-10-06 10:46   ` no-reply [this message]
2026-10-06 10:34 ` [PATCH QEMU HCI-8.0 v6 07/12] usb-host: skip product-string read on CPR incoming #VSTOR-137800 Andrey Drobyshev
2026-10-06 10:47   ` no-reply
2026-10-06 10:34 ` [PATCH QEMU HCI-8.0 v6 08/12] usb-host: hand off the device across cpr-transfer #VSTOR-137800 Andrey Drobyshev
2026-10-06 10:54   ` no-reply
2026-10-06 10:34 ` [PATCH QEMU HCI-8.0 v6 09/12] usb: migrate the interface altsetting #VSTOR-137800 Andrey Drobyshev
2026-10-06 10:52   ` no-reply
2026-10-06 10:34 ` [PATCH QEMU HCI-8.0 v6 10/12] usb-host: reconfigure endpoints on CPR incoming #VSTOR-137800 Andrey Drobyshev
2026-10-06 10:57   ` no-reply
2026-10-06 10:34 ` [PATCH QEMU HCI-8.0 v6 11/12] hcd-xhci: resync isochronous endpoints after CPR #VSTOR-137800 Andrey Drobyshev
2026-10-06 10:57   ` no-reply
2026-10-06 10:34 ` [PATCH QEMU HCI-8.0 v6 12/12] usb-host: make CPR migration blocker conditional #VSTOR-137800 Andrey Drobyshev
2026-10-06 10:58   ` no-reply
2026-10-06 11:49 ` [PATCH QEMU HCI-8.0 v6 00/12] usb-host: support CPR migration Andrey Drobyshev

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=010701a110d22f9b-2bc514aa-aa87-4f14-9f9f-3cfde3d1fe96-000000@eu-central-1.amazonses.com \
    --to=no-reply@sashiko.virtuozzo.com \
    --cc=andrey.drobyshev@virtuozzo.com \
    --cc=den@openvz.org \
    --cc=svt-core@virtuozzo.com \
    /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