From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from DU2PR03CU002.outbound.protection.outlook.com (mail-northeuropeazon11021139.outbound.protection.outlook.com [52.101.65.139]) by lore.virtuozzo.com (Postfix) with ESMTPS id E4FDC8018A for ; Mon, 14 Sep 2026 19:13:22 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=AuB7vaa2c1dRUzGtl8Uj8ebepJ3MKxsFdBEpT1+xmbHhXe4XvTCHcO1Z+dy0pVqSVnhWuJq6XD4f7fztekp3qStssbdX4QfqMboida3UbyU3Yws7JcWTrNHkkkk5z53VdtSd2O8j7m58sN7OgQM+Y7ha6/A5jzo2l0HNcF6+kDIzleAKB6k47Aqq4nsHGJR5LYSjyi3MdTmfx21ampEq5rBiRTYtjxY9c7Hp4cBTG2z2amm2smmTgm/s6ssizHyQa0KL4NZopEaVLVQKOoPlNpbrpKCSyaY+r6lppzGqkRGwk/UWeTysEoJTkaBwLGV+N6893d+EdYqB+h44SOgHrA== 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=0QyvWXSPzBX/0MfgBh2rBJsXBRNCaccCdxBXx+5WhCg=; b=o07xUesHe+dy2zEWbn0oV679M4Pcom/xz/a9MPdd5lpRzk0qC0qTneFBgvLXkbrxKppRZnZfHZ42+k23pEd4i9Faknep9C/sDc8hEe8uoLbERgbu5iuGjB3ZLWsl3nmEEHN2kf5B+tIYE6pNnwjRT5TCuKNFHFgY3Bq/osLua1y+ho6K68u7k2S/W3sSPlU1ouUP+Q9exvsB5j3gdWp2xy83tn/lZBQeRbHi+JDPdtdj2oW41TytqQGD97JWPXi5PFbaDc6/EUGx3W5TQhttrvh5ohxtxb2qdYjYfblYs0xu4yYHy530gv3dtVy9sljh1XKN+NIh9D0Lgdojnz9nvQ== 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=0QyvWXSPzBX/0MfgBh2rBJsXBRNCaccCdxBXx+5WhCg=; b=MUfZLtLKrvH7ZjWpfyGKOkFrn00ANYkzTJqb3VJyQHiglDUdPszkNpYprKYNY5VvLHC7limCRgxA6KiVi1f3EjVGDJNog+d+GUpk/Fk45g0iLTgsUwU/70OofyYt1JlhokDmZlaemFP5r3ZMIHx8n61F0qPUigr2shoPwOqycGZb/FkfOaPyY/Nrsp5Y7fLCUy7bvthmqxyA1ZqD6XXhtCYhogqaPNF/WAZW0vTvEaiGJ048ZA2LfBQw/lkF/1gRgMAluFNzvnYHeOi3oL61lx0FbRAGlg4iHYz4DFg6a32I7dvJ91WfOy0JH8DZMsvju4hGRxSwQjzg5qomrGp/PA== Authentication-Results: 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 PA4PR08MB6192.eurprd08.prod.outlook.com (2603:10a6:102:ea::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.428.8; Mon, 14 Sep 2026 19:13:21 +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.0428.004; Mon, 14 Sep 2026 19:13:21 +0000 From: Andrey Drobyshev Date: Mon, 14 Sep 2026 22:13:14 +0300 Subject: [PATCH QEMU HCI-8.0 v3 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: <20260914-usb-host_v3-v3-6-c43a834ce016@virtuozzo.com> References: <20260914-usb-host_v3-v3-0-c43a834ce016@virtuozzo.com> In-Reply-To: <20260914-usb-host_v3-v3-0-c43a834ce016@virtuozzo.com> To: svt-core@virtuozzo.com Cc: den@openvz.org, andrey.drobyshev@virtuozzo.com X-Mailer: b4 0.16.0 X-ClientProxiedBy: VIUP296CA0097.AUTP296.PROD.OUTLOOK.COM (2603:10a6:800:35c::17) To VI0PR08MB10656.eurprd08.prod.outlook.com (2603:10a6:800:20a::12) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: VI0PR08MB10656:EE_|PA4PR08MB6192:EE_ X-MS-Office365-Filtering-Correlation-Id: e3209e5a-5684-4cc9-14d9-08df12943dfc 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|23010399003|1800799024|52116014|366016|376014|18002099003|10067099003|5113699003|6133799003|22082099003|56012099006|5023799004|38350700014; X-Microsoft-Antispam-Message-Info: NOqk9JaW/3jQPFwS0I9Wr8z4kJUQ0n+a80YxMXeqcjEtq2HbZG5qH9VsKmqSwfrGmh2G64idsPkVFa1eZrx+uX4YoDRuKHSh/zsQ+EVduIymubZIO782vCt3aR/ZD97jycb/Z7+6yeVUTVXVDDI+S47IHKoTHdRChLuJfNpwymKUxSIf30/REhYqyxyWsSYMI52Wi3+ulu9H9f7aQd0KH5gSzsVzO7mmekYVp2hUZe+jDgCUW4gLidXBOu4Pce1jh1bfNwam3vllrBH/rMKksOpADIsQym6/2wv35arZpYVlP5FBpuBKnpTjhMy8EgjZy+nbVNoN5yZPNktLbMbmuIc+Qdd18y/jC2pdqDfIMn/fN/qoOQZ+tHDzT2lWF+KRaWgGDpbiAZjHrS9UD4mR5VOFaR5ua0/+RFKTfkuW9MNzTNneG+9UlaxdmbFRPQ3t768gYriJ9UwI+kiOYgMnNnAcXBggWJO9Obi1sUgB8+rgu3A6+obnprO511RuGP8prNCpz8PTd+9KKskk46YlVl/CB4K1Mxa04x6nK2HOdqRk8ccoI6u+XLV91+GiJy7L8wUD9h2hqNVorxjqmXUsVJs2rDbqhr5v4CwZKXKwCEvXeBMieAN41nUwOQ7iZjJ6FZNkV/tJ3UQyKT/rWkWyLJH9WvGJJxWJXanR9Gbgbt8/mGkgAcCQX1G6Od0BotRuO/47DG4J3Zaq/bM2n6/fc9Dxo6mksA9i1fGeRI+aKy0= 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)(1800799024)(52116014)(366016)(376014)(18002099003)(10067099003)(5113699003)(6133799003)(22082099003)(56012099006)(5023799004)(38350700014);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?Z3QrRVh0c1B5Q09pN3ppTCtiSnY4dXRDYlVqcndpM0tpSHM1WDN5SEJzd0pO?= =?utf-8?B?VGtsYXlKam4xZHUvQ1cwYlUyZTRsTlphOHExcVFtVFY0R2g3bGZ2R2JqcWdH?= =?utf-8?B?TEtkcVI3VS80TWkwNFNJYVhWbUtYU2MyWGErV2FOTHRlRENKYTRnSFdTcGlw?= =?utf-8?B?N05XNmdDWDdkME5jZVoyQlFSLzlsWkoyU2hqdzVWS0k3VlNmdjBBWDJhZjhU?= =?utf-8?B?VVFJYk8ycEZCazluUG9DelhaMjZJckFMVUZVQkNLSDY5WXdvM3B5bXYzMEEw?= =?utf-8?B?YXJoODUrTjEvWW5OMnoxUTZHckdTZ1hBajBUeWpjMVBtenpwUTZua1lmcnJn?= =?utf-8?B?dy9uZi9sYkI5alVTZ2R4TVVZUXFaMGRrS0kzeGRjcFhTWWIwOS9nQ1ROWUcz?= =?utf-8?B?aVVmRjU4cmlqdVFTalBpbUpyTE1naHpBKzRVOHNFSzBoemJ4NWpaNzJxUWJJ?= =?utf-8?B?eTVWMVQwUHZTaTlFcHFnby9OQkNxMUU4enNpZG5pNmR4clpSZmdtWmYvbCsr?= =?utf-8?B?b0k5cHJtV3hONjdCU240RXk0ZU9oRjBYRHJDNzNhTVNLRjc3QWRaTklDbEtF?= =?utf-8?B?bjRRUUp1UDQ0c3BhejF3T1VPR2dqZTcyTm45c0ZKWnlvdHMweUpFYmNjNEty?= =?utf-8?B?cDZKNFpMTWxtbUo1WEY0bXBhMll0QUVHR2JnUEgwSTRKRTRub3BDQ3VnOVNa?= =?utf-8?B?OXMzZHFrRFdXRVVQRmRJVEF6NW40M0trQTBIMXgyZ1BNbTVIV0p2WkJsMURa?= =?utf-8?B?L3FoM01DZjczWjFRMjl1RExXaDhlcXJrZm1IU2tuL0tFelpHR3pzRlBJLzhp?= =?utf-8?B?THJlV041Y1gwSzFtRWlqSGwrSHJFWHd4N0pGa3JPdndPK3BGcE5EM1pEYkJL?= =?utf-8?B?emdoaFZCZ0hQKzczZVdldEUzRCtXa04yK1A4SWZtaUo2aXdmVHdsTFAybjNj?= =?utf-8?B?ekw0WWQzemt4SFJ0QVljZlpJbDdTVGZ6dGl0cnJJNHl3ZzVEYUNaWjBGaGV1?= =?utf-8?B?UEFFTVI2eTV4bzc0WFpFTEQ5UUhReXU0SklzMG0xSGI3aDgxOWw0REdYUis5?= =?utf-8?B?RU1SWm1ZbXNnMWxGdEE2SkVWVE56WVEvdVNUWU9pYVNMWnVUUFhXdE9wM3NU?= =?utf-8?B?OTVIWVJuUlFuWm9rcnBFWEV4V0F0NnoyZmJEbFloZkVPWk9FQXNTRGF6ZDlG?= =?utf-8?B?TFVKbmJoZWt4bUdFdERucStQdkRMZzFMQkk0b1VIUXBqSG5wTU05eit5ancy?= =?utf-8?B?cnQzKzdZK3ZzYjFHMnRyb1ZWVWljTm81bS96SkNZN2prYmpySlNEb0ZMMXRm?= =?utf-8?B?bFEyazEzaVZXbm9HR1RBZ0cwYWFSQklVVGZNdHUzYlpzOVJQMVlUVzNrSkYz?= =?utf-8?B?VUhZNzlSSEIwUTlSRmhDdzBiRVdrRFVsdE1yakk4TjYwSWZjbmcvek0vc25D?= =?utf-8?B?d0tVLzM2Ty9YUjNlb28zQ3pqRnErMVVVeDcrbXU4R2ErRCtueHNIU0ExcHh6?= =?utf-8?B?OGVRczAyeVlMSnFpUXdwd2N6amdmODB6K0hCNXQyNWxLTjlIYVRIdFAyVWUr?= =?utf-8?B?eXNwYjNNUXVmMG1MbE5DN3FSdk5GK3c4T3FXWVVtK0lsd0VMclFVNzFzK09P?= =?utf-8?B?a0JqempwZGo0UGxaMUZWMWxVcDhDMGJJcmgrcU5pT1JYUVpQZWVwTVJqWE1a?= =?utf-8?B?amhNZlZNY21iWWZpVUxOa1JjeDNYVEMwODNGS3hMNmlLZlRITlN3UEU3MjQx?= =?utf-8?B?M0V3dkQvb1E4cldWZEE5OUxuUUgyNTk3SGFQV2hBSFcyWXhnTWgzYmpHRjlx?= =?utf-8?B?ek5lQXVoYjE1WGR3eXhaNzFtSGJwbC9tUXh6WjdlVW5qRWNqMWNJQWRHWEpr?= =?utf-8?B?YTQ1RUlzbTIrZHlSZkd4ZHg5VkU3cGprZjJvR3RLdjI0VWlMbVpocGg5cXd2?= =?utf-8?B?cW5WUzIwN2pQRXduRjlBaWxQMldxT0RyT2NMdXBoZEtGQVk4czVCbHBwVXhC?= =?utf-8?B?T2tjMUNOVlRyOVhOUkZ0ZmplL2JaSHNQNmlJRFBvNUZ3bllNZVNZVUt0N1ln?= =?utf-8?B?SDhld0VKT28vZENaSHVVclo3VHl3VGQzVktqVWR1dG9nMVUzZlFYbzRvQkJ2?= =?utf-8?B?VXZhTC9wMDFFalczZ1pLV3h1VzR5Rzg0S1h1T3NVUGJFSXpQb3JYcUNNemZU?= =?utf-8?B?TzJOcnNsaEpXREhCVXE2eGthVGozR0s4cWxtUlRDM0JWdEhnenhEYmRDQ1du?= =?utf-8?B?aHhTVDIzYjk2N0s3cjdodjArWFRTOVBjd20xWjNieERDbGVRd0xjdGVtMXRL?= =?utf-8?B?M2xia1o3WWRLNDVuRHFDbzUwdTdiK2M2UVRSdGNwU3l3ZHRHRjQ4azBna2F0?= =?utf-8?Q?6Q2zOhAnM+Xm3HUM=3D?= X-OriginatorOrg: virtuozzo.com X-MS-Exchange-CrossTenant-Network-Message-Id: e3209e5a-5684-4cc9-14d9-08df12943dfc X-MS-Exchange-CrossTenant-AuthSource: VI0PR08MB10656.eurprd08.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 14 Sep 2026 19:13:21.6366 (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: DkJfo0L+4xf15UoJmcGgVLq6Hr9zBVFI20mGWBLgbIHKN/kUi4/8lex3j6gjAJTZ54rYE5jT2S0JxdYT7o8aaJY6watr19cDafoCQOE2nQE= X-MS-Exchange-Transport-CrossTenantHeadersStamped: PA4PR08MB6192 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 1331eeefee4..77ee3ca1dd7 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; @@ -1147,8 +1150,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) { @@ -1159,6 +1167,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 @@ -1168,6 +1180,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)) { /* @@ -1284,6 +1297,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); @@ -1360,6 +1420,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, @@ -1393,6 +1461,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) @@ -1400,6 +1471,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