From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from AM0PR02CU008.outbound.protection.outlook.com (mail-westeuropeazon11023073.outbound.protection.outlook.com [52.101.72.73]) by lore.virtuozzo.com (Postfix) with ESMTPS id 81808802A5 for ; Thu, 24 Sep 2026 16:41:40 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=D1DUDoDhI53vJglPklt9KpefAR18rHj/o5i1f4sN35lN31gU17SLFbgyy1W243yuUs8Z6CBGWJ14p3ZOc9lijjH+/jfSG0NuQuAJFC3ayQ2LnC+4+p8eyDf3eGw3zB5xniyPe/vs4VqXJMF8/U7Dwfw6PK9NHYOx2YM8I7w4o4xriYyjtLIDmpiYzeE8qcHk1imCxtptAx8BK5WLI3G8AEQGAYBIaovX+wli5dtr+Fv1zfOAOtOo5TBiwv1tAdVVz1XRAZwWF9szOVYHkVcCz0MPEVlDUjgSMKy4yg/rvnbKzMN/08SmXT+3zpHDumjfvnCAZZW9Fb5000E6Pj6pMg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=MSLN9Jhz+ymORfAleT8dEX/7aUwvI2vpmQxkIxXyrhQ=; b=V7ADtjA/CF34B7ku9AyxFCrYgOc4JvW/aXgfmyFkCRAa5fp5wpOseMeuw2EHZeiBZmmUPgKS44M5+1vx9MOPR9TPMhKX9HH7kuWcN6nIaM89j1ahTl5RFfmU68wHxfrzHStV9q0rHGin3JB/BlKpp4odGdEA1rnWQTRxm376OcyMQn+4y3dmBunXINmL4VyAjYjVsBaerWPsfAWmWl40EjYZDpBGOvfIhu/kd8DcCWE7jH6WjCJ+bMWDCLqIX38gwZjqECE0vAhpPztjOQwnlGYCjz2Z13wVWxvklPjv64k36Opog0VtVPAZKQZtcsYkQG2r56bS/PX+GWhT1qmjmw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=virtuozzo.com; dmarc=pass action=none header.from=virtuozzo.com; dkim=pass header.d=virtuozzo.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=virtuozzo.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=MSLN9Jhz+ymORfAleT8dEX/7aUwvI2vpmQxkIxXyrhQ=; b=u3PwfhD+fpPopSlafThZkGyXte5KSK0bWbwT+NwVUGl14Ty7DlRlFqjn8oIle0LBS5mharAbeA/eGOTIrX/+sJGVOlUiVSIWnCfpGD4BNG8A1eQ/LNTo3rKB9QucKJn0Kba+KLdeuCV64vn4+bIZOFpu5SG4aAsytlYmJu0fp/R02LWQLJg9qPYxomfuqDjHP03xcge3M+F8NQro4NtJ2Bg/DQr2marWO9q1/OVdcnvVVi8w6fsNqlgghRjxI7KnafL81aEm/CIvpV42O1nCTniUidnm3kfiMXCpN8RlfV7I4SjON6GOycZwUbT9W2TmD9qbzzqyjiw5x+JsJKogww== Authentication-Results: mx.microsoft.com 1; dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=virtuozzo.com; Received: from VI0PR08MB10656.eurprd08.prod.outlook.com (2603:10a6:800:20a::12) by BR0PR08MB151385.eurprd08.prod.outlook.com (2603:10a6:2c8:30::20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.451.18; Thu, 24 Sep 2026 16:41:39 +0000 Received: from VI0PR08MB10656.eurprd08.prod.outlook.com ([fe80::4e37:b189:ddcd:3dd8]) by VI0PR08MB10656.eurprd08.prod.outlook.com ([fe80::4e37:b189:ddcd:3dd8%7]) with mapi id 15.21.0451.014; Thu, 24 Sep 2026 16:41:39 +0000 From: Andrey Drobyshev Date: Thu, 24 Sep 2026 19:41:29 +0300 Subject: [PATCH QEMU HCI-8.0 v4 06/12] usb-host: re-issue drained URBs if CPR is aborted #VSTOR-137800 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260924-usb-host_v3-v4-6-1cc48bf630e7@virtuozzo.com> References: <20260924-usb-host_v3-v4-0-1cc48bf630e7@virtuozzo.com> In-Reply-To: <20260924-usb-host_v3-v4-0-1cc48bf630e7@virtuozzo.com> To: svt-core@virtuozzo.com Cc: Andrey Drobyshev , den@openvz.org X-Mailer: b4 0.16.0 X-ClientProxiedBy: VIVP296CA0030.AUTP296.PROD.OUTLOOK.COM (2603:10a6:800:356::12) To VI0PR08MB10656.eurprd08.prod.outlook.com (2603:10a6:800:20a::12) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: VI0PR08MB10656:EE_|BR0PR08MB151385:EE_ X-MS-Office365-Filtering-Correlation-Id: a212616e-8fc2-445b-a976-08df1a5ab4a7 X-LD-Processed: 0bc7f26d-0264-416e-a6fc-8352af79c58f,ExtAddr List-Id: svt-core@virtuozzo.com X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|23010399003|52116014|376014|1800799024|366016|10067099003|5023799004|5113699003|6133799003|18002099003|22082099003|56012099006|38350700014; X-Microsoft-Antispam-Message-Info: 5nul78jnB4kLsRoPQMU0j+tDqGAdVcsFW5ef4Z8hKGyQJeOiKC2z4Yc0JsBPkvA8Q0cRc0urQve4THzBPd7446URhbxuvPAlpjEh1bPRBO28abbsQIU11TJD23t9N3FsdyN5cVa2fTA40Z/pWN+pXu9Yvo63OyUnVYvfYKL3mvsRN3LB39/LNpsye6GuzhbvcnYJlR0Er6ZzeiNVNM7OqhabWQSvXCyTpIR96rNHOcHA2H+//6hHsxnDBcLUU/79TUd0PPAtEPoRQZRwgI4VMP1e5C6Y38f0cZgfR2MnhNjxAYRg2ZcgClVVkhdVQ+0rQiyhdHGXhBlx+vfaFLtixoxSnVrhY4u4bot1AFqE9umT6PZHAfBmffLXA+Z5cXHODhvZ10xuSWJLMB4oS8kJba8c0ZibExqkdFYdpeEwPLkKQoDd1+h2suJb7Sm4fPEA6A8L6UgPLH6xjkBeG7XbRkfNMLfO/Z36YiOs7yMA4sGcJ7OpQV0a9RMo/cR7TlPCkmwU04MRtfbCrJzkczMDIJmU7RkifNtAq0SGjHx6EHQFOGPqBCABrtL1kUirOQigu+aKC8A8Jg5OLaZnpHCcsh5eWHdhcUcezDPeUcv2zBKqSm8fhmbMaRtc3DqzUxCEV5mAlfsZd8JSkVGBFLGu6SUhGp2icv4t5PCIJSK58AatmyLCgNHPms99VvH8avBgKNB532zmYPdRUEXWKToxsaQuxfR/2FZ4/6/iJDZRnfk= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:VI0PR08MB10656.eurprd08.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(23010399003)(52116014)(376014)(1800799024)(366016)(10067099003)(5023799004)(5113699003)(6133799003)(18002099003)(22082099003)(56012099006)(38350700014);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?ZGtZZGttemhsTkhUR2ZXbkF2MDRRbVNiejUxVWlvcnF6WGdkQ1Zva2VRM2x0?= =?utf-8?B?ZWl6RkVqQjczVTU5c2cyUERDNnJHckZJRVArZFNBb251b0c2b3BzdC9OMmdS?= =?utf-8?B?ODRyQ0tycWZ2NitDVDk1U1V3TUswUkZ4S0FvVzdCZlIxUDNqZnRFRSt0YWF0?= =?utf-8?B?SUkyQkUyUUF6SHhla1cvSnpBM0dROENNVlBDLzhrYVVLNHdXT2x3YWNXUUNa?= =?utf-8?B?a3haMTJUYkhiK0hFYmhJMnlVUDU5M0ZTTUpFMjJ0enB4cDdlMG12czdkZDJN?= =?utf-8?B?VkIrOS9zQ2JnNDlJTXR3ZnVUTWMyaWw0ekFXeDBRU1dRSFA0aVJHZk9EemJs?= =?utf-8?B?bVZ0T1ZkeGtrbkl5eEMwVk02Sk1ZalZkdGtBSzgyYzkwTjAxNEhZaWFFRmN3?= =?utf-8?B?andNS3ZxaytWb2Z0TnVjd2lnM24wYnRESFg2OGE1SFphUVJ0aVZEaU5uVUQx?= =?utf-8?B?NnZQVFFuWVdLTVpmYW5wYWRMcGtXVUJHVzRsTFJsaVpXODgybHQ0V2FYbWVw?= =?utf-8?B?dXo2MUpDL2tCbkZnUjlnT1RZRmRnSkQ3VE1nTVNJQ3pxdUhQakk1YTNtNTdY?= =?utf-8?B?UjBjRzNCRFJ3S2xDMUpRdnBMdy85MXhxeHhKMm9wSk1ZVkdxdlE4K3F3dElz?= =?utf-8?B?bWNpY25DaUZBNE55Zk1FVjFMNmd1SFpFZEY5cjZNbmxsbk1jUVVoY2JXNUtO?= =?utf-8?B?WmZnQW05cFVvU204MFZhV24rN000amJoc2ZVbHA5WXUzZDYzdlJBWnFjQnV2?= =?utf-8?B?djBQUmY5UERaVXY5WHhSeGcvTGdFaFk0NnpnWDV4Z1VpZDVlelpLYzFBNXNT?= =?utf-8?B?RXRUQW1NQjE4NEk3VG15OEtyUFBMblU2ZVJkcXA5LzdqdkdxNk0rd0k0VW1q?= =?utf-8?B?ajcwYldCMVU3TzNZMmM1Smo4ZzhBQXlON1EzT3hrMUQyZnhrZkVXcXBWanNI?= =?utf-8?B?aCtvWVVmYUhndDR1NVhtZzJaWWlxZy9BcVoxNy95WS8vNlV5MmRjeTZSNUdS?= =?utf-8?B?M0NVMUV1OURZb3Zhb3dIUTlHQWZtL0V6bTNWT0NiYnE5L0hqL2toRGFLOTV4?= =?utf-8?B?UjhVZjJZZXJzMEZsckwyVnlPeFpKSkk2bjFjc3NRWkU2d3ZYZHdsWkxIZnBv?= =?utf-8?B?elMxdmVZbStxUG5wQnZ5R1o5ZnNKMk1jV1R2SU1KQ1JNbFoyVzVCZkJPYitD?= =?utf-8?B?MjNmQXRpbDcyamlKT1dQRTc1K1kvb0JPTkZMTjhTalNXUkp1MXZMNXRMdFhX?= =?utf-8?B?Qm5LL2J2T2p0dkJYMW1HcVoyZVJHUlRsaCtrOFN5cSt3NlZFTTRHMCswUVRD?= =?utf-8?B?SnNKT0l6OEpVRXN2VVk1dnFVWGt4QWoyZTl2cldOcUlMK1NERThWMTJXSVdK?= =?utf-8?B?Snp1NFBpOHB6SWpYUWdmSk9kZlAwVzJsdUJmLzBncFdFS055aFVsN2ZMaE9u?= =?utf-8?B?aHRaVyt4WTE1anRBTS9qNy9yZEY4K0NnQUdOaUVoY0lLampyalRnSE1FVnA4?= =?utf-8?B?SE0ycFUzQ0pZbjFTdVplWjBiUEZId1F2a1lNVEpaK3Q3cUFUbUl6RUI0WUQ5?= =?utf-8?B?SGpPVU9kcFpDTEpEWWU1elJub1FIc3huNkp3d01RNmh0Z0MvblNSQWRlTHhy?= =?utf-8?B?U1JTKzJPZUtneTYvMmJDM1B2UHRMYUF0ajFSWThObWJpSFAvSUhWclUvV0dI?= =?utf-8?B?Ym9kUko4RDR5M243eVVYaFhnakVFK2oxRzRGb2EyZm9UL21TWS9zcWZqS0Fw?= =?utf-8?B?MXdwenU4VHV0dFdYQ1FvbmVYRjZud2x0czdCaVgzeWJJbE5TamtnSUdweUFl?= =?utf-8?B?b2FKSlZPckNUM1BDR0VyR0dtNTFtbnk3SlpSNFpJNmFhQ1B5SVpvM2pJZ2pa?= =?utf-8?B?UTd5ck5mb2Y5dDg5ZFFXU2J0OXVjejgwZ2JlZ0NwdEZWSDZaSVJDSFZNTzhx?= =?utf-8?B?N1FPZm1pK2JsZEJ6UHVUSHk2RG8vVUI3TERacVBhLzJaRURCNm52d0NSd21D?= =?utf-8?B?Mmw5MzludDJRVEpzUnlVYWFCMTF0S0FYcUswd09MazBxbUgvRVlUbEZmWG8v?= =?utf-8?B?SVdaODFYc0NYNlRXN1pMSWRhZFZWVng4c1hrcWNVZ0FaUDNsWDhFK01pdlRO?= =?utf-8?B?MmhZSkttSE96RG1uNnRYeE9QT0g5K0FJT2xZT0dTeUNXL3U5VnBlY1dzMWMx?= =?utf-8?B?a2w4ZTRJM0toTWNNTmdlak44cUo0NUMwckIvTldlMWtMZUZvRldYVmNrZFpH?= =?utf-8?B?MnYvY2RqeUI2UXoxRk5JajFVbTNyeE1kbG1SbnlEUWxtTDFBenVuYzkvSHEx?= =?utf-8?B?YXF4K3crWUUzZHdVV0Q4eFQyR1ZRVk1YeDdGQXc1U0FjT2RJeWN3b2tWa3BC?= =?utf-8?Q?F06gQtK27NFzY4ck=3D?= X-Auto-Response-Suppress: DR, OOF, AutoReply X-OriginatorOrg: virtuozzo.com X-MS-Exchange-CrossTenant-Network-Message-Id: a212616e-8fc2-445b-a976-08df1a5ab4a7 X-MS-Exchange-CrossTenant-AuthSource: VI0PR08MB10656.eurprd08.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 24 Sep 2026 16:41:39.2396 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 0bc7f26d-0264-416e-a6fc-8352af79c58f X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: MnP1c7ht0c7C7/8X+6vz45ElNj1DnfamVMcSp17xUuZm8X5HPfsNeRb/0RNe9DElxliHtHDPkmxo7jWHYJnBTvWwiKhTasiMJXucye3PMT4= X-MS-Exchange-Transport-CrossTenantHeadersStamped: BR0PR08MB151385 The previous commit drains the in-flight URBs in .pre_save() and leaves their packets ASYNC for the target to replay. If migration fails, the source resumes instead, with those packets still owned by the controller and nothing left to complete them. Remember the drained packets in a list, and re-issue them on the preserved FD from a MIG_EVENT_PRECOPY_FAILED notifier. Control transfers can't be reconstructed from the packet alone, so complete those as errors and let the guest driver retry. Signed-off-by: Andrey Drobyshev --- hw/usb/host-libusb.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index 4ea469de2d9..1e261554609 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -107,6 +107,9 @@ struct USBHostDevice { int hostfd; Error *cpr_blocker; + NotifierWithReturn cpr_notifier; + GSList *cpr_inflight; + bool cpr_drained; libusb_device *dev; libusb_device_handle *dh; struct libusb_device_descriptor ddesc; @@ -1150,8 +1153,13 @@ static bool usb_host_iso_inflight(USBHostDevice *s) } /* - * Quiesce the device for a CPR switchover. Cancel and reap all URBs, - * so that no URB submitted by this process can outlive it. + * Quiesce the device for a CPR switchover. Cancel and reap all URBs + * without completing their packets, so that no URB submitted by this + * process can outlive it. CPR target re-executes them in + * usb_xhci_post_load() kicking the running endpoints. + * + * Keep the list of packets so that they can be re-issued on this side + * instead if MIG_EVENT_PRECOPY_FAILED fires. */ static int usb_host_cpr_drain_xfers(USBHostDevice *s) { @@ -1162,6 +1170,10 @@ static int usb_host_cpr_drain_xfers(USBHostDevice *s) QTAILQ_FOREACH_SAFE(r, &s->requests, next, rtmp) { if (r->p) { + if (r->p->state == USB_PACKET_ASYNC) { + /* In-flight req, in submission order, for the failure path */ + s->cpr_inflight = g_slist_append(s->cpr_inflight, r->p); + } /* * Clear r->p so the reap callback early-outs on it: the * callback must still run (it frees the request), but it @@ -1171,6 +1183,7 @@ static int usb_host_cpr_drain_xfers(USBHostDevice *s) } libusb_cancel_transfer(r->xfer); } + s->cpr_drained = true; if (!usb_host_reap_xfers(s)) { /* @@ -1287,6 +1300,53 @@ static libusb_device *usb_host_find_ref(int bus, int addr) return ret; } +static void usb_host_handle_data(USBDevice *udev, USBPacket *p); + +/* + * A failed CPR migration resumes the source VM with the drained + * packets still owned by the host controller as in-flight. Re-issue + * them on the preserved fd. Control transfers cannot be reconstructed + * from the packet alone; complete them as errors and let the guest + * driver retry. + */ +static int usb_host_cpr_notifier(NotifierWithReturn *notifier, + MigrationEvent *e, Error **errp) +{ + USBHostDevice *s = container_of(notifier, USBHostDevice, cpr_notifier); + USBDevice *udev = USB_DEVICE(s); + GSList *it; + USBPacket *p; + + if (e->type != MIG_EVENT_PRECOPY_FAILED || !s->cpr_drained) { + return 0; + } + + for (it = s->cpr_inflight; it; it = it->next) { + p = it->data; + /* Replay from the start of the TD */ + p->actual_length = 0; + if (p->ep->nr == 0) { + /* + * p->ep[0] is control endpoint. Control transfers can't + * be reconstructed reliably, so complete them as errors + * and let the guest retry. + */ + p->status = USB_RET_IOERROR; + usb_generic_async_ctrl_complete(udev, p); + } else { + usb_host_handle_data(udev, p); + if (p->status != USB_RET_ASYNC) { + /* Completed synchronously with error */ + usb_packet_complete(udev, p); + } + } + } + g_slist_free(s->cpr_inflight); + s->cpr_inflight = NULL; + s->cpr_drained = false; + return 0; +} + static void usb_host_realize(USBDevice *udev, Error **errp) { USBHostDevice *s = USB_HOST_DEVICE(udev); @@ -1363,6 +1423,14 @@ static void usb_host_realize(USBDevice *udev, Error **errp) s->exit.notify = usb_host_exit_notifier; qemu_add_exit_notifier(&s->exit); +#if LIBUSB_API_VERSION >= 0x01000107 && !defined(CONFIG_WIN32) + if (s->hostdevice && DEVICE(s)->id) { + migration_add_notifier_modes(&s->cpr_notifier, usb_host_cpr_notifier, + MIG_MODE_CPR_TRANSFER, + MIG_MODE_CPR_EXEC, -1); + } +#endif + error_setg(&s->cpr_blocker, "usb-host device %s does not support CPR", DEVICE(s)->id ?: "(anonymous)"); if (migrate_add_blocker_modes(&s->cpr_blocker, errp, @@ -1396,6 +1464,9 @@ static void usb_host_unrealize(USBDevice *udev) } usb_host_close(s); migrate_del_blocker(&s->cpr_blocker); + migration_remove_notifier(&s->cpr_notifier); + g_slist_free(s->cpr_inflight); + s->cpr_inflight = NULL; } static void usb_host_cancel_packet(USBDevice *udev, USBPacket *p) @@ -1403,6 +1474,9 @@ static void usb_host_cancel_packet(USBDevice *udev, USBPacket *p) USBHostDevice *s = USB_HOST_DEVICE(udev); USBHostRequest *r; + /* Packet is being cancelled -> it mustn't be re-issued on failed CPR */ + s->cpr_inflight = g_slist_remove(s->cpr_inflight, p); + if (p->combined) { usb_combined_packet_cancel(udev, p); return; -- 2.47.1