From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from AM0PR83CU005.outbound.protection.outlook.com (mail-westeuropeazon11020133.outbound.protection.outlook.com [52.101.69.133]) by lore.virtuozzo.com (Postfix) with ESMTPS id 6BCB380AA4 for ; Tue, 13 Oct 2026 15:28:19 +0000 (UTC) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=fua75QUQzhzgwQx1JUBS1C14t89FC0XNKI62t+V1SpKwU4kxDnigkHGw/R921EDz6giOaUKPNK+Kb/2TW7G5IOUTH6HbH+kxgxcEogeDpWK9DPYOTLY6cSiVobYtPAeaUIHyFSJvGgMGXFO1itRMLfc1zVVt+KHPn0iooxgCrvUnImw1+DTTTn2T3GrVhxC8vr1q96Nyrs+aaPWpBovk99h0jhEzX8azJyeqSpkkxkQUS9IbXlruTXHHDuRMYuHhKl4qGH31TyrtDmZS4YKaiHAhkvWPvrPo4jjdT5CtXDr7WgVXey9AnN901feTJA35zEL/camwzfEyaQuEwh+5AQ== 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=XNdg9O97UTWc2b/cVKE9RR5mUCJzdEDexo8MkAO0UsQ=; b=OOJGQ32kWFg8RHde58S3Q6ZKQPfl75L2M6WiiCexARp47nVNVV/3rUxiffS6vndUwTrtHbqglHRXYI2callx5XzCii0BogL/+TXxGhyXzTuITGJGGNB+yngzKGXHz1myGxAAq728gFzRnArhql2KwmjnoWMnImLkXGX7TSYW92lZjpr00JFumjQOeF8ANLtuiVbcuyrRn+gd0SvdVSlIC1V0Zh9KjRogsvJLoN5NqoLTIdFzL2Z4kgh8V0XoVL2Vg5vuUKp+GQYQODECbsOFR+FUpchMGRBc4Eu4i40l5ga0AWO5Oh9yUmjtbMW3g05IJD8d/mkXMuRDivP0tkgYJg== 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=XNdg9O97UTWc2b/cVKE9RR5mUCJzdEDexo8MkAO0UsQ=; b=ECdWQERjbUCUy7AN0/XDROzwoQ6KN/LNG6phpf5gedrlv9g0n7LwnR7MGMZH40/OkHh4+CuRn8ugcyLEvlyfZG/0gsCxDBhH4BtsWIiQYhIhaXJgk77KJY7O5tEs7boYWIQK2jpnEyOh6es2kPQClnmjVM4dGrKa74QV5e9XTKzxkCbXo+vSrnnGzBIm4T8AogVSxe1SLpvslUidyhXDD2T3lvrG+xwHT49nj4NbXQG/tCExdE/MiUAMVubevu2m3mZBrxKxIJqBdd3oUnN4wfb0oVO0X073opRtSE9Ao4I5YoYowLSJcHLQJEp8orxk3Qci0UHm4I2QWuykMAi9kw== 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 WA4PR08MB366192.eurprd08.prod.outlook.com (2603:10a6:1d0:30::19) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.21.522.12; Tue, 13 Oct 2026 15:28:18 +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.0522.008; Tue, 13 Oct 2026 15:28:18 +0000 From: Andrey Drobyshev Date: Tue, 13 Oct 2026 18:28:27 +0300 Subject: [PATCH QEMU HCI-8.1 v2 23/24] VZ: vfio/region: preserve BAR mappings across cpr-exec #VSTOR-103860 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20261013-vfio_v1-v2-23-433455c0a294@virtuozzo.com> References: <20261013-vfio_v1-v2-0-433455c0a294@virtuozzo.com> In-Reply-To: <20261013-vfio_v1-v2-0-433455c0a294@virtuozzo.com> To: svt-core@virtuozzo.com Cc: andrey.drobyshev@virtuozzo.com X-Mailer: b4 0.16.0 X-ClientProxiedBy: VI5PEPF00000939.AUTP296.PROD.OUTLOOK.COM (2603:10a6:808:1::833) To VI0PR08MB10656.eurprd08.prod.outlook.com (2603:10a6:800:20a::12) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: VI0PR08MB10656:EE_|WA4PR08MB366192:EE_ X-MS-Office365-Filtering-Correlation-Id: ec8ee6e7-c190-4d9e-92fb-08df293e9b3a X-LD-Processed: 0bc7f26d-0264-416e-a6fc-8352af79c58f,ExtAddr List-Id: svt-core@virtuozzo.com 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|376014|1800799024|366016|52116014|5113699003|18002099003|22082099003|10067099003|261009223027099003|56012099006|38350700014; X-Microsoft-Antispam-Message-Info: tLqV0XeTh9KX0ycwy6/6b0T0S9RZAdbI6F7Tofv5tW08no1vwN8GcDVYtVBeKMkJJyWz0SBA0w28Ufow4oXck1FKfMR/VkEz6C6MupOuuJ7WhqhzuziQvvPBvsyi0ppXJ/sN70ZNlyjT5cmBUpVrBSb4/xgXZjQzGeBlgo2g3SI8lc6IzWxuR25+X2tKWdVHMUX8q1oKGQHaLLS7dsgL7r/bQdW6EKQijBPJggtH0v4uwYPpTKzixp/+JMp1G9IDTapznHByundxh/W+EB/7u1zpCfrrpoYRmG/M18DFjjuZiKWakECKsaKStvYwL4GYKQ2/Khx/uu+wvd5JNES70pR+wdqEb1eYfxh0dt4skiuNEUkmFaUdGOlyXxw0lySZoLHKbEsdRmWk7J3F/0vVLdJs/D5sWWKnA0iFjVjSmHTiXq10b7sSGGdjFrZBJYMmrh1CZ+qdGm6iq4tfx/2P71boPBUmHyIjEUtgdeFm3ZxjL1G3CLO9niMN6dYkae/L5rcm4bTCpteVPkvR5ZZQcGGabYFgYhwY93kVYJI9c3TrH8uykkthO26utomMaIW3Zmj9N1sJRv551bPBSA6J87nmfIEQkiQVF+dG+0DcVBgF6aVfd+wrNLXt+fllpxLCzx+83jA09guPZgXDCY6pDFca0IwSvOC4jEl2UZcLYCk9T8LJgsMe5K4dtHeap+0eW/Xf/+q62LDIOFx7/56KSmog3F8aroll0jqbVcm1dMY= 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)(376014)(1800799024)(366016)(52116014)(5113699003)(18002099003)(22082099003)(10067099003)(261009223027099003)(56012099006)(38350700014);DIR:OUT;SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?utf-8?B?d2hRcVR4VHN3MXo4RHJtVGtockQwejVUUEdMblRNdjFiWGlTNTJZTkFKQ0xB?= =?utf-8?B?Qk00c3R5S3ZZSnl4bnlXSFcwL1A2NlVYRitUb3pmZlA3U0J2bzh6Rjh2dEp0?= =?utf-8?B?bkpQZEsrR0dGc1gxNWFYb1BLTDB5SW96ZXNWdlJVcHN2TU4vbFdEdjl4SlI5?= =?utf-8?B?RXVENitQa0c3OW5OVmZoL1FQMXNNZGJ6MGpsMXhKUWZlNjBmVFFGQmlZNGdY?= =?utf-8?B?S1J6NkZGOEFRVVg0ZzRQREM0TFJINjA0VUNvYXcwMGYxUkRpN1NyYis2SWJl?= =?utf-8?B?czJ3OTJDdmJLZzgyeEd2MG1scUZPY3UrbEFQVEpFbzVrY2VkSE1OMU1yZE5n?= =?utf-8?B?OEJXTEk4aEpUUGc1WkM2NHlHTHdya2dSNU9hQWN2TllvOW5YcldxTEwrTGRw?= =?utf-8?B?M3F4ZmppQjhvck0wR3RDZExJUWpjWlJCQ0NxTFhzOER4TVdVaUl4ZC9VOUxY?= =?utf-8?B?TEcvUXdsZjRVdml0ODk4RlVtdXRISUYwamkrQ3ZRcTFjWUsxdnVGTEJid3kx?= =?utf-8?B?bTBWRG5JNTRud3NNQlM1cjNnaC9UQndGb25hdzJhSUhWZHU5VU13c2QxaFF6?= =?utf-8?B?NGhkZzlpVDJIL1gvaGFUKzBLeGE4d2ZOYnVUTnp5OFI3S3o1a1l1alFsRUFR?= =?utf-8?B?dWMwYjdjNlJMcDhXMTFQaFVaTTVIalBEd3JKREZJS3hpQnNvMGNuMS9jYlFR?= =?utf-8?B?UTZmWXdiY2k1Q1hsOUFRYmkvalVTdUcvNzB3dlFnMDltci9ySm03VitpcWZ4?= =?utf-8?B?OGVsZVNFSGh0TzJoL2lCUWViNEpGRXpCcDRVK2ttaXJkZk42WTlqVjVxd0Fl?= =?utf-8?B?QWQ0SytvVFZpNFFNYkFzRG9UaDZOV3Z4RThrSUlmVi9FZ2NVaytBK3dRZVho?= =?utf-8?B?UGdXaysvY0E3NVIwMUdtMWtWWGxEV1RZK3p0aVlNZUNjUXdVT2cvZkQrdlcv?= =?utf-8?B?K0JMVXkrR0dFY3cydHArY2RLNEtPTzB5L3RKMzJkdVU1enBab2tHMlR4SDBy?= =?utf-8?B?KzZCWDZTSTNXVnBWSjZoMnFTd0d2QmJlOEVHRnJmZ1VENGpNY3E2T2IrRE4r?= =?utf-8?B?NzJXYzc2YS9GUUhjR1FKZ3RpYVpkaExYd2pFU3RXZnZjUy9maXFPNldMSHk5?= =?utf-8?B?c05UYnBQNngyam5RSEpLYThNajB3b0hwNlJRZUF6bXVjYkVqbW9yWTVJcHdj?= =?utf-8?B?UC9rYlFzOFNCR25rbXk5L0FOUkxrQUlZRWVlV2lkYzNwTjhja2xzcno3Mmti?= =?utf-8?B?YWJ3cHNQNnJhcXlqSzRVbmszbzhlcitGZ0JJUEVTMEZqZk01Y1Y2OUpLbXU1?= =?utf-8?B?TGIwOHBZT2k1QVZPY2NpL2hQbUVxT0dueDEzSS8wUG90ZWppT3NDc3NyVFlI?= =?utf-8?B?ZzBwVEM2cFA0eXVpcFAzZTRUQ1dqTXMxbzM5c0NYMno1NWhFNmlBSnhzR01m?= =?utf-8?B?OWxJbG13eXVKdi9aQ3FSNWJwSGs4c09BdFFGdTZhbUVOeTE1a2FpblNVQmJV?= =?utf-8?B?ZllNS0tkY3JNK1J4VGdCZWZmVmhDd3BIVEJPRm9MZkhkYzRQRVZETStQYTd4?= =?utf-8?B?MlJVUEhZb0ZleTRIdHNSQmc5ZzJITFZFcjZoMk9sUk9QTUtmVXZabEluZ0pB?= =?utf-8?B?b2tiRTlTemdWamdCdUNHWTVJNWU3YTc3MTNsTFVKNEVVaHZNR2NVLzFGeVgx?= =?utf-8?B?QUFSRUdzamdvU0c1eTNuUGxrWTBIeWVueUlpamFQUlJDRkdteGQ3R3FURHR6?= =?utf-8?B?UlZvbHVFcFVxd0dhVVQ1UXhTMnprRkxMSm5HQTRFQmF1cnRLOXYxY3lWUmRL?= =?utf-8?B?TzRVV3Y4ZW10NXJBTmlBTjJhbDdoa0VaRkI1YUZjSVM5MUc4MVd4RGs1ek5l?= =?utf-8?B?S1ZVVjc4OEozZzAyQnRURWErbjV3Vkc4WVI3Vk5oQ0s2b2haa3d6TVBVV0hF?= =?utf-8?B?aWRtaDdBNTh2cDQvOGo5UEI0eFh2Tk9ER1o1eUhOWGNlZWpCV09ObWFKRHBt?= =?utf-8?B?WG5Sb3pnaHR6S0N2VTkzTStWd2w4TWtHc214WEY1Y25lalA2M1ZIZ2NPZXBY?= =?utf-8?B?UWo5TTFhVmZTdE42YUlibXpNeEhlclhtUVNUZ29UT1JWdklKTk4ybzdIOHd3?= =?utf-8?B?cUhrekU1ZVJ2aU1xc2lRaFhOTjd4YXhpaC82c0hIbUV4NmtKRHpsYVIwL0pO?= =?utf-8?B?RnRlZUcvV0hLaXpHSXNmNy9OT3dRbnlEaWtENk51d2hNZ2ZLNXZValgyRVZt?= =?utf-8?B?NjErTTF5NmdCQnN1Z083NDhwR2pJOUN4UCs5eThWcGVlVmtzMGN4R0pOamoy?= =?utf-8?B?OGNKWVBwRW1mWWVHTERucDhVMU8zcGc5M0xRcTNVclFaZTVLUnZEazB0Sy85?= =?utf-8?Q?Q0XXQWWruWwCMSvs=3D?= X-OriginatorOrg: virtuozzo.com X-MS-Exchange-CrossTenant-Network-Message-Id: ec8ee6e7-c190-4d9e-92fb-08df293e9b3a X-MS-Exchange-CrossTenant-AuthSource: VI0PR08MB10656.eurprd08.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 13 Oct 2026 15:28:18.0111 (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: VMurHfYzSqbhPPvtNfCQP8wcrbnSJQ/ZWCTdjTq2L7mM8VLGWSVPhiFhwJncmd0W+M5Ivo+Was1IFYVFowXDkXzzJdnUAFJ/+aTToWJGOGk= X-MS-Exchange-Transport-CrossTenantHeadersStamped: WA4PR08MB366192 After cpr-exec, new QEMU mmaps the device BARs again on the preserved device fd. Some drivers don't allow that: the NVIDIA vGPU VFIO driver refuses to map a VF BAR that is still recorded as mapped by old QEMU, and that record is dropped only when the device fd is closed. So BAR1 and BAR3 of the vGPU can't be mapped, and the guest loses the device. Keep the mappings instead. Save each BAR mapping in the CPR ramblock list, so cpr_exec_cb() marks it with MADV_DOEXEC together with guest RAM, and new QEMU finds it there and reuses it instead of calling mmap(). Same find-or-create pattern as for other preserved objects, e.g. vector eventfds in vfio_notifier_init(). The ID is what cpr_name() would give to the mmap subregion: "/ mmaps[]". The saved addresses only make sense for cpr-exec, which keeps the address space. A cpr-transfer target is another process and would have to map the regions anew, which the drivers above refuse while the old mappings exist. So block cpr-transfer for devices with mmapped regions. New QEMU checks the saved mappings like ram_block_add() checks RAM blocks: on cpr-exec an entry must exist, otherwise an entry is a bug. This needs a kernel which supports MADV_DOEXEC on shared PFN mappings of device memory. Without it cpr-exec of a VM with VFIO devices fails. Signed-off-by: Andrey Drobyshev --- hw/vfio/device.c | 1 + hw/vfio/region.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++ include/hw/vfio/vfio-cpr.h | 1 + 3 files changed, 74 insertions(+) diff --git a/hw/vfio/device.c b/hw/vfio/device.c index 5a14a7d5c0a..88b9e8752cd 100644 --- a/hw/vfio/device.c +++ b/hw/vfio/device.c @@ -514,6 +514,7 @@ void vfio_device_unprepare(VFIODevice *vbasedev) g_clear_pointer(&vbasedev->reginfo, g_free); g_clear_pointer(&vbasedev->region_fds, g_free); + migrate_del_blocker(&vbasedev->cpr.mmap_blocker); QLIST_REMOVE(vbasedev, container_next); QLIST_REMOVE(vbasedev, global_next); diff --git a/hw/vfio/region.c b/hw/vfio/region.c index 1deaef12fd0..fce09a0d17b 100644 --- a/hw/vfio/region.c +++ b/hw/vfio/region.c @@ -30,6 +30,8 @@ #include "qemu/units.h" #include "monitor/monitor.h" #include "system/ramblock.h" +#include "migration/blocker.h" +#include "migration/cpr.h" #include "vfio-helpers.h" /* @@ -227,8 +229,51 @@ int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, return 0; } +static char *vfio_region_cpr_name(VFIORegion *region, int index) +{ + g_autofree char *path = qdev_get_dev_path(region->vbasedev->dev); + return g_strdup_printf("%s%s%s mmaps[%d]", path ?: "", path ? "/" : "", + memory_region_name(region->mem), index); +} + +/* Same checks as for RAM blocks in ram_block_add() */ +static void *vfio_region_cpr_find(VFIORegion *region, int index) +{ + g_autofree char *name = vfio_region_cpr_name(region, index); + cpr_ramblock_t ram = cpr_find_ramblock(name); + + if (cpr_exec_is_incoming()) { + if (!ram.addr || !ram.length) { + error_report("CPR mode=exec is requested, but mapping %s can't " + "be reused: addr=%p length=%zu. Aborting", + name, (void *)ram.addr, ram.length); + exit(1); + } + assert(ram.length == region->mmaps[index].size); + } else if (ram.addr || ram.length) { + error_report("CPR mode=exec wasn't requested, but mapping %s was " + "saved: addr=%p length=%zu. Aborting", + name, (void *)ram.addr, ram.length); + exit(1); + } + + return (void *)(uintptr_t)ram.addr; +} + +static void vfio_region_cpr_save(VFIORegion *region, int index) +{ + g_autofree char *name = vfio_region_cpr_name(region, index); + void *addr = region->mmaps[index].mmap; + size_t size = region->mmaps[index].size; + + cpr_save_ramblock(name, (cpr_ramblock_t) { (uintptr_t)addr, size }); +} + static void vfio_subregion_unmap(VFIORegion *region, int index) { + g_autofree char *cpr_name = vfio_region_cpr_name(region, index); + + cpr_delete_ramblock(cpr_name); trace_vfio_region_unmap(memory_region_name(®ion->mmaps[index].mem), region->mmaps[index].offset, region->mmaps[index].offset + @@ -307,6 +352,19 @@ int vfio_region_mmap(VFIORegion *region) return 0; } + /* + * Only cpr-exec keeps the address space, a cpr-transfer target would + * have to map the regions anew, which some drivers (NVIDIA vGPU) refuse + * while the old mappings exist. Not supported. + */ + if (!region->vbasedev->cpr.mmap_blocker) { + error_setg(®ion->vbasedev->cpr.mmap_blocker, + "cpr-transfer is not supported with mmapped VFIO regions " + "(%s); use the cpr-exec mode", region->vbasedev->name); + migrate_add_blocker_modes(®ion->vbasedev->cpr.mmap_blocker, + &error_abort, MIG_MODE_CPR_TRANSFER, -1); + } + prot |= region->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0; prot |= region->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0; @@ -314,6 +372,11 @@ int vfio_region_mmap(VFIORegion *region) size_t align = MIN(1ULL << ctz64(region->mmaps[i].size), 1 * GiB); void *map_base, *map_align; + region->mmaps[i].mmap = vfio_region_cpr_find(region, i); + if (region->mmaps[i].mmap) { + goto mapped; + } + /* * Align the mmap for more efficient mapping in the kernel. Ideally * we'd know the PMD and PUD mapping sizes to use as discrete alignment @@ -347,7 +410,9 @@ int vfio_region_mmap(VFIORegion *region) ret = -errno; goto no_mmap; } + vfio_region_cpr_save(region, i); +mapped: name = g_strdup_printf("%s mmaps[%d]", memory_region_name(region->mem), i); memory_region_init_ram_device_ptr(®ion->mmaps[i].mem, @@ -410,6 +475,13 @@ void vfio_region_exit(VFIORegion *region) for (i = 0; i < region->nr_mmaps; i++) { if (region->mmaps[i].mmap) { + /* + * The mapping is unmapped by vfio_region_finalize(), but by + * then the device is unparented and its path, part of the CPR + * name, is gone. So drop the CPR entry here. + */ + g_autofree char *cpr_name = vfio_region_cpr_name(region, i); + cpr_delete_ramblock(cpr_name); memory_region_del_subregion(region->mem, ®ion->mmaps[i].mem); } } diff --git a/include/hw/vfio/vfio-cpr.h b/include/hw/vfio/vfio-cpr.h index 4606da500a7..fa1699857ca 100644 --- a/include/hw/vfio/vfio-cpr.h +++ b/include/hw/vfio/vfio-cpr.h @@ -34,6 +34,7 @@ typedef struct VFIOContainerCPR { typedef struct VFIODeviceCPR { Error *mdev_blocker; Error *id_blocker; + Error *mmap_blocker; uint32_t hwpt_id; uint32_t ioas_id; } VFIODeviceCPR; -- 2.47.1