diff --git a/conf-Turn-virDomainDef.kvm_features-into-a-struct.patch b/conf-Turn-virDomainDef.kvm_features-into-a-struct.patch new file mode 100644 index 0000000000000000000000000000000000000000..5859d5ddd5215c5ae573b3635eb80034870e4382 --- /dev/null +++ b/conf-Turn-virDomainDef.kvm_features-into-a-struct.patch @@ -0,0 +1,139 @@ +From 715288515d2c6eb2c6d036b8068e3a6b15d1adf3 Mon Sep 17 00:00:00 2001 +From: Michal Privoznik +Date: Tue, 14 Dec 2021 10:24:30 +0100 +Subject: [PATCH] conf: Turn virDomainDef.kvm_features into a struct +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +In future commits we will need to store not just an array of +VIR_TRISTATE_SWITCH_* but also an additional integer. Follow the +example of TCG and introduce a structure where both the array an +integer can live. + +Signed-off-by: Michal Privoznik +Reviewed-by: J谩n Tomko +Signed-off-by: Shaokun Wei +--- + src/conf/domain_conf.c | 20 +++++++++++++------- + src/conf/domain_conf.h | 7 ++++++- + src/qemu/qemu_command.c | 4 ++-- + 3 files changed, 21 insertions(+), 10 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index e884d94ef7..e94ae4ea17 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -3476,6 +3476,7 @@ void virDomainDefFree(virDomainDefPtr def) + VIR_FREE(def->emulator); + VIR_FREE(def->description); + VIR_FREE(def->title); ++ VIR_FREE(def->kvm_features); + VIR_FREE(def->hyperv_vendor_id); + + virBlkioDeviceArrayClear(def->blkio.devices, +@@ -20596,7 +20597,9 @@ static int + virDomainFeaturesKVMDefParse(virDomainDef *def, + xmlNodePtr node) + { +- def->features[VIR_DOMAIN_FEATURE_KVM] = VIR_TRISTATE_SWITCH_ON; ++ g_autofree virDomainFeatureKVM *kvm = NULL; ++ ++ kvm = g_new0(virDomainFeatureKVM, 1); + + node = xmlFirstElementChild(node); + while (node) { +@@ -20615,11 +20618,14 @@ virDomainFeaturesKVMDefParse(virDomainDef *def, + &value) < 0) + return -1; + +- def->kvm_features[feature] = value; ++ kvm->features[feature] = value; + + node = xmlNextElementSibling(node); + } + ++ def->features[VIR_DOMAIN_FEATURE_KVM] = VIR_TRISTATE_SWITCH_ON; ++ def->kvm_features = g_steal_pointer(&kvm); ++ + return 0; + } + +@@ -23584,13 +23590,13 @@ virDomainDefFeaturesCheckABIStability(virDomainDefPtr src, + switch ((virDomainKVM) i) { + case VIR_DOMAIN_KVM_HIDDEN: + case VIR_DOMAIN_KVM_DEDICATED: +- if (src->kvm_features[i] != dst->kvm_features[i]) { ++ if (src->kvm_features->features[i] != dst->kvm_features->features[i]) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("State of KVM feature '%s' differs: " + "source: '%s', destination: '%s'"), + virDomainKVMTypeToString(i), +- virTristateSwitchTypeToString(src->kvm_features[i]), +- virTristateSwitchTypeToString(dst->kvm_features[i])); ++ virTristateSwitchTypeToString(src->kvm_features->features[i]), ++ virTristateSwitchTypeToString(dst->kvm_features->features[i])); + return false; + } + +@@ -29201,11 +29207,11 @@ virDomainDefFormatFeatures(virBufferPtr buf, + switch ((virDomainKVM) j) { + case VIR_DOMAIN_KVM_HIDDEN: + case VIR_DOMAIN_KVM_DEDICATED: +- if (def->kvm_features[j]) ++ if (def->kvm_features->features[j]) + virBufferAsprintf(&childBuf, "<%s state='%s'/>\n", + virDomainKVMTypeToString(j), + virTristateSwitchTypeToString( +- def->kvm_features[j])); ++ def->kvm_features->features[j])); + break; + + /* coverity[dead_error_begin] */ +diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h +index 6d56ef0282..d75d06d7b8 100644 +--- a/src/conf/domain_conf.h ++++ b/src/conf/domain_conf.h +@@ -2297,6 +2297,11 @@ struct _virDomainResctrlDef { + size_t nmonitors; + }; + ++typedef struct _virDomainFeatureKVM virDomainFeatureKVM; ++struct _virDomainFeatureKVM { ++ int features[VIR_DOMAIN_KVM_LAST]; ++}; ++ + + struct _virDomainVcpuDef { + bool online; +@@ -2479,7 +2484,7 @@ struct _virDomainDef { + int features[VIR_DOMAIN_FEATURE_LAST]; + int caps_features[VIR_DOMAIN_PROCES_CAPS_FEATURE_LAST]; + int hyperv_features[VIR_DOMAIN_HYPERV_LAST]; +- int kvm_features[VIR_DOMAIN_KVM_LAST]; ++ virDomainFeatureKVM *kvm_features; + int msrs_features[VIR_DOMAIN_MSRS_LAST]; + unsigned int hyperv_spinlocks; + int hyperv_stimer_direct; +diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c +index d7db30d19b..ed843315dc 100644 +--- a/src/qemu/qemu_command.c ++++ b/src/qemu/qemu_command.c +@@ -6911,12 +6911,12 @@ qemuBuildCpuCommandLine(virCommandPtr cmd, + for (i = 0; i < VIR_DOMAIN_KVM_LAST; i++) { + switch ((virDomainKVM) i) { + case VIR_DOMAIN_KVM_HIDDEN: +- if (def->kvm_features[i] == VIR_TRISTATE_SWITCH_ON) ++ if (def->kvm_features->features[i] == VIR_TRISTATE_SWITCH_ON) + virBufferAddLit(&buf, ",kvm=off"); + break; + + case VIR_DOMAIN_KVM_DEDICATED: +- if (def->kvm_features[i] == VIR_TRISTATE_SWITCH_ON) ++ if (def->kvm_features->features[i] == VIR_TRISTATE_SWITCH_ON) + virBufferAddLit(&buf, ",kvm-hint-dedicated=on"); + break; + +-- +2.27.0 + diff --git a/hotpatch-if-hotpatch_path-not-in-qemu.conf-the-hotpa.patch b/hotpatch-if-hotpatch_path-not-in-qemu.conf-the-hotpa.patch new file mode 100644 index 0000000000000000000000000000000000000000..c18d18972390bf242079be531963124bfbfb0cf9 --- /dev/null +++ b/hotpatch-if-hotpatch_path-not-in-qemu.conf-the-hotpa.patch @@ -0,0 +1,32 @@ +From f083c24428a2f4d5106a9369dec0876f6143d270 Mon Sep 17 00:00:00 2001 +From: Dawei Jiang +Date: Mon, 8 Apr 2024 19:59:11 +0800 +Subject: [PATCH] hotpatch: if hotpatch_path not in qemu.conf,the hotpatch + doesn't antoload + +Signed-off-by: Dawei Jiang +--- + src/qemu/qemu_process.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c +index 48d39ba97c..013c9eb847 100644 +--- a/src/qemu/qemu_process.c ++++ b/src/qemu/qemu_process.c +@@ -7330,8 +7330,11 @@ qemuProcessLaunch(virConnectPtr conn, + goto cleanup; + + /* Autoload hotpatch */ +- if ((autoLoadStatus = qemuDomainHotpatchAutoload(vm, cfg->hotpatchPath)) == NULL) { +- VIR_WARN("Failed to autoload the hotpatch for %s.", vm->def->name); ++ if (cfg->hotpatchPath != NULL) { ++ autoLoadStatus = qemuDomainHotpatchAutoload(vm, cfg->hotpatchPath); ++ if (autoLoadStatus == NULL) { ++ VIR_WARN("Failed to autoload the hotpatch for %s.", vm->def->name); ++ } + } + ret = 0; + +-- +2.27.0 + diff --git a/internal.h-Introduce-and-use-VIR_IS_POW2.patch b/internal.h-Introduce-and-use-VIR_IS_POW2.patch new file mode 100644 index 0000000000000000000000000000000000000000..c1bdb80f740bdb8050e9f09f0cd7a0807eb02eb6 --- /dev/null +++ b/internal.h-Introduce-and-use-VIR_IS_POW2.patch @@ -0,0 +1,56 @@ +From d568dc527cd3098df2460d3e991efe3ad8b80410 Mon Sep 17 00:00:00 2001 +From: Michal Privoznik +Date: Wed, 4 Nov 2020 19:41:27 +0100 +Subject: [PATCH] internal.h: Introduce and use VIR_IS_POW2() + +This macro checks whether given number is an integer power of +two. At the same time, I've identified two places where we check +for pow2 and I'm replacing them with the macro. + +Signed-off-by: Michal Privoznik +Reviewed-by: Peter Krempa +Reviewed-by: Daniel Henrique Barboza +Tested-by: Daniel Henrique Barboza +Tested-by: Han Han +Reviewed-by: Shaokun Wei +--- + src/internal.h | 9 +++++++++ + src/util/virrandom.c | 2 +- + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/src/internal.h b/src/internal.h +index 440f01d370..40c993977a 100644 +--- a/src/internal.h ++++ b/src/internal.h +@@ -216,6 +216,15 @@ + (a) = (a) ^ (b); \ + } while (0) + ++/** ++ * VIR_IS_POW2: ++ * ++ * Returns true if given number is a power of two ++ */ ++#define VIR_IS_POW2(x) \ ++ ((x) && !((x) & ((x) - 1))) ++ ++ + /** + * virCheckFlags: + * @supported: an OR'ed set of supported flags +diff --git a/src/util/virrandom.c b/src/util/virrandom.c +index 1b4102cf58..500f55c956 100644 +--- a/src/util/virrandom.c ++++ b/src/util/virrandom.c +@@ -89,7 +89,7 @@ double virRandom(void) + */ + uint32_t virRandomInt(uint32_t max) + { +- if ((max & (max - 1)) == 0) ++ if (VIR_IS_POW2(max)) + return virRandomBits(__builtin_ffs(max) - 1); + + double val = virRandom(); +-- +2.27.0 + diff --git a/libvirt-add-get-tmm-memory-info-API-and-libvirtd-RPC.patch b/libvirt-add-get-tmm-memory-info-API-and-libvirtd-RPC.patch new file mode 100644 index 0000000000000000000000000000000000000000..ad94e4187260790670fe7a5580bd098687bd5243 --- /dev/null +++ b/libvirt-add-get-tmm-memory-info-API-and-libvirtd-RPC.patch @@ -0,0 +1,405 @@ +From cd0f3755bd04bb58089d756400f20c75550e54f2 Mon Sep 17 00:00:00 2001 +From: tujipei +Date: Wed, 12 Jun 2024 12:02:00 +0800 +Subject: [PATCH] libvirt: add get tmm memory info API and libvirtd RPC Add the + get tmm memory info API into libvirt-host. Also should add the RPC calls into + libvirtd for API calling. + +Signed-off-by: tujipei +--- + include/libvirt/libvirt-host.h | 2 + + scripts/apibuild.py | 1 + + scripts/check-aclrules.py | 1 + + src/driver-hypervisor.h | 5 + + src/libvirt-host.c | 35 +++++++ + src/libvirt_public.syms | 1 + + src/qemu/qemu_driver.c | 139 ++++++++++++++++++++++++++++ + src/remote/remote_daemon_dispatch.c | 23 +++++ + src/remote/remote_driver.c | 29 ++++++ + src/remote/remote_protocol.x | 16 +++- + 10 files changed, 251 insertions(+), 1 deletion(-) + +diff --git a/include/libvirt/libvirt-host.h b/include/libvirt/libvirt-host.h +index 6972834175..e7272ccb20 100644 +--- a/include/libvirt/libvirt-host.h ++++ b/include/libvirt/libvirt-host.h +@@ -820,5 +820,7 @@ int virNodeAllocPages(virConnectPtr conn, + unsigned int cellCount, + unsigned int flags); + ++char *virConnectGetTmmMemoryInfo(virConnectPtr conn, ++ unsigned int detail); + + #endif /* LIBVIRT_HOST_H */ +diff --git a/scripts/apibuild.py b/scripts/apibuild.py +index c98bcf6091..9b78754e5d 100755 +--- a/scripts/apibuild.py ++++ b/scripts/apibuild.py +@@ -107,6 +107,7 @@ ignored_functions = { + "virDomainMigrateConfirm3Params": "private function for migration", + "virDomainMigratePrepareTunnel3Params": "private function for tunnelled migration", + "virErrorCopyNew": "private", ++ "virConnectGetTmmMemoryInfo": "private function for tmm", + } + + ignored_macros = { +diff --git a/scripts/check-aclrules.py b/scripts/check-aclrules.py +index e196f81de9..aa5a589c85 100755 +--- a/scripts/check-aclrules.py ++++ b/scripts/check-aclrules.py +@@ -54,6 +54,7 @@ whitelist = { + "localOnly": True, + "domainQemuAttach": True, + "domainHotpatchManage": True, ++ "connectGetTmmMemoryInfo": True, + } + + # XXX this vzDomainMigrateConfirm3Params looks +diff --git a/src/driver-hypervisor.h b/src/driver-hypervisor.h +index 82f808905d..e48b701365 100644 +--- a/src/driver-hypervisor.h ++++ b/src/driver-hypervisor.h +@@ -1402,6 +1402,10 @@ typedef int + typedef struct _virHypervisorDriver virHypervisorDriver; + typedef virHypervisorDriver *virHypervisorDriverPtr; + ++typedef char * ++(*virDrvConnectGetTmmMemoryInfo)(virConnectPtr conn, ++ bool detail); ++ + /** + * _virHypervisorDriver: + * +@@ -1664,4 +1668,5 @@ struct _virHypervisorDriver { + virDrvDomainBackupGetXMLDesc domainBackupGetXMLDesc; + virDrvDomainHotpatchManage domainHotpatchManage; + virDrvDomainStartDirtyRateCalc domainStartDirtyRateCalc; ++ virDrvConnectGetTmmMemoryInfo connectGetTmmMemoryInfo; + }; +diff --git a/src/libvirt-host.c b/src/libvirt-host.c +index bc3d1d2803..d0750d28cc 100644 +--- a/src/libvirt-host.c ++++ b/src/libvirt-host.c +@@ -1754,3 +1754,38 @@ virNodeGetSEVInfo(virConnectPtr conn, + virDispatchError(conn); + return -1; + } ++ ++/* ++ * virConnectGetTmmMemoryInfo: ++ * @conn: pointer to the hypervisor connection ++ * @detail: whether libvirtd return detailed tmm memory information; ++ * the default value is 0 which means don't return detailed tmm memory information. ++ * ++ * If Tmm enable, then will fill the cotents of string buffer with tmm memory information. ++ * ++ * Returns string ptr in case of success, and NULL in case of failure. ++ */ ++char * ++virConnectGetTmmMemoryInfo(virConnectPtr conn, ++ unsigned int detail) ++{ ++ VIR_DEBUG("conn=%p", conn); ++ ++ virResetLastError(); ++ ++ virCheckConnectReturn(conn, NULL); ++ ++ if (conn->driver->connectGetTmmMemoryInfo) { ++ char *ret; ++ ret = conn->driver->connectGetTmmMemoryInfo(conn, detail); ++ if (!ret) ++ goto error; ++ return ret; ++ } ++ ++ virReportUnsupportedError(); ++ error: ++ virDispatchError(conn); ++ return NULL; ++} ++ +diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms +index f006516208..284b7f7873 100644 +--- a/src/libvirt_public.syms ++++ b/src/libvirt_public.syms +@@ -877,5 +877,6 @@ LIBVIRT_6.2.0 { + global: + virDomainHotpatchManage; + virDomainStartDirtyRateCalc; ++ virConnectGetTmmMemoryInfo; + } LIBVIRT_6.0.0; + # .... define new API here using predicted next version number .... +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index 77a139c66b..1e3f63a39a 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -23385,6 +23385,144 @@ qemuDomainStartDirtyRateCalc(virDomainPtr dom, + return ret; + } + ++static int ++qemuConnectTmmInfoListAppend(char ***targetInfoStrList, ++ char **infoStrList, ++ int targetNumaNum, ++ int *startIndex, ++ int maxListSize) ++{ ++ char *numStart; ++ int numaNode, index, ret = 0; ++ ++ for (index = *startIndex; index < maxListSize; index++) { ++ if (strlen(infoStrList[index]) == 0) ++ break; ++ ++ numStart = strstr(infoStrList[index], "node "); ++ if (!numStart) ++ return -1; ++ ++ virSkipToDigit((const char **)(&numStart)); ++ ret = virStrToLong_i(numStart, &numStart, 10, &numaNode); ++ if (ret < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("Failed to get current numa node")); ++ return ret; ++ } ++ ++ if (numaNode == targetNumaNum) { ++ ret = virStringListAdd(targetInfoStrList, infoStrList[index]); ++ if (ret < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s [%d]", ++ _("Failed to get add info list member"), index); ++ return ret; ++ } ++ } else { ++ break; ++ } ++ } ++ ++ *startIndex = index; ++ ++ return ret; ++} ++ ++static char * ++qemuConnectTmmDetailInfoFormat(char *baseMeminfo, ++ char *slabInfo) ++{ ++ int ret, i = 0, j = 0; ++ char *numStart, *numListStart, *format = NULL; ++ char **baseMeminfoSplits = virStringSplit(baseMeminfo, "\n", 0); ++ char **slabInfoSplits = virStringSplit(slabInfo, "\n", 0); ++ char **resultStrList = NULL; ++ int numaSize, numaIndex, headNumaNode; ++ ssize_t meminfoListSize = virStringListLength((const char * const *)baseMeminfoSplits); ++ ssize_t slabInfoSize = virStringListLength((const char * const *)slabInfoSplits); ++ ++ numStart = strchr(baseMeminfoSplits[i], ':'); ++ numListStart = strchr(baseMeminfoSplits[i], '('); ++ if (!numStart || !numListStart) ++ goto cleanup; ++ ++ virSkipToDigit((const char **)(&numStart)); ++ ret = virStrToLong_i(numStart, &numStart, 10, &numaSize); ++ if (ret < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("Failed to get available numa size")); ++ goto cleanup; ++ } ++ ++ ret = virStringListAdd(&resultStrList, baseMeminfoSplits[i++]); ++ if (ret < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s [%d]", ++ _("Failed to get add base memory info list member"), (i - 1)); ++ goto cleanup; ++ } ++ ++ virSkipToDigit((const char **)(&numListStart)); ++ for (numaIndex = 0; *numListStart && numaIndex < numaSize; numaIndex++, numListStart++) { ++ ret = virStrToLong_i(numListStart, &numListStart, 10, &headNumaNode); ++ if (ret < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("Failed to get current numa node")); ++ goto cleanup; ++ } ++ ++ ret = qemuConnectTmmInfoListAppend(&resultStrList, baseMeminfoSplits, headNumaNode, &i, meminfoListSize); ++ if (ret < 0) ++ goto cleanup; ++ ret = qemuConnectTmmInfoListAppend(&resultStrList, slabInfoSplits, headNumaNode, &j, slabInfoSize); ++ if (ret < 0) ++ goto cleanup; ++ } ++ ++ format = virStringListJoin((const char **)resultStrList, "\n"); ++ ++ cleanup: ++ virStringListFree(baseMeminfoSplits); ++ virStringListFree(slabInfoSplits); ++ virStringListFree(resultStrList); ++ return format; ++} ++ ++static char * ++qemuConnectGetTmmMemoryInfo(virConnectPtr conn G_GNUC_UNUSED, ++ bool detail) ++{ ++ int maxLen = 10 * 1024; ++ char *meminfo = NULL; ++ g_autofree char *formatInfo = NULL; ++ g_autofree char *baseMeminfo = NULL; ++ g_autofree char *slabInfo = NULL; ++ g_autofree char *buddyInfo = NULL; ++ ++ if (virFileReadAll("/sys/kernel/tmm/memory_info", maxLen, &baseMeminfo) < 0) ++ goto end; ++ if (detail && virFileReadAll("/sys/kernel/tmm/slab_info", maxLen, &slabInfo) < 0) ++ goto end; ++ if (detail && virFileReadAll("/sys/kernel/tmm/buddy_info", maxLen, &buddyInfo) < 0) ++ goto end; ++ ++ if (detail) { ++ if (!virStringIsEmpty(baseMeminfo) && !virStringIsEmpty(slabInfo)) { ++ formatInfo = qemuConnectTmmDetailInfoFormat(baseMeminfo, slabInfo); ++ if (formatInfo == NULL) ++ goto end; ++ } else { ++ formatInfo = g_strdup_printf(_("%s%s"), baseMeminfo, slabInfo); ++ } ++ ++ meminfo = g_strdup_printf(_("%s\n%s"), formatInfo, buddyInfo); ++ } else { ++ meminfo = g_steal_pointer(&baseMeminfo); ++ } ++ ++end: ++ return meminfo; ++} ++ + + static virHypervisorDriver qemuHypervisorDriver = { + .name = QEMU_DRIVER_NAME, +@@ -23627,6 +23765,7 @@ static virHypervisorDriver qemuHypervisorDriver = { + .domainBackupGetXMLDesc = qemuDomainBackupGetXMLDesc, /* 6.0.0 */ + .domainHotpatchManage = qemuDomainHotpatchManage, /* 6.2.0 */ + .domainStartDirtyRateCalc = qemuDomainStartDirtyRateCalc, /* 6.2.0 */ ++ .connectGetTmmMemoryInfo = qemuConnectGetTmmMemoryInfo, /* 6.2.0 */ + }; + + +diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c +index 0bbcc05235..a9763cee7b 100644 +--- a/src/remote/remote_daemon_dispatch.c ++++ b/src/remote/remote_daemon_dispatch.c +@@ -7268,6 +7268,29 @@ remoteDispatchNetworkPortGetParameters(virNetServerPtr server G_GNUC_UNUSED, + return rv; + } + ++static int ++remoteDispatchConnectGetTmmMemoryInfo(virNetServerPtr server G_GNUC_UNUSED, ++ virNetServerClientPtr client, ++ virNetMessagePtr msg G_GNUC_UNUSED, ++ virNetMessageErrorPtr rerr, ++ remote_connect_get_tmm_memory_info_args *args, ++ remote_connect_get_tmm_memory_info_ret *ret) ++{ ++ int rv = -1; ++ char *meminfo = NULL; ++ virConnectPtr conn = remoteGetHypervisorConn(client); ++ ++ if (conn && (meminfo = virConnectGetTmmMemoryInfo(conn, args->detail))) { ++ rv = 0; ++ ret->meminfo = meminfo; ++ } ++ ++ if (rv < 0) ++ virNetMessageSaveError(rerr); ++ ++ return rv; ++} ++ + + /*----- Helpers. -----*/ + +diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c +index 9c272b4ff8..b597ae614c 100644 +--- a/src/remote/remote_driver.c ++++ b/src/remote/remote_driver.c +@@ -8253,6 +8253,34 @@ remoteDomainGetGuestInfo(virDomainPtr dom, + return rv; + } + ++static char * ++remoteConnectGetTmmMemoryInfo(virConnectPtr conn, ++ bool detail) ++{ ++ char *rv = NULL; ++ struct private_data *priv = conn->privateData; ++ remote_connect_get_tmm_memory_info_args args; ++ remote_connect_get_tmm_memory_info_ret ret; ++ ++ remoteDriverLock(priv); ++ ++ args.detail = detail; ++ ++ memset(&ret, 0, sizeof(ret)); ++ ++ if (call(conn, priv, 0, REMOTE_PROC_CONNECT_GET_TMM_MEMORY_INFO, ++ (xdrproc_t)xdr_remote_connect_get_tmm_memory_info_args, (char *)&args, ++ (xdrproc_t)xdr_remote_connect_get_tmm_memory_info_ret, (char *)&ret) < 0) { ++ goto done; ++ } ++ ++ rv = ret.meminfo; ++ ++ done: ++ remoteDriverUnlock(priv); ++ return rv; ++} ++ + /* get_nonnull_domain and get_nonnull_network turn an on-wire + * (name, uuid) pair into virDomainPtr or virNetworkPtr object. + * These can return NULL if underlying memory allocations fail, +@@ -8686,6 +8714,7 @@ static virHypervisorDriver hypervisor_driver = { + .domainBackupGetXMLDesc = remoteDomainBackupGetXMLDesc, /* 6.0.0 */ + .domainHotpatchManage = remoteDomainHotpatchManage, /* 6.2.0 */ + .domainStartDirtyRateCalc = remoteDomainStartDirtyRateCalc, /* 6.2.0 */ ++ .connectGetTmmMemoryInfo = remoteConnectGetTmmMemoryInfo /* 6.2.0 */ + }; + + static virNetworkDriver network_driver = { +diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x +index d89cc1a087..f37bd332a1 100644 +--- a/src/remote/remote_protocol.x ++++ b/src/remote/remote_protocol.x +@@ -3789,6 +3789,14 @@ struct remote_domain_start_dirty_rate_calc_args { + unsigned int flags; + }; + ++struct remote_connect_get_tmm_memory_info_args { ++ unsigned int detail; ++}; ++ ++struct remote_connect_get_tmm_memory_info_ret { ++ remote_nonnull_string meminfo; ++}; ++ + /*----- Protocol. -----*/ + + /* Define the program number, protocol version and procedure numbers here. */ +@@ -6698,5 +6706,11 @@ enum remote_procedure { + * @generate: both + * @acl: domain:read + */ +- REMOTE_PROC_DOMAIN_HOTPATCH_MANAGE = 800 ++ REMOTE_PROC_DOMAIN_HOTPATCH_MANAGE = 800, ++ ++ /** ++ * @generate: none ++ * @acl: connect:read ++ */ ++ REMOTE_PROC_CONNECT_GET_TMM_MEMORY_INFO = 900 + }; +-- +2.27.0 + diff --git a/libvirt-support-the-virtCCA-feature.patch b/libvirt-support-the-virtCCA-feature.patch new file mode 100644 index 0000000000000000000000000000000000000000..20a4c897e22152b18bdd687437a025cdcba0d0c9 --- /dev/null +++ b/libvirt-support-the-virtCCA-feature.patch @@ -0,0 +1,189 @@ +From a2b13dd8d6e0282d76a583f36965b3a00cdb7eea Mon Sep 17 00:00:00 2001 +From: liupingwei +Date: Wed, 12 Jun 2024 11:39:38 +0800 +Subject: [PATCH] libvirt: support the virtCCA feature Add cvm parameter into + the type of LaunchSecurity which is a optional filed for libvirt xml. Its + purpose is to pass the cvm parameter through to qemu. Also this patch support + virsh edit to save cvm parameter into libvirt temporary xml. + +Signed-off-by: tujipei +--- + docs/schemas/domaincommon.rng | 67 ++++++++++++++++++++--------------- + src/conf/domain_conf.c | 25 ++++++++++--- + src/conf/domain_conf.h | 3 ++ + src/qemu/qemu_command.c | 2 ++ + 4 files changed, 63 insertions(+), 34 deletions(-) + +diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng +index e3b51d333c..a49842a9d0 100644 +--- a/docs/schemas/domaincommon.rng ++++ b/docs/schemas/domaincommon.rng +@@ -460,35 +460,44 @@ + + + +- +- sev +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- ++ ++ ++ ++ sev ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ cvm ++ ++ ++ + + + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index cf807c7747..9219d08753 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -1273,6 +1273,7 @@ VIR_ENUM_IMPL(virDomainLaunchSecurity, + VIR_DOMAIN_LAUNCH_SECURITY_LAST, + "", + "sev", ++ "cvm", + ); + + static virClassPtr virDomainObjClass; +@@ -16823,6 +16824,7 @@ virDomainSEVDefParseXML(xmlNodePtr sevNode, + def->sectype = virDomainLaunchSecurityTypeFromString(type); + switch ((virDomainLaunchSecurity) def->sectype) { + case VIR_DOMAIN_LAUNCH_SECURITY_SEV: ++ case VIR_DOMAIN_LAUNCH_SECURITY_CVM: + break; + case VIR_DOMAIN_LAUNCH_SECURITY_NONE: + case VIR_DOMAIN_LAUNCH_SECURITY_LAST: +@@ -22169,11 +22171,19 @@ virDomainDefParseXML(xmlDocPtr xml, + ctxt->node = node; + VIR_FREE(nodes); + +- /* Check for SEV feature */ ++ /* Check for CVM/SEV feature */ + if ((node = virXPathNode("./launchSecurity", ctxt)) != NULL) { +- def->sev = virDomainSEVDefParseXML(node, ctxt); +- if (!def->sev) +- goto error; ++ tmp = virXMLPropString(node, "type"); ++ if((virDomainLaunchSecurity)virDomainLaunchSecurityTypeFromString(tmp) == VIR_DOMAIN_LAUNCH_SECURITY_CVM) { ++ def->cvm = true; ++ } else { ++ def->sev = virDomainSEVDefParseXML(node, ctxt); ++ if(!def->sev) { ++ VIR_FREE(tmp); ++ goto error; ++ } ++ } ++ VIR_FREE(tmp); + } + + /* analysis of memory devices */ +@@ -29861,7 +29871,12 @@ virDomainDefFormatInternalSetRootName(virDomainDefPtr def, + if (def->keywrap) + virDomainKeyWrapDefFormat(buf, def->keywrap); + +- virDomainSEVDefFormat(buf, def->sev); ++ if (def->cvm) { ++ virBufferAddLit(buf, "\n"); ++ virBufferAddLit(buf, "\n"); ++ } else { ++ virDomainSEVDefFormat(buf, def->sev); ++ } + + virBufferAdjustIndent(buf, -2); + virBufferAsprintf(buf, "\n", rootname); +diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h +index 7419bf8d7e..180975840c 100644 +--- a/src/conf/domain_conf.h ++++ b/src/conf/domain_conf.h +@@ -2373,6 +2373,7 @@ struct _virDomainKeyWrapDef { + typedef enum { + VIR_DOMAIN_LAUNCH_SECURITY_NONE, + VIR_DOMAIN_LAUNCH_SECURITY_SEV, ++ VIR_DOMAIN_LAUNCH_SECURITY_CVM, + + VIR_DOMAIN_LAUNCH_SECURITY_LAST, + } virDomainLaunchSecurity; +@@ -2586,6 +2587,8 @@ struct _virDomainDef { + + /* SEV-specific domain */ + virDomainSEVDefPtr sev; ++ /* CVM-specific domain */ ++ bool cvm; + + /* Application-specific custom metadata */ + xmlNodePtr metadata; +diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c +index 9fcea9d46a..675a624919 100644 +--- a/src/qemu/qemu_command.c ++++ b/src/qemu/qemu_command.c +@@ -7266,6 +7266,8 @@ qemuBuildMachineCommandLine(virCommandPtr cmd, + + if (def->sev) + virBufferAddLit(&buf, ",memory-encryption=sev0"); ++ if (def->cvm) ++ virBufferAddLit(&buf, ",kvm-type=cvm"); + + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_BLOCKDEV)) { + if (priv->pflash0) +-- +2.27.0 + diff --git a/libvirt.spec b/libvirt.spec index caa225680c3e921d115cb8a72395519ec4d13e60..214e57b290fda4e074f2a7d77823366d7bc641cb 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: 64 +Release: 65 License: LGPLv2+ URL: https://libvirt.org/ @@ -514,6 +514,27 @@ Patch0401: interface-fix-udev_device_get_sysattr_value-return-v.patch Patch0402: util-keep-track-of-full-GSource-object-not-source-ID.patch Patch0403: rpc-mark-source-returned-by-virEventGLibAddSocketWat.patch Patch0404: rpc-ensure-temporary-GSource-is-removed-from-client-.patch +Patch0405: hotpatch-if-hotpatch_path-not-in-qemu.conf-the-hotpa.patch +Patch0406: internal.h-Introduce-and-use-VIR_IS_POW2.patch +Patch0407: virDomainFeaturesDefParse-Factor-out-KVM-parsing-int.patch +Patch0408: virDomainFeaturesKVMDefParse-Remove-ctxt.patch +Patch0409: virxml-Add-virXMLPropTristateBool.patch +Patch0410: virxml-Add-virXMLPropTristateSwitch.patch +Patch0411: virxml-Add-virXMLPropInt.patch +Patch0412: virxml-Add-virXMLPropUInt.patch +Patch0413: virDomainFeaturesKVMDefParse-Remove-tautological-swi.patch +Patch0414: virDomainFeaturesKVMDefParse-Remove-tautological-if.patch +Patch0415: qemu_validate-Allow-kvm-hint-dedicated-on-non-passth.patch +Patch0416: conf-Turn-virDomainDef.kvm_features-into-a-struct.patch +Patch0417: qemu-support-dirty-ring-feature.patch +Patch0418: qemu-Generate-command-line-for-dirty-ring-size.patch +Patch0419: virsh-Add-mode-option-to-domdirtyrate-calc-virsh-api.patch +Patch0420: qemu_driver-Add-calc_mode-for-dirtyrate-statistics.patch +Patch0421: libvirt-support-the-virtCCA-feature.patch +Patch0422: libvirt-add-get-tmm-memory-info-API-and-libvirtd-RPC.patch +Patch0423: virsh-add-tmm-main-command-word.patch +Patch0424: qemu-avoid-deadlock-in-qemuDomainObjStopWorker.patch +Patch0425: remote-fix-double-free-of-migration-params-on-error.patch Requires: libvirt-daemon = %{version}-%{release} Requires: libvirt-daemon-config-network = %{version}-%{release} @@ -2250,6 +2271,29 @@ exit 0 %changelog +* Thu Jun 13 2024 Jiabo Feng - 6.2.0-65 +- remote: fix double free of migration params on error +- qemu: avoid deadlock in qemuDomainObjStopWorker We are dropping the only reference here so that the event loop thread is going to be exited synchronously. In order to avoid deadlocks we need to unlock the VM so that any handler being called can finish execution and thus even loop thread be finished too. +- virsh: add tmm main command word Add tmm command word into virsh tool to call get tmm memory info API. It makes virsh can use tmm main commmand to show tmm memory info on console. This command requires specific kernel and a kernel driver to make sure its regular function. If runnning environment missing the above reliance, this command will show error result on console. +- libvirt: add get tmm memory info API and libvirtd RPC Add the get tmm memory info API into libvirt-host. Also should add the RPC calls into libvirtd for API calling. +- libvirt: support the virtCCA feature Add cvm parameter into the type of LaunchSecurity which is a optional filed for libvirt xml. Its purpose is to pass the cvm parameter through to qemu. Also this patch support virsh edit to save cvm parameter into libvirt temporary xml. +- qemu_driver: Add calc_mode for dirtyrate statistics +- virsh: Add mode option to domdirtyrate-calc virsh api +- qemu: Generate command line for dirty-ring-size +- qemu: support dirty ring feature +- conf: Turn virDomainDef.kvm_features into a struct +- qemu_validate: Allow kvm hint-dedicated on non-passthrough VMs +- virDomainFeaturesKVMDefParse: Remove tautological "if" +- virDomainFeaturesKVMDefParse: Remove tautological "switch" +- virxml: Add virXMLPropUInt +- virxml: Add virXMLPropInt +- virxml: Add virXMLPropTristateSwitch +- virxml: Add virXMLPropTristateBool +- virDomainFeaturesKVMDefParse: Remove ctxt +- virDomainFeaturesDefParse: Factor out KVM parsing into separate function +- internal.h: Introduce and use VIR_IS_POW2() +- hotpatch: if hotpatch_path not in qemu.conf,the hotpatch doesn't antoload + * Fri May 24 2024 jiangjiacheng - 6.2.0-64 - util: keep track of full GSource object not source ID number - rpc: mark source returned by virEventGLibAddSocketWatch as unused diff --git a/qemu-Generate-command-line-for-dirty-ring-size.patch b/qemu-Generate-command-line-for-dirty-ring-size.patch new file mode 100644 index 0000000000000000000000000000000000000000..a17d084977c51a478de690ee70b230f62f326a3d --- /dev/null +++ b/qemu-Generate-command-line-for-dirty-ring-size.patch @@ -0,0 +1,56 @@ +From 03df55a833efbf60200e2617d285b54afa916325 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Tue, 23 Nov 2021 09:36:59 -0500 +Subject: [PATCH] qemu: Generate command line for dirty-ring-size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +On QEMU command line it's represented by the dirty-ring-size +attribute of KVM accelerator. + +Signed-off-by: Hyman Huang(榛勫媷) +Reviewed-by: Michal Privoznik +Reviewed-by: Shaokun Wei +--- + src/qemu/qemu_command.c | 9 +++++++++ + tests/qemuxml2argvdata/kvm-features.args | 2 +- + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c +index b879f7f39a..9fcea9d46a 100644 +--- a/src/qemu/qemu_command.c ++++ b/src/qemu/qemu_command.c +@@ -7295,6 +7295,15 @@ qemuBuildAccelCommandLine(virCommand *cmd, + + case VIR_DOMAIN_VIRT_KVM: + virBufferAddLit(&buf, "kvm"); ++ /* ++ * only handle the kvm case, tcg case use the legacy style ++ * not that either kvm or tcg can be specified by libvirt ++ * so do not worry about the conflict of specifying both ++ * */ ++ if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON && ++ def->kvm_features->features[VIR_DOMAIN_KVM_DIRTY_RING] == VIR_TRISTATE_SWITCH_ON) { ++ virBufferAsprintf(&buf, ",dirty-ring-size=%d", def->kvm_features->dirty_ring_size); ++ } + break; + + case VIR_DOMAIN_VIRT_KQEMU: +diff --git a/tests/qemuxml2argvdata/kvm-features.args b/tests/qemuxml2argvdata/kvm-features.args +index 07ab9d5224..d70f0d4846 100644 +--- a/tests/qemuxml2argvdata/kvm-features.args ++++ b/tests/qemuxml2argvdata/kvm-features.args +@@ -11,7 +11,7 @@ QEMU_AUDIO_DRV=none \ + -name QEMUGuest1 \ + -S \ + -machine pc,usb=off,dump-guest-core=off \ +--accel kvm \ ++-accel kvm,dirty-ring-size=4096 \ + -cpu host,kvm=off,kvm-hint-dedicated=on \ + -m 214 \ + -realtime mlock=off \ +-- +2.27.0 + diff --git a/qemu-avoid-deadlock-in-qemuDomainObjStopWorker.patch b/qemu-avoid-deadlock-in-qemuDomainObjStopWorker.patch new file mode 100644 index 0000000000000000000000000000000000000000..5b6185fac29981d9f3c0588efbadca27a4666698 --- /dev/null +++ b/qemu-avoid-deadlock-in-qemuDomainObjStopWorker.patch @@ -0,0 +1,55 @@ +From e69e8b9da6483cb4646869e47d6b808a30f49be4 Mon Sep 17 00:00:00 2001 +From: tangbinzy +Date: Thu, 16 Mar 2023 02:54:16 +0000 +Subject: [PATCH] qemu: avoid deadlock in qemuDomainObjStopWorker We are + dropping the only reference here so that the event loop thread is going to be + exited synchronously. In order to avoid deadlocks we need to unlock the VM so + that any handler being called can finish execution and thus even loop thread + be finished too. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Nikolay Shirokovskiy +Reviewed-by: Daniel Henrique Barboza +Reviewed-by: Daniel P. Berrangé + +Signed-off-by: tangbin +(cherry-pick from 860a999802d3c82538373bb3f314f92a2e258754) +--- + src/qemu/qemu_domain.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c +index 70835e4efd..746adff3f1 100644 +--- a/src/qemu/qemu_domain.c ++++ b/src/qemu/qemu_domain.c +@@ -2192,11 +2192,21 @@ void + qemuDomainObjStopWorker(virDomainObjPtr dom) + { + qemuDomainObjPrivatePtr priv = dom->privateData; ++ virEventThread *eventThread; + +- if (priv->eventThread) { +- g_object_unref(priv->eventThread); +- priv->eventThread = NULL; +- } ++ if (!priv->eventThread) ++ return; ++ ++ /* ++ * We are dropping the only reference here so that the event loop thread ++ * is going to be exited synchronously. In order to avoid deadlocks we ++ * need to unlock the VM so that any handler being called can finish ++ * execution and thus even loop thread be finished too. ++ */ ++ eventThread = g_steal_pointer(&priv->eventThread); ++ virObjectUnlock(dom); ++ g_object_unref(eventThread); ++ virObjectLock(dom); + } + + +-- +2.27.0 + diff --git a/qemu-support-dirty-ring-feature.patch b/qemu-support-dirty-ring-feature.patch new file mode 100644 index 0000000000000000000000000000000000000000..6814fa18d801c719ee987e59a036045d8bc09a95 --- /dev/null +++ b/qemu-support-dirty-ring-feature.patch @@ -0,0 +1,254 @@ +From 24a179c25897dbfaa015ff62940648877d9d50ef Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Tue, 23 Nov 2021 09:36:58 -0500 +Subject: [PATCH] qemu: support dirty ring feature +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Dirty ring feature was introduced in qemu-6.1.0, this patch +add the corresponding feature named 'dirty-ring', which enable +dirty ring feature when starting VM. + +To enable the feature, the following XML needs to be added to +the guest's domain description: + + + + + + + +If property "state=on", property "size" must be specified, which +should be power of 2 and range in [1024, 65526]. + +Signed-off-by: Hyman Huang(榛勫媷) +Signed-off-by: Michal Privoznik +Reviewed-by: Michal Privoznik +Reviewed-by: Shaokun Wei +--- + docs/formatdomain.html.in | 7 ++++ + docs/schemas/domaincommon.rng | 10 +++++ + src/conf/domain_conf.c | 42 +++++++++++++++++++ + src/conf/domain_conf.h | 3 ++ + src/qemu/qemu_command.c | 3 ++ + tests/qemuxml2argvdata/kvm-features-off.xml | 1 + + tests/qemuxml2argvdata/kvm-features.xml | 1 + + tests/qemuxml2xmloutdata/kvm-features-off.xml | 1 + + tests/qemuxml2xmloutdata/kvm-features.xml | 1 + + 9 files changed, 69 insertions(+) + +diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in +index 6e51c3bac9..0521a847d8 100644 +--- a/docs/formatdomain.html.in ++++ b/docs/formatdomain.html.in +@@ -2055,6 +2055,7 @@ + <kvm> + <hidden state='on'/> + <hint-dedicated state='on'/> ++ <dirty-ring state='on' size='4096'/> + </kvm> + <pvspinlock state='on'/> + <gic version='2'/> +@@ -2235,6 +2236,12 @@ + on, off + 5.7.0 (QEMU 2.12.0) + ++ ++ dirty-ring ++ Enable dirty ring feature ++ on, off; size - must be power of 2, range [1024,65536] ++ 8.0.0 (QEMU 6.1) ++ + + +
pmu
+diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng +index 764f826df4..e3b51d333c 100644 +--- a/docs/schemas/domaincommon.rng ++++ b/docs/schemas/domaincommon.rng +@@ -6327,6 +6327,16 @@ + + + ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index e94ae4ea17..cf807c7747 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -205,6 +205,7 @@ VIR_ENUM_IMPL(virDomainKVM, + VIR_DOMAIN_KVM_LAST, + "hidden", + "hint-dedicated", ++ "dirty-ring", + ); + + VIR_ENUM_IMPL(virDomainMsrsUnknown, +@@ -20620,6 +20621,22 @@ virDomainFeaturesKVMDefParse(virDomainDef *def, + + kvm->features[feature] = value; + ++ /* dirty ring feature should parse size property */ ++ if (feature == VIR_DOMAIN_KVM_DIRTY_RING && ++ value == VIR_TRISTATE_SWITCH_ON) { ++ if (virXMLPropUInt(node, "size", 0, VIR_XML_PROP_REQUIRED, ++ &kvm->dirty_ring_size) < 0) { ++ return -1; ++ } ++ if (!VIR_IS_POW2(kvm->dirty_ring_size) || ++ kvm->dirty_ring_size < 1024 || ++ kvm->dirty_ring_size > 65536) { ++ virReportError(VIR_ERR_XML_ERROR, "%s", ++ _("dirty ring must be power of 2 and ranges [1024, 65536]")); ++ return -1; ++ } ++ } ++ + node = xmlNextElementSibling(node); + } + +@@ -23590,6 +23607,7 @@ virDomainDefFeaturesCheckABIStability(virDomainDefPtr src, + switch ((virDomainKVM) i) { + case VIR_DOMAIN_KVM_HIDDEN: + case VIR_DOMAIN_KVM_DEDICATED: ++ case VIR_DOMAIN_KVM_DIRTY_RING: + if (src->kvm_features->features[i] != dst->kvm_features->features[i]) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("State of KVM feature '%s' differs: " +@@ -23607,6 +23625,16 @@ virDomainDefFeaturesCheckABIStability(virDomainDefPtr src, + break; + } + } ++ ++ if (src->kvm_features->dirty_ring_size != dst->kvm_features->dirty_ring_size) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, ++ _("dirty ring size of KVM feature '%s' differs: " ++ "source: '%d', destination: '%d'"), ++ virDomainKVMTypeToString(i), ++ src->kvm_features->dirty_ring_size, ++ dst->kvm_features->dirty_ring_size); ++ return false; ++ } + } + + /* smm */ +@@ -29214,6 +29242,20 @@ virDomainDefFormatFeatures(virBufferPtr buf, + def->kvm_features->features[j])); + break; + ++ case VIR_DOMAIN_KVM_DIRTY_RING: ++ if (def->kvm_features->features[j] != VIR_TRISTATE_SWITCH_ABSENT) { ++ virBufferAsprintf(&childBuf, "<%s state='%s'", ++ virDomainKVMTypeToString(j), ++ virTristateSwitchTypeToString(def->kvm_features->features[j])); ++ if (def->kvm_features->dirty_ring_size > 0) { ++ virBufferAsprintf(&childBuf, " size='%d'/>\n", ++ def->kvm_features->dirty_ring_size); ++ } else { ++ virBufferAddLit(&childBuf, "/>\n"); ++ } ++ } ++ break; ++ + /* coverity[dead_error_begin] */ + case VIR_DOMAIN_KVM_LAST: + break; +diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h +index d75d06d7b8..7419bf8d7e 100644 +--- a/src/conf/domain_conf.h ++++ b/src/conf/domain_conf.h +@@ -1840,6 +1840,7 @@ typedef enum { + typedef enum { + VIR_DOMAIN_KVM_HIDDEN = 0, + VIR_DOMAIN_KVM_DEDICATED, ++ VIR_DOMAIN_KVM_DIRTY_RING, + + VIR_DOMAIN_KVM_LAST + } virDomainKVM; +@@ -2300,6 +2301,8 @@ struct _virDomainResctrlDef { + typedef struct _virDomainFeatureKVM virDomainFeatureKVM; + struct _virDomainFeatureKVM { + int features[VIR_DOMAIN_KVM_LAST]; ++ ++ unsigned int dirty_ring_size; /* size of dirty ring for each vCPU, no units */ + }; + + +diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c +index ed843315dc..b879f7f39a 100644 +--- a/src/qemu/qemu_command.c ++++ b/src/qemu/qemu_command.c +@@ -6920,6 +6920,9 @@ qemuBuildCpuCommandLine(virCommandPtr cmd, + virBufferAddLit(&buf, ",kvm-hint-dedicated=on"); + break; + ++ case VIR_DOMAIN_KVM_DIRTY_RING: ++ break; ++ + /* coverity[dead_error_begin] */ + case VIR_DOMAIN_KVM_LAST: + break; +diff --git a/tests/qemuxml2argvdata/kvm-features-off.xml b/tests/qemuxml2argvdata/kvm-features-off.xml +index 21d492c8b9..f53e31db6b 100644 +--- a/tests/qemuxml2argvdata/kvm-features-off.xml ++++ b/tests/qemuxml2argvdata/kvm-features-off.xml +@@ -13,6 +13,7 @@ + + + ++ + + + +diff --git a/tests/qemuxml2argvdata/kvm-features.xml b/tests/qemuxml2argvdata/kvm-features.xml +index 85f74786c9..fd08a7a0f5 100644 +--- a/tests/qemuxml2argvdata/kvm-features.xml ++++ b/tests/qemuxml2argvdata/kvm-features.xml +@@ -13,6 +13,7 @@ + + + ++ + + + +diff --git a/tests/qemuxml2xmloutdata/kvm-features-off.xml b/tests/qemuxml2xmloutdata/kvm-features-off.xml +index 9068be3e7b..2c8b6a81d3 100644 +--- a/tests/qemuxml2xmloutdata/kvm-features-off.xml ++++ b/tests/qemuxml2xmloutdata/kvm-features-off.xml +@@ -13,6 +13,7 @@ + + + ++ + + + +diff --git a/tests/qemuxml2xmloutdata/kvm-features.xml b/tests/qemuxml2xmloutdata/kvm-features.xml +index 7c554671b3..6e97065fed 100644 +--- a/tests/qemuxml2xmloutdata/kvm-features.xml ++++ b/tests/qemuxml2xmloutdata/kvm-features.xml +@@ -13,6 +13,7 @@ + + + ++ + + + +-- +2.27.0 + diff --git a/qemu_driver-Add-calc_mode-for-dirtyrate-statistics.patch b/qemu_driver-Add-calc_mode-for-dirtyrate-statistics.patch new file mode 100644 index 0000000000000000000000000000000000000000..e5b89b25d5a825d3aba66d2790d5ec962a891afc --- /dev/null +++ b/qemu_driver-Add-calc_mode-for-dirtyrate-statistics.patch @@ -0,0 +1,184 @@ +From e2db7dec8f43ac5ba8eb518a4d6cb6d58f9dee60 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Sun, 20 Feb 2022 21:28:15 +0800 +Subject: [PATCH] qemu_driver: Add calc_mode for dirtyrate statistics +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add calc_mode for dirtyrate statistics retured by +virsh domstats --dirtyrate api, also add vcpu dirtyrate +if dirty-ring mode was used in last measurement. + +Signed-off-by: Hyman Huang(榛勫媷) +Signed-off-by: Michal Privoznik +Reviewed-by: Michal Privoznik +Reviewed-by: Shaokun Wei +--- + src/libvirt-domain.c | 6 ++++ + src/qemu/qemu_driver.c | 22 +++++++++++++-- + src/qemu/qemu_monitor.h | 10 +++++++ + src/qemu/qemu_monitor_json.c | 53 ++++++++++++++++++++++++++++++++++++ + 4 files changed, 88 insertions(+), 3 deletions(-) + +diff --git a/src/libvirt-domain.c b/src/libvirt-domain.c +index 8f6ff2fe22..d2b2c89353 100644 +--- a/src/libvirt-domain.c ++++ b/src/libvirt-domain.c +@@ -11697,6 +11697,12 @@ virConnectGetDomainCapabilities(virConnectPtr conn, + * "dirtyrate.megabytes_per_second" - the calculated memory dirty rate in + * MiB/s as long long. It is produced + * only if the calc_status is measured. ++ * "dirtyrate.calc_mode" - the calculation mode used last measurement, either ++ * of these 3 'page-sampling,dirty-bitmap,dirty-ring' ++ * values returned. ++ * "dirtyrate.vcpu..megabytes_per_second" - the calculated memory dirty ++ * rate for a virtual cpu as ++ * unsigned long long. + * + * Note that entire stats groups or individual stat fields may be missing from + * the output in case they are not supported by the given hypervisor, are not +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index 9cb14b01ad..77a139c66b 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -21723,11 +21723,27 @@ qemuDomainGetStatsDirtyRate(virQEMUDriverPtr driver, + "dirtyrate.calc_period") < 0) + return -1; + +- if ((info.status == VIR_DOMAIN_DIRTYRATE_MEASURED) && +- virTypedParamListAddLLong(params, info.dirtyRate, +- "dirtyrate.megabytes_per_second") < 0) ++ if (virTypedParamListAddString(params, ++ qemuMonitorDirtyRateCalcModeTypeToString(info.mode), ++ "dirtyrate.calc_mode") < 0) + return -1; + ++ if (info.status == VIR_DOMAIN_DIRTYRATE_MEASURED) { ++ if (virTypedParamListAddLLong(params, info.dirtyRate, ++ "dirtyrate.megabytes_per_second") < 0) ++ return -1; ++ ++ if (info.mode == QEMU_MONITOR_DIRTYRATE_CALC_MODE_DIRTY_RING) { ++ size_t i; ++ for (i = 0; i < info.nvcpus; i++) { ++ if (virTypedParamListAddULLong(params, info.rates[i].value, ++ "dirtyrate.vcpu.%d.megabytes_per_second", ++ info.rates[i].idx) < 0) ++ return -1; ++ } ++ } ++ } ++ + return 0; + } + +diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h +index 1c6b001872..949a04f60f 100644 +--- a/src/qemu/qemu_monitor.h ++++ b/src/qemu/qemu_monitor.h +@@ -1464,6 +1464,12 @@ qemuMonitorStartDirtyRateCalc(qemuMonitorPtr mon, + int seconds, + qemuMonitorDirtyRateCalcMode mode); + ++typedef struct _qemuMonitorDirtyRateVcpu qemuMonitorDirtyRateVcpu; ++struct _qemuMonitorDirtyRateVcpu { ++ int idx; /* virtual cpu index */ ++ unsigned long long value; /* virtual cpu dirty page rate in MB/s */ ++}; ++ + typedef struct _qemuMonitorDirtyRateInfo qemuMonitorDirtyRateInfo; + typedef qemuMonitorDirtyRateInfo *qemuMonitorDirtyRateInfoPtr; + +@@ -1473,6 +1479,10 @@ struct _qemuMonitorDirtyRateInfo { + int calcTime; /* the period of dirtyrate calculation */ + long long startTime; /* the start time of dirtyrate calculation */ + long long dirtyRate; /* the dirtyrate in MiB/s */ ++ qemuMonitorDirtyRateCalcMode mode; /* calculation mode used in ++ last measurement */ ++ size_t nvcpus; /* number of virtual cpu */ ++ qemuMonitorDirtyRateVcpu *rates; /* array of dirty page rate */ + }; + + int +diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c +index 8f040bbe59..e7134d90b6 100644 +--- a/src/qemu/qemu_monitor_json.c ++++ b/src/qemu/qemu_monitor_json.c +@@ -9450,12 +9450,46 @@ VIR_ENUM_IMPL(qemuMonitorDirtyRateStatus, + "measuring", + "measured"); + ++static int ++qemuMonitorJSONExtractVcpuDirtyRate(virJSONValue *data, ++ qemuMonitorDirtyRateInfo *info) ++{ ++ size_t nvcpus; ++ size_t i; ++ ++ nvcpus = virJSONValueArraySize(data); ++ info->nvcpus = nvcpus; ++ info->rates = g_new0(qemuMonitorDirtyRateVcpu, nvcpus); ++ ++ for (i = 0; i < nvcpus; i++) { ++ virJSONValue *entry = virJSONValueArrayGet(data, i); ++ if (virJSONValueObjectGetNumberInt(entry, "id", ++ &info->rates[i].idx) < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("query-dirty-rate reply was missing 'id' data")); ++ return -1; ++ } ++ ++ if (virJSONValueObjectGetNumberUlong(entry, "dirty-rate", ++ &info->rates[i].value) < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("query-dirty-rate reply was missing 'dirty-rate' data")); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ + static int + qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data, + qemuMonitorDirtyRateInfoPtr info) + { + const char *statusstr; ++ const char *modestr; + int status; ++ int mode; ++ virJSONValue *rates = NULL; + + if (!(statusstr = virJSONValueObjectGetString(data, "status"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", +@@ -9492,6 +9526,25 @@ qemuMonitorJSONExtractDirtyRateInfo(virJSONValuePtr data, + return -1; + } + ++ if ((modestr = virJSONValueObjectGetString(data, "mode"))) { ++ if ((mode = qemuMonitorDirtyRateCalcModeTypeFromString(modestr)) < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, ++ _("Unknown dirty page rate calculation mode: %s"), modestr); ++ return -1; ++ } ++ info->mode = mode; ++ } else { ++ info->mode = QEMU_MONITOR_DIRTYRATE_CALC_MODE_PAGE_SAMPLING; ++ } ++ ++ if ((rates = virJSONValueObjectGetArray(data, "vcpu-dirty-rate"))) { ++ if (qemuMonitorJSONExtractVcpuDirtyRate(rates, info) < 0) { ++ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", ++ _("query-dirty-rate parsing 'vcpu-dirty-rate' in failure")); ++ return -1; ++ } ++ } ++ + return 0; + } + +-- +2.27.0 + diff --git a/qemu_validate-Allow-kvm-hint-dedicated-on-non-passth.patch b/qemu_validate-Allow-kvm-hint-dedicated-on-non-passth.patch new file mode 100644 index 0000000000000000000000000000000000000000..df94549a8aa36f5c10ba8cbb8a30374872c85997 --- /dev/null +++ b/qemu_validate-Allow-kvm-hint-dedicated-on-non-passth.patch @@ -0,0 +1,58 @@ +From 15746790ca62e46aa68e8a79c51a15bbf9b3d1ab Mon Sep 17 00:00:00 2001 +From: Tim Wiederhake +Date: Fri, 19 Feb 2021 10:54:00 +0100 +Subject: [PATCH] qemu_validate: Allow kvm hint-dedicated on non-passthrough + VMs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A VM defined similar to: + ... + + + ... +is currently invalid, as hint-dedicated is only allowed if cpu mode +is host-passthrough or maximum. This restriction is unnecessary, see +https://bugzilla.redhat.com/show_bug.cgi?id=1857671 + +Signed-off-by: Tim Wiederhake +Reviewed-by: J谩n Tomko +Signed-off-by: J谩n Tomko +Reviewed-by: Shaokun Wei +--- + src/qemu/qemu_domain.c | 11 +---------- + 1 file changed, 1 insertion(+), 10 deletions(-) + +diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c +index fd3e3f64c0..537411a711 100644 +--- a/src/qemu/qemu_domain.c ++++ b/src/qemu/qemu_domain.c +@@ -5251,16 +5251,6 @@ qemuDomainDefValidateFeatures(const virDomainDef *def, + } + break; + +- case VIR_DOMAIN_FEATURE_KVM: +- if (def->kvm_features[VIR_DOMAIN_KVM_DEDICATED] == VIR_TRISTATE_SWITCH_ON && +- (!def->cpu || def->cpu->mode != VIR_CPU_MODE_HOST_PASSTHROUGH)) { +- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", +- _("kvm-hint-dedicated=on is only applicable " +- "for cpu host-passthrough")); +- return -1; +- } +- break; +- + case VIR_DOMAIN_FEATURE_VMPORT: + if (def->features[i] != VIR_TRISTATE_SWITCH_ABSENT && + !virQEMUCapsSupportsVmport(qemuCaps, def)) { +@@ -5333,6 +5323,7 @@ qemuDomainDefValidateFeatures(const virDomainDef *def, + } + break; + ++ case VIR_DOMAIN_FEATURE_KVM: + case VIR_DOMAIN_FEATURE_ACPI: + case VIR_DOMAIN_FEATURE_PAE: + case VIR_DOMAIN_FEATURE_HAP: +-- +2.27.0 + diff --git a/remote-fix-double-free-of-migration-params-on-error.patch b/remote-fix-double-free-of-migration-params-on-error.patch new file mode 100644 index 0000000000000000000000000000000000000000..e3efd2cd122e875f962bc6e88b28529da7c9d3ee --- /dev/null +++ b/remote-fix-double-free-of-migration-params-on-error.patch @@ -0,0 +1,88 @@ +From cec0f6ad7c8de43ec16d200b437533111f991c82 Mon Sep 17 00:00:00 2001 +From: wangmeiyang +Date: Fri, 21 Apr 2023 14:22:52 +0800 +Subject: [PATCH] remote: fix double free of migration params on error +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The remote_*_args methods will generally borrow pointers +passed in the caller, so should not be freed. + +On failure of the virTypedParamsSerialize method, however, +xdr_free was being called. This is presumably because it +was thought that the params may have been partially +serialized and need cleaning up. This is incorrect, as +virTypedParamsSerialize takes care to cleanup partially +serialized data. This xdr_free call would lead to free'ing +the borrowed cookie pointers, which would be a double free. + +origin commit: https://gitlab.com/libvirt/libvirt/-/commit/2b5f9251129d61cfc6cffa63d367af27850602a4 +Reviewed-by: Martin Kletzander +Signed-off-by: Daniel P. Berrang¨¦ +Signed-off-by: Meiyang Wang +--- + src/remote/remote_driver.c | 12 ------------ + 1 file changed, 12 deletions(-) + +diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c +index 9c272b4ff8..fb34b1e727 100644 +--- a/src/remote/remote_driver.c ++++ b/src/remote/remote_driver.c +@@ -7067,8 +7067,6 @@ remoteDomainMigrateBegin3Params(virDomainPtr domain, + (virTypedParameterRemotePtr *) &args.params.params_val, + &args.params.params_len, + VIR_TYPED_PARAM_STRING_OKAY) < 0) { +- xdr_free((xdrproc_t) xdr_remote_domain_migrate_begin3_params_args, +- (char *) &args); + goto cleanup; + } + +@@ -7129,8 +7127,6 @@ remoteDomainMigratePrepare3Params(virConnectPtr dconn, + (virTypedParameterRemotePtr *) &args.params.params_val, + &args.params.params_len, + VIR_TYPED_PARAM_STRING_OKAY) < 0) { +- xdr_free((xdrproc_t) xdr_remote_domain_migrate_prepare3_params_args, +- (char *) &args); + goto cleanup; + } + +@@ -7211,8 +7207,6 @@ remoteDomainMigratePrepareTunnel3Params(virConnectPtr dconn, + (virTypedParameterRemotePtr *) &args.params.params_val, + &args.params.params_len, + VIR_TYPED_PARAM_STRING_OKAY) < 0) { +- xdr_free((xdrproc_t) xdr_remote_domain_migrate_prepare_tunnel3_params_args, +- (char *) &args); + goto cleanup; + } + +@@ -7297,8 +7291,6 @@ remoteDomainMigratePerform3Params(virDomainPtr dom, + (virTypedParameterRemotePtr *) &args.params.params_val, + &args.params.params_len, + VIR_TYPED_PARAM_STRING_OKAY) < 0) { +- xdr_free((xdrproc_t) xdr_remote_domain_migrate_perform3_params_args, +- (char *) &args); + goto cleanup; + } + +@@ -7364,8 +7356,6 @@ remoteDomainMigrateFinish3Params(virConnectPtr dconn, + (virTypedParameterRemotePtr *) &args.params.params_val, + &args.params.params_len, + VIR_TYPED_PARAM_STRING_OKAY) < 0) { +- xdr_free((xdrproc_t) xdr_remote_domain_migrate_finish3_params_args, +- (char *) &args); + goto cleanup; + } + +@@ -7433,8 +7423,6 @@ remoteDomainMigrateConfirm3Params(virDomainPtr domain, + (virTypedParameterRemotePtr *) &args.params.params_val, + &args.params.params_len, + VIR_TYPED_PARAM_STRING_OKAY) < 0) { +- xdr_free((xdrproc_t) xdr_remote_domain_migrate_confirm3_params_args, +- (char *) &args); + goto cleanup; + } + +-- +2.27.0 + diff --git a/virDomainFeaturesDefParse-Factor-out-KVM-parsing-int.patch b/virDomainFeaturesDefParse-Factor-out-KVM-parsing-int.patch new file mode 100644 index 0000000000000000000000000000000000000000..007c2750823281c7de0c684573271d54e681ad3f --- /dev/null +++ b/virDomainFeaturesDefParse-Factor-out-KVM-parsing-int.patch @@ -0,0 +1,157 @@ +From a935e07ee487f10c9d90f16e53fe5be8ef000484 Mon Sep 17 00:00:00 2001 +From: Tim Wiederhake +Date: Tue, 22 Jun 2021 14:22:46 +0200 +Subject: [PATCH] virDomainFeaturesDefParse: Factor out KVM parsing into + separate function + +Only moving code, cleanup to follow. + +Signed-off-by: Tim Wiederhake +Reviewed-by: Michal Privoznik +Reviewed-by: weishaokun +--- + src/conf/domain_conf.c | 110 +++++++++++++++++++++++------------------ + 1 file changed, 63 insertions(+), 47 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 5a04d1b5d1..ac2bb8abb4 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -20592,6 +20592,65 @@ virDomainMemorytuneDefParse(virDomainDefPtr def, + return ret; + } + ++static int ++virDomainFeaturesKVMDefParse(virDomainDef *def, ++ xmlXPathContext *ctxt) ++{ ++ g_autofree char *tmp = NULL; ++ g_autofree xmlNodePtr *nodes = NULL; ++ size_t i; ++ int n; ++ ++ def->features[VIR_DOMAIN_FEATURE_KVM] = VIR_TRISTATE_SWITCH_ON; ++ ++ if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) { ++ int feature; ++ virTristateSwitch value; ++ if ((n = virXPathNodeSet("./features/kvm/*", ctxt, &nodes)) < 0) ++ return -1; ++ ++ for (i = 0; i < n; i++) { ++ feature = virDomainKVMTypeFromString((const char *)nodes[i]->name); ++ if (feature < 0) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, ++ _("unsupported KVM feature: %s"), ++ nodes[i]->name); ++ return -1; ++ } ++ ++ switch ((virDomainKVM) feature) { ++ case VIR_DOMAIN_KVM_HIDDEN: ++ case VIR_DOMAIN_KVM_DEDICATED: ++ if (!(tmp = virXMLPropString(nodes[i], "state"))) { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("missing 'state' attribute for " ++ "KVM feature '%s'"), ++ nodes[i]->name); ++ return -1; ++ } ++ ++ if ((value = virTristateSwitchTypeFromString(tmp)) < 0) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, ++ _("invalid value of state argument " ++ "for KVM feature '%s'"), ++ nodes[i]->name); ++ return -1; ++ } ++ ++ VIR_FREE(tmp); ++ def->kvm_features[feature] = value; ++ break; ++ ++ /* coverity[dead_error_begin] */ ++ case VIR_DOMAIN_KVM_LAST: ++ break; ++ } ++ } ++ VIR_FREE(nodes); ++ } ++ ++ return 0; ++} + + static virDomainDefPtr + virDomainDefParseXML(xmlDocPtr xml, +@@ -21109,11 +21168,14 @@ virDomainDefParseXML(xmlDocPtr xml, + case VIR_DOMAIN_FEATURE_VIRIDIAN: + case VIR_DOMAIN_FEATURE_PRIVNET: + case VIR_DOMAIN_FEATURE_HYPERV: +- case VIR_DOMAIN_FEATURE_KVM: + case VIR_DOMAIN_FEATURE_MSRS: + def->features[val] = VIR_TRISTATE_SWITCH_ON; + break; + ++ case VIR_DOMAIN_FEATURE_KVM: ++ if (virDomainFeaturesKVMDefParse(def, ctxt) < 0) ++ goto error; ++ break; + case VIR_DOMAIN_FEATURE_CAPABILITIES: + if ((tmp = virXMLPropString(nodes[i], "policy"))) { + if ((def->features[val] = virDomainCapabilitiesPolicyTypeFromString(tmp)) == -1) { +@@ -21375,52 +21437,6 @@ virDomainDefParseXML(xmlDocPtr xml, + VIR_FREE(nodes); + } + +- if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) { +- int feature; +- int value; +- if ((n = virXPathNodeSet("./features/kvm/*", ctxt, &nodes)) < 0) +- goto error; +- +- for (i = 0; i < n; i++) { +- feature = virDomainKVMTypeFromString((const char *)nodes[i]->name); +- if (feature < 0) { +- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, +- _("unsupported KVM feature: %s"), +- nodes[i]->name); +- goto error; +- } +- +- switch ((virDomainKVM) feature) { +- case VIR_DOMAIN_KVM_HIDDEN: +- case VIR_DOMAIN_KVM_DEDICATED: +- if (!(tmp = virXMLPropString(nodes[i], "state"))) { +- virReportError(VIR_ERR_XML_ERROR, +- _("missing 'state' attribute for " +- "KVM feature '%s'"), +- nodes[i]->name); +- goto error; +- } +- +- if ((value = virTristateSwitchTypeFromString(tmp)) < 0) { +- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, +- _("invalid value of state argument " +- "for KVM feature '%s'"), +- nodes[i]->name); +- goto error; +- } +- +- VIR_FREE(tmp); +- def->kvm_features[feature] = value; +- break; +- +- /* coverity[dead_error_begin] */ +- case VIR_DOMAIN_KVM_LAST: +- break; +- } +- } +- VIR_FREE(nodes); +- } +- + if (def->features[VIR_DOMAIN_FEATURE_SMM] == VIR_TRISTATE_SWITCH_ON) { + int rv = virDomainParseScaledValue("string(./features/smm/tseg)", + "string(./features/smm/tseg/@unit)", +-- +2.27.0 + diff --git a/virDomainFeaturesKVMDefParse-Remove-ctxt.patch b/virDomainFeaturesKVMDefParse-Remove-ctxt.patch new file mode 100644 index 0000000000000000000000000000000000000000..cb2e96c4d4d74677cb5840075b5aed8928ab9a21 --- /dev/null +++ b/virDomainFeaturesKVMDefParse-Remove-ctxt.patch @@ -0,0 +1,97 @@ +From dcbc9a2cfa0894e2bfc46c2a01659a86518c6e0a Mon Sep 17 00:00:00 2001 +From: Tim Wiederhake +Date: Tue, 22 Jun 2021 14:22:47 +0200 +Subject: [PATCH] virDomainFeaturesKVMDefParse: Remove ctxt + +Iterating over all child elements of a node does not require xpath. +By doing away with xpath for this code, the code can be simplified. + +Signed-off-by: Tim Wiederhake +Reviewed-by: Michal Privoznik +Reviewed-by: Shaokun Wei +--- + src/conf/domain_conf.c | 25 +++++++++++-------------- + 1 file changed, 11 insertions(+), 14 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index ac2bb8abb4..9073db8541 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -20594,38 +20594,34 @@ virDomainMemorytuneDefParse(virDomainDefPtr def, + + static int + virDomainFeaturesKVMDefParse(virDomainDef *def, +- xmlXPathContext *ctxt) ++ xmlNodePtr node) + { + g_autofree char *tmp = NULL; +- g_autofree xmlNodePtr *nodes = NULL; +- size_t i; +- int n; + + def->features[VIR_DOMAIN_FEATURE_KVM] = VIR_TRISTATE_SWITCH_ON; + + if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) { + int feature; + virTristateSwitch value; +- if ((n = virXPathNodeSet("./features/kvm/*", ctxt, &nodes)) < 0) +- return -1; + +- for (i = 0; i < n; i++) { +- feature = virDomainKVMTypeFromString((const char *)nodes[i]->name); ++ node = xmlFirstElementChild(node); ++ while (node) { ++ feature = virDomainKVMTypeFromString((const char *)node->name); + if (feature < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unsupported KVM feature: %s"), +- nodes[i]->name); ++ node->name); + return -1; + } + + switch ((virDomainKVM) feature) { + case VIR_DOMAIN_KVM_HIDDEN: + case VIR_DOMAIN_KVM_DEDICATED: +- if (!(tmp = virXMLPropString(nodes[i], "state"))) { ++ if (!(tmp = virXMLPropString(node, "state"))) { + virReportError(VIR_ERR_XML_ERROR, + _("missing 'state' attribute for " + "KVM feature '%s'"), +- nodes[i]->name); ++ node->name); + return -1; + } + +@@ -20633,7 +20629,7 @@ virDomainFeaturesKVMDefParse(virDomainDef *def, + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("invalid value of state argument " + "for KVM feature '%s'"), +- nodes[i]->name); ++ node->name); + return -1; + } + +@@ -20645,8 +20641,9 @@ virDomainFeaturesKVMDefParse(virDomainDef *def, + case VIR_DOMAIN_KVM_LAST: + break; + } ++ ++ node = xmlNextElementSibling(node); + } +- VIR_FREE(nodes); + } + + return 0; +@@ -21173,7 +21170,7 @@ virDomainDefParseXML(xmlDocPtr xml, + break; + + case VIR_DOMAIN_FEATURE_KVM: +- if (virDomainFeaturesKVMDefParse(def, ctxt) < 0) ++ if (virDomainFeaturesKVMDefParse(def, nodes[i]) < 0) + goto error; + break; + case VIR_DOMAIN_FEATURE_CAPABILITIES: +-- +2.27.0 + diff --git a/virDomainFeaturesKVMDefParse-Remove-tautological-if.patch b/virDomainFeaturesKVMDefParse-Remove-tautological-if.patch new file mode 100644 index 0000000000000000000000000000000000000000..ce48b409c840b5bb0c4dd9038727964f00c1ef07 --- /dev/null +++ b/virDomainFeaturesKVMDefParse-Remove-tautological-if.patch @@ -0,0 +1,62 @@ +From 73d21e001e964d7d86f4659ef9cdee95a90ec97c Mon Sep 17 00:00:00 2001 +From: Tim Wiederhake +Date: Tue, 22 Jun 2021 14:22:49 +0200 +Subject: [PATCH] virDomainFeaturesKVMDefParse: Remove tautological "if" + +Signed-off-by: Tim Wiederhake +Reviewed-by: Michal Privoznik +Reviewed-by: Shaokun Wei +--- + src/conf/domain_conf.c | 30 ++++++++++++++---------------- + 1 file changed, 14 insertions(+), 16 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index dca49b6a55..e884d94ef7 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -20598,28 +20598,26 @@ virDomainFeaturesKVMDefParse(virDomainDef *def, + { + def->features[VIR_DOMAIN_FEATURE_KVM] = VIR_TRISTATE_SWITCH_ON; + +- if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) { ++ node = xmlFirstElementChild(node); ++ while (node) { + int feature; + virTristateSwitch value; + +- node = xmlFirstElementChild(node); +- while (node) { +- feature = virDomainKVMTypeFromString((const char *)node->name); +- if (feature < 0) { +- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, +- _("unsupported KVM feature: %s"), +- node->name); +- return -1; +- } ++ feature = virDomainKVMTypeFromString((const char *)node->name); ++ if (feature < 0) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, ++ _("unsupported KVM feature: %s"), ++ node->name); ++ return -1; ++ } + +- if (virXMLPropTristateSwitch(node, "state", VIR_XML_PROP_REQUIRED, +- &value) < 0) +- return -1; ++ if (virXMLPropTristateSwitch(node, "state", VIR_XML_PROP_REQUIRED, ++ &value) < 0) ++ return -1; + +- def->kvm_features[feature] = value; ++ def->kvm_features[feature] = value; + +- node = xmlNextElementSibling(node); +- } ++ node = xmlNextElementSibling(node); + } + + return 0; +-- +2.27.0 + diff --git a/virDomainFeaturesKVMDefParse-Remove-tautological-swi.patch b/virDomainFeaturesKVMDefParse-Remove-tautological-swi.patch new file mode 100644 index 0000000000000000000000000000000000000000..94808a03234e8eba648d5d7ae3fb08f1a1101d8f --- /dev/null +++ b/virDomainFeaturesKVMDefParse-Remove-tautological-swi.patch @@ -0,0 +1,69 @@ +From 956a277c82699de93d53444a4c8bf451108b501b Mon Sep 17 00:00:00 2001 +From: Tim Wiederhake +Date: Tue, 22 Jun 2021 14:22:48 +0200 +Subject: [PATCH] virDomainFeaturesKVMDefParse: Remove tautological "switch" + +`feature` is always one of the values listed in the switch, +ensured by `virDomainKVMTypeFromString` above. + +Signed-off-by: Tim Wiederhake +Reviewed-by: Michal Privoznik +Reviewed-by: Shaokun Wei +--- + src/conf/domain_conf.c | 32 ++++---------------------------- + 1 file changed, 4 insertions(+), 28 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 9073db8541..dca49b6a55 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -20596,8 +20596,6 @@ static int + virDomainFeaturesKVMDefParse(virDomainDef *def, + xmlNodePtr node) + { +- g_autofree char *tmp = NULL; +- + def->features[VIR_DOMAIN_FEATURE_KVM] = VIR_TRISTATE_SWITCH_ON; + + if (def->features[VIR_DOMAIN_FEATURE_KVM] == VIR_TRISTATE_SWITCH_ON) { +@@ -20614,33 +20612,11 @@ virDomainFeaturesKVMDefParse(virDomainDef *def, + return -1; + } + +- switch ((virDomainKVM) feature) { +- case VIR_DOMAIN_KVM_HIDDEN: +- case VIR_DOMAIN_KVM_DEDICATED: +- if (!(tmp = virXMLPropString(node, "state"))) { +- virReportError(VIR_ERR_XML_ERROR, +- _("missing 'state' attribute for " +- "KVM feature '%s'"), +- node->name); +- return -1; +- } +- +- if ((value = virTristateSwitchTypeFromString(tmp)) < 0) { +- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, +- _("invalid value of state argument " +- "for KVM feature '%s'"), +- node->name); +- return -1; +- } +- +- VIR_FREE(tmp); +- def->kvm_features[feature] = value; +- break; ++ if (virXMLPropTristateSwitch(node, "state", VIR_XML_PROP_REQUIRED, ++ &value) < 0) ++ return -1; + +- /* coverity[dead_error_begin] */ +- case VIR_DOMAIN_KVM_LAST: +- break; +- } ++ def->kvm_features[feature] = value; + + node = xmlNextElementSibling(node); + } +-- +2.27.0 + diff --git a/virsh-Add-mode-option-to-domdirtyrate-calc-virsh-api.patch b/virsh-Add-mode-option-to-domdirtyrate-calc-virsh-api.patch new file mode 100644 index 0000000000000000000000000000000000000000..e2ce9702dd327c4bdffe6a4f490ec8a7b427f4d0 --- /dev/null +++ b/virsh-Add-mode-option-to-domdirtyrate-calc-virsh-api.patch @@ -0,0 +1,178 @@ +From ff93e58df5e280d0d1b89a09999e001a5b4e1f01 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Hyman=20Huang=28=E9=BB=84=E5=8B=87=29?= + +Date: Sun, 20 Feb 2022 21:28:14 +0800 +Subject: [PATCH] virsh: Add mode option to domdirtyrate-calc virsh api +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Extend domdirtyrate-calc virsh api with mode option, either +of these three options "page-sampling,dirty-bitmap,dirty-ring" +can be specified when calculating dirty page rate. + +Signed-off-by: Hyman Huang(榛勫媷) +Signed-off-by: Michal Privoznik +Reviewed-by: Michal Privoznik +Reviewed-by: Shaokun Wei +--- + docs/manpages/virsh.rst | 7 ++++-- + tools/virsh-completer-domain.c | 19 +++++++++++++++ + tools/virsh-completer-domain.h | 5 ++++ + tools/virsh-domain.c | 42 +++++++++++++++++++++++++++++++++- + tools/virsh-domain.h | 9 ++++++++ + 5 files changed, 79 insertions(+), 3 deletions(-) + +diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst +index d7c8b2dfb2..c5be6dec8c 100644 +--- a/docs/manpages/virsh.rst ++++ b/docs/manpages/virsh.rst +@@ -1704,13 +1704,16 @@ domdirtyrate-calc + :: + + domdirtyrate-calc [--seconds ] ++ --mode=[page-sampling | dirty-bitmap | dirty-ring] + + Calculate an active domain's memory dirty rate which may be expected by + user in order to decide whether it's proper to be migrated out or not. + The ``seconds`` parameter can be used to calculate dirty rate in a + specific time which allows 60s at most now and would be default to 1s +-if missing. The calculated dirty rate information is available by calling +-'domstats --dirtyrate'. ++if missing. These three *page-sampling, dirty-bitmap, dirty-ring* modes ++are mutually exclusive and alternative when specify calculation mode, ++*page-sampling* is the default mode if missing. The calculated dirty ++rate information is available by calling 'domstats --dirtyrate'. + + + domdisplay +diff --git a/tools/virsh-completer-domain.c b/tools/virsh-completer-domain.c +index 7e155d9ee2..c21fcb1941 100644 +--- a/tools/virsh-completer-domain.c ++++ b/tools/virsh-completer-domain.c +@@ -335,3 +335,22 @@ virshDomainHostnameSourceCompleter(vshControl *ctl G_GNUC_UNUSED, + + return ret; + } ++ ++ ++char ** ++virshDomainDirtyRateCalcModeCompleter(vshControl *ctl G_GNUC_UNUSED, ++ const vshCmd *cmd G_GNUC_UNUSED, ++ unsigned int flags) ++{ ++ char **ret = NULL; ++ size_t i; ++ ++ virCheckFlags(0, NULL); ++ ++ ret = g_new0(char *, VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_LAST + 1); ++ ++ for (i = 0; i < VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_LAST; i++) ++ ret[i] = g_strdup(virshDomainDirtyRateCalcModeTypeToString(i)); ++ ++ return ret; ++} +diff --git a/tools/virsh-completer-domain.h b/tools/virsh-completer-domain.h +index b00b05e3bd..95773086f7 100644 +--- a/tools/virsh-completer-domain.h ++++ b/tools/virsh-completer-domain.h +@@ -62,3 +62,8 @@ virshDomainInterfaceAddrSourceCompleter(vshControl *ctl, + char ** virshDomainHostnameSourceCompleter(vshControl *ctl, + const vshCmd *cmd, + unsigned int flags); ++ ++char ** ++virshDomainDirtyRateCalcModeCompleter(vshControl *ctl, ++ const vshCmd *cmd, ++ unsigned int flags); +diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c +index 595a210493..c8bd61d5b7 100644 +--- a/tools/virsh-domain.c ++++ b/tools/virsh-domain.c +@@ -14443,15 +14443,29 @@ static const vshCmdOptDef opts_domdirtyrate_calc[] = { + .help = N_("calculate memory dirty rate within specified seconds, " + "the supported value range from 1 to 60, default to 1.") + }, ++ {.name = "mode", ++ .type = VSH_OT_STRING, ++ .completer = virshDomainDirtyRateCalcModeCompleter, ++ .help = N_("dirty page rate calculation mode, either of these 3 options " ++ "'page-sampling, dirty-bitmap, dirty-ring' can be specified.") ++ }, + {.name = NULL} + }; + ++VIR_ENUM_IMPL(virshDomainDirtyRateCalcMode, ++ VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_LAST, ++ "page-sampling", ++ "dirty-bitmap", ++ "dirty-ring"); ++ + static bool + cmdDomDirtyRateCalc(vshControl *ctl, const vshCmd *cmd) + { + virDomainPtr dom = NULL; + int seconds = 1; /* the default value is 1 */ + bool ret = false; ++ const char *modestr = NULL; ++ unsigned int flags = 0; + + if (!(dom = virshCommandOptDomain(ctl, cmd, NULL))) + return false; +@@ -14459,7 +14473,33 @@ cmdDomDirtyRateCalc(vshControl *ctl, const vshCmd *cmd) + if (vshCommandOptInt(ctl, cmd, "seconds", &seconds) < 0) + goto cleanup; + +- if (virDomainStartDirtyRateCalc(dom, seconds, 0) < 0) ++ if (vshCommandOptStringReq(ctl, cmd, "mode", &modestr) < 0) ++ goto cleanup; ++ ++ if (modestr) { ++ int mode = virshDomainDirtyRateCalcModeTypeFromString(modestr); ++ ++ if (mode < 0) { ++ vshError(ctl, _("Unknown calculation mode '%s'"), modestr); ++ goto cleanup; ++ } ++ ++ switch ((virshDomainDirtyRateCalcMode) mode) { ++ case VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_PAGE_SAMPLING: ++ flags |= VIR_DOMAIN_DIRTYRATE_MODE_PAGE_SAMPLING; ++ break; ++ case VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_DIRTY_BITMAP: ++ flags |= VIR_DOMAIN_DIRTYRATE_MODE_DIRTY_BITMAP; ++ break; ++ case VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_DIRTY_RING: ++ flags |= VIR_DOMAIN_DIRTYRATE_MODE_DIRTY_RING; ++ break; ++ case VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_LAST: ++ break; ++ } ++ } ++ ++ if (virDomainStartDirtyRateCalc(dom, seconds, flags) < 0) + goto cleanup; + + vshPrintExtra(ctl, _("Start to calculate domain's memory " +diff --git a/tools/virsh-domain.h b/tools/virsh-domain.h +index 0d59c579d4..ab6147ca7f 100644 +--- a/tools/virsh-domain.h ++++ b/tools/virsh-domain.h +@@ -38,4 +38,13 @@ typedef enum { + + VIR_ENUM_DECL(virshDomainHostnameSource); + ++typedef enum { ++ VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_PAGE_SAMPLING, ++ VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_DIRTY_BITMAP, ++ VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_DIRTY_RING, ++ VIRSH_DOMAIN_DIRTYRATE_CALC_MODE_LAST, ++} virshDomainDirtyRateCalcMode; ++ ++VIR_ENUM_DECL(virshDomainDirtyRateCalcMode); ++ + extern const vshCmdDef domManagementCmds[]; +-- +2.27.0 + diff --git a/virsh-add-tmm-main-command-word.patch b/virsh-add-tmm-main-command-word.patch new file mode 100644 index 0000000000000000000000000000000000000000..26598c0699b2a92bfc1291c92c7fa2727a08fc37 --- /dev/null +++ b/virsh-add-tmm-main-command-word.patch @@ -0,0 +1,134 @@ +From d9599ee42db6a62cac6ae89c8d246c4c47574d5f Mon Sep 17 00:00:00 2001 +From: tujipei +Date: Wed, 12 Jun 2024 14:34:57 +0800 +Subject: [PATCH] virsh: add tmm main command word Add tmm command word into + virsh tool to call get tmm memory info API. It makes virsh can use tmm main + commmand to show tmm memory info on console. This command requires specific + kernel and a kernel driver to make sure its regular function. If runnning + environment missing the above reliance, this command will show error result + on console. + +Signed-off-by: tujipei +--- + tools/virsh-host.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 99 insertions(+) + +diff --git a/tools/virsh-host.c b/tools/virsh-host.c +index 67d5466be2..4f54cafec7 100644 +--- a/tools/virsh-host.c ++++ b/tools/virsh-host.c +@@ -1799,6 +1799,99 @@ cmdHypervisorCPUBaseline(vshControl *ctl, + return ret; + } + ++/* ++ * "securememinfo" command ++ */ ++ ++static const vshCmdInfo info_tmm[] = { ++ {.name = "help", ++ .data = N_("Interaction with the tmm") ++ }, ++ {.name = "desc", ++ .data = N_("Call the host kernel dev which is provided for virsh to use receiving tmm informations.") ++ }, ++ {.name = NULL} ++}; ++ ++static const vshCmdOptDef opts_tmm[] = { ++ {.name = "dev", ++ .type = VSH_OT_DATA, ++ .flags = VSH_OFLAG_REQ, ++ .help = N_("Device name of host kernel dev") ++ }, ++ {.name = "detail", ++ .type = VSH_OT_BOOL, ++ .help = N_("print detailed info if this option contained in cmd") ++ }, ++ {.name = NULL} ++}; ++ ++static bool ++virshGetTmmMemoryInfo(vshControl *ctl, ++ const vshCmd *cmd) ++{ ++ char *tmmMemoryInfo = NULL; ++ bool detail; ++ virshControlPtr priv = ctl->privData; ++ ++ detail = vshCommandOptBool(cmd, "detail"); ++ if (!(tmmMemoryInfo = virConnectGetTmmMemoryInfo(priv->conn, (unsigned int)detail))) { ++ vshError(ctl, _("Get tmm_memory_info failed")); ++ return false; ++ } ++ ++ vshPrintExtra(ctl, _("%s"), tmmMemoryInfo); ++ ++ VIR_FREE(tmmMemoryInfo); ++ return true; ++} ++ ++typedef bool ++(*virshTmmFunc)(vshControl *ctl, ++ const vshCmd *cmd); ++ ++struct _virshTmmFuncInfo { ++ const char *devName; ++ virshTmmFunc funcPtr; ++}; ++ ++typedef struct _virshTmmFuncInfo virshTmmFuncInfo; ++ ++static virshTmmFuncInfo virshTmmFuncMap[] = { ++ {"tmm_memory_info", virshGetTmmMemoryInfo}, ++}; ++ ++static bool ++virshTmmRunFunc(vshControl *ctl, ++ const char *devName, ++ const vshCmd *cmd) ++{ ++ int funcIndex; ++ ++ for (funcIndex = 0; funcIndex < sizeof(virshTmmFuncMap) / sizeof(virshTmmFuncInfo); funcIndex++) { ++ if (strcmp(devName, virshTmmFuncMap[funcIndex].devName) == 0) { ++ virshTmmFuncMap[funcIndex].funcPtr(ctl, cmd); ++ return true; ++ } ++ } ++ ++ vshError(ctl, _("Invalid dev name")); ++ return false; ++} ++ ++static bool ++cmdTmm(vshControl *ctl, const vshCmd *cmd) ++{ ++ const char *devName = NULL; ++ ++ if (vshCommandOptStringReq(ctl, cmd, "dev", &devName) < 0) ++ return false; ++ ++ if (!virshTmmRunFunc(ctl, devName, cmd)) ++ return false; ++ ++ return true; ++} + + const vshCmdDef hostAndHypervisorCmds[] = { + {.name = "allocpages", +@@ -1927,5 +2020,11 @@ const vshCmdDef hostAndHypervisorCmds[] = { + .info = info_version, + .flags = 0 + }, ++ {.name = "tmm", ++ .handler = cmdTmm, ++ .opts = opts_tmm, ++ .info = info_tmm, ++ .flags = 0 ++ }, + {.name = NULL} + }; +-- +2.27.0 + diff --git a/virxml-Add-virXMLPropInt.patch b/virxml-Add-virXMLPropInt.patch new file mode 100644 index 0000000000000000000000000000000000000000..2b541c585f5a66cde0aedc86ad53233180e3f360 --- /dev/null +++ b/virxml-Add-virXMLPropInt.patch @@ -0,0 +1,122 @@ +From 0d94495d109537d7d266071e42e13de9a1539752 Mon Sep 17 00:00:00 2001 +From: Tim Wiederhake +Date: Fri, 16 Apr 2021 11:41:47 +0200 +Subject: [PATCH] virxml: Add virXMLPropInt + +Convenience function to return the value of an integer XML attribute. + +Signed-off-by: Tim Wiederhake +Reviewed-by: Peter Krempa +Reviewed-by: Shaokun Wei +--- + src/libvirt_private.syms | 1 + + src/util/virxml.c | 53 ++++++++++++++++++++++++++++++++++++++++ + src/util/virxml.h | 9 +++++++ + 3 files changed, 63 insertions(+) + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index 15924e69a5..4720bb0ab0 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -3480,6 +3480,7 @@ virXMLNodeSanitizeNamespaces; + virXMLNodeToString; + virXMLParseHelper; + virXMLPickShellSafeComment; ++virXMLPropInt; + virXMLPropString; + virXMLPropStringLimit; + virXMLPropTristateBool; +diff --git a/src/util/virxml.c b/src/util/virxml.c +index b7f8063497..f6f028896e 100644 +--- a/src/util/virxml.c ++++ b/src/util/virxml.c +@@ -647,6 +647,59 @@ virXMLPropTristateSwitch(xmlNodePtr node, + } + + ++/** ++ * virXMLPropInt: ++ * @node: XML dom node pointer ++ * @name: Name of the property (attribute) to get ++ * @base: Number base, see strtol ++ * @flags: Bitwise or of virXMLPropFlags ++ * @result: The returned value ++ * ++ * Convenience function to return value of an integer attribute. ++ * ++ * Returns 1 in case of success in which case @result is set, ++ * or 0 if the attribute is not present, ++ * or -1 and reports an error on failure. ++ */ ++int ++virXMLPropInt(xmlNodePtr node, ++ const char *name, ++ int base, ++ virXMLPropFlags flags, ++ int *result) ++{ ++ g_autofree char *tmp = NULL; ++ int val; ++ ++ if (!(tmp = virXMLPropString(node, name))) { ++ if (!(flags & VIR_XML_PROP_REQUIRED)) ++ return 0; ++ ++ virReportError(VIR_ERR_XML_ERROR, ++ _("Missing required attribute '%s' in element '%s'"), ++ name, node->name); ++ return -1; ++ } ++ ++ if (virStrToLong_i(tmp, NULL, base, &val) < 0) { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("Invalid value for attribute '%s' in element '%s': '%s'. Expected integer value"), ++ name, node->name, tmp); ++ return -1; ++ } ++ ++ if ((flags & VIR_XML_PROP_NONZERO) && (val == 0)) { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("Invalid value for attribute '%s' in element '%s': Zero is not permitted"), ++ name, node->name); ++ return -1; ++ } ++ ++ *result = val; ++ return 1; ++} ++ ++ + /** + * virXPathBoolean: + * @xpath: the XPath string to evaluate +diff --git a/src/util/virxml.h b/src/util/virxml.h +index 0cf293d5ae..28538fe035 100644 +--- a/src/util/virxml.h ++++ b/src/util/virxml.h +@@ -37,6 +37,7 @@ xmlXPathContextPtr virXMLXPathContextNew(xmlDocPtr xml) + typedef enum { + VIR_XML_PROP_OPTIONAL = 0, /* Attribute may be absent */ + VIR_XML_PROP_REQUIRED = 1 << 0, /* Attribute may not be absent */ ++ VIR_XML_PROP_NONZERO = 1 << 1, /* Attribute may not be zero */ + } virXMLPropFlags; + + +@@ -101,6 +102,14 @@ virXMLPropTristateSwitch(xmlNodePtr node, + virTristateSwitch *result) + ATTRIBUTE_NONNULL(0) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); + ++int ++virXMLPropInt(xmlNodePtr node, ++ const char *name, ++ int base, ++ virXMLPropFlags flags, ++ int *result) ++ ATTRIBUTE_NONNULL(0) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4); ++ + /* Internal function; prefer the macros below. */ + xmlDocPtr virXMLParseHelper(int domcode, + const char *filename, +-- +2.27.0 + diff --git a/virxml-Add-virXMLPropTristateBool.patch b/virxml-Add-virXMLPropTristateBool.patch new file mode 100644 index 0000000000000000000000000000000000000000..b5777b1969e0a915d83b7647d18496f03ee2fe14 --- /dev/null +++ b/virxml-Add-virXMLPropTristateBool.patch @@ -0,0 +1,123 @@ +From a664916fd2d121a7aa733fac05bbdbf1d4ac2248 Mon Sep 17 00:00:00 2001 +From: Tim Wiederhake +Date: Fri, 16 Apr 2021 11:41:45 +0200 +Subject: [PATCH] virxml: Add virXMLPropTristateBool + +Convenience function to return the value of a yes / no XML attribute. + +Signed-off-by: Tim Wiederhake +Reviewed-by: Peter Krempa +Reviewed-by: Shaokun Wei +--- + src/libvirt_private.syms | 1 + + src/util/virxml.c | 44 ++++++++++++++++++++++++++++++++++++++++ + src/util/virxml.h | 15 ++++++++++++++ + 3 files changed, 60 insertions(+) + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index a00e354859..42b3700d57 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -3482,6 +3482,7 @@ virXMLParseHelper; + virXMLPickShellSafeComment; + virXMLPropString; + virXMLPropStringLimit; ++virXMLPropTristateBool; + virXMLSaveFile; + virXMLValidateAgainstSchema; + virXMLValidatorFree; +diff --git a/src/util/virxml.c b/src/util/virxml.c +index 9ea7b99dba..a1fe319e08 100644 +--- a/src/util/virxml.c ++++ b/src/util/virxml.c +@@ -559,6 +559,50 @@ virXMLNodeContentString(xmlNodePtr node) + } + + ++/** ++ * virXMLPropTristateBool: ++ * @node: XML dom node pointer ++ * @name: Name of the property (attribute) to get ++ * @flags: Bitwise or of virXMLPropFlags ++ * @result: The returned value ++ * ++ * Convenience function to return value of a yes / no attribute. ++ * ++ * Returns 1 in case of success in which case @result is set, ++ * or 0 if the attribute is not present, ++ * or -1 and reports an error on failure. ++ */ ++int ++virXMLPropTristateBool(xmlNodePtr node, ++ const char* name, ++ virXMLPropFlags flags, ++ virTristateBool *result) ++{ ++ g_autofree char *tmp = NULL; ++ int val; ++ ++ if (!(tmp = virXMLPropString(node, name))) { ++ if (!(flags & VIR_XML_PROP_REQUIRED)) ++ return 0; ++ ++ virReportError(VIR_ERR_XML_ERROR, ++ _("Missing required attribute '%s' in element '%s'"), ++ name, node->name); ++ return -1; ++ } ++ ++ if ((val = virTristateBoolTypeFromString(tmp)) <= 0) { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("Invalid value for attribute '%s' in element '%s': '%s'. Expected 'yes' or 'no'"), ++ name, node->name, tmp); ++ return -1; ++ } ++ ++ *result = val; ++ return 1; ++} ++ ++ + /** + * virXPathBoolean: + * @xpath: the XPath string to evaluate +diff --git a/src/util/virxml.h b/src/util/virxml.h +index 26ab9f9c2d..1d7070b98f 100644 +--- a/src/util/virxml.h ++++ b/src/util/virxml.h +@@ -28,10 +28,18 @@ + #include + + #include "virbuffer.h" ++#include "virenum.h" + + xmlXPathContextPtr virXMLXPathContextNew(xmlDocPtr xml) + G_GNUC_WARN_UNUSED_RESULT; + ++ ++typedef enum { ++ VIR_XML_PROP_OPTIONAL = 0, /* Attribute may be absent */ ++ VIR_XML_PROP_REQUIRED = 1 << 0, /* Attribute may not be absent */ ++} virXMLPropFlags; ++ ++ + int virXPathBoolean(const char *xpath, + xmlXPathContextPtr ctxt); + char * virXPathString(const char *xpath, +@@ -79,6 +87,13 @@ char * virXMLPropStringLimit(xmlNodePtr node, + char * virXMLNodeContentString(xmlNodePtr node); + long virXMLChildElementCount(xmlNodePtr node); + ++int ++virXMLPropTristateBool(xmlNodePtr node, ++ const char *name, ++ virXMLPropFlags flags, ++ virTristateBool *result) ++ ATTRIBUTE_NONNULL(0) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); ++ + /* Internal function; prefer the macros below. */ + xmlDocPtr virXMLParseHelper(int domcode, + const char *filename, +-- +2.27.0 + diff --git a/virxml-Add-virXMLPropTristateSwitch.patch b/virxml-Add-virXMLPropTristateSwitch.patch new file mode 100644 index 0000000000000000000000000000000000000000..d34576441de3c980ac1ba6f3338e6883b6dff53e --- /dev/null +++ b/virxml-Add-virXMLPropTristateSwitch.patch @@ -0,0 +1,104 @@ +From 78bfdbe8b72eb81fbe1e96b1e94a07a5944b0e97 Mon Sep 17 00:00:00 2001 +From: Tim Wiederhake +Date: Fri, 16 Apr 2021 11:41:46 +0200 +Subject: [PATCH] virxml: Add virXMLPropTristateSwitch + +Convenience function to return the value of an on / off XML attribute. + +Signed-off-by: Tim Wiederhake +Reviewed-by: Peter Krempa +Reviewed-by: Shaokun Wei +--- + src/libvirt_private.syms | 1 + + src/util/virxml.c | 44 ++++++++++++++++++++++++++++++++++++++++ + src/util/virxml.h | 7 +++++++ + 3 files changed, 52 insertions(+) + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index 42b3700d57..15924e69a5 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -3483,6 +3483,7 @@ virXMLPickShellSafeComment; + virXMLPropString; + virXMLPropStringLimit; + virXMLPropTristateBool; ++virXMLPropTristateSwitch; + virXMLSaveFile; + virXMLValidateAgainstSchema; + virXMLValidatorFree; +diff --git a/src/util/virxml.c b/src/util/virxml.c +index a1fe319e08..b7f8063497 100644 +--- a/src/util/virxml.c ++++ b/src/util/virxml.c +@@ -603,6 +603,50 @@ virXMLPropTristateBool(xmlNodePtr node, + } + + ++/** ++ * virXMLPropTristateSwitch: ++ * @node: XML dom node pointer ++ * @name: Name of the property (attribute) to get ++ * @flags: Bitwise or of virXMLPropFlags ++ * @result: The returned value ++ * ++ * Convenience function to return value of an on / off attribute. ++ * ++ * Returns 1 in case of success in which case @result is set, ++ * or 0 if the attribute is not present, ++ * or -1 and reports an error on failure. ++ */ ++int ++virXMLPropTristateSwitch(xmlNodePtr node, ++ const char* name, ++ virXMLPropFlags flags, ++ virTristateSwitch *result) ++{ ++ g_autofree char *tmp = NULL; ++ int val; ++ ++ if (!(tmp = virXMLPropString(node, name))) { ++ if (!(flags & VIR_XML_PROP_REQUIRED)) ++ return 0; ++ ++ virReportError(VIR_ERR_XML_ERROR, ++ _("Missing required attribute '%s' in element '%s'"), ++ name, node->name); ++ return -1; ++ } ++ ++ if ((val = virTristateSwitchTypeFromString(tmp)) <= 0) { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("Invalid value for attribute '%s' in element '%s': '%s'. Expected 'on' or 'off'"), ++ name, node->name, tmp); ++ return -1; ++ } ++ ++ *result = val; ++ return 1; ++} ++ ++ + /** + * virXPathBoolean: + * @xpath: the XPath string to evaluate +diff --git a/src/util/virxml.h b/src/util/virxml.h +index 1d7070b98f..0cf293d5ae 100644 +--- a/src/util/virxml.h ++++ b/src/util/virxml.h +@@ -94,6 +94,13 @@ virXMLPropTristateBool(xmlNodePtr node, + virTristateBool *result) + ATTRIBUTE_NONNULL(0) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); + ++int ++virXMLPropTristateSwitch(xmlNodePtr node, ++ const char *name, ++ virXMLPropFlags flags, ++ virTristateSwitch *result) ++ ATTRIBUTE_NONNULL(0) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(3); ++ + /* Internal function; prefer the macros below. */ + xmlDocPtr virXMLParseHelper(int domcode, + const char *filename, +-- +2.27.0 + diff --git a/virxml-Add-virXMLPropUInt.patch b/virxml-Add-virXMLPropUInt.patch new file mode 100644 index 0000000000000000000000000000000000000000..4884303029d5d7a66d9bdcb49de3a430820ce74d --- /dev/null +++ b/virxml-Add-virXMLPropUInt.patch @@ -0,0 +1,129 @@ +From 122ef42d1d0e1d2d66968ab1e038926261e28e22 Mon Sep 17 00:00:00 2001 +From: Tim Wiederhake +Date: Fri, 16 Apr 2021 11:41:48 +0200 +Subject: [PATCH] virxml: Add virXMLPropUInt + +Convenience function to return the value of an unsigned integer XML attribute. + +Signed-off-by: Tim Wiederhake +Reviewed-by: Peter Krempa +Reviewed-by: Shaokun Wei +--- + src/libvirt_private.syms | 1 + + src/util/virxml.c | 60 ++++++++++++++++++++++++++++++++++++++++ + src/util/virxml.h | 9 ++++++ + 3 files changed, 70 insertions(+) + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index 4720bb0ab0..82d720c7c1 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -3485,6 +3485,7 @@ virXMLPropString; + virXMLPropStringLimit; + virXMLPropTristateBool; + virXMLPropTristateSwitch; ++virXMLPropUInt; + virXMLSaveFile; + virXMLValidateAgainstSchema; + virXMLValidatorFree; +diff --git a/src/util/virxml.c b/src/util/virxml.c +index f6f028896e..de86ce3d2b 100644 +--- a/src/util/virxml.c ++++ b/src/util/virxml.c +@@ -700,6 +700,66 @@ virXMLPropInt(xmlNodePtr node, + } + + ++/** ++ * virXMLPropUInt: ++ * @node: XML dom node pointer ++ * @name: Name of the property (attribute) to get ++ * @base: Number base, see strtol ++ * @flags: Bitwise or of virXMLPropFlags ++ * @result: The returned value ++ * ++ * Convenience function to return value of an unsigned integer attribute. ++ * ++ * Returns 1 in case of success in which case @result is set, ++ * or 0 if the attribute is not present, ++ * or -1 and reports an error on failure. ++ */ ++int ++virXMLPropUInt(xmlNodePtr node, ++ const char* name, ++ int base, ++ virXMLPropFlags flags, ++ unsigned int *result) ++{ ++ g_autofree char *tmp = NULL; ++ int ret; ++ unsigned int val; ++ ++ if (!(tmp = virXMLPropString(node, name))) { ++ if (!(flags & VIR_XML_PROP_REQUIRED)) ++ return 0; ++ ++ virReportError(VIR_ERR_XML_ERROR, ++ _("Missing required attribute '%s' in element '%s'"), ++ name, node->name); ++ return -1; ++ } ++ ++ if (flags & VIR_XML_PROP_WRAPNEGATIVE) { ++ ret = virStrToLong_ui(tmp, NULL, base, &val); ++ } else { ++ ret = virStrToLong_uip(tmp, NULL, base, &val); ++ } ++ ++ if (ret < 0) { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("Invalid value for attribute '%s' in element '%s': '%s'. Expected integer value"), ++ name, node->name, tmp); ++ return -1; ++ } ++ ++ if ((flags & VIR_XML_PROP_NONZERO) && (val == 0)) { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("Invalid value for attribute '%s' in element '%s': Zero is not permitted"), ++ name, node->name); ++ return -1; ++ } ++ ++ *result = val; ++ return 1; ++} ++ ++ + /** + * virXPathBoolean: + * @xpath: the XPath string to evaluate +diff --git a/src/util/virxml.h b/src/util/virxml.h +index 28538fe035..d953743ab1 100644 +--- a/src/util/virxml.h ++++ b/src/util/virxml.h +@@ -38,6 +38,7 @@ typedef enum { + VIR_XML_PROP_OPTIONAL = 0, /* Attribute may be absent */ + VIR_XML_PROP_REQUIRED = 1 << 0, /* Attribute may not be absent */ + VIR_XML_PROP_NONZERO = 1 << 1, /* Attribute may not be zero */ ++ VIR_XML_PROP_WRAPNEGATIVE = 1 << 2, /* Wrap around negative values */ + } virXMLPropFlags; + + +@@ -110,6 +111,14 @@ virXMLPropInt(xmlNodePtr node, + int *result) + ATTRIBUTE_NONNULL(0) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4); + ++int ++virXMLPropUInt(xmlNodePtr node, ++ const char* name, ++ int base, ++ virXMLPropFlags flags, ++ unsigned int *result) ++ ATTRIBUTE_NONNULL(0) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4); ++ + /* Internal function; prefer the macros below. */ + xmlDocPtr virXMLParseHelper(int domcode, + const char *filename, +-- +2.27.0 +