diff --git a/libvirt-esx-Abstract-all-URL-creation-code-into-one-function.patch b/libvirt-esx-Abstract-all-URL-creation-code-into-one-function.patch new file mode 100644 index 0000000..a6aebca --- /dev/null +++ b/libvirt-esx-Abstract-all-URL-creation-code-into-one-function.patch @@ -0,0 +1,119 @@ +From 95ff5dcad20269f8e26eda628c85168dd4702285 Mon Sep 17 00:00:00 2001 +Message-ID: <95ff5dcad20269f8e26eda628c85168dd4702285.1769699749.git.jdenemar@redhat.com> +From: "Richard W.M. Jones" +Date: Mon, 26 Jan 2026 10:47:01 +0000 +Subject: [PATCH] esx: Abstract all URL-creation code into one function + +Abstract the places where we create URLs into one place. This is just +refactoring and should not change the behaviour. + +Signed-off-by: Richard W.M. Jones +(cherry picked from commit e013d5b5cae732ddeae479098165b9331b8ea441) +Resolves: https://issues.redhat.com/browse/RHEL-138300 +Signed-off-by: Michal Privoznik +--- + src/esx/esx_driver.c | 53 +++++++++++++++++++++++++++++++++++--------- + 1 file changed, 43 insertions(+), 10 deletions(-) + +diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c +index 9f965811b1..29735e359f 100644 +--- a/src/esx/esx_driver.c ++++ b/src/esx/esx_driver.c +@@ -582,7 +582,37 @@ esxCapsInit(esxPrivate *priv) + return NULL; + } + ++static char * ++esxCreateURL(const char *transport, ++ const char *server, ++ int port, ++ const char *path) ++{ ++ char *url; + ++ url = g_strdup_printf("%s://%s:%d%s", ++ transport, ++ server, ++ port, ++ path); ++ return url; ++} ++ ++/* ++ * Same as above, but add it to a buffer because the calling code will ++ * append query strings etc. ++ */ ++static void ++esxCreateURLBuffer(virBuffer *buffer, ++ const char *transport, ++ const char *server, ++ int port, ++ const char *path) ++{ ++ g_autofree char *url = esxCreateURL(transport, server, port, path); ++ ++ virBufferAdd(buffer, url, -1); ++} + + static int + esxConnectToHost(esxPrivate *priv, +@@ -619,8 +649,8 @@ esxConnectToHost(esxPrivate *priv, + conn->uri->server))) + goto cleanup; + +- url = g_strdup_printf("%s://%s:%d/sdk", priv->parsedUri->transport, +- conn->uri->server, conn->uri->port); ++ url = esxCreateURL(priv->parsedUri->transport, ++ conn->uri->server, conn->uri->port, "/sdk"); + + if (esxVI_Context_Alloc(&priv->host) < 0 || + esxVI_Context_Connect(priv->host, url, ipAddress, username, password, +@@ -706,8 +736,8 @@ esxConnectToVCenter(esxPrivate *priv, + if (!(password = virAuthGetPassword(conn, auth, "esx", username, hostname))) + return -1; + +- url = g_strdup_printf("%s://%s:%d/sdk", priv->parsedUri->transport, hostname, +- conn->uri->port); ++ url = esxCreateURL(priv->parsedUri->transport, hostname, ++ conn->uri->port, "/sdk"); + + if (esxVI_Context_Alloc(&priv->vCenter) < 0 || + esxVI_Context_Connect(priv->vCenter, url, ipAddress, username, +@@ -2357,8 +2387,9 @@ esxDomainScreenshot(virDomainPtr domain, virStreamPtr stream, + } + + /* Build URL */ +- virBufferAsprintf(&buffer, "%s://%s:%d/screen?id=", priv->parsedUri->transport, +- domain->conn->uri->server, domain->conn->uri->port); ++ esxCreateURLBuffer(&buffer, priv->parsedUri->transport, ++ domain->conn->uri->server, domain->conn->uri->port, ++ "/screen?id="); + virBufferURIEncodeString(&buffer, virtualMachine->obj->value); + + url = virBufferContentAndReset(&buffer); +@@ -2563,8 +2594,9 @@ esxDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) + goto cleanup; + } + +- virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport, +- domain->conn->uri->server, domain->conn->uri->port); ++ esxCreateURLBuffer(&buffer, priv->parsedUri->transport, ++ domain->conn->uri->server, domain->conn->uri->port, ++ "/folder/"); + virBufferURIEncodeString(&buffer, directoryAndFileName); + virBufferAddLit(&buffer, "?dcPath="); + virBufferURIEncodeString(&buffer, priv->primary->datacenterPath); +@@ -2987,8 +3019,9 @@ esxDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags) + goto cleanup; + } + +- virBufferAsprintf(&buffer, "%s://%s:%d/folder/", priv->parsedUri->transport, +- conn->uri->server, conn->uri->port); ++ esxCreateURLBuffer(&buffer, priv->parsedUri->transport, ++ conn->uri->server, conn->uri->port, ++ "/folder/"); + + if (directoryName) { + virBufferURIEncodeString(&buffer, directoryName); +-- +2.52.0 diff --git a/libvirt-esx-Debug-URL-just-before-opening-with-curl.patch b/libvirt-esx-Debug-URL-just-before-opening-with-curl.patch new file mode 100644 index 0000000..a8233ef --- /dev/null +++ b/libvirt-esx-Debug-URL-just-before-opening-with-curl.patch @@ -0,0 +1,29 @@ +From 0e5f062ba33929bc592fff175a2cd9d043a32b23 Mon Sep 17 00:00:00 2001 +Message-ID: <0e5f062ba33929bc592fff175a2cd9d043a32b23.1769699749.git.jdenemar@redhat.com> +From: "Richard W.M. Jones" +Date: Mon, 26 Jan 2026 10:38:02 +0000 +Subject: [PATCH] esx: Debug URL just before opening with curl + +Signed-off-by: Richard W.M. Jones +(cherry picked from commit 38c952d89317f5b4bd23223f9a9d8be086ef7a40) +Resolves: https://issues.redhat.com/browse/RHEL-138300 +Signed-off-by: Michal Privoznik +--- + src/esx/esx_vi.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/esx/esx_vi.c b/src/esx/esx_vi.c +index 3264afc13a..8d2ffb3f8f 100644 +--- a/src/esx/esx_vi.c ++++ b/src/esx/esx_vi.c +@@ -231,6 +231,8 @@ esxVI_CURL_Perform(esxVI_CURL *curl, const char *url) + long responseCode = 0; + const char *redirectUrl = NULL; + ++ VIR_DEBUG("URL: %s", url); ++ + errorCode = curl_easy_perform(curl->handle); + + if (errorCode != CURLE_OK) { +-- +2.52.0 diff --git a/libvirt-esx-Switch-to-creating-URLs-using-virURIFormat.patch b/libvirt-esx-Switch-to-creating-URLs-using-virURIFormat.patch new file mode 100644 index 0000000..a990628 --- /dev/null +++ b/libvirt-esx-Switch-to-creating-URLs-using-virURIFormat.patch @@ -0,0 +1,57 @@ +From 1ac21634942d30288dd11005d1d832b8dda86ceb Mon Sep 17 00:00:00 2001 +Message-ID: <1ac21634942d30288dd11005d1d832b8dda86ceb.1769699749.git.jdenemar@redhat.com> +From: "Richard W.M. Jones" +Date: Mon, 26 Jan 2026 17:54:57 +0000 +Subject: [PATCH] esx: Switch to creating URLs using virURIFormat +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since libvirt has existing support for creating URIs, use that rather +than home-rolling our own code without any escaping. + +As a side-effect this ensures that URLs containing IPv6 addresses are +escaped correctly, for example as below (note square brackets): + + https://[1234:56:0:789a:bcde:72ff:fe0a:7baa]:443/sdk + +Fixes: https://issues.redhat.com/browse/RHEL-138300 +Updates: commit 845210011a9ffd9d17e30c51cbc81ba67c5d3166 +Reported-by: Ming Xie +Signed-off-by: Richard W.M. Jones +Reviewed-by: Daniel P. Berrangé +(cherry picked from commit 13889feb14a24fdf7717960aa5331a0b63ce97ed) +Resolves: https://issues.redhat.com/browse/RHEL-138300 +Signed-off-by: Michal Privoznik +--- + src/esx/esx_driver.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c +index 29735e359f..40b7f793cd 100644 +--- a/src/esx/esx_driver.c ++++ b/src/esx/esx_driver.c +@@ -588,14 +588,14 @@ esxCreateURL(const char *transport, + int port, + const char *path) + { +- char *url; ++ virURI uri = { ++ .scheme = (char*)transport, ++ .server = (char*)server, ++ .port = port, ++ .path = (char*)path, ++ }; + +- url = g_strdup_printf("%s://%s:%d%s", +- transport, +- server, +- port, +- path); +- return url; ++ return virURIFormat(&uri); + } + + /* +-- +2.52.0 diff --git a/libvirt-esx-URI-encode-inventory-objects-twice.patch b/libvirt-esx-URI-encode-inventory-objects-twice.patch new file mode 100644 index 0000000..c775ab9 --- /dev/null +++ b/libvirt-esx-URI-encode-inventory-objects-twice.patch @@ -0,0 +1,60 @@ +From 1ff41e00c1d0a280b22ba4f8bf4e86472570486a Mon Sep 17 00:00:00 2001 +Message-ID: <1ff41e00c1d0a280b22ba4f8bf4e86472570486a.1769699749.git.jdenemar@redhat.com> +From: Michal Privoznik +Date: Tue, 6 Jan 2026 17:18:03 +0100 +Subject: [PATCH] esx: URI encode inventory objects twice + +While discouraged by a KB article to use special characters in +inventory object names [1], ESX won't stop you. And thus users +can end up with a datastore named "datastore2+", for instance. +The datastore name (and datacenter path) are important when +fetching/uploading a .vmx file (used in APIs like +virDomainGetXMLDesc() or virDomainDefineXML()). And while we do +URI encode both (dcPath and dsName), encoding them once is not +enough. Cole Robinson discovered [2] that they need to be +URI-encoded twice. Use newly introduced +esxUtil_EscapeInventoryObject() helper to encode them twice. + +1: https://knowledge.broadcom.com/external/article/386368/vcenter-inventory-object-name-with-speci.html +2: https://issues.redhat.com/browse/RHEL-133729#comment-28604072 +Resolves: https://issues.redhat.com/browse/RHEL-134127 +Signed-off-by: Michal Privoznik +Reviewed-by: Jiri Denemark +Reviewed-by: Richard W.M. Jones +(cherry picked from commit 6c9d2591c668732eb05cf17d27c9102ef3d40b39) +Resolves: https://issues.redhat.com/browse/RHEL-140196 +Signed-off-by: Michal Privoznik +--- + src/esx/esx_driver.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/esx/esx_driver.c b/src/esx/esx_driver.c +index 40b7f793cd..010c62b8e8 100644 +--- a/src/esx/esx_driver.c ++++ b/src/esx/esx_driver.c +@@ -2599,9 +2599,9 @@ esxDomainGetXMLDesc(virDomainPtr domain, unsigned int flags) + "/folder/"); + virBufferURIEncodeString(&buffer, directoryAndFileName); + virBufferAddLit(&buffer, "?dcPath="); +- virBufferURIEncodeString(&buffer, priv->primary->datacenterPath); ++ esxUtil_EscapeInventoryObject(&buffer, priv->primary->datacenterPath); + virBufferAddLit(&buffer, "&dsName="); +- virBufferURIEncodeString(&buffer, datastoreName); ++ esxUtil_EscapeInventoryObject(&buffer, datastoreName); + + url = virBufferContentAndReset(&buffer); + +@@ -3035,9 +3035,9 @@ esxDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags) + + virBufferURIEncodeString(&buffer, escapedName); + virBufferAddLit(&buffer, ".vmx?dcPath="); +- virBufferURIEncodeString(&buffer, priv->primary->datacenterPath); ++ esxUtil_EscapeInventoryObject(&buffer, priv->primary->datacenterPath); + virBufferAddLit(&buffer, "&dsName="); +- virBufferURIEncodeString(&buffer, datastoreName); ++ esxUtil_EscapeInventoryObject(&buffer, datastoreName); + + url = virBufferContentAndReset(&buffer); + +-- +2.52.0 diff --git a/libvirt-esx_util-Introduce-esxUtil_EscapeInventoryObject.patch b/libvirt-esx_util-Introduce-esxUtil_EscapeInventoryObject.patch new file mode 100644 index 0000000..34b11ba --- /dev/null +++ b/libvirt-esx_util-Introduce-esxUtil_EscapeInventoryObject.patch @@ -0,0 +1,76 @@ +From 0776d3a966522785927456bf85037503a9d85bd7 Mon Sep 17 00:00:00 2001 +Message-ID: <0776d3a966522785927456bf85037503a9d85bd7.1769699749.git.jdenemar@redhat.com> +From: Michal Privoznik +Date: Wed, 7 Jan 2026 10:34:25 +0100 +Subject: [PATCH] esx_util: Introduce esxUtil_EscapeInventoryObject() + +The aim of this helper function is to URI-encode given string +twice. There's a bug (fixed in next commit) in which we're unable +to fetch .vmx file for a domain if corresponding datastore +contains some special characters (like +). Cole Robinson +discovered that encoding datastore twice enables libvirt to work +around the issue [2]. Well, this function does exactly that. +It was tested with the following inputs and all worked +flawlessly: "datastore", "datastore2", "datastore2+", +"datastore3+-@", "data store2+". + +1: https://issues.redhat.com/browse/RHEL-134127 +2: https://issues.redhat.com/browse/RHEL-133729#comment-28604072 + +Signed-off-by: Michal Privoznik +Reviewed-by: Jiri Denemark +Reviewed-by: Richard W.M. Jones +(cherry picked from commit ffe74c7c551bd641cbcaa2512ed0ad4a25d3980b) +Resolves: https://issues.redhat.com/browse/RHEL-140196 +Signed-off-by: Michal Privoznik +--- + src/esx/esx_util.c | 18 ++++++++++++++++++ + src/esx/esx_util.h | 3 +++ + 2 files changed, 21 insertions(+) + +diff --git a/src/esx/esx_util.c b/src/esx/esx_util.c +index 12a34a2275..963bcd0a75 100644 +--- a/src/esx/esx_util.c ++++ b/src/esx/esx_util.c +@@ -448,3 +448,21 @@ esxUtil_EscapeForXml(const char *string) + + return virBufferContentAndReset(&buffer); + } ++ ++ ++/* esxUtil_EscapeInventoryObject: ++ * @buf: the buffer to append to ++ * @string: the string argument which will be URI-encoded ++ * ++ * URI-encode given @string TWICE and append the result to the @buf. This is ++ * to be used with inventory objects (like 'dcPath' and 'dsName') to work ++ * around a VMware bug in which once round of URI-encoding is not enough. ++ */ ++void ++esxUtil_EscapeInventoryObject(virBuffer *buf, const char *string) ++{ ++ g_autoptr(GString) escaped = g_string_new(NULL); ++ ++ g_string_append_uri_escaped(escaped, string, NULL, false); ++ virBufferURIEncodeString(buf, escaped->str); ++} +diff --git a/src/esx/esx_util.h b/src/esx/esx_util.h +index 58bc44e744..29f01e0c15 100644 +--- a/src/esx/esx_util.h ++++ b/src/esx/esx_util.h +@@ -22,6 +22,7 @@ + #pragma once + + #include "internal.h" ++#include "virbuffer.h" + #include "viruri.h" + + #define ESX_VI_CHECK_ARG_LIST(val) \ +@@ -67,3 +68,5 @@ void esxUtil_ReplaceSpecialWindowsPathChars(char *string); + char *esxUtil_EscapeDatastoreItem(const char *string); + + char *esxUtil_EscapeForXml(const char *string); ++ ++void esxUtil_EscapeInventoryObject(virBuffer *buf, const char *string); +-- +2.52.0 diff --git a/libvirt-qemuDomainSetBlockIoTuneField-Move-setting-of-group_name-out-of-the-loop.patch b/libvirt-qemuDomainSetBlockIoTuneField-Move-setting-of-group_name-out-of-the-loop.patch new file mode 100644 index 0000000..a87a353 --- /dev/null +++ b/libvirt-qemuDomainSetBlockIoTuneField-Move-setting-of-group_name-out-of-the-loop.patch @@ -0,0 +1,68 @@ +From 2f60aff267af628839c90fe36cacbc9d5057509a Mon Sep 17 00:00:00 2001 +Message-ID: <2f60aff267af628839c90fe36cacbc9d5057509a.1769699749.git.jdenemar@redhat.com> +From: Peter Krempa +Date: Fri, 16 Jan 2026 16:38:38 +0100 +Subject: [PATCH] qemuDomainSetBlockIoTuneField: Move setting of 'group_name' + out of the loop + +The refactor will simplify further change which will introduce another +source for the group name. + +Signed-off-by: Peter Krempa +Reviewed-by: Michal Privoznik +(cherry picked from commit fa064375668df0e67b4d68fdfc4a386862026f3f) + +https://issues.redhat.com/browse/RHEL-141820 [rhel-10.2] +https://issues.redhat.com/browse/RHEL-144010 [rhel-9.8] +--- + src/qemu/qemu_driver.c | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index 194017a29a..ecfb65c535 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -15173,6 +15173,7 @@ qemuDomainSetBlockIoTuneFields(virDomainBlockIoTuneInfo *info, + int *eventNparams, + int *eventMaxparams) + { ++ const char *param_group_name = NULL; + size_t i; + + #define SET_IOTUNE_FIELD(FIELD, BOOL, CONST) \ +@@ -15218,15 +15219,8 @@ qemuDomainSetBlockIoTuneFields(virDomainBlockIoTuneInfo *info, + WRITE_IOPS_SEC_MAX); + SET_IOTUNE_FIELD(size_iops_sec, SIZE_IOPS, SIZE_IOPS_SEC); + +- /* NB: Cannot use macro since this is a value.s not a value.ul */ + if (STREQ(param->field, VIR_DOMAIN_BLOCK_IOTUNE_GROUP_NAME)) { +- info->group_name = g_strdup(param->value.s); +- *set_fields |= QEMU_BLOCK_IOTUNE_SET_GROUP_NAME; +- if (virTypedParamsAddString(eventParams, eventNparams, +- eventMaxparams, +- VIR_DOMAIN_TUNABLE_BLKDEV_GROUP_NAME, +- param->value.s) < 0) +- return -1; ++ param_group_name = param->value.s; + continue; + } + +@@ -15244,6 +15238,16 @@ qemuDomainSetBlockIoTuneFields(virDomainBlockIoTuneInfo *info, + WRITE_IOPS_SEC_MAX_LENGTH); + } + ++ if (param_group_name) { ++ info->group_name = g_strdup(param_group_name); ++ *set_fields |= QEMU_BLOCK_IOTUNE_SET_GROUP_NAME; ++ if (virTypedParamsAddString(eventParams, eventNparams, ++ eventMaxparams, ++ VIR_DOMAIN_TUNABLE_BLKDEV_GROUP_NAME, ++ param_group_name) < 0) ++ return -1; ++ } ++ + #undef SET_IOTUNE_FIELD + + return 0; +-- +2.52.0 diff --git a/libvirt-qemuDomainSetThrottleGroup-Always-honour-thottle-group-name-passed-as-argument.patch b/libvirt-qemuDomainSetThrottleGroup-Always-honour-thottle-group-name-passed-as-argument.patch new file mode 100644 index 0000000..0d1b945 --- /dev/null +++ b/libvirt-qemuDomainSetThrottleGroup-Always-honour-thottle-group-name-passed-as-argument.patch @@ -0,0 +1,75 @@ +From f44d3fa49e7f1507e93c1e9525dd0db4227809cc Mon Sep 17 00:00:00 2001 +Message-ID: +From: Peter Krempa +Date: Fri, 16 Jan 2026 16:39:40 +0100 +Subject: [PATCH] qemuDomainSetThrottleGroup: Always honour thottle group name + passed as argument + +Due to the code share with 'qemuDomainSetBlockIoTune' the throttle group +setting code accepts the throttle group name also via typed parameters. + +In 'qemuDomainSetThrottleGroup', this means that there are 2 ways to +pass it the throttle group name and both are handled slightly +differently. Specifically the name of the group used in the list of +groups is the name taken from the typed parameters rather than the one +passed via API. We also don't validate that they match. + +Now if the name in the typed parameters is missing we'd add empty string +to the group list which would later crash when looking up the group +name. + +To avoid this problem always use the name passed via argument. This is +achieved by passing it into 'qemuDomainSetBlockIoTuneFields' so that it +overrides whatever is in the typed parameters. + +Signed-off-by: Peter Krempa +Reviewed-by: Michal Privoznik +(cherry picked from commit 0cd13906dcf15ea5709a7b253466816a1b875640) + +https://issues.redhat.com/browse/RHEL-141820 [rhel-10.2] +https://issues.redhat.com/browse/RHEL-144010 [rhel-9.8] +--- + src/qemu/qemu_driver.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index ecfb65c535..a6d5dd6e05 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -15168,6 +15168,7 @@ static int + qemuDomainSetBlockIoTuneFields(virDomainBlockIoTuneInfo *info, + virTypedParameterPtr params, + int nparams, ++ const char *group_name, + qemuBlockIoTuneSetFlags *set_fields, + virTypedParameterPtr *eventParams, + int *eventNparams, +@@ -15238,6 +15239,10 @@ qemuDomainSetBlockIoTuneFields(virDomainBlockIoTuneInfo *info, + WRITE_IOPS_SEC_MAX_LENGTH); + } + ++ /* The name of the throttle group passed via API always takes precedence */ ++ if (group_name) ++ param_group_name = group_name; ++ + if (param_group_name) { + info->group_name = g_strdup(param_group_name); + *set_fields |= QEMU_BLOCK_IOTUNE_SET_GROUP_NAME; +@@ -15385,6 +15390,7 @@ qemuDomainSetBlockIoTune(virDomainPtr dom, + if (qemuDomainSetBlockIoTuneFields(&info, + params, + nparams, ++ NULL, + &set_fields, + &eventParams, + &eventNparams, +@@ -20379,6 +20385,7 @@ qemuDomainSetThrottleGroup(virDomainPtr dom, + if (qemuDomainSetBlockIoTuneFields(&info, + params, + nparams, ++ groupname, + &set_fields, + &eventParams, + &eventNparams, +-- +2.52.0 diff --git a/libvirt-qemuDomainSetThrottleGroup-Don-t-put-group-name-into-the-tunable-event-twice.patch b/libvirt-qemuDomainSetThrottleGroup-Don-t-put-group-name-into-the-tunable-event-twice.patch new file mode 100644 index 0000000..0f0a739 --- /dev/null +++ b/libvirt-qemuDomainSetThrottleGroup-Don-t-put-group-name-into-the-tunable-event-twice.patch @@ -0,0 +1,43 @@ +From e48225074a9179e73b8ce9a573a513e619ae0a65 Mon Sep 17 00:00:00 2001 +Message-ID: +From: Peter Krempa +Date: Fri, 16 Jan 2026 16:39:49 +0100 +Subject: [PATCH] qemuDomainSetThrottleGroup: Don't put group name into the + 'tunable' event twice + +'qemuDomainSetBlockIoTuneFields' already populates the contents of the +VIR_DOMAIN_EVENT_ID_TUNABLE params with the group name so there's no +need to do it explicitly. We'd report the group name twice: + + event 'tunable' for domain 'cd': + blkdeviotune.group_name: asdf + blkdeviotune.total_bytes_sec: 1234 + blkdeviotune.group_name: asdf + +Signed-off-by: Peter Krempa +Reviewed-by: Michal Privoznik +(cherry picked from commit adcc14e1538433ec1b2f4b103cdf641917e63242) + +https://issues.redhat.com/browse/RHEL-141820 [rhel-10.2] +https://issues.redhat.com/browse/RHEL-144010 [rhel-9.8] +--- + src/qemu/qemu_driver.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index a6d5dd6e05..08a547c546 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -20378,10 +20378,6 @@ qemuDomainSetThrottleGroup(virDomainPtr dom, + if (virDomainObjGetDefs(vm, flags, &def, &persistentDef) < 0) + goto endjob; + +- if (virTypedParamsAddString(&eventParams, &eventNparams, &eventMaxparams, +- VIR_DOMAIN_TUNABLE_BLKDEV_GROUP_NAME, groupname) < 0) +- goto endjob; +- + if (qemuDomainSetBlockIoTuneFields(&info, + params, + nparams, +-- +2.52.0 diff --git a/libvirt-qemuDomainSetThrottleGroup-Enforce-non-zero-groupname-string-length.patch b/libvirt-qemuDomainSetThrottleGroup-Enforce-non-zero-groupname-string-length.patch new file mode 100644 index 0000000..62c27b6 --- /dev/null +++ b/libvirt-qemuDomainSetThrottleGroup-Enforce-non-zero-groupname-string-length.patch @@ -0,0 +1,38 @@ +From fee37458a1f93dc30a209ceeda1ec31847884fcf Mon Sep 17 00:00:00 2001 +Message-ID: +From: Peter Krempa +Date: Fri, 16 Jan 2026 16:36:50 +0100 +Subject: [PATCH] qemuDomainSetThrottleGroup: Enforce non-zero 'groupname' + string length + +Having a name of 0 characters makes no sense. Reject it. + +Signed-off-by: Peter Krempa +Reviewed-by: Michal Privoznik +(cherry picked from commit abcdc9511b1c78df7dcdee9f01c6d55651d3a424) + +https://issues.redhat.com/browse/RHEL-141820 [rhel-10.2] +https://issues.redhat.com/browse/RHEL-144010 [rhel-9.8] +--- + src/qemu/qemu_driver.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index f2e024dae3..194017a29a 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -20345,6 +20345,12 @@ qemuDomainSetThrottleGroup(virDomainPtr dom, + virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | + VIR_DOMAIN_AFFECT_CONFIG, -1); + ++ if (strlen(groupname) == 0) { ++ virReportError(VIR_ERR_INVALID_ARG, "%s", ++ _("'groupname' parameter string must have non-zero length")); ++ return -1; ++ } ++ + if (qemuDomainValidateBlockIoTune(params, nparams) < 0) + return -1; + +-- +2.52.0 diff --git a/libvirt-qemuSnapshotDiskHasBackingDisk-Avoid-call-of-virStorageSourceIsSameLocation-with-NULL-argument.patch b/libvirt-qemuSnapshotDiskHasBackingDisk-Avoid-call-of-virStorageSourceIsSameLocation-with-NULL-argument.patch new file mode 100644 index 0000000..e551ccf --- /dev/null +++ b/libvirt-qemuSnapshotDiskHasBackingDisk-Avoid-call-of-virStorageSourceIsSameLocation-with-NULL-argument.patch @@ -0,0 +1,48 @@ +From 744a5361793546bed7976acebed669b1928e8c9d Mon Sep 17 00:00:00 2001 +Message-ID: <744a5361793546bed7976acebed669b1928e8c9d.1769699749.git.jdenemar@redhat.com> +From: Peter Krempa +Date: Fri, 23 Jan 2026 08:42:50 +0100 +Subject: [PATCH] qemuSnapshotDiskHasBackingDisk: Avoid call of + virStorageSourceIsSameLocation with NULL argument + +When the 'backingStore' pointer is not populated the function calls +'virStorageSourceGetMetadata' to try to populate it but if the on-disk +metadata doesn't have a backing image (e.g. if it's the 'base' image of +the chain) the 'backingStore' or the metadata fetcher fails the pointer +will still be NULL. + +The function then calls 'virStorageSourceIsSameLocation' but the +internal functions for dealing with storage sources don't handle NULL +gracefully. + +Since the code calling 'qemu-img' based on the data detected here +doesn't actually raise errors if the operations fail there's no point +in raising errors here either. + +Closes: https://gitlab.com/libvirt/libvirt/-/issues/844 +Signed-off-by: Peter Krempa +Reviewed-by: Pavel Hrdina +(cherry picked from commit b43aee9cc904961e0f18156c3c84a3e460bdb7be) + + https://issues.redhat.com/browse/RHEL-144089 [rhel-10.2] + https://issues.redhat.com/browse/RHEL-144090 [rhel-9.8] +--- + src/qemu/qemu_snapshot.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c +index 302775af92..dfc3f449e3 100644 +--- a/src/qemu/qemu_snapshot.c ++++ b/src/qemu/qemu_snapshot.c +@@ -3135,7 +3135,8 @@ qemuSnapshotDiskHasBackingDisk(void *payload, + if (!disk->src->backingStore) + ignore_value(virStorageSourceGetMetadata(disk->src, uid, gid, 1, false)); + +- if (virStorageSourceIsSameLocation(disk->src->backingStore, iterdata->diskSrc)) { ++ if (disk->src->backingStore && ++ virStorageSourceIsSameLocation(disk->src->backingStore, iterdata->diskSrc)) { + struct _qemuSnapshotDisksWithBackingStoreData *data = + g_new0(struct _qemuSnapshotDisksWithBackingStoreData, 1); + +-- +2.52.0 diff --git a/libvirt-qemuSnapshotDiskHasBackingDisk-Use-proper-max_depth-when-calling-virStorageSourceGetMetadata.patch b/libvirt-qemuSnapshotDiskHasBackingDisk-Use-proper-max_depth-when-calling-virStorageSourceGetMetadata.patch new file mode 100644 index 0000000..3120c50 --- /dev/null +++ b/libvirt-qemuSnapshotDiskHasBackingDisk-Use-proper-max_depth-when-calling-virStorageSourceGetMetadata.patch @@ -0,0 +1,75 @@ +From 78e9a796a24c4f60c162ee3643c4a251c97ab1d2 Mon Sep 17 00:00:00 2001 +Message-ID: <78e9a796a24c4f60c162ee3643c4a251c97ab1d2.1769699749.git.jdenemar@redhat.com> +From: Peter Krempa +Date: Mon, 26 Jan 2026 16:39:24 +0100 +Subject: [PATCH] qemuSnapshotDiskHasBackingDisk: Use proper 'max_depth' when + calling 'virStorageSourceGetMetadata' + +The 'max_depth' argument of 'virStorageSourceGetMetadata' doesn't just +limit how far the function goes but also fails completely if the chain +is deeper than the passed value. + +In 'qemuSnapshotDiskHasBackingDisk' we only care about finding the +backing image, so just one level below, the passed path, but due to the +above setting '1' as max_depth will make the function simply fail every +time. + +Extract and reuse QEMU_DOMAIN_STORAGE_SOURCE_CHAIN_MAX_DEPTH as the +detection depth. While '200' layers is overkill for this code, we also +start a full qemu instance just to delete an snapshot so this doens't +matter and still protects from self-referential images. + +Signed-off-by: Peter Krempa +Reviewed-by: Pavel Hrdina +(cherry picked from commit 6bcdf4ee59595041c76ed2339c45503723400737) + + https://issues.redhat.com/browse/RHEL-144089 [rhel-10.2] + https://issues.redhat.com/browse/RHEL-144090 [rhel-9.8] +--- + src/qemu/qemu_domain.c | 2 -- + src/qemu/qemu_domain.h | 1 + + src/qemu/qemu_snapshot.c | 4 +++- + 3 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c +index ac56fc7cb4..486a0e7913 100644 +--- a/src/qemu/qemu_domain.c ++++ b/src/qemu/qemu_domain.c +@@ -6297,8 +6297,6 @@ qemuDomainStorageAlias(const char *device, int depth) + } + + +-#define QEMU_DOMAIN_STORAGE_SOURCE_CHAIN_MAX_DEPTH 200 +- + /** + * qemuDomainStorageSourceValidateDepth: + * @src: storage source chain to validate +diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h +index 3396f929fd..b9bb338682 100644 +--- a/src/qemu/qemu_domain.h ++++ b/src/qemu/qemu_domain.h +@@ -706,6 +706,7 @@ int qemuDomainCheckDiskStartupPolicy(virQEMUDriver *driver, + size_t diskIndex, + bool cold_boot); + ++#define QEMU_DOMAIN_STORAGE_SOURCE_CHAIN_MAX_DEPTH 200 + int qemuDomainStorageSourceValidateDepth(virStorageSource *src, + int add, + const char *diskdst); +diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c +index 942ba0d437..c23add5103 100644 +--- a/src/qemu/qemu_snapshot.c ++++ b/src/qemu/qemu_snapshot.c +@@ -3133,7 +3133,9 @@ qemuSnapshotDiskHasBackingDisk(void *payload, + NULL, &uid, &gid); + + if (!disk->src->backingStore) +- ignore_value(virStorageSourceGetMetadata(disk->src, uid, gid, 1, false)); ++ ignore_value(virStorageSourceGetMetadata(disk->src, uid, gid, ++ QEMU_DOMAIN_STORAGE_SOURCE_CHAIN_MAX_DEPTH, ++ false)); + + if (disk->src->backingStore && + virStorageSourceIsSameLocation(disk->src->backingStore, iterdata->diskSrc)) { +-- +2.52.0 diff --git a/libvirt-qemuSnapshotUpdateBackingStore-Remove-stale-comment.patch b/libvirt-qemuSnapshotUpdateBackingStore-Remove-stale-comment.patch new file mode 100644 index 0000000..c8e3ae3 --- /dev/null +++ b/libvirt-qemuSnapshotUpdateBackingStore-Remove-stale-comment.patch @@ -0,0 +1,34 @@ +From ca8a9f6b124dbfe5809c83d7f2d268bb18b9fa75 Mon Sep 17 00:00:00 2001 +Message-ID: +From: Peter Krempa +Date: Fri, 23 Jan 2026 08:54:32 +0100 +Subject: [PATCH] qemuSnapshotUpdateBackingStore: Remove stale comment + +The code does a 'qemu-img rebase' rather than a 'qemu-img create' what +the commit suggests. Since we enumerate all arguments right below, +there's no need for a comment. + +Signed-off-by: Peter Krempa +Reviewed-by: Pavel Hrdina +(cherry picked from commit 452c281aee7a043b59a288de043ea4e3b75a6b7c) + + https://issues.redhat.com/browse/RHEL-144089 [rhel-10.2] + https://issues.redhat.com/browse/RHEL-144090 [rhel-9.8] +--- + src/qemu/qemu_snapshot.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c +index dfc3f449e3..942ba0d437 100644 +--- a/src/qemu/qemu_snapshot.c ++++ b/src/qemu/qemu_snapshot.c +@@ -3698,7 +3698,6 @@ qemuSnapshotUpdateBackingStore(qemuSnapshotDeleteExternalData *data) + struct _qemuSnapshotDisksWithBackingStoreData *backingData = cur->data; + g_autoptr(virCommand) cmd = NULL; + +- /* creates cmd line args: qemu-img create -f qcow2 -o */ + if (!(cmd = virCommandNewArgList("qemu-img", + "rebase", + "-u", +-- +2.52.0 diff --git a/libvirt-qemuSnapshotUpdateBackingStore-Retry-as-curent-user-if-qemu-img-fails.patch b/libvirt-qemuSnapshotUpdateBackingStore-Retry-as-curent-user-if-qemu-img-fails.patch new file mode 100644 index 0000000..0b1fa87 --- /dev/null +++ b/libvirt-qemuSnapshotUpdateBackingStore-Retry-as-curent-user-if-qemu-img-fails.patch @@ -0,0 +1,97 @@ +From 7d39e57db8479f4c481636c8c41311f3eabc935f Mon Sep 17 00:00:00 2001 +Message-ID: <7d39e57db8479f4c481636c8c41311f3eabc935f.1769699749.git.jdenemar@redhat.com> +From: Peter Krempa +Date: Mon, 26 Jan 2026 16:49:50 +0100 +Subject: [PATCH] qemuSnapshotUpdateBackingStore: Retry as curent user if + qemu-img fails + +The code calls 'qemu-img rebase' to fix the backing store references. +The 'qemu-img' process here is run as the 'qemu' user or whatever the +defaults and domain XML resolve to. Since this, in certain cases, works +also on images which are not part of the backing chain and in privileged +deployments thus can be owned by 'root:root' the update may fail +(silently). + +To preserver root-squash deployments but fix also the above case, retry +the operation on failure as current user. + +Signed-off-by: Peter Krempa +Reviewed-by: Pavel Hrdina +(cherry picked from commit 6bb982178b40768f37c5177f317e73562733530f) + + https://issues.redhat.com/browse/RHEL-144089 [rhel-10.2] + https://issues.redhat.com/browse/RHEL-144090 [rhel-9.8] +--- + src/qemu/qemu_snapshot.c | 53 ++++++++++++++++++++++++++++------------ + 1 file changed, 38 insertions(+), 15 deletions(-) + +diff --git a/src/qemu/qemu_snapshot.c b/src/qemu/qemu_snapshot.c +index c23add5103..e30ade9dc8 100644 +--- a/src/qemu/qemu_snapshot.c ++++ b/src/qemu/qemu_snapshot.c +@@ -3698,25 +3698,48 @@ qemuSnapshotUpdateBackingStore(qemuSnapshotDeleteExternalData *data) + + for (cur = data->disksWithBacking; cur; cur = g_slist_next(cur)) { + struct _qemuSnapshotDisksWithBackingStoreData *backingData = cur->data; +- g_autoptr(virCommand) cmd = NULL; ++ /* Try to run the command first as the appropriate user based on the ++ * domain definition and config. If error is returned retry as current ++ * (possibly privileged) user for cases where seclabels were reset ++ * to the default */ ++ g_autoptr(virCommand) cmd_user_qemu = NULL; ++ g_autoptr(virCommand) cmd_user_curr = NULL; + +- if (!(cmd = virCommandNewArgList("qemu-img", +- "rebase", +- "-u", +- "-F", +- virStorageFileFormatTypeToString(data->parentDiskSrc->format), +- "-f", +- virStorageFileFormatTypeToString(backingData->diskSrc->format), +- "-b", +- data->parentDiskSrc->path, +- backingData->diskSrc->path, +- NULL))) ++ if (!(cmd_user_qemu = virCommandNewArgList("qemu-img", ++ "rebase", ++ "-u", ++ "-F", ++ virStorageFileFormatTypeToString(data->parentDiskSrc->format), ++ "-f", ++ virStorageFileFormatTypeToString(backingData->diskSrc->format), ++ "-b", ++ data->parentDiskSrc->path, ++ backingData->diskSrc->path, ++ NULL))) + continue; + +- virCommandSetUID(cmd, backingData->uid); +- virCommandSetGID(cmd, backingData->gid); ++ virCommandSetUID(cmd_user_qemu, backingData->uid); ++ virCommandSetGID(cmd_user_qemu, backingData->gid); + +- ignore_value(virCommandRun(cmd, NULL)); ++ /* done on success */ ++ if (virCommandRun(cmd_user_qemu, NULL) == 0) ++ continue; ++ ++ /* retry as current user */ ++ if (!(cmd_user_curr = virCommandNewArgList("qemu-img", ++ "rebase", ++ "-u", ++ "-F", ++ virStorageFileFormatTypeToString(data->parentDiskSrc->format), ++ "-f", ++ virStorageFileFormatTypeToString(backingData->diskSrc->format), ++ "-b", ++ data->parentDiskSrc->path, ++ backingData->diskSrc->path, ++ NULL))) ++ continue; ++ ++ ignore_value(virCommandRun(cmd_user_curr, NULL)); + } + } + +-- +2.52.0 diff --git a/libvirt-virDomainSnapshotDefAssignExternalNames-Improve-error-message.patch b/libvirt-virDomainSnapshotDefAssignExternalNames-Improve-error-message.patch new file mode 100644 index 0000000..b3d3826 --- /dev/null +++ b/libvirt-virDomainSnapshotDefAssignExternalNames-Improve-error-message.patch @@ -0,0 +1,37 @@ +From 12d480034a41e3066c6c5adab27b504cfaefea6a Mon Sep 17 00:00:00 2001 +Message-ID: <12d480034a41e3066c6c5adab27b504cfaefea6a.1769699749.git.jdenemar@redhat.com> +From: Peter Krempa +Date: Mon, 26 Jan 2026 16:39:45 +0100 +Subject: [PATCH] virDomainSnapshotDefAssignExternalNames: Improve error + message + +Mention the 'path' where the detection failed as well as include the +possibility that the 'path' doesn't exist in the message itself. + +Signed-off-by: Peter Krempa +Reviewed-by: Pavel Hrdina +(cherry picked from commit f1ad5219368b1b2c603d876f28dc852fd6da3a8d) + + https://issues.redhat.com/browse/RHEL-144089 [rhel-10.2] + https://issues.redhat.com/browse/RHEL-144090 [rhel-9.8] +--- + src/conf/snapshot_conf.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/conf/snapshot_conf.c b/src/conf/snapshot_conf.c +index 039ed77b84..4309667a34 100644 +--- a/src/conf/snapshot_conf.c ++++ b/src/conf/snapshot_conf.c +@@ -541,8 +541,8 @@ virDomainSnapshotDefAssignExternalNames(virDomainSnapshotDef *def, + + if (stat(origpath, &sb) < 0 || !S_ISREG(sb.st_mode)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, +- _("source for disk '%1$s' is not a regular file; refusing to generate external snapshot name"), +- disk->name); ++ _("source for disk '%1$s' (%2$s) doesn't exist or is not a regular file; refusing to generate external snapshot name"), ++ disk->name, origpath); + return -1; + } + +-- +2.52.0 diff --git a/libvirt.spec b/libvirt.spec index a5eee78..b41c459 100644 --- a/libvirt.spec +++ b/libvirt.spec @@ -294,7 +294,7 @@ Summary: Library providing a simple virtualization API Name: libvirt Version: 11.10.0 -Release: 3%{?dist}%{?extra_release} +Release: 4%{?dist}%{?extra_release} License: GPL-2.0-or-later AND LGPL-2.1-only AND LGPL-2.1-or-later AND OFL-1.1 URL: https://libvirt.org/ @@ -313,6 +313,20 @@ Patch8: libvirt-util-json-Increase-JSON-nesting-limit-when-parsing-to-300.patch Patch9: libvirt-virjsontest-Add-test-for-nesting-depth.patch Patch10: libvirt-qemuSecurityMoveImageMetadata-Move-seclabels-only-to-virStorageSource-of-same-type.patch Patch11: libvirt-esx-Allow-connecting-to-IPv6-server.patch +Patch12: libvirt-qemuDomainSetThrottleGroup-Enforce-non-zero-groupname-string-length.patch +Patch13: libvirt-qemuDomainSetBlockIoTuneField-Move-setting-of-group_name-out-of-the-loop.patch +Patch14: libvirt-qemuDomainSetThrottleGroup-Always-honour-thottle-group-name-passed-as-argument.patch +Patch15: libvirt-qemuDomainSetThrottleGroup-Don-t-put-group-name-into-the-tunable-event-twice.patch +Patch16: libvirt-qemuSnapshotDiskHasBackingDisk-Avoid-call-of-virStorageSourceIsSameLocation-with-NULL-argument.patch +Patch17: libvirt-qemuSnapshotUpdateBackingStore-Remove-stale-comment.patch +Patch18: libvirt-qemuSnapshotDiskHasBackingDisk-Use-proper-max_depth-when-calling-virStorageSourceGetMetadata.patch +Patch19: libvirt-virDomainSnapshotDefAssignExternalNames-Improve-error-message.patch +Patch20: libvirt-qemuSnapshotUpdateBackingStore-Retry-as-curent-user-if-qemu-img-fails.patch +Patch21: libvirt-esx-Debug-URL-just-before-opening-with-curl.patch +Patch22: libvirt-esx-Abstract-all-URL-creation-code-into-one-function.patch +Patch23: libvirt-esx-Switch-to-creating-URLs-using-virURIFormat.patch +Patch24: libvirt-esx_util-Introduce-esxUtil_EscapeInventoryObject.patch +Patch25: libvirt-esx-URI-encode-inventory-objects-twice.patch Requires: libvirt-daemon = %{version}-%{release} @@ -2704,6 +2718,22 @@ exit 0 %endif %changelog +* Thu Jan 29 2026 Jiri Denemark - 11.10.0-4 +- qemuDomainSetThrottleGroup: Enforce non-zero 'groupname' string length (RHEL-141820) +- qemuDomainSetBlockIoTuneField: Move setting of 'group_name' out of the loop (RHEL-141820) +- qemuDomainSetThrottleGroup: Always honour thottle group name passed as argument (RHEL-141820) +- qemuDomainSetThrottleGroup: Don't put group name into the 'tunable' event twice (RHEL-141820) +- qemuSnapshotDiskHasBackingDisk: Avoid call of virStorageSourceIsSameLocation with NULL argument (RHEL-144089) +- qemuSnapshotUpdateBackingStore: Remove stale comment (RHEL-144089) +- qemuSnapshotDiskHasBackingDisk: Use proper 'max_depth' when calling 'virStorageSourceGetMetadata' (RHEL-144089) +- virDomainSnapshotDefAssignExternalNames: Improve error message (RHEL-144089) +- qemuSnapshotUpdateBackingStore: Retry as curent user if qemu-img fails (RHEL-144089) +- esx: Debug URL just before opening with curl (RHEL-138300) +- esx: Abstract all URL-creation code into one function (RHEL-138300) +- esx: Switch to creating URLs using virURIFormat (RHEL-138300) +- esx_util: Introduce esxUtil_EscapeInventoryObject() (RHEL-140196) +- esx: URI encode inventory objects twice (RHEL-140196) + * Fri Jan 23 2026 Jiri Denemark - 11.10.0-3 - util: json: Increase JSON nesting limit when parsing to 300 (RHEL-135181) - virjsontest: Add test for nesting depth (RHEL-135181)