All Virtuozzo development lists (kernel + QEMU)
 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 v7 12/14] usb-host: reconfigure endpoints on CPR incoming #VSTOR-137800
Date: Tue, 6 Oct 2026 15:57:44 +0000	[thread overview]
Message-ID: <010701a111ef64d7-70ed69c3-6036-445d-90de-70722b7b8580-000000@eu-central-1.amazonses.com> (raw)
In-Reply-To: <20261006-usb-host_v3-v7-12-044f668789a1@virtuozzo.com>

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Medium] usb-host: failed CPR post_load makes target exit notifier reset the shared device
- [Medium] usb-host: CPR reclaim claims all interfaces and sets configuration even if guest never configured
- [Medium] usb-host: CPR post_load dereferences NULL dev/dh when device was not opened
- [Low] usb-host: usb_host_ep_update() on CPR target resets endpoint halt state
- [Low] usb-host: reclaim comment claims no half-claimed state but claim loop can fail midway
--

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

usb-host: reconfigure endpoints on CPR incoming #VSTOR-137800

This patch makes the CPR target call usb_host_ep_update() after vmload, so
endpoints for a non-zero altsetting are rebuilt. It also re-claims the
interfaces through libusb so libusb's view matches the preserved fd. The
new helper usb_host_cpr_reclaim_interfaces() validates the migrated
altsetting values before claiming.

> 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

[ ... ]

> +static int usb_host_cpr_reclaim_interfaces(USBHostDevice *s)
> +{
> +    USBDevice *udev = USB_DEVICE(s);
> +    struct libusb_config_descriptor *conf;
> +    int rc;
> +
> +    rc = libusb_get_active_config_descriptor(s->dev, &conf);

[Severity: Medium]
Can s->dev (and later s->dh in libusb_claim_interface()) be NULL here?

usb_host_post_load() takes the CPR branch whenever cpr_is_incoming(), and
neither usb_host_cpr_reclaim_interfaces() nor usb_host_ep_update() checks
dev->dh or dev->dev first.

On the target, only the hostdevice= path opens the device in realize().
With autoscan (hostvendor/hostproduct/hostport), usb_host_auto_check()
only calls usb_host_open() under runstate_is_running().

If the target command line differs from the source's, a NULL pointer would
be passed to libusb.  This is somewhat speculative.  Would an
"if (!dev->dh)" guard make sense?

[ ... ]

> +    /* Data is sane: claim each interface on the fd and record it. */
> +    for (int i = 0; i < conf->bNumInterfaces; i++) {
> +        int ifnum = conf->interface[i].altsetting[0].bInterfaceNumber;
> +
> +        rc = libusb_claim_interface(s->dh, ifnum);
> +        if (rc != 0) {
> +            usb_host_libusb_error("libusb_claim_interface", rc);
> +            libusb_free_config_descriptor(conf);
> +            return -1;
> +        }
> +        s->ifs[ifnum].claimed = true;
> +    }
> +
> +    udev->ninterfaces = conf->bNumInterfaces;
> +    udev->configuration = conf->bConfigurationValue;

[Severity: Medium]
Does this claim every interface and set udev->configuration even when the
guest never configured the device on the source?

On the source, claims are only made in usb_host_claim_interfaces(), which
is reached from usb_host_set_config().  usb_host_open() only detaches
kernel drivers.

If the guest had not issued SET_CONFIGURATION at CPR time,
libusb_get_active_config_descriptor() can still succeed for a
kernel-autoconfigured device.  The target would then create claims the
source never made.  It would also set configuration and ninterfaces from
the host's active config, so the guest would see a configured device.

If migration fails and the source resumes, its ifs[].claimed flags and
configuration would disagree with the kernel state.

The commit message says the re-claim is "a no-op at the usbfs level
anyway".  Does that hold when the source never claimed the interfaces?  I
could not confirm that this case is reachable in practice.

> +    libusb_free_config_descriptor(conf);
> +
> +    return 0;
> +}

[Severity: Low]
The comment above this function and the one in the validation loop say
validation happens first so "garbage migration data can't leave it
half-claimed".  However, the claim loop can still fail partway through
libusb_claim_interface().

In that case the function returns -1 with the earlier interfaces claimed
and marked in s->ifs[].claimed, and nothing rolls that back.  Could the
comment be adjusted, or the claims be undone on failure?

>  static int usb_host_post_load(void *opaque, int version_id)
>  {
>      USBHostDevice *dev = opaque;
[ ... ]
>      if (cpr_is_incoming()) {
> +        /*
> +         * The device stayed open, so rebuild libusb's claims and endpoints,
> +         * and start reaping now that the source has handed the fd off.
> +         */
> +        if (usb_host_cpr_reclaim_interfaces(dev) < 0) {
> +            return -1;
> +        }

[Severity: Medium]
Can this new failure return cause the target's exit notifier to reset the
shared device?

If usb_host_cpr_reclaim_interfaces() returns -1, the incoming migration
fails and the target process exits through usb_host_exit_notifier().  On
the target, s->dh is set and s->cpr_handed_off is false, because it is
only set by usb_host_cpr_quiesce() on the source:

usb_host_exit_notifier() {
    ...
    if (!s->cpr_handed_off) {
        usb_host_abort_xfers(s);
        usb_host_release_interfaces(s);
        libusb_reset_device(s->dh);
        usb_host_attach_kernel(s);
    }
    ...
}

That would reset and release a device on an fd that the still-live source
expects to keep.  Any s->ifs[].claimed flags set by a partial reclaim also
feed usb_host_release_interfaces().

The notifier still gates this only on cpr_handed_off, and the later patch
"usb-host: make CPR migration blocker conditional" does not change that.
Should the target be marked as not owning the device when post_load fails?

> +        usb_host_ep_update(dev);

[Severity: Low]
Does usb_host_ep_update() here reset per-endpoint runtime state that the
guest changed on the source?

It calls usb_ep_reset() and then usb_ep_set_halted(udev, pid, ep, 0) for
every endpoint, and the vmstate carries only the altsetting.  A halted
endpoint would be un-halted without CLEAR_FEATURE(ENDPOINT_HALT), and
max_streams would be rebuilt in default form.

>          usb_host_start_events();
>          return 0;
>      }

-- 
Sashiko AI review · https://sashiko.vzint.dev/#/patchset/20261006-usb-host_v3-v7-0-044f668789a1@virtuozzo.com?part=12

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

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

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=010701a111ef64d7-70ed69c3-6036-445d-90de-70722b7b8580-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.