From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from PA4PR04CU001.outbound.protection.outlook.com (mail-francecentralazon11023082.outbound.protection.outlook.com [40.107.162.82]) by lore.virtuozzo.com (Postfix) with ESMTPS id 92FA6803C4 for ; Fri, 4 Sep 2026 19:05:02 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=zHxtu0+stYJeI0D5KEBg12EvgRGOCMCBKIVFVhAHsZqiVx2uhYwOfJVTUXRfv6BChuobnRLNFxSNsmBarvu9gCPgr1AvbcHmuwzkH0xhSYFh7KQxolv1qLid19+kHj+REo0p/WIx55yBgydofevRyg44dfWeXaT3Y8yKe6GNZ+B337Y+98Jt3ZFUmbMncdsT+YTFVkAwZ68w3INV106UR/MB3OGOaGg8n4B6Xou0TcTh9HERXTlDMuCym/VHG4lwwlCL5eeudRmfBUL44kXdg7Orv4Fjql8+F8d5lQR6sMunS9E31iIqB3TvtHppRt4XH4OpkMBJY89TpW1CiSORpA== 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=4gPUHFMs1+U5Kg6cxWp4JDLcY+rChkKjvYKGRRvQ9rY=; b=IAXjQq5D6tyxaGOX6GaHhIA7MUBaLhcAxJzvKPOUfu3N41N32HSBRgTusXScpmWCKNyNL+M9q+WNJLy2wEi/bYD1x1hlog7xZ2PV9m1TMVzcZ1belXpsv/zAO72JNNSCfEA35cOFxl8ItUa2EVp09TST7YScZjvlHkv2Orp5tuT53GSp+3IwUko9MBk9APJcKNrdgvcGgULbYM9xZDFIZyhptxWmayXUSq2FHlH5PAyv9lKXCcW9W+a2H86WpGHHjU6WvVXJgtMzlatC8u7Wf5yynYB+/SYRy/plTjavBy3ZtMN/xWqzYwjHyI3cywuN11mHwCz0QhYid3h1oNU9sg== 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=4gPUHFMs1+U5Kg6cxWp4JDLcY+rChkKjvYKGRRvQ9rY=; b=E2R8sAbH8EHWPz+3MzKYmNncywjagwDwPH69PtMeigG/qAiVYZb/LH9TFny3DBDYDSopOCC86tiNNWZT7mykU2zh0+gnBeRHcTORoispekKZKOEGMvO9G1ixsErShfX3IGkanQ0G2wiVgFqbgDKLnO10oVHm8RleQ4uVVe8fvnSyKNE5wQ2NzKXVBgUnqlvH7z2zFp8TM99/CvaJH3irpBvs372+O+f8+QiJYJ6OQcBqzQkAdaWKbx5iVp2/PKUV/d81pJHk20aCPBh3ZnNhqntbicKMQBhBNRc7UzZ/VmvQs7IM69KAA8luaZw8QlfmN8Gv8HDoJLOLIA3qDKNq8Q== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=virtuozzo.com; Received: from DBBPR08MB10650.eurprd08.prod.outlook.com (2603:10a6:10:52d::7) by DB9PR08MB9827.eurprd08.prod.outlook.com (2603:10a6:10:460::14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.382.10; Fri, 4 Sep 2026 19:05:00 +0000 Received: from DBBPR08MB10650.eurprd08.prod.outlook.com ([fe80::1b2a:832c:d136:a37c]) by DBBPR08MB10650.eurprd08.prod.outlook.com ([fe80::1b2a:832c:d136:a37c%5]) with mapi id 15.21.0382.007; Fri, 4 Sep 2026 19:05:00 +0000 From: Andrey Drobyshev To: svt-core@virtuozzo.com Cc: andrey.drobyshev@virtuozzo.com, den@openvz.org Subject: [QEMU HCI-8.0 PATCH v2 07/13] usb-host: re-issue drained URBs if CPR is aborted #VSTOR-137800 Date: Fri, 4 Sep 2026 22:04:37 +0300 Message-ID: <20260904190443.795902-8-andrey.drobyshev@virtuozzo.com> X-Mailer: git-send-email 2.47.1 In-Reply-To: <20260904190443.795902-1-andrey.drobyshev@virtuozzo.com> References: <20260904190443.795902-1-andrey.drobyshev@virtuozzo.com> Content-Transfer-Encoding: 8bit Content-Type: text/plain X-ClientProxiedBy: VI1PR07CA0215.eurprd07.prod.outlook.com (2603:10a6:802:58::18) To DBBPR08MB10650.eurprd08.prod.outlook.com (2603:10a6:10:52d::7) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: DBBPR08MB10650:EE_|DB9PR08MB9827:EE_ X-MS-Office365-Filtering-Correlation-Id: cb0cffc3-66ee-4fa1-b5f8-08df0ab769a9 List-Id: svt-core@virtuozzo.com X-LD-Processed: 0bc7f26d-0264-416e-a6fc-8352af79c58f,ExtAddr X-MS-Exchange-Transport-Rules-Loop: 1 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|52116014|1800799024|23010399003|366016|5023799004|38350700014|10067099003|6133799003|22082099003|5113699003|18002099003|56012099006; X-Microsoft-Antispam-Message-Info: v79C7p9H1vEkdoWSrt/cE4EiJz9UxgQUqro53gUW20Chr4X0QCe6pNGRO09ef0eopcFn3i+sgN5uV42LNlalIcvyZf72Z/lYEUpt8S8Upi+z8iJ3oOKEroMXJ7rZkcL3ai4Fleog4cjP+LZpZ4s+e4lvoGflDjE42NqXfIa4q8476L/pyb5Lj/2UBNH31ddEN76nemp/NFgop1NYZBvV4nh9+Z4Lvp6trqk+0hWg1zJ3PpEvyTKJKQYqzOfw0ajePkicHAUy4A1yCouyCO9SrQ9huht1grt3QS+QmEzcDhb1Iw9c7eXmDT7L55S2lntt2d/gm2rkCUEzL0f5Xbapetio5LLY1nYNTaBD/gYR44jlqwhZDmQVGqvgBrSUd7DV0AcbJyn+NS+HmyPValusUOaP0WdgQh6l6uUaPJH9F6uOmeRQnB8MeYAAPnLCo+4OoP7UjdlN5MWRkb5z0ZKDGtRSrinZPtIk901p+9xy4xPEt5l6ucIKeQl03ynjDRwuOrueKS5F3aLaO9AwpX2JwYogDsL7K3strZU0O6GQ4GMG8Z59iON0wxt12STk1dczion2zb2IZ4kgtjzxog1UK9VjH+o6XJlIEmIlSLprFojKX7UlnkjpzBzyZYs1UnfC4gMJw8lG9B3iDplIoDOQu22b6r+HeMGZOf3IF4Q053reSO/JYkQ+tkyr0y4qthBJiPMNXugqAE3KdMZtRvuwN/5Ai0e7idL+64fULimSs9c= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:DBBPR08MB10650.eurprd08.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(376014)(52116014)(1800799024)(23010399003)(366016)(5023799004)(38350700014)(10067099003)(6133799003)(22082099003)(5113699003)(18002099003)(56012099006);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?FxkVZXG868NnkVQrb/CrnYxLZAJ+WRZnrjGDMMjz1riWlr7JhYSiAHtJXdX8?= =?us-ascii?Q?pou/Yk9bEhqf/4GgVCullE0hlvrXA2RdGFFC0mLsG1b1yQPoFr6uGwiJJtSa?= =?us-ascii?Q?aCPKHbevEUpRpmZFnkX4TIzlhOBPFR9+kR9vSBPD0MXJYbo3gXgZnSviufqx?= =?us-ascii?Q?yuezv2GFjs9866alPfvDaVn1yGftYtOW7p5E8MnHBS6Cwt6ptzbVn+IFNuTc?= =?us-ascii?Q?xBp15rN/wileZPihpJ9p2dUGGQtscV+ZCmMdk6SGSZYE6bvaeedD9GvSnm8C?= =?us-ascii?Q?FJe5jmSnNFmzPWal/InyMWNJur/yVMgoBpoDcv7wu9kLwkzIMLE7lJjsAzgK?= =?us-ascii?Q?FEECBWhGSNoPURtqgw6dXwOYOW+jZ+1Pfwfue3fIyBaoYqdtOE6AXxRvhTJ3?= =?us-ascii?Q?bv9d6rZj+fTHt3Q0QfI61q92kfeTIKnQY3gM1BFDylk7g/NiWy5ovg+XTjeJ?= =?us-ascii?Q?5JReJq+pkljF8434Z697hqZw2rTewUrcD18koBA4Bm1eE5sl0B+3cKutiBmV?= =?us-ascii?Q?DHPlqSsXgUmgJPk9jjytatvNNo7AKvV64aitQ3Bp5sV797fMPMg5rax+w9ay?= =?us-ascii?Q?fwoRvkoqkBCWv47Nhy/pIAFK2g6nExrASOPz+VGFuZUQ7z/A5ryBNnCmnVv1?= =?us-ascii?Q?3GY6KNpMnMxKo03+druQ9Xm+g7vq0qfJOu/YFS3JeVKbWHa/5bW1BK51WyIN?= =?us-ascii?Q?DWCbpkgjuuDYuJNfsZvcFteM5z8xDaxXkXlRqVmsr2sqhcTvqwBtXdA9KD2y?= =?us-ascii?Q?U9TVE8E9R6hIsWQXVZI+uWqL/GvtJua6OhlyiT5eRhvAdimruB5Ulczl1faV?= =?us-ascii?Q?fb/wA9yVN2KUExuegtPluRz+qdJDi+Dt9f0dmGQRBWVEx4NNbmFPww4XMTVS?= =?us-ascii?Q?1zQq/16yqesSn05lDlA/SiDyQxb0/UXCPlUeABkNmolkjuQGogSPWM3YcK3y?= =?us-ascii?Q?6+Yomhxc7cYmHZcDD8hPKCuBFdbAYqW0mWKuIXj/HozZYvyBHihhnGGH+gCa?= =?us-ascii?Q?xI0fIYnlpyocn5fXy+vBYAwgtGWS8cc1oGHDkrBlkZFJxriPGTrUf8AuPaZ4?= =?us-ascii?Q?V6/pFh9uSM/750kWk44FX2/IqKytYpGBTqgMW/KoYL3s63xb2fJ+Qi0zrqy4?= =?us-ascii?Q?JQ/eWrMCG6GO2bTVlSkrbhlaZ+AaSih5s3AG8TKxb1oiCB0RiiQodctgsNX+?= =?us-ascii?Q?iZC7Z3hh2gLJ6AI5DdhahJtkF43UzIagWbBqjjvK61+uzS8O9z0FA5OWZbbg?= =?us-ascii?Q?daWbaX5tqHx+Y70W8AmB/wnpeLEJAfXIuHCEZdsBxw6oqSV+7F2cGjrW/8Ma?= =?us-ascii?Q?+7xlcaKefu2D/5FOVi8Bo3p02hyPHAbva2fRX0hdmG5u50rsSwmJN0kF9cEY?= =?us-ascii?Q?MM+9SU6Qto/BY/roZp77wCM73uV+IowoDPEVKSBc/ONDKLYkPRF9baNkCc3u?= =?us-ascii?Q?6L7fJeR2RBiUmvAqXBh4oC4ye/ny4Jm8IhwHbKxO9JUKETtXDUujB9hADilE?= =?us-ascii?Q?aIF7xCU8vl5inariXKoWKZ/WsEWN+UjoK+bTGVABF3HHxWbOT3o2da62cnXd?= =?us-ascii?Q?oszUHbjzADCpKRQU2++2Jk3RuAI1VTg/wm03TF44EDQ49kN4Id/KzqX9si3A?= =?us-ascii?Q?pme6tTBcxJf+UpNTeNjTLCRCTFohvGESFSM5LTwLRWJKKbpO9lEEnKp1B+iT?= =?us-ascii?Q?qhu0lsGaUc8J6X9ei/Gxhh7Nnpei1iVk1//au5gsQr5/StPZc9cfHCp0x7t7?= =?us-ascii?Q?qU7VyxBJ2HPv6x25Rz7aANE/fmfAr3c=3D?= X-OriginatorOrg: virtuozzo.com X-MS-Exchange-CrossTenant-Network-Message-Id: cb0cffc3-66ee-4fa1-b5f8-08df0ab769a9 X-MS-Exchange-CrossTenant-AuthSource: DBBPR08MB10650.eurprd08.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 04 Sep 2026 19:04:57.9741 (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: gAW/uUnN1eAg6Sc4oM/N0/i28+lLB2Tw0TdNgDxeqRNL7koXRxC1LDamWpRDMMI+vFEHyGdhELSIExhX13OaRm4msgCoCNXp53XCLiP0SfA= X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB9PR08MB9827 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 | 75 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index c8a893073a6..8483df0d12c 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; @@ -1159,8 +1162,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) { @@ -1171,6 +1179,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 * must not complete the packet. */ @@ -1178,6 +1190,7 @@ static int usb_host_cpr_drain_xfers(USBHostDevice *s) } libusb_cancel_transfer(r->xfer); } + s->cpr_drained = true; usb_host_reap_xfers(s); @@ -1288,6 +1301,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); @@ -1365,6 +1425,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, @@ -1398,6 +1466,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) -- 2.47.1