diff --git a/libvirt-Support-specifying-the-cache-size-presented-.patch b/libvirt-Support-specifying-the-cache-size-presented-.patch new file mode 100644 index 0000000000000000000000000000000000000000..8484e5787a34fb8bd1b860d0fd90a9285601157a --- /dev/null +++ b/libvirt-Support-specifying-the-cache-size-presented-.patch @@ -0,0 +1,240 @@ +From e267875480c6ace0cbc0326cbbfb95462a3bd9ad Mon Sep 17 00:00:00 2001 +From: Chengfei Huang +Date: Tue, 25 Feb 2025 15:46:50 +0800 +Subject: [PATCH] libvirt: Support specifying the cache size presented to guest + +Add configuration item to specifying the cache size presented to guest in Bytes. +for example: + + + + + + +--- + src/conf/cpu_conf.c | 98 ++++++++++++++++++++++++++++++++++++++++ + src/conf/cpu_conf.h | 21 +++++++++ + src/libvirt_private.syms | 2 + + src/qemu/qemu_command.c | 10 ++++ + 4 files changed, 131 insertions(+) + +diff --git a/src/conf/cpu_conf.c b/src/conf/cpu_conf.c +index 3c2ee73a0e..519e67dc63 100644 +--- a/src/conf/cpu_conf.c ++++ b/src/conf/cpu_conf.c +@@ -81,6 +81,15 @@ VIR_ENUM_IMPL(virCPUCacheMode, + "disable", + ); + ++VIR_ENUM_IMPL(virCPUCacheLevelAndType, ++ VIR_CPU_CACHE_LEVEL_AND_TYPE_LAST, ++ "l1d", ++ "l1i", ++ "l1", ++ "l2", ++ "l3", ++); ++ + + virCPUDefPtr virCPUDefNew(void) + { +@@ -127,6 +136,8 @@ virCPUDefFree(virCPUDefPtr def) + virCPUDefFreeModel(def); + VIR_FREE(def->cache); + VIR_FREE(def->tsc); ++ VIR_FREE(def->cacheinfo); ++ def->ncacheinfo = 0; + VIR_FREE(def); + } + } +@@ -252,6 +263,17 @@ virCPUDefCopyWithoutModel(const virCPUDef *cpu) + *copy->cache = *cpu->cache; + } + ++ if (cpu->ncacheinfo > 0) { ++ if (VIR_ALLOC_N(copy->cacheinfo, cpu->ncacheinfo) < 0) ++ goto error; ++ ++ for (size_t i = 0; i < cpu->ncacheinfo; i++) { ++ copy->cacheinfo[i] = cpu->cacheinfo[i]; ++ } ++ ++ copy->ncacheinfo = cpu->ncacheinfo; ++ } ++ + if (cpu->tsc) { + if (VIR_ALLOC(copy->tsc) < 0) + goto error; +@@ -644,6 +666,60 @@ virCPUDefParseXML(xmlXPathContextPtr ctxt, + def->features[i].policy = policy; + } + ++ VIR_FREE(nodes); ++ ++ if ((n = virXPathNodeSet("./cacheinfo", ctxt, &nodes)) < 0) ++ goto cleanup; ++ ++ if (n > VIR_CPU_CACHE_LEVEL_AND_TYPE_LAST) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", ++ _("Exceeded the maximum number of cacheinfo")); ++ goto cleanup; ++ } ++ ++ if (n > 0) { ++ if (VIR_ALLOC_N(def->cacheinfo, n) < 0) ++ goto cleanup; ++ ++ def->ncacheinfo = n; ++ } ++ ++ for (i = 0; i < n; i++) { ++ virCPUCacheLevelAndType cache; ++ char *tmp; ++ unsigned long long size; ++ ++ tmp = virXMLPropString(nodes[i], "cache"); ++ if (tmp == NULL) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", ++ _("Missing cache level and type")); ++ goto cleanup; ++ } ++ cache = virCPUCacheLevelAndTypeTypeFromString(tmp); ++ VIR_FREE(tmp); ++ ++ if (cache < 0) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", ++ _("Invalid CPU cache level and type")); ++ goto cleanup; ++ } ++ ++ tmp = virXMLPropString(nodes[i], "size"); ++ if (tmp == NULL) { ++ size = 0; ++ } ++ if (virStrToLong_ullp(tmp, NULL, 10, &size) < 0) { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("invalid setting for cache size '%s'"), tmp); ++ VIR_FREE(tmp); ++ goto cleanup; ++ } ++ VIR_FREE(tmp); ++ ++ def->cacheinfo[i].cache = cache; ++ def->cacheinfo[i].size = size; ++ } ++ + if (virXPathInt("count(./cache)", ctxt, &n) < 0) { + goto cleanup; + } else if (n > 1) { +@@ -866,6 +942,14 @@ virCPUDefFormatBuf(virBufferPtr buf, + virBufferAddLit(buf, "/>\n"); + } + ++ for (i = 0; i < def->ncacheinfo; i++) { ++ virCPUCacheInfoDefPtr cacheinfo = def->cacheinfo + i; ++ ++ virBufferAsprintf(buf, "\n", ++ virCPUCacheLevelAndTypeTypeToString(cacheinfo->cache), ++ cacheinfo->size); ++ } ++ + for (i = 0; i < def->nfeatures; i++) { + virCPUFeatureDefPtr feature = def->features + i; + +@@ -1144,6 +1228,20 @@ virCPUDefIsEqual(virCPUDefPtr src, + return false; + } + ++ if (src->ncacheinfo != dst->ncacheinfo) { ++ MISMATCH(_("Target CPU cacheinfo count %zu does not match source %zu"), ++ dst->ncacheinfo, src->ncacheinfo); ++ return false; ++ } ++ ++ for (i = 0; i < src->ncacheinfo; i++) { ++ if (src->cacheinfo[i].cache != dst->cacheinfo[i].cache || ++ src->cacheinfo[i].size != dst->cacheinfo[i].size) { ++ MISMATCH("%s", _("Target CPU cacheinfo does not match source")); ++ return false; ++ } ++ } ++ + #undef MISMATCH + + return true; +diff --git a/src/conf/cpu_conf.h b/src/conf/cpu_conf.h +index 10a2252249..42ef4fbe56 100644 +--- a/src/conf/cpu_conf.h ++++ b/src/conf/cpu_conf.h +@@ -117,6 +117,25 @@ struct _virCPUCacheDef { + virCPUCacheMode mode; + }; + ++typedef enum { ++ VIR_CPU_CACHE_LEVEL_AND_TYPE_L1D, ++ VIR_CPU_CACHE_LEVEL_AND_TYPE_L1I, ++ VIR_CPU_CACHE_LEVEL_AND_TYPE_L1, ++ VIR_CPU_CACHE_LEVEL_AND_TYPE_L2, ++ VIR_CPU_CACHE_LEVEL_AND_TYPE_L3, ++ ++ VIR_CPU_CACHE_LEVEL_AND_TYPE_LAST ++} virCPUCacheLevelAndType; ++ ++VIR_ENUM_DECL(virCPUCacheLevelAndType); ++ ++typedef struct _virCPUCacheInfoDef virCPUCacheInfoDef; ++typedef virCPUCacheInfoDef *virCPUCacheInfoDefPtr; ++struct _virCPUCacheInfoDef { ++ virCPUCacheLevelAndType cache; ++ unsigned long long size; ++}; ++ + + typedef struct _virCPUDef virCPUDef; + typedef virCPUDef *virCPUDefPtr; +@@ -142,6 +161,8 @@ struct _virCPUDef { + virCPUFeatureDefPtr features; + virCPUCacheDefPtr cache; + virHostCPUTscInfoPtr tsc; ++ size_t ncacheinfo; ++ virCPUCacheInfoDefPtr cacheinfo; + }; + + virCPUDefPtr virCPUDefNew(void); +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index 82d720c7c1..b9085e1c74 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -92,6 +92,8 @@ virDomainCheckpointTypeToString; + + + # conf/cpu_conf.h ++virCPUCacheLevelAndTypeTypeFromString; ++virCPUCacheLevelAndTypeTypeToString; + virCPUCacheModeTypeFromString; + virCPUCacheModeTypeToString; + virCPUDefAddFeature; +diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c +index 3dd5681a41..62e7e881a9 100644 +--- a/src/qemu/qemu_command.c ++++ b/src/qemu/qemu_command.c +@@ -7278,6 +7278,16 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, + virBufferAsprintf(&buf, ",pflash1=%s", priv->pflash1->nodeformat); + } + ++ if (cpu) { ++ for (i = 0; i < cpu->ncacheinfo; i++) { ++ const char *str; ++ str = virCPUCacheLevelAndTypeTypeToString(cpu->cacheinfo[i].cache); ++ virBufferAsprintf(&buf, ",smp-cache.%zu.cache=%s", i, str); ++ virBufferAsprintf(&buf, ",smp-cache.%zu.size=%llu", i, ++ cpu->cacheinfo[i].size); ++ } ++ } ++ + virCommandAddArgBuffer(cmd, &buf); + + return 0; +-- +2.41.0.windows.1 + diff --git a/libvirt.spec b/libvirt.spec index f3bc157dddf00740b16583d639d08bb510666431..f511a1a04061edb0784977df6b2b18768d036377 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -101,7 +101,7 @@ Summary: Library providing a simple virtualization API Name: libvirt Version: 6.2.0 -Release: 68 +Release: 69 License: LGPLv2+ URL: https://libvirt.org/ @@ -541,6 +541,11 @@ Patch0428: cpu-Modify-virCPUarmCompare-to-perform-compare-actio.patch Patch0429: cpu-revert-Modify-virCPUarmCompare-to-perform-compar.patch Patch0430: virt-host-validate-Fix-IOMMU-output-on-aarch64.patch Patch0431: vdpa-support-vdpa-device-bootindex-config.patch +Patch0432: qemu-DomainGetGuestVcpusParams-reduce-scope-of-tmp.patch +Patch0433: test-Fix-testNodeGetFreePages.patch +Patch0434: util-fix-success-return-for-virProcessKillPainfullyD.patch +Patch0435: libvirt-Support-specifying-the-cache-size-presented-.patch +Patch0436: migration-support-vfio-pci-device-migration.patch Requires: libvirt-daemon = %{version}-%{release} Requires: libvirt-daemon-config-network = %{version}-%{release} @@ -2277,6 +2282,13 @@ exit 0 %changelog +* Thu May 22 2025 Jiabo Feng - 6.2.0-69 +- migration: support vfio-pci device migration +- libvirt: Support specifying the cache size presented to guest +- util: fix success return for virProcessKillPainfullyDelay() +- test: Fix testNodeGetFreePages +- qemu: DomainGetGuestVcpusParams: reduce scope of tmp + * Wed Sep 18 2024 Jiabo Feng - 6.2.0-68 - vdpa: support vdpa device bootindex config diff --git a/migration-support-vfio-pci-device-migration.patch b/migration-support-vfio-pci-device-migration.patch new file mode 100644 index 0000000000000000000000000000000000000000..6d1366e3fc9ef31db712aaf18b56cb71aa1c6caf --- /dev/null +++ b/migration-support-vfio-pci-device-migration.patch @@ -0,0 +1,108 @@ +From eef5f43793b5feb9bda6974ead16a60891d2c486 Mon Sep 17 00:00:00 2001 +From: Chengfei Huang +Date: Mon, 19 May 2025 18:44:00 +0800 +Subject: [PATCH] migration: support vfio-pci device migration + +add "migration" attribute to +Set migration='on' to enable migration. + +Signed-off-by: Chengfei Huang +--- + src/conf/domain_conf.c | 15 +++++++++++++++ + src/conf/domain_conf.h | 1 + + src/qemu/qemu_command.c | 5 +++++ + src/qemu/qemu_migration.c | 4 ++++ + 4 files changed, 25 insertions(+) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 9219d08753..ed15f95519 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -8628,6 +8628,7 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, + virDomainHostdevSubsysSCSIVHostPtr scsihostsrc = &def->source.subsys.u.scsi_host; + virDomainHostdevSubsysMediatedDevPtr mdevsrc = &def->source.subsys.u.mdev; + g_autofree char *managed = NULL; ++ g_autofree char *migration = NULL; + g_autofree char *sgio = NULL; + g_autofree char *rawio = NULL; + g_autofree char *backendStr = NULL; +@@ -8643,12 +8644,22 @@ virDomainHostdevDefParseXMLSubsys(xmlNodePtr node, + if ((managed = virXMLPropString(node, "managed")) != NULL) + ignore_value(virStringParseYesNo(managed, &def->managed)); + ++ migration = virXMLPropString(node, "migration"); + sgio = virXMLPropString(node, "sgio"); + rawio = virXMLPropString(node, "rawio"); + model = virXMLPropString(node, "model"); + display = virXMLPropString(node, "display"); + ramfb = virXMLPropString(node, "ramfb"); + ++ if (migration && ++ (def->migration = virTristateSwitchTypeFromString(migration)) <= 0) { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("unknown value '%s' for attribute " ++ "'migration'"), ++ migration); ++ return -1; ++ } ++ + /* @type is passed in from the caller rather than read from the + * xml document, because it is specified in different places for + * different kinds of defs - it is an attribute of +@@ -28214,6 +28225,10 @@ virDomainHostdevDefFormat(virBufferPtr buf, + virBufferAsprintf(buf, " managed='%s'", + def->managed ? "yes" : "no"); + ++ if (def->migration != VIR_TRISTATE_SWITCH_ABSENT) ++ virBufferAsprintf(buf, " migration='%s'", ++ virTristateSwitchTypeToString(def->migration)); ++ + if (def->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI && + scsisrc->sgio) + virBufferAsprintf(buf, " sgio='%s'", +diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h +index 180975840c..43b42e433c 100644 +--- a/src/conf/domain_conf.h ++++ b/src/conf/domain_conf.h +@@ -348,6 +348,7 @@ struct _virDomainHostdevDef { + + int mode; /* enum virDomainHostdevMode */ + int startupPolicy; /* enum virDomainStartupPolicy */ ++ int migration; + bool managed; + bool missing; + bool readonly; +diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c +index 62e7e881a9..316aedc50e 100644 +--- a/src/qemu/qemu_command.c ++++ b/src/qemu/qemu_command.c +@@ -4840,6 +4840,11 @@ qemuBuildPCIHostdevDevStr(const virDomainDef *def, + switch ((virDomainHostdevSubsysPCIBackendType)backend) { + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_VFIO: + virBufferAddLit(&buf, "vfio-pci"); ++ ++ if (dev->migration == VIR_TRISTATE_SWITCH_ON) { ++ virBufferAsprintf(&buf, ",x-enable-migration=true"); ++ } ++ + break; + + case VIR_DOMAIN_HOSTDEV_PCI_BACKEND_KVM: +diff --git a/src/qemu/qemu_migration.c b/src/qemu/qemu_migration.c +index 04b9333fae..d8fb420a5a 100644 +--- a/src/qemu/qemu_migration.c ++++ b/src/qemu/qemu_migration.c +@@ -1138,6 +1138,10 @@ qemuMigrationSrcIsAllowedHostdev(const virDomainDef *def) + continue; + } + ++ if (hostdev->migration == VIR_TRISTATE_SWITCH_ON) { ++ continue; ++ } ++ + /* all other PCI hostdevs can't be migrated */ + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, + _("cannot migrate a domain with "), +-- +2.41.0.windows.1 + diff --git a/qemu-DomainGetGuestVcpusParams-reduce-scope-of-tmp.patch b/qemu-DomainGetGuestVcpusParams-reduce-scope-of-tmp.patch new file mode 100644 index 0000000000000000000000000000000000000000..f1c01ab79eda94d13ec95ad523f2b7cae5d8a80d --- /dev/null +++ b/qemu-DomainGetGuestVcpusParams-reduce-scope-of-tmp.patch @@ -0,0 +1,52 @@ +From 4cc0ae2e8a262e09dcff1b019e1fd5bbaf50b2cc Mon Sep 17 00:00:00 2001 +From: tangzhongrui +Date: Sat, 7 Oct 2023 14:43:30 +0800 +Subject: [PATCH] qemu: DomainGetGuestVcpusParams: reduce scope of tmp +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Wrap the macro body in a new block and move the declaration of 'tmp' +into it, to avoid the need to mix g_autofree with manual freeing. + +Signed-off-by: Ján Tomko +Reviewed-by: Jonathon Jongsma + +Signed-off-by: Zhongrui Tang +--- + src/qemu/qemu_driver.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index f4bc4d2064..94fef3c79c 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -22400,7 +22400,6 @@ qemuDomainGetGuestVcpusParams(virTypedParameterPtr *params, + virBitmapPtr vcpus = NULL; + virBitmapPtr online = NULL; + virBitmapPtr offlinable = NULL; +- g_autofree char *tmp = NULL; + size_t i; + int ret = -1; + +@@ -22425,10 +22424,13 @@ qemuDomainGetGuestVcpusParams(virTypedParameterPtr *params, + } + + #define ADD_BITMAP(name) \ +- if (!(tmp = virBitmapFormat(name))) \ +- goto cleanup; \ +- if (virTypedParamsAddString(&par, &npar, &maxpar, #name, tmp) < 0) \ +- goto cleanup; \ ++ do { \ ++ g_autofree char *tmp = NULL; \ ++ if (!(tmp = virBitmapFormat(name))) \ ++ goto cleanup; \ ++ if (virTypedParamsAddString(&par, &npar, &maxpar, #name, tmp) < 0) \ ++ goto cleanup; \ ++ } while (0) + + ADD_BITMAP(vcpus); + ADD_BITMAP(online); +-- +2.41.0.windows.1 + diff --git a/test-Fix-testNodeGetFreePages.patch b/test-Fix-testNodeGetFreePages.patch new file mode 100644 index 0000000000000000000000000000000000000000..9e70bc212bd933594b307a2f8df36813d883aa70 --- /dev/null +++ b/test-Fix-testNodeGetFreePages.patch @@ -0,0 +1,59 @@ +From 63798875fa20bd908f2ae5dd011209293ad839e5 Mon Sep 17 00:00:00 2001 +From: Martin Kletzander +Date: Tue, 26 Sep 2023 14:18:53 +0200 +Subject: [PATCH] test: Fix testNodeGetFreePages +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The function is supposed to return the number of items filled into the +array and not zero. Also change the initialization of the "randomness" +to be based on the startCell so that the values are different for each +cell even for separate calls. + +Signed-off-by: Martin Kletzander +(cherry picked from commit 208569b07b6479e0acd05c5a7e1978b0b641e188) +Reviewed-by: Ján Tomko +Reviewed-by: Michal Privoznik + +Signed-off-by: Zhongrui Tang +--- + src/test/test_driver.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/test/test_driver.c b/src/test/test_driver.c +index e0d9c4fa0b..f311d874c5 100644 +--- a/src/test/test_driver.c ++++ b/src/test/test_driver.c +@@ -4340,24 +4340,25 @@ static int + testNodeGetFreePages(virConnectPtr conn G_GNUC_UNUSED, + unsigned int npages, + unsigned int *pages G_GNUC_UNUSED, +- int startCell G_GNUC_UNUSED, ++ int startCell, + unsigned int cellCount, + unsigned long long *counts, + unsigned int flags) + { + size_t i = 0, j = 0; +- int x = 6; + + virCheckFlags(0, -1); + + for (i = 0; i < cellCount; i++) { ++ int x = (startCell + i) * 6; ++ + for (j = 0; j < npages; j++) { + x = x * 2 + 7; + counts[(i * npages) + j] = x; + } + } + +- return 0; ++ return cellCount * npages; + } + + static int testDomainCreateWithFlags(virDomainPtr domain, unsigned int flags) +-- +2.41.0.windows.1 + diff --git a/util-fix-success-return-for-virProcessKillPainfullyD.patch b/util-fix-success-return-for-virProcessKillPainfullyD.patch new file mode 100644 index 0000000000000000000000000000000000000000..052351d29ef4a5b8c4a400ea46bdaabf63b94ef1 --- /dev/null +++ b/util-fix-success-return-for-virProcessKillPainfullyD.patch @@ -0,0 +1,53 @@ +From 1700182e336f749cce0ada00a95c750128a1adb2 Mon Sep 17 00:00:00 2001 +From: tangzhongrui +Date: Sat, 7 Oct 2023 15:40:59 +0800 +Subject: [PATCH] util: fix success return for virProcessKillPainfullyDelay() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +virProcessKillPainfullyDelay() currently almost always returns 1 or -1, +even though the documentation indicates that it should return 0 if the +process was terminated gracefully. But the computation of the return +code is faulty and the only case where it currently returns 0 is when it +is called with the pid of a process that does not exist. + +Since no callers ever even distinguish between the 0 and 1 response +codes, simply get rid of the distinction and return 0 for both cases. + +Signed-off-by: Jonathon Jongsma +Reviewed-by: Ján Tomko + +Signed-off-by: Zhongrui Tang +--- + src/util/virprocess.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/src/util/virprocess.c b/src/util/virprocess.c +index c3f88d206b..5181692f8a 100644 +--- a/src/util/virprocess.c ++++ b/src/util/virprocess.c +@@ -366,9 +366,8 @@ int virProcessKill(pid_t pid, int sig) + /* + * Try to kill the process and verify it has exited + * +- * Returns 0 if it was killed gracefully, 1 if it +- * was killed forcibly, -1 if it is still alive, +- * or another error occurred. ++ * Returns 0 if it was killed, -1 if it is still alive or another error ++ * occurred. + * + * Callers can proide an extra delay in seconds to + * wait longer than the default. +@@ -422,7 +421,7 @@ virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay) + (long long)pid, signame); + return -1; + } +- return signum == SIGTERM ? 0 : 1; ++ return 0; + } + + g_usleep(200 * 1000); +-- +2.41.0.windows.1 +