From 8c03ec6cc944cf4270ebd4895bf06266e170e1fd Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Oct 05 2021 22:26:23 +0000 Subject: import libvirt-6.0.0-37.module+el8.5.0+12162+40884dd2 --- diff --git a/SOURCES/libvirt-cgroup-use-virCgroupSetCpuShares-instead-of-virCgroupSetupCpuShares.patch b/SOURCES/libvirt-cgroup-use-virCgroupSetCpuShares-instead-of-virCgroupSetupCpuShares.patch new file mode 100644 index 0000000..9eec89b --- /dev/null +++ b/SOURCES/libvirt-cgroup-use-virCgroupSetCpuShares-instead-of-virCgroupSetupCpuShares.patch @@ -0,0 +1,146 @@ +From 8d08db00d403ddd17cb51d972842c6d13a122d57 Mon Sep 17 00:00:00 2001 +Message-Id: <8d08db00d403ddd17cb51d972842c6d13a122d57@dist-git> +From: Pavel Hrdina +Date: Thu, 4 Mar 2021 12:57:58 +0100 +Subject: [PATCH] cgroup: use virCgroupSetCpuShares instead of + virCgroupSetupCpuShares +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Now that we enforce the cpu.shares range kernel will no longer silently +change the value that libvirt configures so there is no need to read +the value back to get the actual configuration. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit e95489d813cb7cc68b02905ce3ec059bc395b465) + +Conflicts: + src/lxc/lxc_cgroup.c + src/lxc/lxc_driver.c + src/qemu/qemu_cgroup.c + src/qemu/qemu_driver.c + - downstream doesn't have virCgroupSetupCpuShares() function + so we just remove usage of virCgroupGetCpuShares() + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463 + +Signed-off-by: Pavel Hrdina +Message-Id: +Reviewed-by: Ján Tomko +--- + src/lxc/lxc_cgroup.c | 5 ----- + src/lxc/lxc_driver.c | 6 +----- + src/qemu/qemu_cgroup.c | 20 -------------------- + src/qemu/qemu_driver.c | 8 ++------ + 4 files changed, 3 insertions(+), 36 deletions(-) + +diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c +index 7f3701593a..f785f50754 100644 +--- a/src/lxc/lxc_cgroup.c ++++ b/src/lxc/lxc_cgroup.c +@@ -38,13 +38,8 @@ static int virLXCCgroupSetupCpuTune(virDomainDefPtr def, + virCgroupPtr cgroup) + { + if (def->cputune.sharesSpecified) { +- unsigned long long val; + if (virCgroupSetCpuShares(cgroup, def->cputune.shares) < 0) + return -1; +- +- if (virCgroupGetCpuShares(cgroup, &val) < 0) +- return -1; +- def->cputune.shares = val; + } + + if (def->cputune.quota != 0 && +diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c +index a8c93dd228..853ddac8b9 100644 +--- a/src/lxc/lxc_driver.c ++++ b/src/lxc/lxc_driver.c +@@ -1909,14 +1909,10 @@ lxcDomainSetSchedulerParametersFlags(virDomainPtr dom, + + if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) { + if (def) { +- unsigned long long val; + if (virCgroupSetCpuShares(priv->cgroup, params[i].value.ul) < 0) + goto endjob; + +- if (virCgroupGetCpuShares(priv->cgroup, &val) < 0) +- goto endjob; +- +- def->cputune.shares = val; ++ def->cputune.shares = params[i].value.ul; + def->cputune.sharesSpecified = true; + } + +diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c +index 3a62b4ac15..95ea5bed74 100644 +--- a/src/qemu/qemu_cgroup.c ++++ b/src/qemu/qemu_cgroup.c +@@ -933,10 +933,6 @@ static int + qemuSetupCpuCgroup(virDomainObjPtr vm) + { + qemuDomainObjPrivatePtr priv = vm->privateData; +- virObjectEventPtr event = NULL; +- virTypedParameterPtr eventParams = NULL; +- int eventNparams = 0; +- int eventMaxparams = 0; + + if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) { + if (vm->def->cputune.sharesSpecified) { +@@ -949,24 +945,8 @@ qemuSetupCpuCgroup(virDomainObjPtr vm) + } + + if (vm->def->cputune.sharesSpecified) { +- unsigned long long val; + if (virCgroupSetCpuShares(priv->cgroup, vm->def->cputune.shares) < 0) + return -1; +- +- if (virCgroupGetCpuShares(priv->cgroup, &val) < 0) +- return -1; +- if (vm->def->cputune.shares != val) { +- vm->def->cputune.shares = val; +- if (virTypedParamsAddULLong(&eventParams, &eventNparams, +- &eventMaxparams, +- VIR_DOMAIN_TUNABLE_CPU_CPU_SHARES, +- val) < 0) +- return -1; +- +- event = virDomainEventTunableNewFromObj(vm, eventParams, eventNparams); +- } +- +- virObjectEventStateQueue(priv->driver->domainEventState, event); + } + + return 0; +diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c +index a1103a96dd..3914d3ff68 100644 +--- a/src/qemu/qemu_driver.c ++++ b/src/qemu/qemu_driver.c +@@ -10625,20 +10625,16 @@ qemuDomainSetSchedulerParametersFlags(virDomainPtr dom, + + if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) { + if (def) { +- unsigned long long val; + if (virCgroupSetCpuShares(priv->cgroup, value_ul) < 0) + goto endjob; + +- if (virCgroupGetCpuShares(priv->cgroup, &val) < 0) +- goto endjob; +- +- def->cputune.shares = val; ++ def->cputune.shares = value_ul; + def->cputune.sharesSpecified = true; + + if (virTypedParamsAddULLong(&eventParams, &eventNparams, + &eventMaxNparams, + VIR_DOMAIN_TUNABLE_CPU_CPU_SHARES, +- val) < 0) ++ value_ul) < 0) + goto endjob; + } + +-- +2.30.0 + diff --git a/SOURCES/libvirt-conf-introduce-support-for-firmware-auto-selection-feature-filtering.patch b/SOURCES/libvirt-conf-introduce-support-for-firmware-auto-selection-feature-filtering.patch new file mode 100644 index 0000000..2b876eb --- /dev/null +++ b/SOURCES/libvirt-conf-introduce-support-for-firmware-auto-selection-feature-filtering.patch @@ -0,0 +1,415 @@ +From 6f02748897062d40b411177ef752644505189a72 Mon Sep 17 00:00:00 2001 +Message-Id: <6f02748897062d40b411177ef752644505189a72@dist-git> +From: Pavel Hrdina +Date: Fri, 21 May 2021 14:16:11 +0200 +Subject: [PATCH] conf: introduce support for firmware auto-selection feature + filtering + +When the firmware auto-selection was introduced it always picked first +usable firmware based on the JSON descriptions on the host. It is +possible to add/remove/change the JSON files but it will always be for +the whole host. + +This patch introduces support for configuring the auto-selection per VM +by adding users an option to limit what features they would like to have +available in the firmware. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit cff524af6c5e1ddc11149394ed7f985242ebea0f) + +Conflicts: + docs/formatdomain.rst + - we still have formatdomain.html.in in downstream + src/conf/domain_conf.c + - missing following upstream commits: + 0280fc72708b9d0f162a808bcc8d78137a68d58d + 104dadcff6023da676df3905d1ed8688aea15e86 + 2d5f7a49ae0780143566932ab38215433982c89f + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1929357 + +Signed-off-by: Pavel Hrdina +Message-Id: <631e05bc5363abb3e48d8b652a806324801cce16.1621599207.git.phrdina@redhat.com> +Reviewed-by: Michal Privoznik +--- + docs/formatdomain.html.in | 58 +++++++++++++ + docs/schemas/domaincommon.rng | 23 +++++ + src/conf/domain_conf.c | 83 ++++++++++++++++++- + src/conf/domain_conf.h | 10 +++ + ...os-firmware-invalid-type.x86_64-latest.err | 1 + + .../os-firmware-invalid-type.xml | 28 +++++++ + tests/qemuxml2argvtest.c | 1 + + ...aarch64-os-firmware-efi.aarch64-latest.xml | 1 + + .../os-firmware-bios.x86_64-latest.xml | 1 + + .../os-firmware-efi-secboot.x86_64-latest.xml | 1 + + .../os-firmware-efi.x86_64-latest.xml | 1 + + tests/vmx2xmldata/vmx2xml-firmware-efi.xml | 1 + + 12 files changed, 206 insertions(+), 3 deletions(-) + create mode 100644 tests/qemuxml2argvdata/os-firmware-invalid-type.x86_64-latest.err + create mode 100644 tests/qemuxml2argvdata/os-firmware-invalid-type.xml + +diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in +index a40bed347b..11f31618af 100644 +--- a/docs/formatdomain.html.in ++++ b/docs/formatdomain.html.in +@@ -180,6 +180,64 @@ + ESX and VMWare hypervisor drivers, however, + the i686 arch will always be chosen even on an + x86_64 host. Since 0.0.1 ++
firmware
++
++

Since 7.2.0 QEMU/KVM only

++

++ When used together with firmware attribute of ++ os element the type attribute must ++ have the same value. ++

++

++ List of mandatory attributes: ++

    ++
  • ++ type (accepted values are bios ++ and efi) same as the firmware ++ attribute of os element. ++
  • ++
++

++

++ When using firmware auto-selection there are different features ++ enabled in the firmwares. The list of features can be used to ++ limit what firmware should be automatically selected for the VM. ++ The list of features can be specified using zero or more ++ feature elements. Libvirt will take into consideration ++ only the listed features and ignore the rest when selecting the firmware. ++ ++

++
feature
++
++ The list of mandatory attributes: ++ ++
    ++
  • ++ enabled (accepted values are yes ++ and no) is used to tell libvirt if the feature ++ must be enabled or not in the automatically selected firmware ++
  • ++
  • ++ name the name of the feature, the list of the features: ++
      ++
    • ++ enrolled-keys whether the selected nvram template ++ has default certificate enrolled. Firmware with Secure Boot ++ feature but without enrolled keys will successfully boot ++ non-signed binaries as well. Valid only for firmwares with ++ Secure Boot feature. ++
    • ++
    • ++ secure-boot whether the firmware implements ++ UEFI Secure boot feature. ++
    • ++
    ++
  • ++
++
++
++

++
+
loader
+
The optional loader tag refers to a firmware blob, + which is specified by absolute path, +diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng +index 6671ef3dfa..b7f6a6b494 100644 +--- a/docs/schemas/domaincommon.rng ++++ b/docs/schemas/domaincommon.rng +@@ -268,6 +268,29 @@ + + + ++ ++ ++ ++ ++ bios ++ efi ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ enrolled-keys ++ secure-boot ++ ++ ++ ++ ++ ++ + + + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 93a78f8277..28c8d0ecbd 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -1240,6 +1240,12 @@ VIR_ENUM_IMPL(virDomainOsDefFirmware, + "efi", + ); + ++VIR_ENUM_IMPL(virDomainOsDefFirmwareFeature, ++ VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_LAST, ++ "enrolled-keys", ++ "secure-boot", ++); ++ + /* Internal mapping: subset of block job types that can be present in + * XML (remaining types are not two-phase). */ + VIR_ENUM_DECL(virDomainBlockJob); +@@ -19382,22 +19388,67 @@ virDomainDefParseBootFirmwareOptions(virDomainDefPtr def, + xmlXPathContextPtr ctxt) + { + g_autofree char *firmware = virXPathString("string(./os/@firmware)", ctxt); ++ g_autofree char *type = virXPathString("string(./os/firmware/@type)", ctxt); ++ g_autofree xmlNodePtr *nodes = NULL; ++ g_autofree int *features = NULL; + int fw = 0; ++ int n = 0; ++ size_t i; + +- if (!firmware) ++ if (!firmware && !type) + return 0; + +- fw = virDomainOsDefFirmwareTypeFromString(firmware); ++ if (firmware && type && STRNEQ(firmware, type)) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", ++ _("firmware attribute and firmware type has to be the same")); ++ return -1; ++ } ++ ++ if (!type) ++ type = g_steal_pointer(&firmware); ++ ++ fw = virDomainOsDefFirmwareTypeFromString(type); + + if (fw <= 0) { + virReportError(VIR_ERR_XML_ERROR, + _("unknown firmware value %s"), +- firmware); ++ type); + return -1; + } + + def->os.firmware = fw; + ++ if ((n = virXPathNodeSet("./os/firmware/feature", ctxt, &nodes)) < 0) ++ return -1; ++ ++ if (n > 0) ++ features = g_new0(int, VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_LAST); ++ ++ for (i = 0; i < n; i++) { ++ g_autofree char *name = virXMLPropString(nodes[i], "name"); ++ g_autofree char *enabled = virXMLPropString(nodes[i], "enabled"); ++ int feature = virDomainOsDefFirmwareFeatureTypeFromString(name); ++ int val = virTristateBoolTypeFromString(enabled); ++ ++ if (feature < 0) { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("invalid firmware feature name '%s'"), ++ name); ++ return -1; ++ } ++ ++ if (val < 0) { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("invalid firmware feature enabled value '%s'"), ++ enabled); ++ return -1; ++ } ++ ++ features[feature] = val; ++ } ++ ++ def->os.firmwareFeatures = g_steal_pointer(&features); ++ + return 0; + } + +@@ -28987,6 +29038,32 @@ virDomainDefFormatInternalSetRootName(virDomainDefPtr def, + virBufferAsprintf(buf, ">%s\n", + virDomainOSTypeToString(def->os.type)); + ++ if (def->os.firmware) { ++ virBufferAsprintf(buf, "os.firmware)); ++ ++ if (def->os.firmwareFeatures) { ++ virBufferAddLit(buf, ">\n"); ++ ++ virBufferAdjustIndent(buf, 2); ++ ++ for (i = 0; i < VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_LAST; i++) { ++ if (def->os.firmwareFeatures[i] == VIR_TRISTATE_BOOL_ABSENT) ++ continue; ++ ++ virBufferAsprintf(buf, "\n", ++ virTristateBoolTypeToString(def->os.firmwareFeatures[i]), ++ virDomainOsDefFirmwareFeatureTypeToString(i)); ++ } ++ ++ virBufferAdjustIndent(buf, -2); ++ ++ virBufferAddLit(buf, "\n"); ++ } else { ++ virBufferAddLit(buf, "/>\n"); ++ } ++ } ++ + virBufferEscapeString(buf, "%s\n", + def->os.init); + for (i = 0; def->os.initargv && def->os.initargv[i]; i++) +diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h +index 3aed1fb22a..1ad77ecac6 100644 +--- a/src/conf/domain_conf.h ++++ b/src/conf/domain_conf.h +@@ -1967,9 +1967,19 @@ G_STATIC_ASSERT((int)VIR_DOMAIN_OS_DEF_FIRMWARE_LAST == (int)VIR_DOMAIN_LOADER_T + + VIR_ENUM_DECL(virDomainOsDefFirmware); + ++typedef enum { ++ VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_ENROLLED_KEYS, ++ VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_SECURE_BOOT, ++ ++ VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_LAST ++} virDomainOsDefFirmwareFeature; ++ ++VIR_ENUM_DECL(virDomainOsDefFirmwareFeature); ++ + struct _virDomainOSDef { + int type; + virDomainOsDefFirmware firmware; ++ int *firmwareFeatures; + virArch arch; + char *machine; + size_t nBootDevs; +diff --git a/tests/qemuxml2argvdata/os-firmware-invalid-type.x86_64-latest.err b/tests/qemuxml2argvdata/os-firmware-invalid-type.x86_64-latest.err +new file mode 100644 +index 0000000000..c8174b1c8b +--- /dev/null ++++ b/tests/qemuxml2argvdata/os-firmware-invalid-type.x86_64-latest.err +@@ -0,0 +1 @@ ++unsupported configuration: firmware attribute and firmware type has to be the same +diff --git a/tests/qemuxml2argvdata/os-firmware-invalid-type.xml b/tests/qemuxml2argvdata/os-firmware-invalid-type.xml +new file mode 100644 +index 0000000000..41360df0f7 +--- /dev/null ++++ b/tests/qemuxml2argvdata/os-firmware-invalid-type.xml +@@ -0,0 +1,28 @@ ++ ++ fedora ++ 63840878-0deb-4095-97e6-fc444d9bc9fa ++ 8192 ++ 8192 ++ 1 ++ ++ hvm ++ ++ ++ /var/lib/libvirt/qemu/nvram/fedora_VARS.fd ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ destroy ++ restart ++ restart ++ ++ /usr/bin/qemu-system-x86_64 ++ ++ ++ +diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c +index a22e3ba157..bc04bea692 100644 +--- a/tests/qemuxml2argvtest.c ++++ b/tests/qemuxml2argvtest.c +@@ -3094,6 +3094,7 @@ mymain(void) + DO_TEST_CAPS_LATEST("os-firmware-bios"); + DO_TEST_CAPS_LATEST("os-firmware-efi"); + DO_TEST_CAPS_LATEST("os-firmware-efi-secboot"); ++ DO_TEST_CAPS_LATEST_PARSE_ERROR("os-firmware-invalid-type"); + DO_TEST_CAPS_ARCH_LATEST("aarch64-os-firmware-efi", "aarch64"); + + DO_TEST_CAPS_LATEST("vhost-user-vga"); +diff --git a/tests/qemuxml2xmloutdata/aarch64-os-firmware-efi.aarch64-latest.xml b/tests/qemuxml2xmloutdata/aarch64-os-firmware-efi.aarch64-latest.xml +index 1e51d55305..3cac8fc5c6 100644 +--- a/tests/qemuxml2xmloutdata/aarch64-os-firmware-efi.aarch64-latest.xml ++++ b/tests/qemuxml2xmloutdata/aarch64-os-firmware-efi.aarch64-latest.xml +@@ -6,6 +6,7 @@ + 1 + + hvm ++ + /aarch64.kernel + /aarch64.initrd + earlyprintk console=ttyAMA0,115200n8 rw root=/dev/vda rootwait +diff --git a/tests/qemuxml2xmloutdata/os-firmware-bios.x86_64-latest.xml b/tests/qemuxml2xmloutdata/os-firmware-bios.x86_64-latest.xml +index 60d3498765..ef24f2fece 100644 +--- a/tests/qemuxml2xmloutdata/os-firmware-bios.x86_64-latest.xml ++++ b/tests/qemuxml2xmloutdata/os-firmware-bios.x86_64-latest.xml +@@ -6,6 +6,7 @@ + 1 + + hvm ++ + + /var/lib/libvirt/qemu/nvram/fedora_VARS.fd + +diff --git a/tests/qemuxml2xmloutdata/os-firmware-efi-secboot.x86_64-latest.xml b/tests/qemuxml2xmloutdata/os-firmware-efi-secboot.x86_64-latest.xml +index 938da73711..3757191e8e 100644 +--- a/tests/qemuxml2xmloutdata/os-firmware-efi-secboot.x86_64-latest.xml ++++ b/tests/qemuxml2xmloutdata/os-firmware-efi-secboot.x86_64-latest.xml +@@ -6,6 +6,7 @@ + 1 + + hvm ++ + + /var/lib/libvirt/qemu/nvram/fedora_VARS.fd + +diff --git a/tests/qemuxml2xmloutdata/os-firmware-efi.x86_64-latest.xml b/tests/qemuxml2xmloutdata/os-firmware-efi.x86_64-latest.xml +index 97ce8a75c7..f2e6b7f36d 100644 +--- a/tests/qemuxml2xmloutdata/os-firmware-efi.x86_64-latest.xml ++++ b/tests/qemuxml2xmloutdata/os-firmware-efi.x86_64-latest.xml +@@ -6,6 +6,7 @@ + 1 + + hvm ++ + + /var/lib/libvirt/qemu/nvram/fedora_VARS.fd + +diff --git a/tests/vmx2xmldata/vmx2xml-firmware-efi.xml b/tests/vmx2xmldata/vmx2xml-firmware-efi.xml +index e21158cebf..375c47d281 100644 +--- a/tests/vmx2xmldata/vmx2xml-firmware-efi.xml ++++ b/tests/vmx2xmldata/vmx2xml-firmware-efi.xml +@@ -5,6 +5,7 @@ + 1 + + hvm ++ + + + destroy +-- +2.31.1 + diff --git a/SOURCES/libvirt-conf-introduce-virDomainDefParseBootAcpiOptions.patch b/SOURCES/libvirt-conf-introduce-virDomainDefParseBootAcpiOptions.patch new file mode 100644 index 0000000..f3d6fd4 --- /dev/null +++ b/SOURCES/libvirt-conf-introduce-virDomainDefParseBootAcpiOptions.patch @@ -0,0 +1,124 @@ +From 7ba2905bfcab4dbe4a491ee8587dd4c9ef457c0b Mon Sep 17 00:00:00 2001 +Message-Id: <7ba2905bfcab4dbe4a491ee8587dd4c9ef457c0b@dist-git> +From: Pavel Hrdina +Date: Fri, 21 May 2021 14:16:09 +0200 +Subject: [PATCH] conf: introduce virDomainDefParseBootAcpiOptions + +Extract the code to it's own function. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit 108cb29c1c7eec7b9089dd431e0bdcd82a0b07f1) + +Conflicts: + src/conf/domain_conf.c + - missing upstream commit d293a556d710754d8aa8d5caac0bb01a365fcbd8 + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1929357 + +Signed-off-by: Pavel Hrdina +Message-Id: <5fb7ee0165340ff517b3f7f16ddc542813ac385d.1621599207.git.phrdina@redhat.com> +Reviewed-by: Michal Privoznik +--- + src/conf/domain_conf.c | 71 ++++++++++++++++++++++++------------------ + 1 file changed, 41 insertions(+), 30 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 493700ed6b..f8d8d33245 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -19429,13 +19429,51 @@ virDomainDefParseBootLoaderOptions(virDomainDefPtr def, + + + static int +-virDomainDefParseBootOptions(virDomainDefPtr def, +- xmlXPathContextPtr ctxt) ++virDomainDefParseBootAcpiOptions(virDomainDefPtr def, ++ xmlXPathContextPtr ctxt) + { + int n; + g_autofree xmlNodePtr *nodes = NULL; + g_autofree char *tmp = NULL; + ++ if ((n = virXPathNodeSet("./os/acpi/table", ctxt, &nodes)) < 0) ++ return -1; ++ ++ if (n > 1) { ++ virReportError(VIR_ERR_XML_ERROR, "%s", ++ _("Only one acpi table is supported")); ++ return -1; ++ } ++ ++ if (n == 1) { ++ tmp = virXMLPropString(nodes[0], "type"); ++ ++ if (!tmp) { ++ virReportError(VIR_ERR_XML_ERROR, "%s", ++ _("Missing acpi table type")); ++ return -1; ++ } ++ ++ if (STREQ_NULLABLE(tmp, "slic")) { ++ VIR_FREE(tmp); ++ tmp = virXMLNodeContentString(nodes[0]); ++ def->os.slic_table = virFileSanitizePath(tmp); ++ } else { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("Unknown acpi table type: %s"), ++ tmp); ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ ++ ++static int ++virDomainDefParseBootOptions(virDomainDefPtr def, ++ xmlXPathContextPtr ctxt) ++{ + /* + * Booting options for different OS types.... + * +@@ -19467,36 +19505,9 @@ virDomainDefParseBootOptions(virDomainDefPtr def, + } + + if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) { +- if ((n = virXPathNodeSet("./os/acpi/table", ctxt, &nodes)) < 0) ++ if (virDomainDefParseBootAcpiOptions(def, ctxt) < 0) + return -1; + +- if (n > 1) { +- virReportError(VIR_ERR_XML_ERROR, "%s", +- _("Only one acpi table is supported")); +- return -1; +- } +- +- if (n == 1) { +- tmp = virXMLPropString(nodes[0], "type"); +- +- if (!tmp) { +- virReportError(VIR_ERR_XML_ERROR, "%s", +- _("Missing acpi table type")); +- return -1; +- } +- +- if (STREQ_NULLABLE(tmp, "slic")) { +- VIR_FREE(tmp); +- tmp = virXMLNodeContentString(nodes[0]); +- def->os.slic_table = virFileSanitizePath(tmp); +- } else { +- virReportError(VIR_ERR_XML_ERROR, +- _("Unknown acpi table type: %s"), +- tmp); +- return -1; +- } +- } +- + if (virDomainDefParseBootXML(ctxt, def) < 0) + return -1; + } +-- +2.31.1 + diff --git a/SOURCES/libvirt-conf-introduce-virDomainDefParseBootFirmwareOptions.patch b/SOURCES/libvirt-conf-introduce-virDomainDefParseBootFirmwareOptions.patch new file mode 100644 index 0000000..409c3bd --- /dev/null +++ b/SOURCES/libvirt-conf-introduce-virDomainDefParseBootFirmwareOptions.patch @@ -0,0 +1,86 @@ +From 2a019bfa26e697c60893afd09fcc2f0c3218691b Mon Sep 17 00:00:00 2001 +Message-Id: <2a019bfa26e697c60893afd09fcc2f0c3218691b@dist-git> +From: Pavel Hrdina +Date: Fri, 21 May 2021 14:16:07 +0200 +Subject: [PATCH] conf: introduce virDomainDefParseBootFirmwareOptions + +Extract the code to it's own function. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit bcf97abfc6b45694f0d789ae2bdf87c8d082fddf) + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1929357 + +Signed-off-by: Pavel Hrdina +Message-Id: <9a090d9f2a43b261ed1b6db608779a01a7594f4a.1621599207.git.phrdina@redhat.com> +Reviewed-by: Michal Privoznik +--- + src/conf/domain_conf.c | 39 +++++++++++++++++++++++++++------------ + 1 file changed, 27 insertions(+), 12 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 432ad938f9..bb484a57c6 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -19377,6 +19377,31 @@ virDomainDefParseBootKernelOptions(virDomainDefPtr def, + } + + ++static int ++virDomainDefParseBootFirmwareOptions(virDomainDefPtr def, ++ xmlXPathContextPtr ctxt) ++{ ++ g_autofree char *firmware = virXPathString("string(./os/@firmware)", ctxt); ++ int fw = 0; ++ ++ if (!firmware) ++ return 0; ++ ++ fw = virDomainOsDefFirmwareTypeFromString(firmware); ++ ++ if (fw <= 0) { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("unknown firmware value %s"), ++ firmware); ++ return -1; ++ } ++ ++ def->os.firmware = fw; ++ ++ return 0; ++} ++ ++ + static int + virDomainDefParseBootOptions(virDomainDefPtr def, + xmlXPathContextPtr ctxt) +@@ -19403,23 +19428,13 @@ virDomainDefParseBootOptions(virDomainDefPtr def, + def->os.type == VIR_DOMAIN_OSTYPE_XENPVH || + def->os.type == VIR_DOMAIN_OSTYPE_HVM || + def->os.type == VIR_DOMAIN_OSTYPE_UML) { +- g_autofree char *firmware = NULL; + xmlNodePtr loader_node; + + virDomainDefParseBootKernelOptions(def, ctxt); + +- if (def->os.type == VIR_DOMAIN_OSTYPE_HVM && +- (firmware = virXPathString("string(./os/@firmware)", ctxt))) { +- int fw = virDomainOsDefFirmwareTypeFromString(firmware); +- +- if (fw <= 0) { +- virReportError(VIR_ERR_XML_ERROR, +- _("unknown firmware value %s"), +- firmware); ++ if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) { ++ if (virDomainDefParseBootFirmwareOptions(def, ctxt) < 0) + return -1; +- } +- +- def->os.firmware = fw; + } + + if ((loader_node = virXPathNode("./os/loader[1]", ctxt))) { +-- +2.31.1 + diff --git a/SOURCES/libvirt-conf-introduce-virDomainDefParseBootInitOptions.patch b/SOURCES/libvirt-conf-introduce-virDomainDefParseBootInitOptions.patch new file mode 100644 index 0000000..4195af7 --- /dev/null +++ b/SOURCES/libvirt-conf-introduce-virDomainDefParseBootInitOptions.patch @@ -0,0 +1,173 @@ +From adafaa880b67f1025c64515352e5e851daa62ae9 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Pavel Hrdina +Date: Fri, 21 May 2021 14:16:05 +0200 +Subject: [PATCH] conf: introduce virDomainDefParseBootInitOptions + +Extract the code to it's own function. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit b07116438c96fddfa00bdb57878a707240574b42) + +Conflicts: + src/conf/domain_conf.c + - using VIR_ALLOC in downstream instead of g_new0 + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1929357 + +Signed-off-by: Pavel Hrdina +Message-Id: +Reviewed-by: Michal Privoznik +--- + src/conf/domain_conf.c | 115 +++++++++++++++++++++++------------------ + 1 file changed, 64 insertions(+), 51 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 444657c9a1..9eb418c7c0 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -19302,76 +19302,89 @@ virDomainVcpuParse(virDomainDefPtr def, + + + static int +-virDomainDefParseBootOptions(virDomainDefPtr def, +- xmlXPathContextPtr ctxt) ++virDomainDefParseBootInitOptions(virDomainDefPtr def, ++ xmlXPathContextPtr ctxt) + { + char *name = NULL; + size_t i; + int n; + g_autofree xmlNodePtr *nodes = NULL; +- g_autofree char *tmp = NULL; + +- /* +- * Booting options for different OS types.... +- * +- * - A bootloader (and optional kernel+initrd) (xen) +- * - A kernel + initrd (xen) +- * - A boot device (and optional kernel+initrd) (hvm) +- * - An init script (exe) +- */ ++ def->os.init = virXPathString("string(./os/init[1])", ctxt); ++ def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt); ++ def->os.initdir = virXPathString("string(./os/initdir[1])", ctxt); ++ def->os.inituser = virXPathString("string(./os/inituser[1])", ctxt); ++ def->os.initgroup = virXPathString("string(./os/initgroup[1])", ctxt); + +- if (def->os.type == VIR_DOMAIN_OSTYPE_EXE) { +- def->os.init = virXPathString("string(./os/init[1])", ctxt); +- def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt); +- def->os.initdir = virXPathString("string(./os/initdir[1])", ctxt); +- def->os.inituser = virXPathString("string(./os/inituser[1])", ctxt); +- def->os.initgroup = virXPathString("string(./os/initgroup[1])", ctxt); ++ if ((n = virXPathNodeSet("./os/initarg", ctxt, &nodes)) < 0) ++ return -1; + +- if ((n = virXPathNodeSet("./os/initarg", ctxt, &nodes)) < 0) ++ if (VIR_ALLOC_N(def->os.initargv, n+1) < 0) ++ return -1; ++ for (i = 0; i < n; i++) { ++ if (!nodes[i]->children || ++ !nodes[i]->children->content) { ++ virReportError(VIR_ERR_XML_ERROR, "%s", ++ _("No data supplied for element")); + return -1; ++ } ++ def->os.initargv[i] = g_strdup((const char *)nodes[i]->children->content); ++ } ++ def->os.initargv[n] = NULL; ++ VIR_FREE(nodes); + +- if (VIR_ALLOC_N(def->os.initargv, n+1) < 0) ++ if ((n = virXPathNodeSet("./os/initenv", ctxt, &nodes)) < 0) ++ return -1; ++ ++ if (VIR_ALLOC_N(def->os.initenv, n+1) < 0) ++ return -1; ++ for (i = 0; i < n; i++) { ++ if (!(name = virXMLPropString(nodes[i], "name"))) { ++ virReportError(VIR_ERR_XML_ERROR, "%s", ++ _("No name supplied for element")); + return -1; +- for (i = 0; i < n; i++) { +- if (!nodes[i]->children || +- !nodes[i]->children->content) { +- virReportError(VIR_ERR_XML_ERROR, "%s", +- _("No data supplied for element")); +- return -1; +- } +- def->os.initargv[i] = g_strdup((const char *)nodes[i]->children->content); + } +- def->os.initargv[n] = NULL; +- VIR_FREE(nodes); + +- if ((n = virXPathNodeSet("./os/initenv", ctxt, &nodes)) < 0) ++ if (!nodes[i]->children || ++ !nodes[i]->children->content) { ++ virReportError(VIR_ERR_XML_ERROR, ++ _("No value supplied for element"), ++ name); + return -1; ++ } + +- if (VIR_ALLOC_N(def->os.initenv, n+1) < 0) ++ if (VIR_ALLOC(def->os.initenv[i]) < 0) + return -1; +- for (i = 0; i < n; i++) { +- if (!(name = virXMLPropString(nodes[i], "name"))) { +- virReportError(VIR_ERR_XML_ERROR, "%s", +- _("No name supplied for element")); +- return -1; +- } + +- if (!nodes[i]->children || +- !nodes[i]->children->content) { +- virReportError(VIR_ERR_XML_ERROR, +- _("No value supplied for element"), +- name); +- return -1; +- } ++ def->os.initenv[i]->name = name; ++ def->os.initenv[i]->value = g_strdup((const char *)nodes[i]->children->content); ++ } ++ def->os.initenv[n] = NULL; + +- if (VIR_ALLOC(def->os.initenv[i]) < 0) +- return -1; ++ return 0; ++} + +- def->os.initenv[i]->name = name; +- def->os.initenv[i]->value = g_strdup((const char *)nodes[i]->children->content); +- } +- def->os.initenv[n] = NULL; +- VIR_FREE(nodes); ++ ++static int ++virDomainDefParseBootOptions(virDomainDefPtr def, ++ xmlXPathContextPtr ctxt) ++{ ++ int n; ++ g_autofree xmlNodePtr *nodes = NULL; ++ g_autofree char *tmp = NULL; ++ ++ /* ++ * Booting options for different OS types.... ++ * ++ * - A bootloader (and optional kernel+initrd) (xen) ++ * - A kernel + initrd (xen) ++ * - A boot device (and optional kernel+initrd) (hvm) ++ * - An init script (exe) ++ */ ++ ++ if (def->os.type == VIR_DOMAIN_OSTYPE_EXE) { ++ if (virDomainDefParseBootInitOptions(def, ctxt) < 0) ++ return -1; + } + + if (def->os.type == VIR_DOMAIN_OSTYPE_XEN || +-- +2.31.1 + diff --git a/SOURCES/libvirt-conf-introduce-virDomainDefParseBootKernelOptions.patch b/SOURCES/libvirt-conf-introduce-virDomainDefParseBootKernelOptions.patch new file mode 100644 index 0000000..a418a03 --- /dev/null +++ b/SOURCES/libvirt-conf-introduce-virDomainDefParseBootKernelOptions.patch @@ -0,0 +1,60 @@ +From a62075772680bd30ced25d7177048ab26db8ea09 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Pavel Hrdina +Date: Fri, 21 May 2021 14:16:06 +0200 +Subject: [PATCH] conf: introduce virDomainDefParseBootKernelOptions + +Extract the code to it's own function. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit bf9b3f8e573092cc98ea647f25cf116e22bbfe3c) + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1929357 + +Signed-off-by: Pavel Hrdina +Message-Id: <936428a5fa6d4104361ac8080639a55111c14965.1621599207.git.phrdina@redhat.com> +Reviewed-by: Michal Privoznik +--- + src/conf/domain_conf.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 9eb418c7c0..432ad938f9 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -19365,6 +19365,18 @@ virDomainDefParseBootInitOptions(virDomainDefPtr def, + } + + ++static void ++virDomainDefParseBootKernelOptions(virDomainDefPtr def, ++ xmlXPathContextPtr ctxt) ++{ ++ def->os.kernel = virXPathString("string(./os/kernel[1])", ctxt); ++ def->os.initrd = virXPathString("string(./os/initrd[1])", ctxt); ++ def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt); ++ def->os.dtb = virXPathString("string(./os/dtb[1])", ctxt); ++ def->os.root = virXPathString("string(./os/root[1])", ctxt); ++} ++ ++ + static int + virDomainDefParseBootOptions(virDomainDefPtr def, + xmlXPathContextPtr ctxt) +@@ -19394,11 +19406,7 @@ virDomainDefParseBootOptions(virDomainDefPtr def, + g_autofree char *firmware = NULL; + xmlNodePtr loader_node; + +- def->os.kernel = virXPathString("string(./os/kernel[1])", ctxt); +- def->os.initrd = virXPathString("string(./os/initrd[1])", ctxt); +- def->os.cmdline = virXPathString("string(./os/cmdline[1])", ctxt); +- def->os.dtb = virXPathString("string(./os/dtb[1])", ctxt); +- def->os.root = virXPathString("string(./os/root[1])", ctxt); ++ virDomainDefParseBootKernelOptions(def, ctxt); + + if (def->os.type == VIR_DOMAIN_OSTYPE_HVM && + (firmware = virXPathString("string(./os/@firmware)", ctxt))) { +-- +2.31.1 + diff --git a/SOURCES/libvirt-conf-introduce-virDomainDefParseBootLoaderOptions.patch b/SOURCES/libvirt-conf-introduce-virDomainDefParseBootLoaderOptions.patch new file mode 100644 index 0000000..599fbfc --- /dev/null +++ b/SOURCES/libvirt-conf-introduce-virDomainDefParseBootLoaderOptions.patch @@ -0,0 +1,97 @@ +From 6891ef941e693d86ebbab9e529e908dacf4a7dc6 Mon Sep 17 00:00:00 2001 +Message-Id: <6891ef941e693d86ebbab9e529e908dacf4a7dc6@dist-git> +From: Pavel Hrdina +Date: Fri, 21 May 2021 14:16:08 +0200 +Subject: [PATCH] conf: introduce virDomainDefParseBootLoaderOptions + +Extract the code to it's own function. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit b8dd70db4ee2f3a5edcbbeb8515830db9652cb59) + +Conflicts: + src/conf/domain_conf.c + - using VIR_ALLOC in downstream instead of g_new0 + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1929357 + +Signed-off-by: Pavel Hrdina +Message-Id: +Reviewed-by: Michal Privoznik +--- + src/conf/domain_conf.c | 44 +++++++++++++++++++++++++++--------------- + 1 file changed, 28 insertions(+), 16 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index bb484a57c6..493700ed6b 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -19402,6 +19402,32 @@ virDomainDefParseBootFirmwareOptions(virDomainDefPtr def, + } + + ++static int ++virDomainDefParseBootLoaderOptions(virDomainDefPtr def, ++ xmlXPathContextPtr ctxt) ++{ ++ xmlNodePtr loader_node = virXPathNode("./os/loader[1]", ctxt); ++ const bool fwAutoSelect = def->os.firmware != VIR_DOMAIN_OS_DEF_FIRMWARE_NONE; ++ ++ if (!loader_node) ++ return 0; ++ ++ if (VIR_ALLOC(def->os.loader) < 0) ++ return -1; ++ ++ if (virDomainLoaderDefParseXML(loader_node, ++ def->os.loader, ++ fwAutoSelect) < 0) ++ return -1; ++ ++ def->os.loader->nvram = virXPathString("string(./os/nvram[1])", ctxt); ++ if (!fwAutoSelect) ++ def->os.loader->templt = virXPathString("string(./os/nvram[1]/@template)", ctxt); ++ ++ return 0; ++} ++ ++ + static int + virDomainDefParseBootOptions(virDomainDefPtr def, + xmlXPathContextPtr ctxt) +@@ -19428,7 +19454,6 @@ virDomainDefParseBootOptions(virDomainDefPtr def, + def->os.type == VIR_DOMAIN_OSTYPE_XENPVH || + def->os.type == VIR_DOMAIN_OSTYPE_HVM || + def->os.type == VIR_DOMAIN_OSTYPE_UML) { +- xmlNodePtr loader_node; + + virDomainDefParseBootKernelOptions(def, ctxt); + +@@ -19437,21 +19462,8 @@ virDomainDefParseBootOptions(virDomainDefPtr def, + return -1; + } + +- if ((loader_node = virXPathNode("./os/loader[1]", ctxt))) { +- const bool fwAutoSelect = def->os.firmware != VIR_DOMAIN_OS_DEF_FIRMWARE_NONE; +- +- if (VIR_ALLOC(def->os.loader) < 0) +- return -1; +- +- if (virDomainLoaderDefParseXML(loader_node, +- def->os.loader, +- fwAutoSelect) < 0) +- return -1; +- +- def->os.loader->nvram = virXPathString("string(./os/nvram[1])", ctxt); +- if (!fwAutoSelect) +- def->os.loader->templt = virXPathString("string(./os/nvram[1]/@template)", ctxt); +- } ++ if (virDomainDefParseBootLoaderOptions(def, ctxt) < 0) ++ return -1; + } + + if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) { +-- +2.31.1 + diff --git a/SOURCES/libvirt-conf-remove-duplicated-firmware-type-attribute.patch b/SOURCES/libvirt-conf-remove-duplicated-firmware-type-attribute.patch new file mode 100644 index 0000000..3bc500f --- /dev/null +++ b/SOURCES/libvirt-conf-remove-duplicated-firmware-type-attribute.patch @@ -0,0 +1,317 @@ +From 4ca3f2f590fb860b01f1eb5fec8929ceba702dc6 Mon Sep 17 00:00:00 2001 +Message-Id: <4ca3f2f590fb860b01f1eb5fec8929ceba702dc6@dist-git> +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Fri, 21 May 2021 14:16:14 +0200 +Subject: [PATCH] conf: remove duplicated firmware type attribute +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The + + + + + + + +repeats the firmware attribute twice. This has no functional benefit, as +evidenced by fact that we use a single struct field to store both +attributes, while needlessly introducing an error scenario. The XML can +just be simplified to: + + + + + + + +which also means that we don't need to emit the empty element + for all existing configs too. + +Reviewed-by: Pavel Hrdina +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit a9b1375d7d2f7d240dce09c5f8b62e568e386051) + +Conflicts: + docs/formatdomain.rst + - we still have formatdomain.html.in in downstream + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1929357 + +Signed-off-by: Pavel Hrdina +Message-Id: <299fd16fc3ce632bf25ca55cc4bb65a225437d61.1621599207.git.phrdina@redhat.com> +Reviewed-by: Michal Privoznik +--- + docs/formatdomain.html.in | 15 ------ + docs/schemas/domaincommon.rng | 10 +--- + src/conf/domain_conf.c | 48 ++++++------------- + .../os-firmware-efi-no-enrolled-keys.xml | 2 +- + .../os-firmware-invalid-type.xml | 28 ----------- + tests/qemuxml2argvtest.c | 1 - + ...aarch64-os-firmware-efi.aarch64-latest.xml | 1 - + .../os-firmware-bios.x86_64-latest.xml | 1 - + .../os-firmware-efi-secboot.x86_64-latest.xml | 1 - + .../os-firmware-efi.x86_64-latest.xml | 1 - + tests/vmx2xmldata/vmx2xml-firmware-efi.xml | 1 - + 11 files changed, 18 insertions(+), 91 deletions(-) + delete mode 100644 tests/qemuxml2argvdata/os-firmware-invalid-type.xml + +diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in +index 11f31618af..79e2e51c54 100644 +--- a/docs/formatdomain.html.in ++++ b/docs/formatdomain.html.in +@@ -183,21 +183,6 @@ +
firmware
+
+

Since 7.2.0 QEMU/KVM only

+-

+- When used together with firmware attribute of +- os element the type attribute must +- have the same value. +-

+-

+- List of mandatory attributes: +-

    +-
  • +- type (accepted values are bios +- and efi) same as the firmware +- attribute of os element. +-
  • +-
+-

+

+ When using firmware auto-selection there are different features + enabled in the firmwares. The list of features can be used to +diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng +index b7f6a6b494..ec8167e588 100644 +--- a/docs/schemas/domaincommon.rng ++++ b/docs/schemas/domaincommon.rng +@@ -270,13 +270,7 @@ + + + +- +- +- bios +- efi +- +- +- ++ + + + +@@ -288,7 +282,7 @@ + + + +- ++ + + + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 2ffa9c8a2a..6806064016 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -19389,31 +19389,21 @@ virDomainDefParseBootFirmwareOptions(virDomainDefPtr def, + xmlXPathContextPtr ctxt) + { + g_autofree char *firmware = virXPathString("string(./os/@firmware)", ctxt); +- g_autofree char *type = virXPathString("string(./os/firmware/@type)", ctxt); + g_autofree xmlNodePtr *nodes = NULL; + g_autofree int *features = NULL; + int fw = 0; + int n = 0; + size_t i; + +- if (!firmware && !type) ++ if (!firmware) + return 0; + +- if (firmware && type && STRNEQ(firmware, type)) { +- virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", +- _("firmware attribute and firmware type has to be the same")); +- return -1; +- } +- +- if (!type) +- type = g_steal_pointer(&firmware); +- +- fw = virDomainOsDefFirmwareTypeFromString(type); ++ fw = virDomainOsDefFirmwareTypeFromString(firmware); + + if (fw <= 0) { + virReportError(VIR_ERR_XML_ERROR, + _("unknown firmware value %s"), +- type); ++ firmware); + return -1; + } + +@@ -29039,30 +29029,22 @@ virDomainDefFormatInternalSetRootName(virDomainDefPtr def, + virBufferAsprintf(buf, ">%s\n", + virDomainOSTypeToString(def->os.type)); + +- if (def->os.firmware) { +- virBufferAsprintf(buf, "os.firmware)); +- +- if (def->os.firmwareFeatures) { +- virBufferAddLit(buf, ">\n"); +- +- virBufferAdjustIndent(buf, 2); ++ if (def->os.firmwareFeatures) { ++ virBufferAddLit(buf, "\n"); ++ virBufferAdjustIndent(buf, 2); + +- for (i = 0; i < VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_LAST; i++) { +- if (def->os.firmwareFeatures[i] == VIR_TRISTATE_BOOL_ABSENT) +- continue; ++ for (i = 0; i < VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_LAST; i++) { ++ if (def->os.firmwareFeatures[i] == VIR_TRISTATE_BOOL_ABSENT) ++ continue; + +- virBufferAsprintf(buf, "\n", +- virTristateBoolTypeToString(def->os.firmwareFeatures[i]), +- virDomainOsDefFirmwareFeatureTypeToString(i)); +- } ++ virBufferAsprintf(buf, "\n", ++ virTristateBoolTypeToString(def->os.firmwareFeatures[i]), ++ virDomainOsDefFirmwareFeatureTypeToString(i)); ++ } + +- virBufferAdjustIndent(buf, -2); ++ virBufferAdjustIndent(buf, -2); + +- virBufferAddLit(buf, "\n"); +- } else { +- virBufferAddLit(buf, "/>\n"); +- } ++ virBufferAddLit(buf, "\n"); + } + + virBufferEscapeString(buf, "%s\n", +diff --git a/tests/qemuxml2argvdata/os-firmware-efi-no-enrolled-keys.xml b/tests/qemuxml2argvdata/os-firmware-efi-no-enrolled-keys.xml +index 7f8f57a859..4999c4f125 100644 +--- a/tests/qemuxml2argvdata/os-firmware-efi-no-enrolled-keys.xml ++++ b/tests/qemuxml2argvdata/os-firmware-efi-no-enrolled-keys.xml +@@ -6,7 +6,7 @@ + 1 + + hvm +- ++ + + + +diff --git a/tests/qemuxml2argvdata/os-firmware-invalid-type.xml b/tests/qemuxml2argvdata/os-firmware-invalid-type.xml +deleted file mode 100644 +index 41360df0f7..0000000000 +--- a/tests/qemuxml2argvdata/os-firmware-invalid-type.xml ++++ /dev/null +@@ -1,28 +0,0 @@ +- +- fedora +- 63840878-0deb-4095-97e6-fc444d9bc9fa +- 8192 +- 8192 +- 1 +- +- hvm +- +- +- /var/lib/libvirt/qemu/nvram/fedora_VARS.fd +- +- +- +- +- +- +- +- +- +- destroy +- restart +- restart +- +- /usr/bin/qemu-system-x86_64 +- +- +- +diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c +index 5e16d7fd31..be8054fa6a 100644 +--- a/tests/qemuxml2argvtest.c ++++ b/tests/qemuxml2argvtest.c +@@ -3095,7 +3095,6 @@ mymain(void) + DO_TEST_CAPS_LATEST("os-firmware-efi"); + DO_TEST_CAPS_LATEST("os-firmware-efi-secboot"); + DO_TEST_CAPS_LATEST("os-firmware-efi-no-enrolled-keys"); +- DO_TEST_CAPS_LATEST_PARSE_ERROR("os-firmware-invalid-type"); + DO_TEST_CAPS_ARCH_LATEST("aarch64-os-firmware-efi", "aarch64"); + + DO_TEST_CAPS_LATEST("vhost-user-vga"); +diff --git a/tests/qemuxml2xmloutdata/aarch64-os-firmware-efi.aarch64-latest.xml b/tests/qemuxml2xmloutdata/aarch64-os-firmware-efi.aarch64-latest.xml +index 3cac8fc5c6..1e51d55305 100644 +--- a/tests/qemuxml2xmloutdata/aarch64-os-firmware-efi.aarch64-latest.xml ++++ b/tests/qemuxml2xmloutdata/aarch64-os-firmware-efi.aarch64-latest.xml +@@ -6,7 +6,6 @@ + 1 + + hvm +- + /aarch64.kernel + /aarch64.initrd + earlyprintk console=ttyAMA0,115200n8 rw root=/dev/vda rootwait +diff --git a/tests/qemuxml2xmloutdata/os-firmware-bios.x86_64-latest.xml b/tests/qemuxml2xmloutdata/os-firmware-bios.x86_64-latest.xml +index ef24f2fece..60d3498765 100644 +--- a/tests/qemuxml2xmloutdata/os-firmware-bios.x86_64-latest.xml ++++ b/tests/qemuxml2xmloutdata/os-firmware-bios.x86_64-latest.xml +@@ -6,7 +6,6 @@ + 1 + + hvm +- + + /var/lib/libvirt/qemu/nvram/fedora_VARS.fd + +diff --git a/tests/qemuxml2xmloutdata/os-firmware-efi-secboot.x86_64-latest.xml b/tests/qemuxml2xmloutdata/os-firmware-efi-secboot.x86_64-latest.xml +index 3757191e8e..938da73711 100644 +--- a/tests/qemuxml2xmloutdata/os-firmware-efi-secboot.x86_64-latest.xml ++++ b/tests/qemuxml2xmloutdata/os-firmware-efi-secboot.x86_64-latest.xml +@@ -6,7 +6,6 @@ + 1 + + hvm +- + + /var/lib/libvirt/qemu/nvram/fedora_VARS.fd + +diff --git a/tests/qemuxml2xmloutdata/os-firmware-efi.x86_64-latest.xml b/tests/qemuxml2xmloutdata/os-firmware-efi.x86_64-latest.xml +index f2e6b7f36d..97ce8a75c7 100644 +--- a/tests/qemuxml2xmloutdata/os-firmware-efi.x86_64-latest.xml ++++ b/tests/qemuxml2xmloutdata/os-firmware-efi.x86_64-latest.xml +@@ -6,7 +6,6 @@ + 1 + + hvm +- + + /var/lib/libvirt/qemu/nvram/fedora_VARS.fd + +diff --git a/tests/vmx2xmldata/vmx2xml-firmware-efi.xml b/tests/vmx2xmldata/vmx2xml-firmware-efi.xml +index 375c47d281..e21158cebf 100644 +--- a/tests/vmx2xmldata/vmx2xml-firmware-efi.xml ++++ b/tests/vmx2xmldata/vmx2xml-firmware-efi.xml +@@ -5,7 +5,6 @@ + 1 + + hvm +- + + + destroy +-- +2.31.1 + diff --git a/SOURCES/libvirt-conf-use-switch-in-virDomainDefParseBootOptions.patch b/SOURCES/libvirt-conf-use-switch-in-virDomainDefParseBootOptions.patch new file mode 100644 index 0000000..e4a8822 --- /dev/null +++ b/SOURCES/libvirt-conf-use-switch-in-virDomainDefParseBootOptions.patch @@ -0,0 +1,89 @@ +From 75470b7c297be9bdd712282b89c48465dbe8d400 Mon Sep 17 00:00:00 2001 +Message-Id: <75470b7c297be9bdd712282b89c48465dbe8d400@dist-git> +From: Pavel Hrdina +Date: Fri, 21 May 2021 14:16:10 +0200 +Subject: [PATCH] conf: use switch in virDomainDefParseBootOptions + +The original code used a lot of conditions and was not that obvious +when each XML bits are parsed. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit 6330be1ba3af5c4d2150fe2b831f7bc5d87c6d2a) + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1929357 + +Signed-off-by: Pavel Hrdina +Message-Id: <900c870b1720688123ed7b69850548ae308ea9a8.1621599207.git.phrdina@redhat.com> +Reviewed-by: Michal Privoznik +--- + src/conf/domain_conf.c | 42 ++++++++++++++++++++++++++---------------- + 1 file changed, 26 insertions(+), 16 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index f8d8d33245..93a78f8277 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -19483,33 +19483,43 @@ virDomainDefParseBootOptions(virDomainDefPtr def, + * - An init script (exe) + */ + +- if (def->os.type == VIR_DOMAIN_OSTYPE_EXE) { +- if (virDomainDefParseBootInitOptions(def, ctxt) < 0) +- return -1; +- } +- +- if (def->os.type == VIR_DOMAIN_OSTYPE_XEN || +- def->os.type == VIR_DOMAIN_OSTYPE_XENPVH || +- def->os.type == VIR_DOMAIN_OSTYPE_HVM || +- def->os.type == VIR_DOMAIN_OSTYPE_UML) { +- ++ switch ((virDomainOSType) def->os.type) { ++ case VIR_DOMAIN_OSTYPE_HVM: + virDomainDefParseBootKernelOptions(def, ctxt); + +- if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) { +- if (virDomainDefParseBootFirmwareOptions(def, ctxt) < 0) +- return -1; +- } ++ if (virDomainDefParseBootFirmwareOptions(def, ctxt) < 0) ++ return -1; + + if (virDomainDefParseBootLoaderOptions(def, ctxt) < 0) + return -1; +- } + +- if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) { + if (virDomainDefParseBootAcpiOptions(def, ctxt) < 0) + return -1; + + if (virDomainDefParseBootXML(ctxt, def) < 0) + return -1; ++ ++ break; ++ ++ case VIR_DOMAIN_OSTYPE_XEN: ++ case VIR_DOMAIN_OSTYPE_XENPVH: ++ case VIR_DOMAIN_OSTYPE_UML: ++ virDomainDefParseBootKernelOptions(def, ctxt); ++ ++ if (virDomainDefParseBootLoaderOptions(def, ctxt) < 0) ++ return -1; ++ ++ break; ++ ++ case VIR_DOMAIN_OSTYPE_EXE: ++ if (virDomainDefParseBootInitOptions(def, ctxt) < 0) ++ return -1; ++ ++ break; ++ ++ case VIR_DOMAIN_OSTYPE_LINUX: ++ case VIR_DOMAIN_OSTYPE_LAST: ++ break; + } + + return 0; +-- +2.31.1 + diff --git a/SOURCES/libvirt-cpu_map-Add-EPYC-Milan-x86-CPU-model.patch b/SOURCES/libvirt-cpu_map-Add-EPYC-Milan-x86-CPU-model.patch new file mode 100644 index 0000000..3257983 --- /dev/null +++ b/SOURCES/libvirt-cpu_map-Add-EPYC-Milan-x86-CPU-model.patch @@ -0,0 +1,145 @@ +From b5716d1b191eb52cd88d7b94cb9bf0186f3e427b Mon Sep 17 00:00:00 2001 +Message-Id: +From: Jiri Denemark +Date: Wed, 3 Mar 2021 11:11:54 +0100 +Subject: [PATCH] cpu_map: Add EPYC-Milan x86 CPU model +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Introduced in QEMU 6.0.0 by 623972ceae091b31331ae4a1dc94fe5cbb891937 + +Signed-off-by: Jiri Denemark +Reviewed-by: Ján Tomko +(cherry picked from commit f321a4822e9fa6542e48a78611989ecd9acaa83a) + +https://bugzilla.redhat.com/show_bug.cgi?id=1926864 + +Conflicts: + src/cpu_map/index.xml + - context: commit 82bebba1803c63a733e17f5ab2618e020e4abd8d + "cpu_map: Unify apostrophe and quotation mark usage" was + not backported + +Signed-off-by: Jiri Denemark +Message-Id: <715abc0f90faafb7daa193dd24bad65046c36de0.1614766279.git.jdenemar@redhat.com> +Reviewed-by: Ján Tomko +--- + src/cpu_map/index.xml | 1 + + src/cpu_map/x86_EPYC-Milan.xml | 92 ++++++++++++++++++++++++++++++++++ + 2 files changed, 93 insertions(+) + create mode 100644 src/cpu_map/x86_EPYC-Milan.xml + +diff --git a/src/cpu_map/index.xml b/src/cpu_map/index.xml +index 2f58261e6d..c3dda794b1 100644 +--- a/src/cpu_map/index.xml ++++ b/src/cpu_map/index.xml +@@ -68,6 +68,7 @@ + + + ++ + + + +diff --git a/src/cpu_map/x86_EPYC-Milan.xml b/src/cpu_map/x86_EPYC-Milan.xml +new file mode 100644 +index 0000000000..53f0cd6aac +--- /dev/null ++++ b/src/cpu_map/x86_EPYC-Milan.xml +@@ -0,0 +1,92 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +-- +2.30.0 + diff --git a/SOURCES/libvirt-cpu_map-Fix-spelling-of-svme-addr-chk-feature.patch b/SOURCES/libvirt-cpu_map-Fix-spelling-of-svme-addr-chk-feature.patch new file mode 100644 index 0000000..a603df9 --- /dev/null +++ b/SOURCES/libvirt-cpu_map-Fix-spelling-of-svme-addr-chk-feature.patch @@ -0,0 +1,59 @@ +From a7fb45c4e5a807a7b437a91cfc96c8c811351578 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Jiri Denemark +Date: Thu, 4 Mar 2021 09:41:53 +0100 +Subject: [PATCH] cpu_map: Fix spelling of svme-addr-chk feature +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit a208176ca1d9eedf8aa6bf12fde6a7a9579ab549 introduced this feature +with an incorrect "svme-addr-check" spelling. + +Signed-off-by: Jiri Denemark +Reviewed-by: Tim Wiederhake +(cherry picked from commit b5abf9a192248b1005f63a7102d2627375d70fe5) + +https://bugzilla.redhat.com/show_bug.cgi?id=1926864 + +Conflicts: + src/cpu_map/sync_qemu_i386.py + - the original change to this file was not backported + +Signed-off-by: Jiri Denemark +Message-Id: <75071287f9fc55f4bec82916726fcb8f31c1e014.1614847231.git.jdenemar@redhat.com> +Reviewed-by: Ján Tomko +--- + src/cpu_map/x86_EPYC-Milan.xml | 2 +- + src/cpu_map/x86_features.xml | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/cpu_map/x86_EPYC-Milan.xml b/src/cpu_map/x86_EPYC-Milan.xml +index 53f0cd6aac..3055e175fa 100644 +--- a/src/cpu_map/x86_EPYC-Milan.xml ++++ b/src/cpu_map/x86_EPYC-Milan.xml +@@ -76,7 +76,7 @@ + + + +- ++ + + + +diff --git a/src/cpu_map/x86_features.xml b/src/cpu_map/x86_features.xml +index 8acd42f796..ba23f553c3 100644 +--- a/src/cpu_map/x86_features.xml ++++ b/src/cpu_map/x86_features.xml +@@ -548,7 +548,7 @@ + + + +- ++ + + + +-- +2.30.0 + diff --git a/SOURCES/libvirt-cpu_map-Install-x86_EPYC-Milan.xml.patch b/SOURCES/libvirt-cpu_map-Install-x86_EPYC-Milan.xml.patch new file mode 100644 index 0000000..4652d0e --- /dev/null +++ b/SOURCES/libvirt-cpu_map-Install-x86_EPYC-Milan.xml.patch @@ -0,0 +1,41 @@ +From 8b1e1aa7cb9dc428a36b549a73286ec7040864ed Mon Sep 17 00:00:00 2001 +Message-Id: <8b1e1aa7cb9dc428a36b549a73286ec7040864ed@dist-git> +From: Jiri Denemark +Date: Wed, 3 Mar 2021 11:11:55 +0100 +Subject: [PATCH] cpu_map: Install x86_EPYC-Milan.xml +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Jiri Denemark +Reviewed-by: Pavel Hrdina +(cherry picked from commit d3de79dbfc20dc4dfc19154b16079861c542b71e) + +https://bugzilla.redhat.com/show_bug.cgi?id=1926864 + +Conflicts: + src/cpu_map/meson.build + - change goes to Makefile.inc.am instead + +Signed-off-by: Jiri Denemark +Message-Id: <77cf69a7222fd9fc5ef0f1c25f0534090c29865f.1614766279.git.jdenemar@redhat.com> +Reviewed-by: Ján Tomko +--- + src/cpu_map/Makefile.inc.am | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/cpu_map/Makefile.inc.am b/src/cpu_map/Makefile.inc.am +index 1dd78c6715..45dbe9e216 100644 +--- a/src/cpu_map/Makefile.inc.am ++++ b/src/cpu_map/Makefile.inc.am +@@ -30,6 +30,7 @@ cpumap_DATA = \ + cpu_map/x86_Dhyana.xml \ + cpu_map/x86_EPYC.xml \ + cpu_map/x86_EPYC-IBPB.xml \ ++ cpu_map/x86_EPYC-Milan.xml \ + cpu_map/x86_EPYC-Rome.xml \ + cpu_map/x86_Haswell.xml \ + cpu_map/x86_Haswell-IBRS.xml \ +-- +2.30.0 + diff --git a/SOURCES/libvirt-cpumap-Add-support-for-ibrs-CPU-feature.patch b/SOURCES/libvirt-cpumap-Add-support-for-ibrs-CPU-feature.patch new file mode 100644 index 0000000..9fcd3a4 --- /dev/null +++ b/SOURCES/libvirt-cpumap-Add-support-for-ibrs-CPU-feature.patch @@ -0,0 +1,65 @@ +From bb9f39342d4ea6b76b67378f514f52a9627206b9 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Tim Wiederhake +Date: Wed, 3 Mar 2021 11:11:52 +0100 +Subject: [PATCH] cpumap: Add support for ibrs CPU feature +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Tim Wiederhake +Reviewed-by: Jiri Denemark +(cherry picked from commit 5c17a7ba41670f3182186c06e621995b5d03fc95) + +https://bugzilla.redhat.com/show_bug.cgi?id=1926864 + +Signed-off-by: Jiri Denemark +Message-Id: <0aee3baa35e04f56e3c95bb2f60c8a17d7806e7a.1614766279.git.jdenemar@redhat.com> +Reviewed-by: Ján Tomko +--- + src/cpu_map/x86_features.xml | 3 +++ + tests/cputestdata/x86_64-cpuid-EPYC-7502-32-Core-guest.xml | 1 + + tests/cputestdata/x86_64-cpuid-EPYC-7502-32-Core-host.xml | 1 + + 3 files changed, 5 insertions(+) + +diff --git a/src/cpu_map/x86_features.xml b/src/cpu_map/x86_features.xml +index 83d8e641a8..abefb7928e 100644 +--- a/src/cpu_map/x86_features.xml ++++ b/src/cpu_map/x86_features.xml +@@ -501,6 +501,9 @@ + + + ++ ++ ++ + + + +diff --git a/tests/cputestdata/x86_64-cpuid-EPYC-7502-32-Core-guest.xml b/tests/cputestdata/x86_64-cpuid-EPYC-7502-32-Core-guest.xml +index 6d95b508b2..40e7912398 100644 +--- a/tests/cputestdata/x86_64-cpuid-EPYC-7502-32-Core-guest.xml ++++ b/tests/cputestdata/x86_64-cpuid-EPYC-7502-32-Core-guest.xml +@@ -17,6 +17,7 @@ + + + ++ + + + +diff --git a/tests/cputestdata/x86_64-cpuid-EPYC-7502-32-Core-host.xml b/tests/cputestdata/x86_64-cpuid-EPYC-7502-32-Core-host.xml +index 65eaeabdd0..9f8108cdaa 100644 +--- a/tests/cputestdata/x86_64-cpuid-EPYC-7502-32-Core-host.xml ++++ b/tests/cputestdata/x86_64-cpuid-EPYC-7502-32-Core-host.xml +@@ -18,6 +18,7 @@ + + + ++ + + + +-- +2.30.0 + diff --git a/SOURCES/libvirt-cpumap-Add-support-for-svme-addr-check-CPU-feature.patch b/SOURCES/libvirt-cpumap-Add-support-for-svme-addr-check-CPU-feature.patch new file mode 100644 index 0000000..97d1b6f --- /dev/null +++ b/SOURCES/libvirt-cpumap-Add-support-for-svme-addr-check-CPU-feature.patch @@ -0,0 +1,39 @@ +From 87fdbd2d0ab24f00c70a298317d50df44a5f76ad Mon Sep 17 00:00:00 2001 +Message-Id: <87fdbd2d0ab24f00c70a298317d50df44a5f76ad@dist-git> +From: Tim Wiederhake +Date: Wed, 3 Mar 2021 11:11:53 +0100 +Subject: [PATCH] cpumap: Add support for svme-addr-check CPU feature +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Tim Wiederhake +Reviewed-by: Jiri Denemark +(cherry picked from commit 5ac6ab2fde63881d3c5cc7372a0d0e59618feb55) + +https://bugzilla.redhat.com/show_bug.cgi?id=1926864 + +Signed-off-by: Jiri Denemark +Message-Id: +Reviewed-by: Ján Tomko +--- + src/cpu_map/x86_features.xml | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/cpu_map/x86_features.xml b/src/cpu_map/x86_features.xml +index abefb7928e..8acd42f796 100644 +--- a/src/cpu_map/x86_features.xml ++++ b/src/cpu_map/x86_features.xml +@@ -548,6 +548,9 @@ + + + ++ ++ ++ + + + +-- +2.30.0 + diff --git a/SOURCES/libvirt-docs-improve-description-of-secure-attribute-for-loader-element.patch b/SOURCES/libvirt-docs-improve-description-of-secure-attribute-for-loader-element.patch new file mode 100644 index 0000000..9114b14 --- /dev/null +++ b/SOURCES/libvirt-docs-improve-description-of-secure-attribute-for-loader-element.patch @@ -0,0 +1,47 @@ +From 3398815aa337278fe4085f06f3586b2a1a98ab3d Mon Sep 17 00:00:00 2001 +Message-Id: <3398815aa337278fe4085f06f3586b2a1a98ab3d@dist-git> +From: Pavel Hrdina +Date: Fri, 21 May 2021 14:16:04 +0200 +Subject: [PATCH] docs: improve description of secure attribute for loader + element + +The original text was not explaining what this attribute actually +controls and could have been interpreted as a control switch for the +Secure boot feature in firmwares. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Kashyap Chamarthy +Reviewed-by: Michal Privoznik +(cherry picked from commit f47d06260b9698f705ab2c079c573f89f832e376) + +Conflicts: + docs/formatdomain.rst + - we still have formatdomain.html.in in downstream + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1929357 + +Signed-off-by: Pavel Hrdina +Message-Id: +Reviewed-by: Michal Privoznik +--- + docs/formatdomain.html.in | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in +index 7ac9523684..a40bed347b 100644 +--- a/docs/formatdomain.html.in ++++ b/docs/formatdomain.html.in +@@ -197,7 +197,9 @@ + path points to an UEFI image, type should be + pflash. Moreover, some firmwares may + implement the Secure boot feature. Attribute +- secure can be used then to control it. ++ secure can be used to tell the hypervisor that the ++ firmware is capable of Secure Boot feature. It cannot be used to ++ enable or disable the feature itself in the firmware. + Since 2.1.0

+
nvram
+
Some UEFI firmwares may want to use a non-volatile memory to store +-- +2.31.1 + diff --git a/SOURCES/libvirt-docs-use-proper-cpu-quota-value-in-our-documentation.patch b/SOURCES/libvirt-docs-use-proper-cpu-quota-value-in-our-documentation.patch new file mode 100644 index 0000000..abe880f --- /dev/null +++ b/SOURCES/libvirt-docs-use-proper-cpu-quota-value-in-our-documentation.patch @@ -0,0 +1,101 @@ +From c9113d8cd9d68c932175ea63b634fc5cb7e51ef2 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Pavel Hrdina +Date: Thu, 4 Mar 2021 12:57:56 +0100 +Subject: [PATCH] docs: use proper cpu quota value in our documentation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit changed the cpu quota +value that reflects what kernel allows but did not update our +documentation. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit 992635b142b261cedb6075e459918418fe6e6962) + +Conflicts: + docs/formatdomain.rst + - missing in downstream, we use formatdomain.html.in + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463 + +Signed-off-by: Pavel Hrdina +Message-Id: +Reviewed-by: Ján Tomko +--- + docs/formatdomain.html.in | 8 ++++---- + docs/manpages/virsh.rst | 2 +- + docs/schemas/domaincommon.rng | 2 +- + 3 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in +index 127dd13cc0..4341e256a8 100644 +--- a/docs/formatdomain.html.in ++++ b/docs/formatdomain.html.in +@@ -872,7 +872,7 @@ + bandwidth (unit: microseconds). A domain with quota as any + negative value indicates that the domain has infinite bandwidth for + vCPU threads, which means that it is not bandwidth controlled. The value +- should be in range [1000, 18446744073709551] or less than 0. A quota ++ should be in range [1000, 17592186044415] or less than 0. A quota + with value 0 means no value. You can use this feature to ensure that all + vCPUs run at the same speed. + Only QEMU driver support since 0.9.4, LXC since +@@ -894,7 +894,7 @@ + domain. A domain with global_quota as any negative + value indicates that the domain has infinite bandwidth, which means that + it is not bandwidth controlled. The value should be in range +- [1000, 18446744073709551] or less than 0. A global_quota ++ [1000, 17592186044415] or less than 0. A global_quota + with value 0 means no value. + Only QEMU driver support since 1.3.3 +
+@@ -915,7 +915,7 @@ + excluding vCPUs). A domain with emulator_quota as any negative + value indicates that the domain has infinite bandwidth for emulator threads + (those excluding vCPUs), which means that it is not bandwidth controlled. +- The value should be in range [1000, 18446744073709551] or less than 0. A ++ The value should be in range [1000, 17592186044415] or less than 0. A + quota with value 0 means no value. + Only QEMU driver support since 0.10.0 + +@@ -937,7 +937,7 @@ + iothread_quota as any negative value indicates that the + domain IOThreads have infinite bandwidth, which means that it is + not bandwidth controlled. The value should be in range +- [1000, 18446744073709551] or less than 0. An iothread_quota ++ [1000, 17592186044415] or less than 0. An iothread_quota + with value 0 means no value. You can use this feature to ensure that + all IOThreads run at the same speed. + Only QEMU driver support since 2.1.0 +diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst +index 0804465d44..a5b95c1123 100644 +--- a/docs/manpages/virsh.rst ++++ b/docs/manpages/virsh.rst +@@ -3715,7 +3715,7 @@ XEN_CREDIT scheduler. + ``Note``: The vcpu_period, emulator_period, and iothread_period parameters + have a valid value range of 1000-1000000 or 0, and the vcpu_quota, + emulator_quota, and iothread_quota parameters have a valid value range of +-1000-18446744073709551 or less than 0. The value 0 for ++1000-17592186044415 or less than 0. The value 0 for + either parameter is the same as not specifying that parameter. + + +diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng +index 4a42cb9b40..6671ef3dfa 100644 +--- a/docs/schemas/domaincommon.rng ++++ b/docs/schemas/domaincommon.rng +@@ -6649,7 +6649,7 @@ + + + -?[0-9]+ +- 18446744073709551 ++ 17592186044415 + -1 + + +-- +2.30.0 + diff --git a/SOURCES/libvirt-domain_conf-Don-t-leak-def-os.firmwareFeatures.patch b/SOURCES/libvirt-domain_conf-Don-t-leak-def-os.firmwareFeatures.patch new file mode 100644 index 0000000..431bb2f --- /dev/null +++ b/SOURCES/libvirt-domain_conf-Don-t-leak-def-os.firmwareFeatures.patch @@ -0,0 +1,43 @@ +From 8ad6e3bc6d3e9e55093b546ee886a2a2d9e875f5 Mon Sep 17 00:00:00 2001 +Message-Id: <8ad6e3bc6d3e9e55093b546ee886a2a2d9e875f5@dist-git> +From: Michal Privoznik +Date: Fri, 21 May 2021 14:16:13 +0200 +Subject: [PATCH] domain_conf: Don't leak def->os.firmwareFeatures + +The firmwareFeatures member of virDomainOSDef struct is allocated +in virDomainDefParseBootFirmwareOptions() but never freed. + +Signed-off-by: Michal Privoznik +Reviewed-by: Pavel Hrdina +(cherry picked from commit c116b9481426f86188c71f340d5e3db103120bf8) + +Conflicts: + src/conf/domain_conf.c + - missing upstream commits: + 77f8e48fc35eaf867eae4f623e381f87f6e29930 + f9f81f1c8f855b8c21aeae4441abfc877ff2bfc3 + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1929357 + +Signed-off-by: Pavel Hrdina +Message-Id: <82f4beea71e682c43ec10370d5a43a608d1cb411.1621599207.git.phrdina@redhat.com> +Reviewed-by: Michal Privoznik +--- + src/conf/domain_conf.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 28c8d0ecbd..2ffa9c8a2a 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -3431,6 +3431,7 @@ void virDomainDefFree(virDomainDefPtr def) + VIR_FREE(def->idmap.uidmap); + VIR_FREE(def->idmap.gidmap); + ++ VIR_FREE(def->os.firmwareFeatures); + VIR_FREE(def->os.machine); + VIR_FREE(def->os.init); + for (i = 0; def->os.initargv && def->os.initargv[i]; i++) +-- +2.31.1 + diff --git a/SOURCES/libvirt-domain_validate-use-defines-for-cpu-period-and-quota-limits.patch b/SOURCES/libvirt-domain_validate-use-defines-for-cpu-period-and-quota-limits.patch new file mode 100644 index 0000000..e293dd5 --- /dev/null +++ b/SOURCES/libvirt-domain_validate-use-defines-for-cpu-period-and-quota-limits.patch @@ -0,0 +1,85 @@ +From 499e3eb6bdca10a5fac9279261e32e64c28273bd Mon Sep 17 00:00:00 2001 +Message-Id: <499e3eb6bdca10a5fac9279261e32e64c28273bd@dist-git> +From: Pavel Hrdina +Date: Thu, 4 Mar 2021 12:57:55 +0100 +Subject: [PATCH] domain_validate: use defines for cpu period and quota limits +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commints and +<98a09ca48ed4fc011abf2aa290e02ce1b8f1bb5f> fixed the code to use +defines instead of magic numbers but missed this place. + +Following commit changed +the cpu quota limit to reflect what kernel actually allows so using +the defines fixes XML validations as well. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit 22cae2ea4bad7e285ba19d536bd475f8b00841f8) + +Conflicts: + src/conf/domain_validate.c + - not present in downstream, the code is still part of + domain_conf.c + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463 + +Signed-off-by: Pavel Hrdina +Message-Id: <63a44700876e2bd59f276fcd8395abaff011b4c1.1614858616.git.phrdina@redhat.com> +Reviewed-by: Ján Tomko +--- + src/conf/domain_conf.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 166c3e48d2..9f6cdb0de8 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -34,6 +34,7 @@ + #include "domain_addr.h" + #include "domain_conf.h" + #include "snapshot_conf.h" ++#include "vircgroup.h" + #include "viralloc.h" + #include "virxml.h" + #include "viruuid.h" +@@ -6997,10 +6998,13 @@ virDomainDefLifecycleActionValidate(const virDomainDef *def) + #define CPUTUNE_VALIDATE_PERIOD(name) \ + do { \ + if (def->cputune.name > 0 && \ +- (def->cputune.name < 1000 || def->cputune.name > 1000000)) { \ ++ (def->cputune.name < VIR_CGROUP_CPU_PERIOD_MIN || \ ++ def->cputune.name > VIR_CGROUP_CPU_PERIOD_MAX)) { \ + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \ +- _("Value of cputune '%s' must be in range " \ +- "[1000, 1000000]"), #name); \ ++ _("Value of cputune '%s' must be in range [%llu, %llu]"), \ ++ #name, \ ++ VIR_CGROUP_CPU_PERIOD_MIN, \ ++ VIR_CGROUP_CPU_PERIOD_MAX); \ + return -1; \ + } \ + } while (0) +@@ -7008,11 +7012,13 @@ virDomainDefLifecycleActionValidate(const virDomainDef *def) + #define CPUTUNE_VALIDATE_QUOTA(name) \ + do { \ + if (def->cputune.name > 0 && \ +- (def->cputune.name < 1000 || \ +- def->cputune.name > 18446744073709551LL)) { \ ++ (def->cputune.name < VIR_CGROUP_CPU_QUOTA_MIN || \ ++ def->cputune.name > VIR_CGROUP_CPU_QUOTA_MAX)) { \ + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, \ +- _("Value of cputune '%s' must be in range " \ +- "[1000, 18446744073709551]"), #name); \ ++ _("Value of cputune '%s' must be in range [%llu, %llu]"), \ ++ #name, \ ++ VIR_CGROUP_CPU_QUOTA_MIN, \ ++ VIR_CGROUP_CPU_QUOTA_MAX); \ + return -1; \ + } \ + } while (0) +-- +2.30.0 + diff --git a/SOURCES/libvirt-hostdev-Update-mdev-pointer-reference-after-checking-device-type.patch b/SOURCES/libvirt-hostdev-Update-mdev-pointer-reference-after-checking-device-type.patch new file mode 100644 index 0000000..96deffe --- /dev/null +++ b/SOURCES/libvirt-hostdev-Update-mdev-pointer-reference-after-checking-device-type.patch @@ -0,0 +1,50 @@ +From bad40f7148a5849e84e9cdc341ff1fa03dc94fc6 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Thomas Huth +Date: Tue, 11 May 2021 14:10:27 +0200 +Subject: [PATCH] hostdev: Update mdev pointer reference after checking device + type +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +We set the pointer to some garbage packed structure data without +knowing whether we were actually handling the type of device we +expected to be handling. On its own, this was harmless, because we'd +never use the pointer as we'd skip the device if it were not the +expected type. However, it's better to make the logic even more +explicit - we first check the device and only when we're sure we have +the expected type we then update the pointer shortcut. + +Signed-off-by: Erik Skultety +Reviewed-by: Ján Tomko +(cherry picked from commit 964738cff3d949d90fc5c3317a2618fcd8d217b4) +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1940449 +Signed-off-by: Thomas Huth +Message-Id: <20210511121028.304070-2-thuth@redhat.com> +Reviewed-by: Erik Skultety +--- + src/util/virhostdev.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c +index 9596482146..b7050e99e4 100644 +--- a/src/util/virhostdev.c ++++ b/src/util/virhostdev.c +@@ -2030,11 +2030,11 @@ virHostdevReAttachMediatedDevices(virHostdevManagerPtr mgr, + virDomainHostdevSubsysMediatedDevPtr mdevsrc; + virDomainHostdevDefPtr hostdev = hostdevs[i]; + +- mdevsrc = &hostdev->source.subsys.u.mdev; +- + if (!virHostdevIsMdevDevice(hostdev)) + continue; + ++ mdevsrc = &hostdev->source.subsys.u.mdev; ++ + if (!(mdev = virMediatedDeviceNew(mdevsrc->uuidstr, + mdevsrc->model))) + continue; +-- +2.31.1 + diff --git a/SOURCES/libvirt-hostdev-mdev-Lookup-mdevs-by-sysfs-path-rather-than-mdev-struct.patch b/SOURCES/libvirt-hostdev-mdev-Lookup-mdevs-by-sysfs-path-rather-than-mdev-struct.patch new file mode 100644 index 0000000..3b68fb0 --- /dev/null +++ b/SOURCES/libvirt-hostdev-mdev-Lookup-mdevs-by-sysfs-path-rather-than-mdev-struct.patch @@ -0,0 +1,166 @@ +From 9e97e35031572e0f6ace32e2fb094f0f358f0391 Mon Sep 17 00:00:00 2001 +Message-Id: <9e97e35031572e0f6ace32e2fb094f0f358f0391@dist-git> +From: Thomas Huth +Date: Tue, 11 May 2021 14:10:28 +0200 +Subject: [PATCH] hostdev: mdev: Lookup mdevs by sysfs path rather than mdev + struct +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The lookup didn't do anything apart from comparing the sysfs paths +anyway since that's what makes each mdev unique. +The most ridiculous usage of the old logic was in +virHostdevReAttachMediatedDevices where in order to drop an mdev +hostdev from the list of active devices we first had to create a new +mdev and use it in the lookup call. Why couldn't we have used the +hostdev directly? Because the hostdev and mdev structures are +incompatible. + +The way mdevs are currently removed is via a write to a specific sysfs +attribute. If you do it while the machine which has the mdev assigned +is running, the write call may block (with a new enough kernel, with +older kernels it would return a write error!) until the device +is no longer in use which is when the QEMU process exits. + +The interesting part here comes afterwards when we're cleaning up and +call virHostdevReAttachMediatedDevices. The domain doesn't exist +anymore, so the list of active hostdevs needs to be updated and the +respective hostdevs removed from the list, but remember we had to +create an mdev object in the memory in order to find it in the list +first which will fail because the write to sysfs had already removed +the mdev instance from the host system. +And so the next time you try to start the same domain you'll get: + +"Requested operation is not valid: mediated device is in use by +driver QEMU, domain " + +Fixes: https://gitlab.com/libvirt/libvirt/-/issues/119 + +Signed-off-by: Erik Skultety +Reviewed-by: Ján Tomko +(cherry picked from commit 49cb59778a4e6c2d04bb9383a9d97fbbc83f9fce) +Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1940449 +Signed-off-by: Thomas Huth +Message-Id: <20210511121028.304070-3-thuth@redhat.com> +Reviewed-by: Erik Skultety +--- + src/util/virhostdev.c | 10 ++++------ + src/util/virmdev.c | 16 ++++++++-------- + src/util/virmdev.h | 4 ++-- + 3 files changed, 14 insertions(+), 16 deletions(-) + +diff --git a/src/util/virhostdev.c b/src/util/virhostdev.c +index b7050e99e4..392e94307c 100644 +--- a/src/util/virhostdev.c ++++ b/src/util/virhostdev.c +@@ -2025,7 +2025,7 @@ virHostdevReAttachMediatedDevices(virHostdevManagerPtr mgr, + + virObjectLock(mgr->activeMediatedHostdevs); + for (i = 0; i < nhostdevs; i++) { +- g_autoptr(virMediatedDevice) mdev = NULL; ++ g_autofree char *sysfspath = NULL; + virMediatedDevicePtr tmp; + virDomainHostdevSubsysMediatedDevPtr mdevsrc; + virDomainHostdevDefPtr hostdev = hostdevs[i]; +@@ -2034,14 +2034,12 @@ virHostdevReAttachMediatedDevices(virHostdevManagerPtr mgr, + continue; + + mdevsrc = &hostdev->source.subsys.u.mdev; +- +- if (!(mdev = virMediatedDeviceNew(mdevsrc->uuidstr, +- mdevsrc->model))) +- continue; ++ sysfspath = virMediatedDeviceGetSysfsPath(mdevsrc->uuidstr); + + /* Remove from the list only mdevs assigned to @drv_name/@dom_name */ + +- tmp = virMediatedDeviceListFind(mgr->activeMediatedHostdevs, mdev); ++ tmp = virMediatedDeviceListFind(mgr->activeMediatedHostdevs, ++ sysfspath); + + /* skip inactive devices */ + if (!tmp) +diff --git a/src/util/virmdev.c b/src/util/virmdev.c +index c2499c0a20..bae4a7d2c1 100644 +--- a/src/util/virmdev.c ++++ b/src/util/virmdev.c +@@ -312,7 +312,7 @@ int + virMediatedDeviceListAdd(virMediatedDeviceListPtr list, + virMediatedDevicePtr *dev) + { +- if (virMediatedDeviceListFind(list, *dev)) { ++ if (virMediatedDeviceListFind(list, (*dev)->path)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("device %s is already in use"), (*dev)->path); + return -1; +@@ -358,7 +358,7 @@ virMediatedDevicePtr + virMediatedDeviceListSteal(virMediatedDeviceListPtr list, + virMediatedDevicePtr dev) + { +- int idx = virMediatedDeviceListFindIndex(list, dev); ++ int idx = virMediatedDeviceListFindIndex(list, dev->path); + + return virMediatedDeviceListStealIndex(list, idx); + } +@@ -374,13 +374,13 @@ virMediatedDeviceListDel(virMediatedDeviceListPtr list, + + int + virMediatedDeviceListFindIndex(virMediatedDeviceListPtr list, +- virMediatedDevicePtr dev) ++ const char *sysfspath) + { + size_t i; + + for (i = 0; i < list->count; i++) { +- virMediatedDevicePtr other = list->devs[i]; +- if (STREQ(other->path, dev->path)) ++ virMediatedDevicePtr dev = list->devs[i]; ++ if (STREQ(sysfspath, dev->path)) + return i; + } + return -1; +@@ -389,11 +389,11 @@ virMediatedDeviceListFindIndex(virMediatedDeviceListPtr list, + + virMediatedDevicePtr + virMediatedDeviceListFind(virMediatedDeviceListPtr list, +- virMediatedDevicePtr dev) ++ const char *sysfspath) + { + int idx; + +- if ((idx = virMediatedDeviceListFindIndex(list, dev)) >= 0) ++ if ((idx = virMediatedDeviceListFindIndex(list, sysfspath)) >= 0) + return list->devs[idx]; + else + return NULL; +@@ -407,7 +407,7 @@ virMediatedDeviceIsUsed(virMediatedDevicePtr dev, + const char *drvname, *domname; + virMediatedDevicePtr tmp = NULL; + +- if ((tmp = virMediatedDeviceListFind(list, dev))) { ++ if ((tmp = virMediatedDeviceListFind(list, dev->path))) { + virMediatedDeviceGetUsedBy(tmp, &drvname, &domname); + virReportError(VIR_ERR_OPERATION_INVALID, + _("mediated device %s is in use by " +diff --git a/src/util/virmdev.h b/src/util/virmdev.h +index e0905a3f6e..3022ab9948 100644 +--- a/src/util/virmdev.h ++++ b/src/util/virmdev.h +@@ -120,11 +120,11 @@ virMediatedDeviceListDel(virMediatedDeviceListPtr list, + + virMediatedDevicePtr + virMediatedDeviceListFind(virMediatedDeviceListPtr list, +- virMediatedDevicePtr dev); ++ const char *sysfspath); + + int + virMediatedDeviceListFindIndex(virMediatedDeviceListPtr list, +- virMediatedDevicePtr dev); ++ const char *sysfspath); + + int + virMediatedDeviceListMarkDevices(virMediatedDeviceListPtr dst, +-- +2.31.1 + diff --git a/SOURCES/libvirt-network-force-re-creation-of-iptables-private-chains-on-firewalld-restart.patch b/SOURCES/libvirt-network-force-re-creation-of-iptables-private-chains-on-firewalld-restart.patch new file mode 100644 index 0000000..f35830d --- /dev/null +++ b/SOURCES/libvirt-network-force-re-creation-of-iptables-private-chains-on-firewalld-restart.patch @@ -0,0 +1,282 @@ +From 021167719bebe7fb7a0e366c371b6c7057ebed7e Mon Sep 17 00:00:00 2001 +Message-Id: <021167719bebe7fb7a0e366c371b6c7057ebed7e@dist-git> +From: Laine Stump +Date: Wed, 14 Apr 2021 23:25:34 -0400 +Subject: [PATCH] network: force re-creation of iptables private chains on + firewalld restart +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When firewalld is stopped, it removes *all* iptables rules and chains, +including those added by libvirt. Since restarting firewalld means +stopping and then starting it, any time it is restarted, libvirt needs +to recreate all the private iptables chains it uses, along with all +the rules it adds. + +We already have code in place to call networkReloadFirewallRules() any +time we're notified of a firewalld start, and +networkReloadFirewallRules() will call +networkPreReloadFirewallRules(), which calls +networkSetupPrivateChains(); unfortunately that last call is called +using virOnce(), meaning that it will only be called the first time +through networkPreReloadFirewallRules() after libvirtd starts - so of +course when firewalld is later restarted, the call to +networkSetupPrivateChains() is skipped. + +The neat and tidy way to fix this would be if there was a standard way +to reset a pthread_once_t object so that the next time virOnce was +called, it would think the function hadn't been called, and call it +again. Unfortunately, there isn't any official way of doing that (we +*could* just fill it with 0 and hope for the best, but that doesn't +seem very safe. + +So instead, this patch just adds a static variable called +chainInitDone, which is set to true after networkSetupPrivateChains() +is called for the first time, and then during calls to +networkPreReloadFirewallRules(), if chainInitDone is set, we call +networkSetupPrivateChains() directly instead of via virOnce(). + +It may seem unsafe to directly call a function that is meant to be +called only once, but I think in this case we're safe - there's +nothing in the function that is inherently "once only" - it doesn't +initialize anything that can't safely be re-initialized (as long as +two threads don't try to do it at the same time), and it only happens +when responding to a dbus message that firewalld has been started (and +I don't think it's possible for us to be processing two of those at +once), and even then only if the initial call to the function has +already been completed (so we're safe if we receive a firewalld +restart call at a time when we haven't yet called it, or even if +another thread is already in the process of executing it. The only +problematic bit I can think of is if another thread is in the process +of adding an iptable rule at the time we're executing this function, +but 1) none of those threads will be trying to add chains, and 2) if +there was a concurrency problem with other threads adding iptables +rules while firewalld was being restarted, it would still be a problem +even without this change. + +This is yet another patch that fixes an occurrence of this error: + +COMMAND_FAILED: '/usr/sbin/iptables -w10 -w --table filter --insert LIBVIRT_INP --in-interface virbr0 --protocol tcp --destination-port 67 --jump ACCEPT' failed: iptables: No chain/target/match by that name. + +Signed-off-by: Laine Stump +Reviewed-by: Daniel P. Berrangé +(cherry picked from commit f5418b427e7d2f26803880309478de9103680826) + +https://bugzilla.redhat.com/1942805 +(cloned from the RHEL-AV version: https://bugzilla.redhat.com/1813830 ) + +Conflicts: + src/network/bridge_driver.c: + In one place a later commit was backported prior to this commit, + removing a VIR_DEBUG line and some { }. (see upstream commit + c102bbd3efc35, which was backported for + https://bugzilla.redhat.com/1607929 + +Signed-off-by: Laine Stump +Message-Id: <20210415032534.723202-3-laine@redhat.com> +Reviewed-by: Pavel Hrdina +--- + src/network/bridge_driver.c | 16 ++++--- + src/network/bridge_driver_linux.c | 69 ++++++++++++++++++---------- + src/network/bridge_driver_nop.c | 3 +- + src/network/bridge_driver_platform.h | 2 +- + 4 files changed, 58 insertions(+), 32 deletions(-) + +diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c +index 5995396f78..b8118067d1 100644 +--- a/src/network/bridge_driver.c ++++ b/src/network/bridge_driver.c +@@ -271,7 +271,9 @@ static int + networkShutdownNetworkExternal(virNetworkObjPtr obj); + + static void +-networkReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup); ++networkReloadFirewallRules(virNetworkDriverStatePtr driver, ++ bool startup, ++ bool force); + + static void + networkRefreshDaemons(virNetworkDriverStatePtr driver); +@@ -690,7 +692,7 @@ firewalld_dbus_filter_bridge(DBusConnection *connection G_GNUC_UNUSED, + } + + if (reload) +- networkReloadFirewallRules(driver, false); ++ networkReloadFirewallRules(driver, false, true); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } +@@ -791,7 +793,7 @@ networkStateInitialize(bool privileged, + virNetworkObjListPrune(network_driver->networks, + VIR_CONNECT_LIST_NETWORKS_INACTIVE | + VIR_CONNECT_LIST_NETWORKS_TRANSIENT); +- networkReloadFirewallRules(network_driver, true); ++ networkReloadFirewallRules(network_driver, true, false); + networkRefreshDaemons(network_driver); + + if (virDriverShouldAutostart(network_driver->stateDir, &autostart) < 0) +@@ -861,7 +863,7 @@ networkStateReload(void) + network_driver->networkConfigDir, + network_driver->networkAutostartDir, + network_driver->xmlopt); +- networkReloadFirewallRules(network_driver, false); ++ networkReloadFirewallRules(network_driver, false, false); + networkRefreshDaemons(network_driver); + virNetworkObjListForEach(network_driver->networks, + networkAutostartConfig, +@@ -2229,14 +2231,16 @@ networkReloadFirewallRulesHelper(virNetworkObjPtr obj, + + + static void +-networkReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup) ++networkReloadFirewallRules(virNetworkDriverStatePtr driver, ++ bool startup, ++ bool force) + { + VIR_INFO("Reloading iptables rules"); + /* Ideally we'd not even register the driver when unprivilegd + * but until we untangle the virt driver that's not viable */ + if (!driver->privileged) + return; +- networkPreReloadFirewallRules(driver, startup); ++ networkPreReloadFirewallRules(driver, startup, force); + virNetworkObjListForEach(driver->networks, + networkReloadFirewallRulesHelper, + NULL); +diff --git a/src/network/bridge_driver_linux.c b/src/network/bridge_driver_linux.c +index b6b324d1d5..f707bf8e47 100644 +--- a/src/network/bridge_driver_linux.c ++++ b/src/network/bridge_driver_linux.c +@@ -36,11 +36,14 @@ VIR_LOG_INIT("network.bridge_driver_linux"); + #define PROC_NET_ROUTE "/proc/net/route" + + static virOnceControl createdOnce; +-static bool createdChains; ++static bool chainInitDone; /* true iff networkSetupPrivateChains was ever called */ ++static bool createdChains; /* true iff networkSetupPrivateChains created chains during most recent call */ + static virErrorPtr errInitV4; + static virErrorPtr errInitV6; + +-/* Only call via virOnce */ ++/* Usually only called via virOnce, but can also be called directly in ++ * response to firewalld reload (if chainInitDone == true) ++ */ + static void networkSetupPrivateChains(void) + { + int rc; +@@ -82,6 +85,8 @@ static void networkSetupPrivateChains(void) + VIR_DEBUG("Global IPv6 chains already exist"); + } + } ++ ++ chainInitDone = true; + } + + +@@ -111,7 +116,10 @@ networkHasRunningNetworks(virNetworkDriverStatePtr driver) + } + + +-void networkPreReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup) ++void ++networkPreReloadFirewallRules(virNetworkDriverStatePtr driver, ++ bool startup, ++ bool force) + { + /* + * If there are any running networks, we need to +@@ -130,29 +138,42 @@ void networkPreReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup + * of starting the network though as that makes them + * more likely to be seen by a human + */ +- if (!networkHasRunningNetworks(driver)) { +- VIR_DEBUG("Delayed global rule setup as no networks are running"); +- return; +- } ++ if (chainInitDone && force) { ++ /* The Private chains have already been initialized once ++ * during this run of libvirtd, so 1) we can't do it again via ++ * virOnce(), and 2) we need to re-add the private chains even ++ * if there are currently no running networks, because the ++ * next time a network is started, libvirt will expect that ++ * the chains have already been added. So we call directly ++ * instead of via virOnce(). ++ */ ++ networkSetupPrivateChains(); + +- ignore_value(virOnce(&createdOnce, networkSetupPrivateChains)); ++ } else { ++ if (!networkHasRunningNetworks(driver)) { ++ VIR_DEBUG("Delayed global rule setup as no networks are running"); ++ return; ++ } + +- /* +- * If this is initial startup, and we just created the +- * top level private chains we either +- * +- * - upgraded from old libvirt +- * - freshly booted from clean state +- * +- * In the first case we must delete the old rules from +- * the built-in chains, instead of our new private chains. +- * In the second case it doesn't matter, since no existing +- * rules will be present. Thus we can safely just tell it +- * to always delete from the builin chain +- */ +- if (startup && createdChains) { +- VIR_DEBUG("Requesting cleanup of legacy firewall rules"); +- iptablesSetDeletePrivate(false); ++ ignore_value(virOnce(&createdOnce, networkSetupPrivateChains)); ++ ++ /* ++ * If this is initial startup, and we just created the ++ * top level private chains we either ++ * ++ * - upgraded from old libvirt ++ * - freshly booted from clean state ++ * ++ * In the first case we must delete the old rules from ++ * the built-in chains, instead of our new private chains. ++ * In the second case it doesn't matter, since no existing ++ * rules will be present. Thus we can safely just tell it ++ * to always delete from the builin chain ++ */ ++ if (startup && createdChains) { ++ VIR_DEBUG("Requesting cleanup of legacy firewall rules"); ++ iptablesSetDeletePrivate(false); ++ } + } + } + +diff --git a/src/network/bridge_driver_nop.c b/src/network/bridge_driver_nop.c +index 08d737511f..db89c10023 100644 +--- a/src/network/bridge_driver_nop.c ++++ b/src/network/bridge_driver_nop.c +@@ -20,7 +20,8 @@ + #include + + void networkPreReloadFirewallRules(virNetworkDriverStatePtr driver G_GNUC_UNUSED, +- bool startup G_GNUC_UNUSED) ++ bool startup G_GNUC_UNUSED, ++ bool force G_GNUC_UNUSED) + { + } + +diff --git a/src/network/bridge_driver_platform.h b/src/network/bridge_driver_platform.h +index 169417a6c0..48ab52c160 100644 +--- a/src/network/bridge_driver_platform.h ++++ b/src/network/bridge_driver_platform.h +@@ -62,7 +62,7 @@ struct _virNetworkDriverState { + typedef struct _virNetworkDriverState virNetworkDriverState; + typedef virNetworkDriverState *virNetworkDriverStatePtr; + +-void networkPreReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup); ++void networkPreReloadFirewallRules(virNetworkDriverStatePtr driver, bool startup, bool force); + void networkPostReloadFirewallRules(bool startup); + + int networkCheckRouteCollision(virNetworkDefPtr def); +-- +2.31.1 + diff --git a/SOURCES/libvirt-network-make-it-safe-to-call-networkSetupPrivateChains-multiple-times.patch b/SOURCES/libvirt-network-make-it-safe-to-call-networkSetupPrivateChains-multiple-times.patch new file mode 100644 index 0000000..b07b70d --- /dev/null +++ b/SOURCES/libvirt-network-make-it-safe-to-call-networkSetupPrivateChains-multiple-times.patch @@ -0,0 +1,65 @@ +From 4792bd80c542f7af373bc939492017bd420a3f3b Mon Sep 17 00:00:00 2001 +Message-Id: <4792bd80c542f7af373bc939492017bd420a3f3b@dist-git> +From: Laine Stump +Date: Wed, 14 Apr 2021 23:25:33 -0400 +Subject: [PATCH] network: make it safe to call networkSetupPrivateChains() + multiple times +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +networkSetupPrivateChains() is currently called only once per run of +libvirtd, so it can assume that errInitV4 and errInitV6 are empty/null +when it is called. In preparation for potentially calling this +function multiple times during one run, this patch moves the reset of +errInitV[46] to the top of the function, to assure no memory is +leaked. + +Signed-off-by: Laine Stump +Reviewed-by: Daniel P. Berrangé +(cherry picked from commit de110f110fb917a31b9f33ad8e4b3c1d3284766a) + +https://bugzilla.redhat.com/1942805 + +Message-Id: <20210415032534.723202-2-laine@redhat.com> +Reviewed-by: Pavel Hrdina +--- + src/network/bridge_driver_linux.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/network/bridge_driver_linux.c b/src/network/bridge_driver_linux.c +index 9de8e93c60..b6b324d1d5 100644 +--- a/src/network/bridge_driver_linux.c ++++ b/src/network/bridge_driver_linux.c +@@ -48,6 +48,10 @@ static void networkSetupPrivateChains(void) + VIR_DEBUG("Setting up global firewall chains"); + + createdChains = false; ++ virFreeError(errInitV4); ++ errInitV4 = NULL; ++ virFreeError(errInitV6); ++ errInitV6 = NULL; + + rc = iptablesSetupPrivateChains(VIR_FIREWALL_LAYER_IPV4); + if (rc < 0) { +@@ -56,8 +60,6 @@ static void networkSetupPrivateChains(void) + errInitV4 = virSaveLastError(); + virResetLastError(); + } else { +- virFreeError(errInitV4); +- errInitV4 = NULL; + if (rc) { + VIR_DEBUG("Created global IPv4 chains"); + createdChains = true; +@@ -73,8 +75,6 @@ static void networkSetupPrivateChains(void) + errInitV6 = virSaveLastError(); + virResetLastError(); + } else { +- virFreeError(errInitV6); +- errInitV6 = NULL; + if (rc) { + VIR_DEBUG("Created global IPv6 chains"); + createdChains = true; +-- +2.31.1 + diff --git a/SOURCES/libvirt-qemu-Add-virtio-related-options-to-vsock.patch b/SOURCES/libvirt-qemu-Add-virtio-related-options-to-vsock.patch new file mode 100644 index 0000000..4b1eab9 --- /dev/null +++ b/SOURCES/libvirt-qemu-Add-virtio-related-options-to-vsock.patch @@ -0,0 +1,312 @@ +From 362d106d8897a3982f5eaed0c4bc0194d6f9ef28 Mon Sep 17 00:00:00 2001 +Message-Id: <362d106d8897a3982f5eaed0c4bc0194d6f9ef28@dist-git> +From: Boris Fiuczynski +Date: Fri, 26 Feb 2021 06:43:35 -0500 +Subject: [PATCH] qemu: Add virtio related options to vsock + +Add virtio related options iommu, ats and packed as driver element attributes +to vsock devices. Ex: + + + + + + +Signed-off-by: Boris Fiuczynski +Signed-off-by: Michal Privoznik +Reviewed-by: Michal Privoznik +(cherry picked from commit bd112c9e0f7523b90bf1362cf60deea7db05a32b) + +Resolves: https://bugzilla.redhat.com/1931548 + +Note: since the virtio option packed is not yet available in the code +version it will also not be available with this backported patch. + +Conflicts: docs/formatdomain.rst: + converted changes into docs/formatdomain.html.in + src/conf/domain_conf.c: + resolved conflicts by moving the code into the correct methods + src/conf/domain_validate.c: + does not exist downstream. moved code to src/conf/domain_conf.c + src/qemu/qemu_validate.c: + does not exist downstream. can be neglected + +Message-Id: <20210226114335.100390-2-bfiuczyn@redhat.com> +Reviewed-by: Pavel Hrdina +--- + docs/formatdomain.html.in | 5 ++- + docs/schemas/domaincommon.rng | 5 +++ + src/conf/domain_conf.c | 27 ++++++++++++++ + src/conf/domain_conf.h | 1 + + src/qemu/qemu_command.c | 4 ++ + .../vhost-vsock-ccw-iommu.s390x-latest.args | 37 +++++++++++++++++++ + .../vhost-vsock-ccw-iommu.xml | 37 +++++++++++++++++++ + tests/qemuxml2argvtest.c | 1 + + .../vhost-vsock-ccw-iommu.s390x-latest.xml | 1 + + tests/qemuxml2xmltest.c | 2 + + 10 files changed, 119 insertions(+), 1 deletion(-) + create mode 100644 tests/qemuxml2argvdata/vhost-vsock-ccw-iommu.s390x-latest.args + create mode 100644 tests/qemuxml2argvdata/vhost-vsock-ccw-iommu.xml + create mode 120000 tests/qemuxml2xmloutdata/vhost-vsock-ccw-iommu.s390x-latest.xml + +diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in +index bec753e37f..127dd13cc0 100644 +--- a/docs/formatdomain.html.in ++++ b/docs/formatdomain.html.in +@@ -9240,7 +9240,10 @@ qemu-kvm -net nic,model=? /dev/null + element specifies the CID assigned to the guest. If the attribute + auto is set to yes, libvirt + will assign a free CID automatically on domain startup. +- Since 4.4.0

++ Since 4.4.0 ++ The optional driver element allows to specify virtio options, see ++ Virtio-specific options for more details. ++ Since 7.1.0

+ +
+ ...
+diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
+index 9fda5f17e0..4a42cb9b40 100644
+--- a/docs/schemas/domaincommon.rng
++++ b/docs/schemas/domaincommon.rng
+@@ -4685,6 +4685,11 @@
+         
+           
+         
++        
++          
++            
++          
++        
+       
+     
+   
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index c5a0442c6f..166c3e48d2 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -2392,6 +2392,7 @@ virDomainVsockDefFree(virDomainVsockDefPtr vsock)
+ 
+     virObjectUnref(vsock->privateData);
+     virDomainDeviceInfoClear(&vsock->info);
++    VIR_FREE(vsock->virtio);
+     VIR_FREE(vsock);
+ }
+ 
+@@ -6504,6 +6505,15 @@ virDomainMemoryDefValidate(const virDomainMemoryDef *mem)
+ }
+ 
+ 
++static bool
++virDomainVsockIsVirtioModel(const virDomainVsockDef *vsock)
++{
++    return (vsock->model == VIR_DOMAIN_VSOCK_MODEL_VIRTIO ||
++            vsock->model == VIR_DOMAIN_VSOCK_MODEL_VIRTIO_TRANSITIONAL ||
++            vsock->model == VIR_DOMAIN_VSOCK_MODEL_VIRTIO_NON_TRANSITIONAL);
++}
++
++
+ static int
+ virDomainVsockDefValidate(const virDomainVsockDef *vsock)
+ {
+@@ -6513,6 +6523,10 @@ virDomainVsockDefValidate(const virDomainVsockDef *vsock)
+         return -1;
+     }
+ 
++    if (!virDomainVsockIsVirtioModel(vsock) &&
++        virDomainCheckVirtioOptions(vsock->virtio) < 0)
++        return -1;
++
+     return 0;
+ }
+ 
+@@ -16649,6 +16663,11 @@ virDomainVsockDefParseXML(virDomainXMLOptionPtr xmlopt,
+     if (virDomainDeviceInfoParseXML(xmlopt, node, &vsock->info, flags) < 0)
+         return NULL;
+ 
++    if (virDomainVirtioOptionsParseXML(virXPathNode("./driver", ctxt),
++                                       &vsock->virtio) < 0)
++        return NULL;
++
++
+     return g_steal_pointer(&vsock);
+ }
+ 
+@@ -23350,6 +23369,10 @@ virDomainVsockDefCheckABIStability(virDomainVsockDefPtr src,
+         return false;
+     }
+ 
++    if (src->virtio && dst->virtio &&
++        !virDomainVirtioOptionsCheckABIStability(src->virtio, dst->virtio))
++        return false;
++
+     if (!virDomainDeviceInfoCheckABIStability(&src->info, &dst->info))
+         return false;
+ 
+@@ -28364,6 +28387,7 @@ virDomainVsockDefFormat(virBufferPtr buf,
+     g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
+     g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
+     g_auto(virBuffer) cidAttrBuf = VIR_BUFFER_INITIALIZER;
++    g_auto(virBuffer) drvAttrBuf = VIR_BUFFER_INITIALIZER;
+ 
+     if (vsock->model) {
+         virBufferAsprintf(&attrBuf, " model='%s'",
+@@ -28381,6 +28405,9 @@ virDomainVsockDefFormat(virBufferPtr buf,
+     if (virDomainDeviceInfoFormat(&childBuf, &vsock->info, 0) < 0)
+         return -1;
+ 
++    virDomainVirtioOptionsFormat(&drvAttrBuf, vsock->virtio);
++
++    virXMLFormatElement(&childBuf, "driver", &drvAttrBuf, NULL);
+     virXMLFormatElement(buf, "vsock", &attrBuf, &childBuf);
+ 
+     return 0;
+diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
+index 118077edaa..3aed1fb22a 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -2389,6 +2389,7 @@ struct _virDomainVsockDef {
+     virTristateBool auto_cid;
+ 
+     virDomainDeviceInfo info;
++    virDomainVirtioOptionsPtr virtio;
+ };
+ 
+ struct _virDomainVirtioOptions {
+diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
+index 67d7334b0f..998c3c90f8 100644
+--- a/src/qemu/qemu_command.c
++++ b/src/qemu/qemu_command.c
+@@ -9965,6 +9965,10 @@ qemuBuildVsockDevStr(virDomainDefPtr def,
+     virBufferAsprintf(&buf, ",id=%s", vsock->info.alias);
+     virBufferAsprintf(&buf, ",guest-cid=%u", vsock->guest_cid);
+     virBufferAsprintf(&buf, ",vhostfd=%s%u", fdprefix, priv->vhostfd);
++
++    if (qemuBuildVirtioOptionsStr(&buf, vsock->virtio, qemuCaps) < 0)
++        return NULL;
++
+     if (qemuBuildDeviceAddressStr(&buf, def, &vsock->info, qemuCaps) < 0)
+         return NULL;
+ 
+diff --git a/tests/qemuxml2argvdata/vhost-vsock-ccw-iommu.s390x-latest.args b/tests/qemuxml2argvdata/vhost-vsock-ccw-iommu.s390x-latest.args
+new file mode 100644
+index 0000000000..78eede78d3
+--- /dev/null
++++ b/tests/qemuxml2argvdata/vhost-vsock-ccw-iommu.s390x-latest.args
+@@ -0,0 +1,37 @@
++LC_ALL=C \
++PATH=/bin \
++HOME=/tmp/lib/domain--1-QEMUGuest1 \
++USER=test \
++LOGNAME=test \
++XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \
++XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \
++XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \
++QEMU_AUDIO_DRV=none \
++/usr/bin/qemu-system-s390x \
++-name guest=QEMUGuest1,debug-threads=on \
++-S \
++-object secret,id=masterKey0,format=raw,\
++file=/tmp/lib/domain--1-QEMUGuest1/master-key.aes \
++-machine s390-ccw-virtio,accel=tcg,usb=off,dump-guest-core=off \
++-cpu qemu \
++-m 214 \
++-overcommit mem-lock=off \
++-smp 1,sockets=1,cores=1,threads=1 \
++-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \
++-display none \
++-no-user-config \
++-nodefaults \
++-chardev socket,id=charmonitor,fd=1729,server,nowait \
++-mon chardev=charmonitor,id=monitor,mode=control \
++-rtc base=utc \
++-no-shutdown \
++-boot strict=on \
++-drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-virtio-disk0 \
++-device virtio-blk-ccw,scsi=off,devno=fe.0.0000,drive=drive-virtio-disk0,\
++id=virtio-disk0,bootindex=1 \
++-device virtio-balloon-ccw,id=balloon0,devno=fe.0.0001 \
++-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,\
++resourcecontrol=deny \
++-device vhost-vsock-ccw,id=vsock0,guest-cid=4,vhostfd=6789,iommu_platform=on,\
++devno=fe.0.0002 \
++-msg timestamp=on
+diff --git a/tests/qemuxml2argvdata/vhost-vsock-ccw-iommu.xml b/tests/qemuxml2argvdata/vhost-vsock-ccw-iommu.xml
+new file mode 100644
+index 0000000000..dbfe082a6f
+--- /dev/null
++++ b/tests/qemuxml2argvdata/vhost-vsock-ccw-iommu.xml
+@@ -0,0 +1,37 @@
++
++  QEMUGuest1
++  c7a5fdbd-edaf-9455-926a-d65c16db1809
++  219136
++  219136
++  1
++  
++    hvm
++    
++  
++  
++    qemu
++  
++  
++  destroy
++  restart
++  destroy
++  
++    /usr/bin/qemu-system-s390x
++    
++      
++      
++      
++      
++ ++ ++ ++
++ ++ ++ ++ ++
++ ++ ++ ++ +diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c +index 629f5ac100..a22e3ba157 100644 +--- a/tests/qemuxml2argvtest.c ++++ b/tests/qemuxml2argvtest.c +@@ -3056,6 +3056,7 @@ mymain(void) + DO_TEST_CAPS_LATEST("vhost-vsock-auto"); + DO_TEST_CAPS_ARCH_LATEST("vhost-vsock-ccw", "s390x"); + DO_TEST_CAPS_ARCH_LATEST("vhost-vsock-ccw-auto", "s390x"); ++ DO_TEST_CAPS_ARCH_LATEST("vhost-vsock-ccw-iommu", "s390x"); + + DO_TEST_CAPS_VER("launch-security-sev", "2.12.0"); + +diff --git a/tests/qemuxml2xmloutdata/vhost-vsock-ccw-iommu.s390x-latest.xml b/tests/qemuxml2xmloutdata/vhost-vsock-ccw-iommu.s390x-latest.xml +new file mode 120000 +index 0000000000..78971a8ef9 +--- /dev/null ++++ b/tests/qemuxml2xmloutdata/vhost-vsock-ccw-iommu.s390x-latest.xml +@@ -0,0 +1 @@ ++../qemuxml2argvdata/vhost-vsock-ccw-iommu.xml +\ No newline at end of file +diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c +index 60efcac6c8..461b5bc68f 100644 +--- a/tests/qemuxml2xmltest.c ++++ b/tests/qemuxml2xmltest.c +@@ -1433,6 +1433,8 @@ mymain(void) + QEMU_CAPS_CCW); + DO_TEST("vhost-vsock-ccw-auto", QEMU_CAPS_DEVICE_VHOST_VSOCK, + QEMU_CAPS_CCW); ++ DO_TEST_CAPS_ARCH_LATEST("vhost-vsock-ccw-iommu", "s390x"); ++ + + DO_TEST_CAPS_LATEST("vhost-user-fs-fd-memory"); + DO_TEST_CAPS_LATEST("vhost-user-fs-hugepages"); +-- +2.30.0 + diff --git a/SOURCES/libvirt-qemu-implement-support-for-firmware-auto-selection-feature-filtering.patch b/SOURCES/libvirt-qemu-implement-support-for-firmware-auto-selection-feature-filtering.patch new file mode 100644 index 0000000..f780cd6 --- /dev/null +++ b/SOURCES/libvirt-qemu-implement-support-for-firmware-auto-selection-feature-filtering.patch @@ -0,0 +1,248 @@ +From d1c5d166a891a2abf408a5879b95bded23b45825 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Pavel Hrdina +Date: Fri, 21 May 2021 14:16:12 +0200 +Subject: [PATCH] qemu: implement support for firmware auto-selection feature + filtering + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit c91fa273062ec388385bf8cc081117c78c2f7af5) + +Conflicts: + tests/qemuxml2argvdata/os-firmware-efi-no-enrolled-keys.x86_64-latest.args + - missing upstream commits: + d96fb5cb31b870e1539bd8ee95fb27dbe461a357 + 43c9c0859f2d53321ccc646ab905beec0740490b + 88957116c9d3cb4705380c3702c9d4315fb500bb + + tests/qemuxml2argvdata/os-firmware-efi-no-enrolled-keys.xml + - missing upstream commits: + e88367095f3cad2cf80a687fd599dfaeb3073841 + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1929357 + +Signed-off-by: Pavel Hrdina +Message-Id: +Reviewed-by: Michal Privoznik +--- + src/qemu/qemu_firmware.c | 40 +++++++++++++++ + ...re-efi-no-enrolled-keys.x86_64-latest.args | 47 ++++++++++++++++++ + .../os-firmware-efi-no-enrolled-keys.xml | 49 +++++++++++++++++++ + tests/qemuxml2argvtest.c | 1 + + ...are-efi-no-enrolled-keys.x86_64-latest.xml | 1 + + tests/qemuxml2xmltest.c | 1 + + 6 files changed, 139 insertions(+) + create mode 100644 tests/qemuxml2argvdata/os-firmware-efi-no-enrolled-keys.x86_64-latest.args + create mode 100644 tests/qemuxml2argvdata/os-firmware-efi-no-enrolled-keys.xml + create mode 120000 tests/qemuxml2xmloutdata/os-firmware-efi-no-enrolled-keys.x86_64-latest.xml + +diff --git a/src/qemu/qemu_firmware.c b/src/qemu/qemu_firmware.c +index 8ef515ca57..e875e355c7 100644 +--- a/src/qemu/qemu_firmware.c ++++ b/src/qemu/qemu_firmware.c +@@ -952,6 +952,10 @@ qemuFirmwareMatchDomain(const virDomainDef *def, + bool supportsS4 = false; + bool requiresSMM = false; + bool supportsSEV = false; ++ bool supportsSecureBoot = false; ++ bool hasEnrolledKeys = false; ++ int reqSecureBoot; ++ int reqEnrolledKeys; + + want = qemuFirmwareOSInterfaceTypeFromOsDefFirmware(def->os.firmware); + +@@ -1001,7 +1005,13 @@ qemuFirmwareMatchDomain(const virDomainDef *def, + break; + + case QEMU_FIRMWARE_FEATURE_SECURE_BOOT: ++ supportsSecureBoot = true; ++ break; ++ + case QEMU_FIRMWARE_FEATURE_ENROLLED_KEYS: ++ hasEnrolledKeys = true; ++ break; ++ + case QEMU_FIRMWARE_FEATURE_VERBOSE_DYNAMIC: + case QEMU_FIRMWARE_FEATURE_VERBOSE_STATIC: + case QEMU_FIRMWARE_FEATURE_NONE: +@@ -1022,6 +1032,36 @@ qemuFirmwareMatchDomain(const virDomainDef *def, + return false; + } + ++ if (def->os.firmwareFeatures) { ++ reqSecureBoot = def->os.firmwareFeatures[VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_SECURE_BOOT]; ++ if (reqSecureBoot != VIR_TRISTATE_BOOL_ABSENT) { ++ if (reqSecureBoot == VIR_TRISTATE_BOOL_YES && !supportsSecureBoot) { ++ VIR_DEBUG("User requested Secure Boot, firmware '%s' doesn't support it", ++ path); ++ return false; ++ } ++ ++ if (reqSecureBoot == VIR_TRISTATE_BOOL_NO && supportsSecureBoot) { ++ VIR_DEBUG("User refused Secure Boot, firmware '%s' supports it", path); ++ return false; ++ } ++ } ++ ++ reqEnrolledKeys = def->os.firmwareFeatures[VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_ENROLLED_KEYS]; ++ if (reqEnrolledKeys != VIR_TRISTATE_BOOL_ABSENT) { ++ if (reqEnrolledKeys == VIR_TRISTATE_BOOL_YES && !hasEnrolledKeys) { ++ VIR_DEBUG("User requested Enrolled keys, firmware '%s' doesn't have them", ++ path); ++ return false; ++ } ++ ++ if (reqEnrolledKeys == VIR_TRISTATE_BOOL_NO && hasEnrolledKeys) { ++ VIR_DEBUG("User refused Enrolled keys, firmware '%s' has them", path); ++ return false; ++ } ++ } ++ } ++ + if (def->os.loader && + def->os.loader->secure == VIR_TRISTATE_BOOL_YES && + !requiresSMM) { +diff --git a/tests/qemuxml2argvdata/os-firmware-efi-no-enrolled-keys.x86_64-latest.args b/tests/qemuxml2argvdata/os-firmware-efi-no-enrolled-keys.x86_64-latest.args +new file mode 100644 +index 0000000000..c3c838fb1a +--- /dev/null ++++ b/tests/qemuxml2argvdata/os-firmware-efi-no-enrolled-keys.x86_64-latest.args +@@ -0,0 +1,47 @@ ++LC_ALL=C \ ++PATH=/bin \ ++HOME=/tmp/lib/domain--1-fedora \ ++USER=test \ ++LOGNAME=test \ ++XDG_DATA_HOME=/tmp/lib/domain--1-fedora/.local/share \ ++XDG_CACHE_HOME=/tmp/lib/domain--1-fedora/.cache \ ++XDG_CONFIG_HOME=/tmp/lib/domain--1-fedora/.config \ ++QEMU_AUDIO_DRV=none \ ++/usr/bin/qemu-system-x86_64 \ ++-name guest=fedora,debug-threads=on \ ++-S \ ++-object secret,id=masterKey0,format=raw,\ ++file=/tmp/lib/domain--1-fedora/master-key.aes \ ++-blockdev '{"driver":"file","filename":"/usr/share/OVMF/OVMF_CODE.fd",\ ++"node-name":"libvirt-pflash0-storage","auto-read-only":true,\ ++"discard":"unmap"}' \ ++-blockdev '{"node-name":"libvirt-pflash0-format","read-only":true,\ ++"driver":"raw","file":"libvirt-pflash0-storage"}' \ ++-blockdev '{"driver":"file",\ ++"filename":"/var/lib/libvirt/qemu/nvram/fedora_VARS.fd",\ ++"node-name":"libvirt-pflash1-storage","auto-read-only":true,\ ++"discard":"unmap"}' \ ++-blockdev '{"node-name":"libvirt-pflash1-format","read-only":false,\ ++"driver":"raw","file":"libvirt-pflash1-storage"}' \ ++-machine pc-q35-4.0,accel=kvm,usb=off,dump-guest-core=off,\ ++pflash0=libvirt-pflash0-format,pflash1=libvirt-pflash1-format \ ++-cpu qemu64 \ ++-m 8 \ ++-overcommit mem-lock=off \ ++-smp 1,sockets=1,cores=1,threads=1 \ ++-uuid 63840878-0deb-4095-97e6-fc444d9bc9fa \ ++-display none \ ++-no-user-config \ ++-nodefaults \ ++-chardev socket,id=charmonitor,fd=1729,server,nowait \ ++-mon chardev=charmonitor,id=monitor,mode=control \ ++-rtc base=utc \ ++-no-shutdown \ ++-boot strict=on \ ++-device pcie-root-port,port=0x8,chassis=1,id=pci.1,bus=pcie.0,multifunction=on,\ ++addr=0x1 \ ++-device pcie-root-port,port=0x9,chassis=2,id=pci.2,bus=pcie.0,addr=0x1.0x1 \ ++-device qemu-xhci,id=usb,bus=pci.1,addr=0x0 \ ++-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,\ ++resourcecontrol=deny \ ++-msg timestamp=on +diff --git a/tests/qemuxml2argvdata/os-firmware-efi-no-enrolled-keys.xml b/tests/qemuxml2argvdata/os-firmware-efi-no-enrolled-keys.xml +new file mode 100644 +index 0000000000..7f8f57a859 +--- /dev/null ++++ b/tests/qemuxml2argvdata/os-firmware-efi-no-enrolled-keys.xml +@@ -0,0 +1,49 @@ ++ ++ fedora ++ 63840878-0deb-4095-97e6-fc444d9bc9fa ++ 8192 ++ 8192 ++ 1 ++ ++ hvm ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ qemu64 ++ ++ ++ destroy ++ restart ++ destroy ++ ++ /usr/bin/qemu-system-x86_64 ++ ++ ++ ++ ++
++ ++ ++ ++ ++
++ ++ ++
++ ++ ++
++ ++ ++ ++ ++ ++ +diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c +index bc04bea692..5e16d7fd31 100644 +--- a/tests/qemuxml2argvtest.c ++++ b/tests/qemuxml2argvtest.c +@@ -3094,6 +3094,7 @@ mymain(void) + DO_TEST_CAPS_LATEST("os-firmware-bios"); + DO_TEST_CAPS_LATEST("os-firmware-efi"); + DO_TEST_CAPS_LATEST("os-firmware-efi-secboot"); ++ DO_TEST_CAPS_LATEST("os-firmware-efi-no-enrolled-keys"); + DO_TEST_CAPS_LATEST_PARSE_ERROR("os-firmware-invalid-type"); + DO_TEST_CAPS_ARCH_LATEST("aarch64-os-firmware-efi", "aarch64"); + +diff --git a/tests/qemuxml2xmloutdata/os-firmware-efi-no-enrolled-keys.x86_64-latest.xml b/tests/qemuxml2xmloutdata/os-firmware-efi-no-enrolled-keys.x86_64-latest.xml +new file mode 120000 +index 0000000000..902ccb783b +--- /dev/null ++++ b/tests/qemuxml2xmloutdata/os-firmware-efi-no-enrolled-keys.x86_64-latest.xml +@@ -0,0 +1 @@ ++../qemuxml2argvdata/os-firmware-efi-no-enrolled-keys.xml +\ No newline at end of file +diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c +index 461b5bc68f..9e5747290a 100644 +--- a/tests/qemuxml2xmltest.c ++++ b/tests/qemuxml2xmltest.c +@@ -1122,6 +1122,7 @@ mymain(void) + DO_TEST_CAPS_LATEST("os-firmware-bios"); + DO_TEST_CAPS_LATEST("os-firmware-efi"); + DO_TEST_CAPS_LATEST("os-firmware-efi-secboot"); ++ DO_TEST_CAPS_LATEST("os-firmware-efi-no-enrolled-keys"); + + DO_TEST("aarch64-aavmf-virtio-mmio", + QEMU_CAPS_DEVICE_VIRTIO_MMIO, +-- +2.31.1 + diff --git a/SOURCES/libvirt-qemu_firmware-don-t-error-out-for-unknown-firmware-features.patch b/SOURCES/libvirt-qemu_firmware-don-t-error-out-for-unknown-firmware-features.patch new file mode 100644 index 0000000..6cab919 --- /dev/null +++ b/SOURCES/libvirt-qemu_firmware-don-t-error-out-for-unknown-firmware-features.patch @@ -0,0 +1,68 @@ +From c8ede44db2e94444e5a8ee38e21eda2b42717879 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Pavel Hrdina +Date: Tue, 18 May 2021 15:03:02 +0200 +Subject: [PATCH] qemu_firmware: don't error out for unknown firmware features +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When QEMU introduces new firmware features libvirt will fail until we +list that feature in our code as well which doesn't sound right. + +We should simply ignore the new feature until we add a proper support +for it. + +Reported-by: Laszlo Ersek +Signed-off-by: Pavel Hrdina +Reviewed-by: Peter Krempa +Reviewed-by: Daniel P. Berrangé +(cherry picked from commit 61d95a1073833ec4323c1ef28e71e913c55aa7b9) + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1961562 + +Signed-off-by: Pavel Hrdina +Message-Id: <8989d70d49d8a720532a8c25e3e73d9b3bf2a495.1621342722.git.phrdina@redhat.com> +Reviewed-by: Michal Privoznik +--- + src/qemu/qemu_firmware.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/src/qemu/qemu_firmware.c b/src/qemu/qemu_firmware.c +index c84d03f0a8..8ef515ca57 100644 +--- a/src/qemu/qemu_firmware.c ++++ b/src/qemu/qemu_firmware.c +@@ -570,6 +570,7 @@ qemuFirmwareFeatureParse(const char *path, + virJSONValuePtr featuresJSON; + g_autoptr(qemuFirmwareFeature) features = NULL; + size_t nfeatures; ++ size_t nparsed = 0; + size_t i; + + if (!(featuresJSON = virJSONValueObjectGetArray(doc, "features"))) { +@@ -590,17 +591,16 @@ qemuFirmwareFeatureParse(const char *path, + int tmp; + + if ((tmp = qemuFirmwareFeatureTypeFromString(tmpStr)) <= 0) { +- virReportError(VIR_ERR_INTERNAL_ERROR, +- _("unknown feature %s"), +- tmpStr); +- return -1; ++ VIR_DEBUG("ignoring unknown QEMU firmware feature '%s'", tmpStr); ++ continue; + } + +- features[i] = tmp; ++ features[nparsed] = tmp; ++ nparsed++; + } + + fw->features = g_steal_pointer(&features); +- fw->nfeatures = nfeatures; ++ fw->nfeatures = nparsed; + return 0; + } + +-- +2.31.1 + diff --git a/SOURCES/libvirt-security-fix-SELinux-label-generation-logic.patch b/SOURCES/libvirt-security-fix-SELinux-label-generation-logic.patch new file mode 100644 index 0000000..d32275b --- /dev/null +++ b/SOURCES/libvirt-security-fix-SELinux-label-generation-logic.patch @@ -0,0 +1,58 @@ +From 0f7c8a271f07b3f9aff07dd814d7bec80ddac362 Mon Sep 17 00:00:00 2001 +Message-Id: <0f7c8a271f07b3f9aff07dd814d7bec80ddac362@dist-git> +From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= +Date: Wed, 28 Jul 2021 14:59:00 +0200 +Subject: [PATCH] security: fix SELinux label generation logic +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +A process can access a file if the set of MCS categories +for the file is equal-to *or* a subset-of, the set of +MCS categories for the process. + +If there are two VMs: + + a) svirt_t:s0:c117 + b) svirt_t:s0:c117,c720 + +Then VM (b) is able to access files labelled for VM (a). + +IOW, we must discard case where the categories are equal +because that is a subset of many other valid category pairs. + +Fixes: https://gitlab.com/libvirt/libvirt/-/issues/153 +CVE-2021-3631 +Reviewed-by: Peter Krempa +Signed-off-by: Daniel P. Berrangé +(cherry picked from commit 15073504dbb624d3f6c911e85557019d3620fdb2) +Message-Id: <38c6a7b570b8eb2114d9f1ff0c84a8346e01472f.1627476632.git.pkrempa@redhat.com> +Reviewed-by: Ján Tomko +--- + src/security/security_selinux.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c +index 985c7eda1a..93fae831ca 100644 +--- a/src/security/security_selinux.c ++++ b/src/security/security_selinux.c +@@ -391,7 +391,15 @@ virSecuritySELinuxMCSFind(virSecurityManagerPtr mgr, + VIR_DEBUG("Try cat %s:c%d,c%d", sens, c1 + catMin, c2 + catMin); + + if (c1 == c2) { +- mcs = g_strdup_printf("%s:c%d", sens, catMin + c1); ++ /* ++ * A process can access a file if the set of MCS categories ++ * for the file is equal-to *or* a subset-of, the set of ++ * MCS categories for the process. ++ * ++ * IOW, we must discard case where the categories are equal ++ * because that is a subset of other category pairs. ++ */ ++ continue; + } else { + if (c1 > c2) { + int t = c1; +-- +2.32.0 + diff --git a/SOURCES/libvirt-storage_driver-Unlock-object-on-ACL-fail-in-storagePoolLookupByTargetPath.patch b/SOURCES/libvirt-storage_driver-Unlock-object-on-ACL-fail-in-storagePoolLookupByTargetPath.patch new file mode 100644 index 0000000..370de09 --- /dev/null +++ b/SOURCES/libvirt-storage_driver-Unlock-object-on-ACL-fail-in-storagePoolLookupByTargetPath.patch @@ -0,0 +1,44 @@ +From b794a0e4e657defe9a491eb20adf61eafa443ca3 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Peter Krempa +Date: Wed, 28 Jul 2021 14:59:01 +0200 +Subject: [PATCH] storage_driver: Unlock object on ACL fail in + storagePoolLookupByTargetPath +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +'virStoragePoolObjListSearch' returns a locked and refed object, thus we +must release it on ACL permission failure. + +Fixes: 7aa0e8c0cb8 +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1984318 +Signed-off-by: Peter Krempa +Reviewed-by: Michal Privoznik +(cherry picked from commit 447f69dec47e1b0bd15ecd7cd49a9fd3b050fb87) +CVE-2021-3667 +Message-Id: +Reviewed-by: Ján Tomko +--- + src/storage/storage_driver.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c +index 0bb116cf08..4f0b8c1218 100644 +--- a/src/storage/storage_driver.c ++++ b/src/storage/storage_driver.c +@@ -1733,8 +1733,10 @@ storagePoolLookupByTargetPath(virConnectPtr conn, + storagePoolLookupByTargetPathCallback, + cleanpath))) { + def = virStoragePoolObjGetDef(obj); +- if (virStoragePoolLookupByTargetPathEnsureACL(conn, def) < 0) ++ if (virStoragePoolLookupByTargetPathEnsureACL(conn, def) < 0) { ++ virStoragePoolObjEndAPI(&obj); + return NULL; ++ } + + pool = virGetStoragePool(conn, def->name, def->uuid, NULL, NULL); + virStoragePoolObjEndAPI(&obj); +-- +2.32.0 + diff --git a/SOURCES/libvirt-tests-add-cgroup-nested-tests.patch b/SOURCES/libvirt-tests-add-cgroup-nested-tests.patch new file mode 100644 index 0000000..300ab47 --- /dev/null +++ b/SOURCES/libvirt-tests-add-cgroup-nested-tests.patch @@ -0,0 +1,226 @@ +From c94691d796682d951ffa8fb3a4fcb985aae17d9b Mon Sep 17 00:00:00 2001 +Message-Id: +From: Pavel Hrdina +Date: Fri, 19 Feb 2021 13:34:00 +0100 +Subject: [PATCH] tests: add cgroup nested tests +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit 85099c339346e41f457234e8ad831841aef1d5e3) + +Conflicts: + tests/vircgrouptest.c + - missing upstream g_autofree rewrite + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463 + +Signed-off-by: Pavel Hrdina +Message-Id: +Reviewed-by: Ján Tomko +--- + tests/vircgroupdata/systemd-legacy.cgroups | 12 +++ + tests/vircgroupdata/systemd-legacy.mounts | 11 +++ + .../vircgroupdata/systemd-legacy.self.cgroup | 11 +++ + tests/vircgroupdata/systemd-unified.cgroups | 13 +++ + tests/vircgroupdata/systemd-unified.mounts | 1 + + .../vircgroupdata/systemd-unified.self.cgroup | 1 + + tests/vircgrouptest.c | 82 +++++++++++++++++++ + 7 files changed, 131 insertions(+) + create mode 100644 tests/vircgroupdata/systemd-legacy.cgroups + create mode 100644 tests/vircgroupdata/systemd-legacy.mounts + create mode 100644 tests/vircgroupdata/systemd-legacy.self.cgroup + create mode 100644 tests/vircgroupdata/systemd-unified.cgroups + create mode 100644 tests/vircgroupdata/systemd-unified.mounts + create mode 100644 tests/vircgroupdata/systemd-unified.self.cgroup + +diff --git a/tests/vircgroupdata/systemd-legacy.cgroups b/tests/vircgroupdata/systemd-legacy.cgroups +new file mode 100644 +index 0000000000..444354e3c8 +--- /dev/null ++++ b/tests/vircgroupdata/systemd-legacy.cgroups +@@ -0,0 +1,12 @@ ++#subsys_name hierarchy num_cgroups enabled ++blkio 1 1 1 ++cpu 2 1 1 ++cpuacct 3 1 1 ++cpuset 4 1 1 ++devices 5 1 1 ++freezer 6 1 1 ++hugetlb 7 1 1 ++memory 8 1 1 ++net_cls 9 1 1 ++perf_event 10 1 1 ++pids 11 1 1 +diff --git a/tests/vircgroupdata/systemd-legacy.mounts b/tests/vircgroupdata/systemd-legacy.mounts +new file mode 100644 +index 0000000000..23462e9e68 +--- /dev/null ++++ b/tests/vircgroupdata/systemd-legacy.mounts +@@ -0,0 +1,11 @@ ++cgroup /not/really/sys/fs/cgroup/blkio cgroup rw,seclabel,nosuid,nodev,noexec,relatime,blkio 0 0 ++cgroup /not/really/sys/fs/cgroup/cpu cgroup rw,seclabel,nosuid,nodev,noexec,relatime,cpu 0 0 ++cgroup /not/really/sys/fs/cgroup/cpuacct cgroup rw,seclabel,nosuid,nodev,noexec,relatime,cpuacct 0 0 ++cgroup /not/really/sys/fs/cgroup/cpuset cgroup rw,seclabel,nosuid,nodev,noexec,relatime,cpuset 0 0 ++cgroup /not/really/sys/fs/cgroup/devices cgroup rw,seclabel,nosuid,nodev,noexec,relatime,devices 0 0 ++cgroup /not/really/sys/fs/cgroup/freezer cgroup rw,seclabel,nosuid,nodev,noexec,relatime,freezer 0 0 ++cgroup /not/really/sys/fs/cgroup/hugetlb cgroup rw,seclabel,nosuid,nodev,noexec,relatime,hugetlb 0 0 ++cgroup /not/really/sys/fs/cgroup/memory cgroup rw,seclabel,nosuid,nodev,noexec,relatime,memory 0 0 ++cgroup /not/really/sys/fs/cgroup/net_cls cgroup rw,seclabel,nosuid,nodev,noexec,relatime,net_cls 0 0 ++cgroup /not/really/sys/fs/cgroup/perf_event cgroup rw,seclabel,nosuid,nodev,noexec,relatime,perf_event 0 0 ++cgroup /not/really/sys/fs/cgroup/pids cgroup rw,seclabel,nosuid,nodev,noexec,relatime,pids 0 0 +diff --git a/tests/vircgroupdata/systemd-legacy.self.cgroup b/tests/vircgroupdata/systemd-legacy.self.cgroup +new file mode 100644 +index 0000000000..5c133a3c08 +--- /dev/null ++++ b/tests/vircgroupdata/systemd-legacy.self.cgroup +@@ -0,0 +1,11 @@ ++1:blkio:/libvirt ++2:cpu:/libvirt/emulator ++3:cpuacct:/libvirt/emulator ++4:cpuset:/libvirt/emulator ++5:devices:/libvirt ++6:freezer:/libvirt ++7:hugetlb:/ ++8:memory:/libvirt ++9:net_cls:/libvirt ++10:perf_event:/libvirt ++11:pids:/ +diff --git a/tests/vircgroupdata/systemd-unified.cgroups b/tests/vircgroupdata/systemd-unified.cgroups +new file mode 100644 +index 0000000000..e0d8a3561c +--- /dev/null ++++ b/tests/vircgroupdata/systemd-unified.cgroups +@@ -0,0 +1,13 @@ ++#subsys_name hierarchy num_cgroups enabled ++cpuset 0 1 1 ++cpu 0 1 1 ++cpuacct 0 1 1 ++blkio 0 1 1 ++memory 0 1 1 ++devices 0 1 1 ++freezer 0 1 1 ++net_cls 0 1 1 ++perf_event 0 1 1 ++net_prio 0 1 1 ++hugetlb 0 1 1 ++pids 0 1 1 +diff --git a/tests/vircgroupdata/systemd-unified.mounts b/tests/vircgroupdata/systemd-unified.mounts +new file mode 100644 +index 0000000000..8225f37f45 +--- /dev/null ++++ b/tests/vircgroupdata/systemd-unified.mounts +@@ -0,0 +1 @@ ++cgroup2 /not/really/sys/fs/cgroup cgroup2 rw,seclabel,nosuid,nodev,noexec,relatime,nsdelegate 0 0 +diff --git a/tests/vircgroupdata/systemd-unified.self.cgroup b/tests/vircgroupdata/systemd-unified.self.cgroup +new file mode 100644 +index 0000000000..6007ce7e18 +--- /dev/null ++++ b/tests/vircgroupdata/systemd-unified.self.cgroup +@@ -0,0 +1 @@ ++0::/libvirt/emulator +diff --git a/tests/vircgrouptest.c b/tests/vircgrouptest.c +index 2d6f52fb6e..aebb90c16c 100644 +--- a/tests/vircgrouptest.c ++++ b/tests/vircgrouptest.c +@@ -636,6 +636,74 @@ static int testCgroupNewForSelfHybrid(const void *args G_GNUC_UNUSED) + } + + ++static int testCgroupNewForSelfSystemdLegacy(const void *args G_GNUC_UNUSED) ++{ ++ virCgroupPtr cgroup = NULL; ++ int ret = -1; ++ const char *empty[VIR_CGROUP_CONTROLLER_LAST] = { 0 }; ++ const char *mounts[VIR_CGROUP_CONTROLLER_LAST] = { ++ [VIR_CGROUP_CONTROLLER_BLKIO] = "/not/really/sys/fs/cgroup/blkio", ++ [VIR_CGROUP_CONTROLLER_CPU] = "/not/really/sys/fs/cgroup/cpu", ++ [VIR_CGROUP_CONTROLLER_CPUACCT] = "/not/really/sys/fs/cgroup/cpuacct", ++ [VIR_CGROUP_CONTROLLER_CPUSET] = "/not/really/sys/fs/cgroup/cpuset", ++ [VIR_CGROUP_CONTROLLER_DEVICES] = "/not/really/sys/fs/cgroup/devices", ++ [VIR_CGROUP_CONTROLLER_FREEZER] = "/not/really/sys/fs/cgroup/freezer", ++ [VIR_CGROUP_CONTROLLER_MEMORY] = "/not/really/sys/fs/cgroup/memory", ++ [VIR_CGROUP_CONTROLLER_NET_CLS] = "/not/really/sys/fs/cgroup/net_cls", ++ [VIR_CGROUP_CONTROLLER_PERF_EVENT] = "/not/really/sys/fs/cgroup/perf_event", ++ }; ++ const char *placement[VIR_CGROUP_CONTROLLER_LAST] = { ++ [VIR_CGROUP_CONTROLLER_BLKIO] = "", ++ [VIR_CGROUP_CONTROLLER_CPU] = "", ++ [VIR_CGROUP_CONTROLLER_CPUACCT] = "", ++ [VIR_CGROUP_CONTROLLER_CPUSET] = "", ++ [VIR_CGROUP_CONTROLLER_DEVICES] = "", ++ [VIR_CGROUP_CONTROLLER_FREEZER] = "", ++ [VIR_CGROUP_CONTROLLER_MEMORY] = "", ++ [VIR_CGROUP_CONTROLLER_NET_CLS] = "", ++ [VIR_CGROUP_CONTROLLER_PERF_EVENT] = "", ++ }; ++ ++ if (virCgroupNewSelf(&cgroup) < 0) { ++ fprintf(stderr, "Cannot create cgroup for self\n"); ++ goto cleanup; ++ } ++ ++ ret = validateCgroup(cgroup, "", mounts, empty, placement, NULL, NULL, 0); ++ ++ cleanup: ++ virCgroupFree(&cgroup); ++ return ret; ++} ++ ++ ++static int testCgroupNewForSelfSystemdUnified(const void *args G_GNUC_UNUSED) ++{ ++ virCgroupPtr cgroup = NULL; ++ int ret = -1; ++ const char *empty[VIR_CGROUP_CONTROLLER_LAST] = { 0 }; ++ unsigned int controllers = ++ (1 << VIR_CGROUP_CONTROLLER_CPU) | ++ (1 << VIR_CGROUP_CONTROLLER_CPUACCT) | ++ (1 << VIR_CGROUP_CONTROLLER_MEMORY) | ++ (1 << VIR_CGROUP_CONTROLLER_DEVICES) | ++ (1 << VIR_CGROUP_CONTROLLER_BLKIO); ++ ++ if (virCgroupNewSelf(&cgroup) < 0) { ++ fprintf(stderr, "Cannot create cgroup for self\n"); ++ goto cleanup; ++ } ++ ++ ret = validateCgroup(cgroup, "", empty, empty, empty, ++ "/not/really/sys/fs/cgroup", "", ++ controllers); ++ ++ cleanup: ++ virCgroupFree(&cgroup); ++ return ret; ++} ++ ++ + static int testCgroupAvailable(const void *args) + { + bool got = virCgroupAvailable(); +@@ -1125,6 +1193,20 @@ mymain(void) + ret = -1; + cleanupFakeFS(fakerootdir); + ++ fakerootdir = initFakeFS("legacy", "systemd-legacy"); ++ if (virTestRun("New cgroup for self (systemd-legacy)", ++ testCgroupNewForSelfSystemdLegacy, NULL) < 0) { ++ ret = -1; ++ } ++ cleanupFakeFS(fakerootdir); ++ ++ fakerootdir = initFakeFS("unified", "systemd-unified"); ++ if (virTestRun("New cgroup for self (systemd-unified)", ++ testCgroupNewForSelfSystemdUnified, NULL) < 0) { ++ ret = -1; ++ } ++ cleanupFakeFS(fakerootdir); ++ + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; + } + +-- +2.30.0 + diff --git a/SOURCES/libvirt-vircgroup-correctly-free-nested-virCgroupPtr.patch b/SOURCES/libvirt-vircgroup-correctly-free-nested-virCgroupPtr.patch new file mode 100644 index 0000000..e72b84d --- /dev/null +++ b/SOURCES/libvirt-vircgroup-correctly-free-nested-virCgroupPtr.patch @@ -0,0 +1,45 @@ +From 7cdf83f2e699a9c9b8cafbc09dbd21d2cb3a3b45 Mon Sep 17 00:00:00 2001 +Message-Id: <7cdf83f2e699a9c9b8cafbc09dbd21d2cb3a3b45@dist-git> +From: Pavel Hrdina +Date: Fri, 19 Feb 2021 13:34:01 +0100 +Subject: [PATCH] vircgroup: correctly free nested virCgroupPtr +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Fixes: 184245f53b94fc84f727eb6e8a2aa52df02d69c0 + +Signed-off-by: Pavel Hrdina +Reviewed-by: Daniel Henrique Barboza +(cherry picked from commit 6a1f5e8a4f3184bb54b9dcaa3afcf8c97adccb62) + +Conflicts: + src/util/vircgroup.c + - missing upstream g_free rewrite + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463 + +Signed-off-by: Pavel Hrdina +Message-Id: +Reviewed-by: Ján Tomko +--- + src/util/vircgroup.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c +index d0f867ba7f..0a6404e97c 100644 +--- a/src/util/vircgroup.c ++++ b/src/util/vircgroup.c +@@ -3711,7 +3711,8 @@ virCgroupFree(virCgroupPtr *group) + VIR_FREE((*group)->unified.mountPoint); + VIR_FREE((*group)->unified.placement); + VIR_FREE((*group)->unitName); +- VIR_FREE((*group)->nested); ++ ++ virCgroupFree(&(*group)->nested); + + VIR_FREE((*group)->path); + VIR_FREE(*group); +-- +2.30.0 + diff --git a/SOURCES/libvirt-vircgroup-enforce-range-limit-for-cpu.shares.patch b/SOURCES/libvirt-vircgroup-enforce-range-limit-for-cpu.shares.patch new file mode 100644 index 0000000..d800b77 --- /dev/null +++ b/SOURCES/libvirt-vircgroup-enforce-range-limit-for-cpu.shares.patch @@ -0,0 +1,147 @@ +From c82c32f60579d148f37064e5156e857fa3c84c2f Mon Sep 17 00:00:00 2001 +Message-Id: +From: Pavel Hrdina +Date: Thu, 4 Mar 2021 12:57:57 +0100 +Subject: [PATCH] vircgroup: enforce range limit for cpu.shares +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Before the conversion to using systemd DBus API to set the cpu.shares +there was some magic conversion done by kernel which was documented in +virsh manpage as well. Now systemd errors out if the value is out of +range. + +Since we enforce the range for other cpu cgroup attributes 'quota' and +'period' it makes sense to do the same for 'shares' as well. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit 1d9d9961ada6c2d0b9facae0ef8be4f459cf7fc9) + +Conflicts: + docs/formatdomain.rst + src/conf/domain_validate.c + - both are not present in downstream + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463 + +Signed-off-by: Pavel Hrdina +Message-Id: <79b9ef9f98b3ab35061f8c4e4acf7b6861d28055.1614858616.git.phrdina@redhat.com> +Reviewed-by: Ján Tomko +--- + docs/formatdomain.html.in | 1 + + docs/manpages/virsh.rst | 5 +---- + src/conf/domain_conf.c | 10 ++++++++++ + src/util/vircgroup.h | 2 ++ + src/util/vircgroupv1.c | 10 ++++++++++ + src/util/vircgroupv2.c | 10 ++++++++++ + 6 files changed, 34 insertions(+), 4 deletions(-) + +diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in +index 4341e256a8..7ac9523684 100644 +--- a/docs/formatdomain.html.in ++++ b/docs/formatdomain.html.in +@@ -854,6 +854,7 @@ + it's a relative measure based on the setting of other VM, + e.g. A VM configured with value + 2048 will get twice as much CPU time as a VM configured with value 1024. ++ The value should be in range [2, 262144]. + Since 0.9.0 + +
period
+diff --git a/docs/manpages/virsh.rst b/docs/manpages/virsh.rst +index a5b95c1123..01e1c01912 100644 +--- a/docs/manpages/virsh.rst ++++ b/docs/manpages/virsh.rst +@@ -3704,10 +3704,7 @@ If *--live* is specified, set scheduler information of a running guest. + If *--config* is specified, affect the next boot of a persistent guest. + If *--current* is specified, affect the current guest state. + +-``Note``: The cpu_shares parameter has a valid value range of 0-262144; Negative +-values are wrapped to positive, and larger values are capped at the maximum. +-Therefore, -1 is a useful shorthand for 262144. On the Linux kernel, the +-values 0 and 1 are automatically converted to a minimal value of 2. ++``Note``: The cpu_shares parameter has a valid value range of 2-262144. + + ``Note``: The weight and cap parameters are defined only for the + XEN_CREDIT scheduler. +diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c +index 9f6cdb0de8..444657c9a1 100644 +--- a/src/conf/domain_conf.c ++++ b/src/conf/domain_conf.c +@@ -7026,6 +7026,16 @@ virDomainDefLifecycleActionValidate(const virDomainDef *def) + static int + virDomainDefCputuneValidate(const virDomainDef *def) + { ++ if (def->cputune.shares > 0 && ++ (def->cputune.shares < VIR_CGROUP_CPU_SHARES_MIN || ++ def->cputune.shares > VIR_CGROUP_CPU_SHARES_MAX)) { ++ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, ++ _("Value of cputune 'shares' must be in range [%llu, %llu]"), ++ VIR_CGROUP_CPU_SHARES_MIN, ++ VIR_CGROUP_CPU_SHARES_MAX); ++ return -1; ++ } ++ + CPUTUNE_VALIDATE_PERIOD(period); + CPUTUNE_VALIDATE_PERIOD(global_period); + CPUTUNE_VALIDATE_PERIOD(emulator_period); +diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h +index 1c6edea0be..938cfdfbe3 100644 +--- a/src/util/vircgroup.h ++++ b/src/util/vircgroup.h +@@ -243,6 +243,8 @@ virCgroupGetDomainTotalCpuStats(virCgroupPtr group, + int virCgroupSetCpuShares(virCgroupPtr group, unsigned long long shares); + int virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares); + ++#define VIR_CGROUP_CPU_SHARES_MIN 2LL ++#define VIR_CGROUP_CPU_SHARES_MAX 262144LL + #define VIR_CGROUP_CPU_PERIOD_MIN 1000LL + #define VIR_CGROUP_CPU_PERIOD_MAX 1000000LL + #define VIR_CGROUP_CPU_QUOTA_MIN 1000LL +diff --git a/src/util/vircgroupv1.c b/src/util/vircgroupv1.c +index 49a2cb023e..d417446447 100644 +--- a/src/util/vircgroupv1.c ++++ b/src/util/vircgroupv1.c +@@ -1901,6 +1901,16 @@ static int + virCgroupV1SetCpuShares(virCgroupPtr group, + unsigned long long shares) + { ++ if (shares < VIR_CGROUP_CPU_SHARES_MIN || ++ shares > VIR_CGROUP_CPU_SHARES_MAX) { ++ virReportError(VIR_ERR_INVALID_ARG, ++ _("shares '%llu' must be in range [%llu, %llu]"), ++ shares, ++ VIR_CGROUP_CPU_SHARES_MIN, ++ VIR_CGROUP_CPU_SHARES_MAX); ++ return -1; ++ } ++ + if (group->unitName) { + return virCgroupSetValueDBus(group->unitName, "CPUShares", + "t", shares); +diff --git a/src/util/vircgroupv2.c b/src/util/vircgroupv2.c +index a14fc669fb..079fe6a8ec 100644 +--- a/src/util/vircgroupv2.c ++++ b/src/util/vircgroupv2.c +@@ -1499,6 +1499,16 @@ static int + virCgroupV2SetCpuShares(virCgroupPtr group, + unsigned long long shares) + { ++ if (shares < VIR_CGROUP_CPU_SHARES_MIN || ++ shares > VIR_CGROUP_CPU_SHARES_MAX) { ++ virReportError(VIR_ERR_INVALID_ARG, ++ _("shares '%llu' must be in range [%llu, %llu]"), ++ shares, ++ VIR_CGROUP_CPU_SHARES_MIN, ++ VIR_CGROUP_CPU_SHARES_MAX); ++ return -1; ++ } ++ + if (group->unitName) { + return virCgroupSetValueDBus(group->unitName, "CPUWeight", + "t", shares); +-- +2.30.0 + diff --git a/SOURCES/libvirt-vircgroup-introduce-nested-cgroup-to-properly-work-with-systemd.patch b/SOURCES/libvirt-vircgroup-introduce-nested-cgroup-to-properly-work-with-systemd.patch new file mode 100644 index 0000000..435dc6a --- /dev/null +++ b/SOURCES/libvirt-vircgroup-introduce-nested-cgroup-to-properly-work-with-systemd.patch @@ -0,0 +1,879 @@ +From 2593f2e4626fbb6dfef2317bceea4d1b8275f9d8 Mon Sep 17 00:00:00 2001 +Message-Id: <2593f2e4626fbb6dfef2317bceea4d1b8275f9d8@dist-git> +From: Pavel Hrdina +Date: Fri, 19 Feb 2021 13:33:59 +0100 +Subject: [PATCH] vircgroup: introduce nested cgroup to properly work with + systemd +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When running on host with systemd we register VMs with machined. +In this case systemd creates the root VM cgroup for us. This has some +implications where one of them is that systemd owns all files inside +the root VM cgroup and we should not touch them. + +We already use DBus calls for some of the APIs but for the remaining +ones we will continue accessing the files directly. Systemd doesn't +support threaded cgroups so we need to do this. + +The reason why we don't use DBus for most of the APIs is that we already +have a code that works with files and we would have to check if systemd +supports each API. + +This change introduces new topology on systemd hosts: + +$ROOT + | + +- machine.slice + | + +- machine-qemu\x2d1\x2dvm1.scope + | + +- libvirt + | + +- emulator + +- vcpu0 + +- vcpu0 + +compared to the previous topology: + +$ROOT + | + +- machine.slice + | + +- machine-qemu\x2d1\x2dvm1.scope + | + +- emulator + +- vcpu0 + +- vcpu0 + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit 184245f53b94fc84f727eb6e8a2aa52df02d69c0) + +Conflicts: + src/util/vircgroup.c + - missing upstream g_free and g_autofree rewrite + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463 + +Signed-off-by: Pavel Hrdina +Message-Id: <51312c8b520e4ed794f8cd8a77b77c228387bb15.1613737828.git.phrdina@redhat.com> +Reviewed-by: Ján Tomko +--- + docs/cgroups.html.in | 29 +++-- + src/util/vircgroup.c | 256 +++++++++++++++++++++++++++++++-------- + src/util/vircgrouppriv.h | 4 + + src/util/vircgroupv1.c | 15 ++- + src/util/vircgroupv2.c | 6 + + 5 files changed, 245 insertions(+), 65 deletions(-) + +diff --git a/docs/cgroups.html.in b/docs/cgroups.html.in +index 78dede1bba..412a9360ff 100644 +--- a/docs/cgroups.html.in ++++ b/docs/cgroups.html.in +@@ -117,21 +117,27 @@ $ROOT + | + +- machine-qemu\x2d1\x2dvm1.scope + | | +- | +- emulator +- | +- vcpu0 +- | +- vcpu1 ++ | +- libvirt ++ | | ++ | +- emulator ++ | +- vcpu0 ++ | +- vcpu1 + | + +- machine-qemu\x2d2\x2dvm2.scope + | | +- | +- emulator +- | +- vcpu0 +- | +- vcpu1 ++ | +- libvirt ++ | | ++ | +- emulator ++ | +- vcpu0 ++ | +- vcpu1 + | + +- machine-qemu\x2d3\x2dvm3.scope + | | +- | +- emulator +- | +- vcpu0 +- | +- vcpu1 ++ | +- libvirt ++ | | ++ | +- emulator ++ | +- vcpu0 ++ | +- vcpu1 + | + +- machine-engineering.slice + | | +@@ -148,6 +154,11 @@ $ROOT + +- machine-lxc\x2d33333\x2dcontainer3.scope +
+ ++

++ Prior libvirt 7.1.0 the topology doesn't have extra ++ libvirt directory. ++

++ +

Non-systemd cgroups layout

+ +

+diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c +index 8f5bcd94f4..d0f867ba7f 100644 +--- a/src/util/vircgroup.c ++++ b/src/util/vircgroup.c +@@ -639,6 +639,22 @@ virCgroupMakeGroup(virCgroupPtr parent, + } + + ++static bool ++virCgroupExists(virCgroupPtr group) ++{ ++ size_t i; ++ ++ for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) { ++ if (group->backends[i] && ++ !group->backends[i]->exists(group)) { ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++ + /** + * virCgroupNew: + * @path: path for the new group +@@ -695,10 +711,11 @@ virCgroupAddTaskInternal(virCgroupPtr group, + unsigned int flags) + { + size_t i; ++ virCgroupPtr parent = virCgroupGetNested(group); + + for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) { +- if (group->backends[i] && +- group->backends[i]->addTask(group, pid, flags) < 0) { ++ if (parent->backends[i] && ++ parent->backends[i]->addTask(parent, pid, flags) < 0) { + return -1; + } + } +@@ -871,6 +888,30 @@ virCgroupNewPartition(const char *path, + } + + ++static int ++virCgroupNewNested(virCgroupPtr parent, ++ int controllers, ++ bool create, ++ pid_t pid, ++ virCgroupPtr *nested) ++{ ++ virCgroupPtr new = NULL; ++ ++ if (virCgroupNew(-1, "libvirt", parent, controllers, &new) < 0) ++ return -1; ++ ++ if (create) { ++ if (virCgroupMakeGroup(parent, new, create, pid, VIR_CGROUP_NONE) < 0) { ++ virCgroupFree(&new); ++ return -1; ++ } ++ } ++ ++ *nested = g_steal_pointer(&new); ++ return 0; ++} ++ ++ + /** + * virCgroupNewSelf: + * +@@ -954,6 +995,7 @@ virCgroupNewThread(virCgroupPtr domain, + virCgroupPtr *group) + { + g_autofree char *name = NULL; ++ virCgroupPtr parent = NULL; + int controllers; + + switch (nameval) { +@@ -976,10 +1018,12 @@ virCgroupNewThread(virCgroupPtr domain, + (1 << VIR_CGROUP_CONTROLLER_CPUACCT) | + (1 << VIR_CGROUP_CONTROLLER_CPUSET)); + +- if (virCgroupNew(-1, name, domain, controllers, group) < 0) ++ parent = virCgroupGetNested(domain); ++ ++ if (virCgroupNew(-1, name, parent, controllers, group) < 0) + return -1; + +- if (virCgroupMakeGroup(domain, *group, create, -1, VIR_CGROUP_THREAD) < 0) { ++ if (virCgroupMakeGroup(parent, *group, create, -1, VIR_CGROUP_THREAD) < 0) { + virCgroupFree(group); + return -1; + } +@@ -1009,6 +1053,7 @@ virCgroupNewDetectMachine(const char *name, + virCgroupPtr *group) + { + size_t i; ++ virCgroupPtr nested = NULL; + + if (virCgroupNewDetect(pid, controllers, group) < 0) { + if (virCgroupNewIgnoreError()) +@@ -1032,6 +1077,14 @@ virCgroupNewDetectMachine(const char *name, + if (virSystemdHasMachined() == 0 && !(*group)->unitName) + return -1; + ++ if (virCgroupNewNested((*group), controllers, false, -1, &nested) < 0) ++ return -1; ++ ++ if (virCgroupExists(nested)) ++ (*group)->nested = g_steal_pointer(&nested); ++ ++ virCgroupFree(&nested); ++ + return 0; + } + +@@ -1107,6 +1160,7 @@ virCgroupNewMachineSystemd(const char *name, + { + int rv; + virCgroupPtr init; ++ virCgroupPtr nested = NULL; + g_autofree char *path = NULL; + size_t i; + +@@ -1157,6 +1211,13 @@ virCgroupNewMachineSystemd(const char *name, + return -1; + } + ++ if (virCgroupNewNested((*group), controllers, true, pidleader, &nested) < 0) { ++ virCgroupFree(group); ++ return -1; ++ } ++ ++ (*group)->nested = nested; ++ + if (virCgroupAddProcess(*group, pidleader) < 0) { + virErrorPtr saved; + +@@ -1349,7 +1410,9 @@ virCgroupGetBlkioIoServiced(virCgroupPtr group, + long long *requests_read, + long long *requests_write) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO, + getBlkioIoServiced, -1, + bytes_read, bytes_write, + requests_read, requests_write); +@@ -1376,7 +1439,9 @@ virCgroupGetBlkioIoDeviceServiced(virCgroupPtr group, + long long *requests_read, + long long *requests_write) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO, + getBlkioIoDeviceServiced, -1, + path, bytes_read, bytes_write, + requests_read, requests_write); +@@ -1427,7 +1492,9 @@ virCgroupSetBlkioDeviceReadIops(virCgroupPtr group, + const char *path, + unsigned int riops) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO, + setBlkioDeviceReadIops, -1, path, riops); + } + +@@ -1445,7 +1512,9 @@ virCgroupSetBlkioDeviceWriteIops(virCgroupPtr group, + const char *path, + unsigned int wiops) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO, + setBlkioDeviceWriteIops, -1, path, wiops); + } + +@@ -1463,7 +1532,9 @@ virCgroupSetBlkioDeviceReadBps(virCgroupPtr group, + const char *path, + unsigned long long rbps) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO, + setBlkioDeviceReadBps, -1, path, rbps); + } + +@@ -1480,7 +1551,9 @@ virCgroupSetBlkioDeviceWriteBps(virCgroupPtr group, + const char *path, + unsigned long long wbps) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO, + setBlkioDeviceWriteBps, -1, path, wbps); + } + +@@ -1516,7 +1589,9 @@ virCgroupGetBlkioDeviceReadIops(virCgroupPtr group, + const char *path, + unsigned int *riops) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO, + getBlkioDeviceReadIops, -1, path, riops); + } + +@@ -1533,7 +1608,9 @@ virCgroupGetBlkioDeviceWriteIops(virCgroupPtr group, + const char *path, + unsigned int *wiops) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO, + getBlkioDeviceWriteIops, -1, path, wiops); + } + +@@ -1550,7 +1627,9 @@ virCgroupGetBlkioDeviceReadBps(virCgroupPtr group, + const char *path, + unsigned long long *rbps) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO, + getBlkioDeviceReadBps, -1, path, rbps); + } + +@@ -1567,7 +1646,9 @@ virCgroupGetBlkioDeviceWriteBps(virCgroupPtr group, + const char *path, + unsigned long long *wbps) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_BLKIO, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_BLKIO, + getBlkioDeviceWriteBps, -1, path, wbps); + } + +@@ -1600,7 +1681,9 @@ virCgroupGetBlkioDeviceWeight(virCgroupPtr group, + int + virCgroupSetMemory(virCgroupPtr group, unsigned long long kb) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY, + setMemory, -1, kb); + } + +@@ -1627,7 +1710,9 @@ virCgroupGetMemoryStat(virCgroupPtr group, + unsigned long long *inactiveFile, + unsigned long long *unevictable) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY, + getMemoryStat, -1, cache, + activeAnon, inactiveAnon, + activeFile, inactiveFile, +@@ -1646,7 +1731,9 @@ virCgroupGetMemoryStat(virCgroupPtr group, + int + virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY, + getMemoryUsage, -1, kb); + } + +@@ -1662,7 +1749,9 @@ virCgroupGetMemoryUsage(virCgroupPtr group, unsigned long *kb) + int + virCgroupSetMemoryHardLimit(virCgroupPtr group, unsigned long long kb) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY, + setMemoryHardLimit, -1, kb); + } + +@@ -1678,7 +1767,9 @@ virCgroupSetMemoryHardLimit(virCgroupPtr group, unsigned long long kb) + int + virCgroupGetMemoryHardLimit(virCgroupPtr group, unsigned long long *kb) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY, + getMemoryHardLimit, -1, kb); + } + +@@ -1694,7 +1785,9 @@ virCgroupGetMemoryHardLimit(virCgroupPtr group, unsigned long long *kb) + int + virCgroupSetMemorySoftLimit(virCgroupPtr group, unsigned long long kb) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY, + setMemorySoftLimit, -1, kb); + } + +@@ -1710,7 +1803,9 @@ virCgroupSetMemorySoftLimit(virCgroupPtr group, unsigned long long kb) + int + virCgroupGetMemorySoftLimit(virCgroupPtr group, unsigned long long *kb) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY, + getMemorySoftLimit, -1, kb); + } + +@@ -1726,7 +1821,9 @@ virCgroupGetMemorySoftLimit(virCgroupPtr group, unsigned long long *kb) + int + virCgroupSetMemSwapHardLimit(virCgroupPtr group, unsigned long long kb) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY, + setMemSwapHardLimit, -1, kb); + } + +@@ -1742,7 +1839,9 @@ virCgroupSetMemSwapHardLimit(virCgroupPtr group, unsigned long long kb) + int + virCgroupGetMemSwapHardLimit(virCgroupPtr group, unsigned long long *kb) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY, + getMemSwapHardLimit, -1, kb); + } + +@@ -1758,7 +1857,9 @@ virCgroupGetMemSwapHardLimit(virCgroupPtr group, unsigned long long *kb) + int + virCgroupGetMemSwapUsage(virCgroupPtr group, unsigned long long *kb) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_MEMORY, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_MEMORY, + getMemSwapUsage, -1, kb); + } + +@@ -1774,7 +1875,9 @@ virCgroupGetMemSwapUsage(virCgroupPtr group, unsigned long long *kb) + int + virCgroupSetCpusetMems(virCgroupPtr group, const char *mems) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUSET, + setCpusetMems, -1, mems); + } + +@@ -1790,7 +1893,9 @@ virCgroupSetCpusetMems(virCgroupPtr group, const char *mems) + int + virCgroupGetCpusetMems(virCgroupPtr group, char **mems) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUSET, + getCpusetMems, -1, mems); + } + +@@ -1806,7 +1911,9 @@ virCgroupGetCpusetMems(virCgroupPtr group, char **mems) + int + virCgroupSetCpusetMemoryMigrate(virCgroupPtr group, bool migrate) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUSET, + setCpusetMemoryMigrate, -1, migrate); + } + +@@ -1822,7 +1929,9 @@ virCgroupSetCpusetMemoryMigrate(virCgroupPtr group, bool migrate) + int + virCgroupGetCpusetMemoryMigrate(virCgroupPtr group, bool *migrate) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUSET, + getCpusetMemoryMigrate, -1, migrate); + } + +@@ -1838,7 +1947,9 @@ virCgroupGetCpusetMemoryMigrate(virCgroupPtr group, bool *migrate) + int + virCgroupSetCpusetCpus(virCgroupPtr group, const char *cpus) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUSET, + setCpusetCpus, -1, cpus); + } + +@@ -1854,7 +1965,9 @@ virCgroupSetCpusetCpus(virCgroupPtr group, const char *cpus) + int + virCgroupGetCpusetCpus(virCgroupPtr group, char **cpus) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUSET, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUSET, + getCpusetCpus, -1, cpus); + } + +@@ -1869,7 +1982,9 @@ virCgroupGetCpusetCpus(virCgroupPtr group, char **cpus) + int + virCgroupDenyAllDevices(virCgroupPtr group) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_DEVICES, + denyAllDevices, -1); + } + +@@ -1890,7 +2005,9 @@ virCgroupDenyAllDevices(virCgroupPtr group) + int + virCgroupAllowAllDevices(virCgroupPtr group, int perms) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_DEVICES, + allowAllDevices, -1, perms); + } + +@@ -1910,7 +2027,9 @@ int + virCgroupAllowDevice(virCgroupPtr group, char type, int major, int minor, + int perms) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_DEVICES, + allowDevice, -1, type, major, minor, perms); + } + +@@ -1936,6 +2055,7 @@ virCgroupAllowDevicePath(virCgroupPtr group, + bool ignoreEacces) + { + struct stat sb; ++ virCgroupPtr parent = virCgroupGetNested(group); + + if (stat(path, &sb) < 0) { + if (errno == EACCES && ignoreEacces) +@@ -1950,7 +2070,7 @@ virCgroupAllowDevicePath(virCgroupPtr group, + if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode)) + return 1; + +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES, ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_DEVICES, + allowDevice, -1, + S_ISCHR(sb.st_mode) ? 'c' : 'b', + major(sb.st_rdev), +@@ -1974,7 +2094,9 @@ int + virCgroupDenyDevice(virCgroupPtr group, char type, int major, int minor, + int perms) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_DEVICES, + denyDevice, -1, type, major, minor, perms); + } + +@@ -2000,6 +2122,7 @@ virCgroupDenyDevicePath(virCgroupPtr group, + bool ignoreEacces) + { + struct stat sb; ++ virCgroupPtr parent = virCgroupGetNested(group); + + if (stat(path, &sb) < 0) { + if (errno == EACCES && ignoreEacces) +@@ -2014,7 +2137,7 @@ virCgroupDenyDevicePath(virCgroupPtr group, + if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode)) + return 1; + +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_DEVICES, ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_DEVICES, + denyDevice, -1, + S_ISCHR(sb.st_mode) ? 'c' : 'b', + major(sb.st_rdev), +@@ -2282,7 +2405,9 @@ virCgroupGetCpuShares(virCgroupPtr group, unsigned long long *shares) + int + virCgroupSetCpuCfsPeriod(virCgroupPtr group, unsigned long long cfs_period) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPU, + setCpuCfsPeriod, -1, cfs_period); + } + +@@ -2298,7 +2423,9 @@ virCgroupSetCpuCfsPeriod(virCgroupPtr group, unsigned long long cfs_period) + int + virCgroupGetCpuCfsPeriod(virCgroupPtr group, unsigned long long *cfs_period) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPU, + getCpuCfsPeriod, -1, cfs_period); + } + +@@ -2315,7 +2442,9 @@ virCgroupGetCpuCfsPeriod(virCgroupPtr group, unsigned long long *cfs_period) + int + virCgroupSetCpuCfsQuota(virCgroupPtr group, long long cfs_quota) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPU, + setCpuCfsQuota, -1, cfs_quota); + } + +@@ -2323,7 +2452,9 @@ virCgroupSetCpuCfsQuota(virCgroupPtr group, long long cfs_quota) + int + virCgroupGetCpuacctPercpuUsage(virCgroupPtr group, char **usage) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUACCT, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUACCT, + getCpuacctPercpuUsage, -1, usage); + } + +@@ -2669,7 +2800,9 @@ virCgroupKillPainfully(virCgroupPtr group) + int + virCgroupGetCpuCfsQuota(virCgroupPtr group, long long *cfs_quota) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPU, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPU, + getCpuCfsQuota, -1, cfs_quota); + } + +@@ -2677,7 +2810,9 @@ virCgroupGetCpuCfsQuota(virCgroupPtr group, long long *cfs_quota) + int + virCgroupGetCpuacctUsage(virCgroupPtr group, unsigned long long *usage) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUACCT, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUACCT, + getCpuacctUsage, -1, usage); + } + +@@ -2686,7 +2821,9 @@ int + virCgroupGetCpuacctStat(virCgroupPtr group, unsigned long long *user, + unsigned long long *sys) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_CPUACCT, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPUACCT, + getCpuacctStat, -1, user, sys); + } + +@@ -2694,7 +2831,9 @@ virCgroupGetCpuacctStat(virCgroupPtr group, unsigned long long *user, + int + virCgroupSetFreezerState(virCgroupPtr group, const char *state) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_FREEZER, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_FREEZER, + setFreezerState, -1, state); + } + +@@ -2702,7 +2841,9 @@ virCgroupSetFreezerState(virCgroupPtr group, const char *state) + int + virCgroupGetFreezerState(virCgroupPtr group, char **state) + { +- VIR_CGROUP_BACKEND_CALL(group, VIR_CGROUP_CONTROLLER_FREEZER, ++ virCgroupPtr parent = virCgroupGetNested(group); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_FREEZER, + getFreezerState, -1, state); + } + +@@ -2712,10 +2853,11 @@ virCgroupBindMount(virCgroupPtr group, const char *oldroot, + const char *mountopts) + { + size_t i; ++ virCgroupPtr parent = virCgroupGetNested(group); + + for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) { +- if (group->backends[i] && +- group->backends[i]->bindMount(group, oldroot, mountopts) < 0) { ++ if (parent->backends[i] && ++ parent->backends[i]->bindMount(parent, oldroot, mountopts) < 0) { + return -1; + } + } +@@ -2730,10 +2872,11 @@ int virCgroupSetOwner(virCgroupPtr cgroup, + int controllers) + { + size_t i; ++ virCgroupPtr parent = virCgroupGetNested(cgroup); + + for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) { +- if (cgroup->backends[i] && +- cgroup->backends[i]->setOwner(cgroup, uid, gid, controllers) < 0) { ++ if (parent->backends[i] && ++ parent->backends[i]->setOwner(parent, uid, gid, controllers) < 0) { + return -1; + } + } +@@ -2752,7 +2895,9 @@ int virCgroupSetOwner(virCgroupPtr cgroup, + bool + virCgroupSupportsCpuBW(virCgroupPtr cgroup) + { +- VIR_CGROUP_BACKEND_CALL(cgroup, VIR_CGROUP_CONTROLLER_CPU, ++ virCgroupPtr parent = virCgroupGetNested(cgroup); ++ ++ VIR_CGROUP_BACKEND_CALL(parent, VIR_CGROUP_CONTROLLER_CPU, + supportsCpuBW, false); + } + +@@ -2760,10 +2905,11 @@ int + virCgroupHasEmptyTasks(virCgroupPtr cgroup, int controller) + { + size_t i; ++ virCgroupPtr parent = virCgroupGetNested(cgroup); + + for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) { +- if (cgroup->backends[i]) { +- int rc = cgroup->backends[i]->hasEmptyTasks(cgroup, controller); ++ if (parent->backends[i]) { ++ int rc = parent->backends[i]->hasEmptyTasks(parent, controller); + if (rc <= 0) + return rc; + } +@@ -3565,6 +3711,7 @@ virCgroupFree(virCgroupPtr *group) + VIR_FREE((*group)->unified.mountPoint); + VIR_FREE((*group)->unified.placement); + VIR_FREE((*group)->unitName); ++ VIR_FREE((*group)->nested); + + VIR_FREE((*group)->path); + VIR_FREE(*group); +@@ -3577,9 +3724,12 @@ virCgroupDelThread(virCgroupPtr cgroup, + int idx) + { + virCgroupPtr new_cgroup = NULL; ++ virCgroupPtr parent = NULL; + + if (cgroup) { +- if (virCgroupNewThread(cgroup, nameval, idx, false, &new_cgroup) < 0) ++ parent = virCgroupGetNested(cgroup); ++ ++ if (virCgroupNewThread(parent, nameval, idx, false, &new_cgroup) < 0) + return -1; + + /* Remove the offlined cgroup */ +diff --git a/src/util/vircgrouppriv.h b/src/util/vircgrouppriv.h +index b4a9e0b379..104d74e4d7 100644 +--- a/src/util/vircgrouppriv.h ++++ b/src/util/vircgrouppriv.h +@@ -69,8 +69,12 @@ struct _virCgroup { + virCgroupV2Controller unified; + + char *unitName; ++ virCgroupPtr nested; + }; + ++#define virCgroupGetNested(cgroup) \ ++ (cgroup->nested ? cgroup->nested : cgroup) ++ + #define virCgroupSetValueDBus(unitName, key, ...) \ + ({ \ + int __ret = -1; \ +diff --git a/src/util/vircgroupv1.c b/src/util/vircgroupv1.c +index 57d617cb69..49a2cb023e 100644 +--- a/src/util/vircgroupv1.c ++++ b/src/util/vircgroupv1.c +@@ -338,6 +338,8 @@ virCgroupV1DetectPlacement(virCgroupPtr group, + + for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { + const char *typestr = virCgroupV1ControllerTypeToString(i); ++ g_autofree char* placement = NULL; ++ char *tmp = NULL; + + if (!virCgroupV1MountOptsMatchController(controllers, typestr)) + continue; +@@ -348,17 +350,24 @@ virCgroupV1DetectPlacement(virCgroupPtr group, + if (group->legacy[i].placement) + continue; + ++ /* On systemd we create a nested cgroup for some cgroup tasks ++ * but the placement should point to the root cgroup. */ ++ placement = g_strdup(selfpath); ++ tmp = g_strrstr(placement, "/libvirt"); ++ if (tmp) ++ *tmp = '\0'; ++ + /* + * selfpath == "/" + path="" -> "/" + * selfpath == "/libvirt.service" + path == "" -> "/libvirt.service" + * selfpath == "/libvirt.service" + path == "foo" -> "/libvirt.service/foo" + */ + if (i == VIR_CGROUP_CONTROLLER_SYSTEMD) { +- group->legacy[i].placement = g_strdup(selfpath); ++ group->legacy[i].placement = g_strdup(placement); + } else { +- bool delim = STREQ(selfpath, "/") || STREQ(path, ""); ++ bool delim = STREQ(placement, "/") || STREQ(path, ""); + +- group->legacy[i].placement = g_strdup_printf("%s%s%s", selfpath, ++ group->legacy[i].placement = g_strdup_printf("%s%s%s", placement, + delim ? "" : "/", + path); + } +diff --git a/src/util/vircgroupv2.c b/src/util/vircgroupv2.c +index d15e2354cf..a14fc669fb 100644 +--- a/src/util/vircgroupv2.c ++++ b/src/util/vircgroupv2.c +@@ -210,6 +210,12 @@ virCgroupV2DetectPlacement(virCgroupPtr group, + if (tmp) + *tmp = '\0'; + ++ /* On systemd we create a nested cgroup for some cgroup tasks ++ * but the placement should point to the root cgroup. */ ++ tmp = g_strrstr(placement, "/libvirt"); ++ if (tmp) ++ *tmp = '\0'; ++ + /* + * selfpath == "/" + path="" -> "/" + * selfpath == "/libvirt.service" + path == "" -> "/libvirt.service" +-- +2.30.0 + diff --git a/SOURCES/libvirt-vircgroup-introduce-virCgroupV1Exists-and-virCgroupV2Exists.patch b/SOURCES/libvirt-vircgroup-introduce-virCgroupV1Exists-and-virCgroupV2Exists.patch new file mode 100644 index 0000000..c73bf43 --- /dev/null +++ b/SOURCES/libvirt-vircgroup-introduce-virCgroupV1Exists-and-virCgroupV2Exists.patch @@ -0,0 +1,129 @@ +From f835b834d7922bed1ccda35885e42ab7c3f4a70f Mon Sep 17 00:00:00 2001 +Message-Id: +From: Pavel Hrdina +Date: Fri, 19 Feb 2021 13:33:58 +0100 +Subject: [PATCH] vircgroup: introduce virCgroupV1Exists and virCgroupV2Exists +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This will check if the cgroup actually exists on the system. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit badc2bcc7398d8c0a739998a80411ddebf129512) + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463 + +Signed-off-by: Pavel Hrdina +Message-Id: <14297ed923f0f23cc52506e61e637c8f45e331ee.1613737828.git.phrdina@redhat.com> +Reviewed-by: Ján Tomko +--- + src/util/vircgroupbackend.h | 4 ++++ + src/util/vircgroupv1.c | 27 +++++++++++++++++++++++++++ + src/util/vircgroupv2.c | 15 +++++++++++++++ + 3 files changed, 46 insertions(+) + +diff --git a/src/util/vircgroupbackend.h b/src/util/vircgroupbackend.h +index ac7b3ae517..dabc7bd4b4 100644 +--- a/src/util/vircgroupbackend.h ++++ b/src/util/vircgroupbackend.h +@@ -115,6 +115,9 @@ typedef int + const char *key, + char **path); + ++typedef bool ++(*virCgroupExistsCB)(virCgroupPtr group); ++ + typedef int + (*virCgroupMakeGroupCB)(virCgroupPtr parent, + virCgroupPtr group, +@@ -378,6 +381,7 @@ struct _virCgroupBackend { + virCgroupGetAnyControllerCB getAnyController; + virCgroupPathOfControllerCB pathOfController; + virCgroupMakeGroupCB makeGroup; ++ virCgroupExistsCB exists; + virCgroupRemoveCB remove; + virCgroupAddTaskCB addTask; + virCgroupHasEmptyTasksCB hasEmptyTasks; +diff --git a/src/util/vircgroupv1.c b/src/util/vircgroupv1.c +index eb2b611cee..57d617cb69 100644 +--- a/src/util/vircgroupv1.c ++++ b/src/util/vircgroupv1.c +@@ -670,6 +670,32 @@ virCgroupV1MakeGroup(virCgroupPtr parent, + } + + ++static bool ++virCgroupV1Exists(virCgroupPtr group) ++{ ++ size_t i; ++ ++ for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { ++ g_autofree char *path = NULL; ++ ++ if (i == VIR_CGROUP_CONTROLLER_SYSTEMD) ++ continue; ++ ++ if (!group->legacy[i].mountPoint) ++ continue; ++ ++ if (virCgroupV1PathOfController(group, i, "", &path) < 0) ++ return false; ++ ++ if (!virFileExists(path)) { ++ return false; ++ } ++ } ++ ++ return true; ++} ++ ++ + static int + virCgroupV1Remove(virCgroupPtr group) + { +@@ -2136,6 +2162,7 @@ virCgroupBackend virCgroupV1Backend = { + .getAnyController = virCgroupV1GetAnyController, + .pathOfController = virCgroupV1PathOfController, + .makeGroup = virCgroupV1MakeGroup, ++ .exists = virCgroupV1Exists, + .remove = virCgroupV1Remove, + .addTask = virCgroupV1AddTask, + .hasEmptyTasks = virCgroupV1HasEmptyTasks, +diff --git a/src/util/vircgroupv2.c b/src/util/vircgroupv2.c +index 5e19ed8332..d15e2354cf 100644 +--- a/src/util/vircgroupv2.c ++++ b/src/util/vircgroupv2.c +@@ -493,6 +493,20 @@ virCgroupV2MakeGroup(virCgroupPtr parent, + } + + ++static bool ++virCgroupV2Exists(virCgroupPtr group) ++{ ++ g_autofree char *path = NULL; ++ int controller; ++ ++ controller = virCgroupV2GetAnyController(group); ++ if (virCgroupV2PathOfController(group, controller, "", &path) < 0) ++ return false; ++ ++ return virFileExists(path); ++} ++ ++ + static int + virCgroupV2Remove(virCgroupPtr group) + { +@@ -1886,6 +1900,7 @@ virCgroupBackend virCgroupV2Backend = { + .getAnyController = virCgroupV2GetAnyController, + .pathOfController = virCgroupV2PathOfController, + .makeGroup = virCgroupV2MakeGroup, ++ .exists = virCgroupV2Exists, + .remove = virCgroupV2Remove, + .addTask = virCgroupV2AddTask, + .hasEmptyTasks = virCgroupV2HasEmptyTasks, +-- +2.30.0 + diff --git a/SOURCES/libvirt-vircgroup-use-DBus-call-to-systemd-for-some-APIs.patch b/SOURCES/libvirt-vircgroup-use-DBus-call-to-systemd-for-some-APIs.patch new file mode 100644 index 0000000..8d300b3 --- /dev/null +++ b/SOURCES/libvirt-vircgroup-use-DBus-call-to-systemd-for-some-APIs.patch @@ -0,0 +1,310 @@ +From 205289d2792aacf68ed2cb8563d1860bd36137a0 Mon Sep 17 00:00:00 2001 +Message-Id: <205289d2792aacf68ed2cb8563d1860bd36137a0@dist-git> +From: Pavel Hrdina +Date: Fri, 19 Feb 2021 13:33:55 +0100 +Subject: [PATCH] vircgroup: use DBus call to systemd for some APIs +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When running on host with systemd we register VMs with machined. +In this case systemd creates the root VM cgroup for us. This has some +implications where one of them is that systemd owns all files inside +the root VM cgroup and we should not touch them. + +If we change any value in file that systemd knows about it will be +changed to what systemd thinks it should be when executing +`systemctl daemon-reload`. + +These are the APIs that we need to call using systemd because they set +limits that are proportional to sibling cgroups. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit 9c1693eff427661616ce1bd2795688f87288a412) + +Conflicts: + src/util/vircgroup.c + - missing upstream g_autofree rewrite + - missing upstream glib dbus rewrite, hence the ugly macro + instead of a function + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463 + +Signed-off-by: Pavel Hrdina +Message-Id: <5d22d307112333f1da565cb642ea9001a7b8b55b.1613737828.git.phrdina@redhat.com> +Reviewed-by: Ján Tomko +--- + src/util/vircgroup.c | 11 ++++++++++ + src/util/vircgrouppriv.h | 25 +++++++++++++++++++++++ + src/util/vircgroupv1.c | 44 +++++++++++++++++++++++++++------------- + src/util/vircgroupv2.c | 44 +++++++++++++++++++++++++++------------- + tests/Makefile.am | 1 + + 5 files changed, 97 insertions(+), 28 deletions(-) + +diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c +index a45c2e7f2f..10b934291c 100644 +--- a/src/util/vircgroup.c ++++ b/src/util/vircgroup.c +@@ -1027,6 +1027,10 @@ virCgroupNewDetectMachine(const char *name, + } + } + ++ (*group)->unitName = virSystemdGetMachineUnitByPID(pid); ++ if (virSystemdHasMachined() == 0 && !(*group)->unitName) ++ return -1; ++ + return 0; + } + +@@ -1146,6 +1150,12 @@ virCgroupNewMachineSystemd(const char *name, + return -1; + } + ++ (*group)->unitName = virSystemdGetMachineUnitByPID(pidleader); ++ if (!(*group)->unitName) { ++ virCgroupFree(group); ++ return -1; ++ } ++ + if (virCgroupAddProcess(*group, pidleader) < 0) { + virErrorPtr saved; + +@@ -3553,6 +3563,7 @@ virCgroupFree(virCgroupPtr *group) + + VIR_FREE((*group)->unified.mountPoint); + VIR_FREE((*group)->unified.placement); ++ VIR_FREE((*group)->unitName); + + VIR_FREE((*group)->path); + VIR_FREE(*group); +diff --git a/src/util/vircgrouppriv.h b/src/util/vircgrouppriv.h +index f2a80aeb82..b4a9e0b379 100644 +--- a/src/util/vircgrouppriv.h ++++ b/src/util/vircgrouppriv.h +@@ -27,6 +27,7 @@ + + #include "vircgroup.h" + #include "vircgroupbackend.h" ++#include "virdbus.h" + + struct _virCgroupV1Controller { + int type; +@@ -66,8 +67,32 @@ struct _virCgroup { + + virCgroupV1Controller legacy[VIR_CGROUP_CONTROLLER_LAST]; + virCgroupV2Controller unified; ++ ++ char *unitName; + }; + ++#define virCgroupSetValueDBus(unitName, key, ...) \ ++ ({ \ ++ int __ret = -1; \ ++ do { \ ++ DBusConnection *__conn; \ ++ if (!(__conn = virDBusGetSystemBus())) \ ++ break; \ ++ __ret = virDBusCallMethod(__conn, NULL, NULL, \ ++ "org.freedesktop.systemd1", \ ++ "/org/freedesktop/systemd1", \ ++ "org.freedesktop.systemd1.Manager", \ ++ "SetUnitProperties", \ ++ "sba(sv)", \ ++ unitName, \ ++ true, \ ++ 1, \ ++ key, \ ++ __VA_ARGS__); \ ++ } while (0); \ ++ __ret; \ ++ }) ++ + int virCgroupSetValueRaw(const char *path, + const char *value); + +diff --git a/src/util/vircgroupv1.c b/src/util/vircgroupv1.c +index c35088a3c4..7ec8f3a316 100644 +--- a/src/util/vircgroupv1.c ++++ b/src/util/vircgroupv1.c +@@ -931,7 +931,6 @@ virCgroupV1SetBlkioWeight(virCgroupPtr group, + unsigned int weight) + { + g_autofree char *path = NULL; +- g_autofree char *value = NULL; + + if (virCgroupV1PathOfController(group, VIR_CGROUP_CONTROLLER_BLKIO, + "blkio.bfq.weight", &path) < 0) { +@@ -953,9 +952,14 @@ virCgroupV1SetBlkioWeight(virCgroupPtr group, + return -1; + } + +- value = g_strdup_printf("%u", weight); ++ if (group->unitName) { ++ return virCgroupSetValueDBus(group->unitName, "BlockIOWeight", ++ "t", (unsigned long long) weight); ++ } else { ++ g_autofree char *value = g_strdup_printf("%u", weight); + +- return virCgroupSetValueRaw(path, value); ++ return virCgroupSetValueRaw(path, value); ++ } + } + + +@@ -1188,15 +1192,8 @@ virCgroupV1SetBlkioDeviceWeight(virCgroupPtr group, + const char *devPath, + unsigned int weight) + { +- g_autofree char *str = NULL; +- g_autofree char *blkstr = NULL; + g_autofree char *path = NULL; + +- if (!(blkstr = virCgroupGetBlockDevString(devPath))) +- return -1; +- +- str = g_strdup_printf("%s%d", blkstr, weight); +- + if (virCgroupV1PathOfController(group, VIR_CGROUP_CONTROLLER_BLKIO, + "blkio.weight_device", &path) < 0) { + return -1; +@@ -1208,7 +1205,21 @@ virCgroupV1SetBlkioDeviceWeight(virCgroupPtr group, + return -1; + } + +- return virCgroupSetValueRaw(path, str); ++ if (group->unitName) { ++ return virCgroupSetValueDBus(group->unitName, "BlockIODeviceWeight", ++ "a(st)", ++ 1, path, (unsigned long long) weight); ++ } else { ++ g_autofree char *str = NULL; ++ g_autofree char *blkstr = NULL; ++ ++ if (!(blkstr = virCgroupGetBlockDevString(devPath))) ++ return -1; ++ ++ str = g_strdup_printf("%s%d", blkstr, weight); ++ ++ return virCgroupSetValueRaw(path, str); ++ } + } + + +@@ -1849,9 +1860,14 @@ static int + virCgroupV1SetCpuShares(virCgroupPtr group, + unsigned long long shares) + { +- return virCgroupSetValueU64(group, +- VIR_CGROUP_CONTROLLER_CPU, +- "cpu.shares", shares); ++ if (group->unitName) { ++ return virCgroupSetValueDBus(group->unitName, "CPUShares", ++ "t", shares); ++ } else { ++ return virCgroupSetValueU64(group, ++ VIR_CGROUP_CONTROLLER_CPU, ++ "cpu.shares", shares); ++ } + } + + +diff --git a/src/util/vircgroupv2.c b/src/util/vircgroupv2.c +index 4682a6a920..8fe4894a9e 100644 +--- a/src/util/vircgroupv2.c ++++ b/src/util/vircgroupv2.c +@@ -606,7 +606,6 @@ virCgroupV2SetBlkioWeight(virCgroupPtr group, + unsigned int weight) + { + g_autofree char *path = NULL; +- g_autofree char *value = NULL; + const char *format = "%u"; + + if (virCgroupV2PathOfController(group, VIR_CGROUP_CONTROLLER_BLKIO, +@@ -630,9 +629,14 @@ virCgroupV2SetBlkioWeight(virCgroupPtr group, + return -1; + } + +- value = g_strdup_printf(format, weight); ++ if (group->unitName) { ++ return virCgroupSetValueDBus(group->unitName, "IOWeight", ++ "t", (unsigned long long) weight); ++ } else { ++ g_autofree char *value = g_strdup_printf(format, weight); + +- return virCgroupSetValueRaw(path, value); ++ return virCgroupSetValueRaw(path, value); ++ } + } + + +@@ -817,13 +821,6 @@ virCgroupV2SetBlkioDeviceWeight(virCgroupPtr group, + unsigned int weight) + { + g_autofree char *path = NULL; +- g_autofree char *str = NULL; +- g_autofree char *blkstr = NULL; +- +- if (!(blkstr = virCgroupGetBlockDevString(devPath))) +- return -1; +- +- str = g_strdup_printf("%s%d", blkstr, weight); + + if (virCgroupV2PathOfController(group, VIR_CGROUP_CONTROLLER_BLKIO, + "io.weight", &path) < 0) { +@@ -836,7 +833,21 @@ virCgroupV2SetBlkioDeviceWeight(virCgroupPtr group, + return -1; + } + +- return virCgroupSetValueRaw(path, str); ++ if (group->unitName) { ++ return virCgroupSetValueDBus(group->unitName, "IODeviceWeight", ++ "a(st)", ++ 1, path, (unsigned long long) weight); ++ } else { ++ g_autofree char *str = NULL; ++ g_autofree char *blkstr = NULL; ++ ++ if (!(blkstr = virCgroupGetBlockDevString(devPath))) ++ return -1; ++ ++ str = g_strdup_printf("%s%d", blkstr, weight); ++ ++ return virCgroupSetValueRaw(path, str); ++ } + } + + +@@ -1455,9 +1466,14 @@ static int + virCgroupV2SetCpuShares(virCgroupPtr group, + unsigned long long shares) + { +- return virCgroupSetValueU64(group, +- VIR_CGROUP_CONTROLLER_CPU, +- "cpu.weight", shares); ++ if (group->unitName) { ++ return virCgroupSetValueDBus(group->unitName, "CPUWeight", ++ "t", shares); ++ } else { ++ return virCgroupSetValueU64(group, ++ VIR_CGROUP_CONTROLLER_CPU, ++ "cpu.weight", shares); ++ } + } + + +diff --git a/tests/Makefile.am b/tests/Makefile.am +index f957c7d1ba..b030d0e8f6 100644 +--- a/tests/Makefile.am ++++ b/tests/Makefile.am +@@ -1188,6 +1188,7 @@ libvirportallocatormock_la_LIBADD = $(MOCKLIBS_LIBS) + + vircgrouptest_SOURCES = \ + vircgrouptest.c testutils.h testutils.c ++vircgrouptest_CFLAGS = $(DBUS_CFLAGS) $(AM_CFLAGS) + vircgrouptest_LDADD = $(LDADDS) + + libvircgroupmock_la_SOURCES = \ +-- +2.30.0 + diff --git a/SOURCES/libvirt-vircgroupv1-refactor-virCgroupV1DetectPlacement.patch b/SOURCES/libvirt-vircgroupv1-refactor-virCgroupV1DetectPlacement.patch new file mode 100644 index 0000000..d8035c1 --- /dev/null +++ b/SOURCES/libvirt-vircgroupv1-refactor-virCgroupV1DetectPlacement.patch @@ -0,0 +1,77 @@ +From a88996cc6c72a6f7fd034c0890747c54cc377484 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Pavel Hrdina +Date: Fri, 19 Feb 2021 13:33:56 +0100 +Subject: [PATCH] vircgroupv1: refactor virCgroupV1DetectPlacement +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Remove one level of indentation by splitting the condition. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit 5f56dd7c83493f14a471bb9e33415b04329a08bf) + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463 + +Signed-off-by: Pavel Hrdina +Message-Id: +Reviewed-by: Ján Tomko +--- + src/util/vircgroupv1.c | 39 ++++++++++++++++++++++----------------- + 1 file changed, 22 insertions(+), 17 deletions(-) + +diff --git a/src/util/vircgroupv1.c b/src/util/vircgroupv1.c +index 7ec8f3a316..09165ece4d 100644 +--- a/src/util/vircgroupv1.c ++++ b/src/util/vircgroupv1.c +@@ -339,23 +339,28 @@ virCgroupV1DetectPlacement(virCgroupPtr group, + for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { + const char *typestr = virCgroupV1ControllerTypeToString(i); + +- if (virCgroupV1MountOptsMatchController(controllers, typestr) && +- group->legacy[i].mountPoint != NULL && +- group->legacy[i].placement == NULL) { +- /* +- * selfpath == "/" + path="" -> "/" +- * selfpath == "/libvirt.service" + path == "" -> "/libvirt.service" +- * selfpath == "/libvirt.service" + path == "foo" -> "/libvirt.service/foo" +- */ +- if (i == VIR_CGROUP_CONTROLLER_SYSTEMD) { +- group->legacy[i].placement = g_strdup(selfpath); +- } else { +- bool delim = STREQ(selfpath, "/") || STREQ(path, ""); +- +- group->legacy[i].placement = g_strdup_printf("%s%s%s", selfpath, +- delim ? "" : "/", +- path); +- } ++ if (!virCgroupV1MountOptsMatchController(controllers, typestr)) ++ continue; ++ ++ if (!group->legacy[i].mountPoint) ++ continue; ++ ++ if (group->legacy[i].placement) ++ continue; ++ ++ /* ++ * selfpath == "/" + path="" -> "/" ++ * selfpath == "/libvirt.service" + path == "" -> "/libvirt.service" ++ * selfpath == "/libvirt.service" + path == "foo" -> "/libvirt.service/foo" ++ */ ++ if (i == VIR_CGROUP_CONTROLLER_SYSTEMD) { ++ group->legacy[i].placement = g_strdup(selfpath); ++ } else { ++ bool delim = STREQ(selfpath, "/") || STREQ(path, ""); ++ ++ group->legacy[i].placement = g_strdup_printf("%s%s%s", selfpath, ++ delim ? "" : "/", ++ path); + } + } + +-- +2.30.0 + diff --git a/SOURCES/libvirt-vircgroupv2-move-task-into-cgroup-before-enabling-controllers.patch b/SOURCES/libvirt-vircgroupv2-move-task-into-cgroup-before-enabling-controllers.patch new file mode 100644 index 0000000..7a161d9 --- /dev/null +++ b/SOURCES/libvirt-vircgroupv2-move-task-into-cgroup-before-enabling-controllers.patch @@ -0,0 +1,155 @@ +From 41a7547b32786b1a84c8ee7bad0c4cf9559ea4b9 Mon Sep 17 00:00:00 2001 +Message-Id: <41a7547b32786b1a84c8ee7bad0c4cf9559ea4b9@dist-git> +From: Pavel Hrdina +Date: Fri, 19 Feb 2021 13:33:57 +0100 +Subject: [PATCH] vircgroupv2: move task into cgroup before enabling + controllers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When we create a new child cgroup and the parent cgroup has any process +attached to it enabling controllers for the child cgroup fails with +error. We need to move the process into the child cgroup first before +enabling any controllers. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit 382fa15cde538cba3888a89b301fd3d9a0ce69ea) + +Conflicts: + src/util/vircgroup.c + - missing upstream g_autofree rewrite + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463 + +Signed-off-by: Pavel Hrdina +Message-Id: <85d34403caacb571cb78539d5c4f56eee9484d57.1613737828.git.phrdina@redhat.com> +Reviewed-by: Ján Tomko +--- + src/util/vircgroup.c | 13 +++++++------ + src/util/vircgroupbackend.h | 1 + + src/util/vircgroupv1.c | 1 + + src/util/vircgroupv2.c | 13 +++++++++++++ + 4 files changed, 22 insertions(+), 6 deletions(-) + +diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c +index 10b934291c..8f5bcd94f4 100644 +--- a/src/util/vircgroup.c ++++ b/src/util/vircgroup.c +@@ -622,13 +622,14 @@ static int + virCgroupMakeGroup(virCgroupPtr parent, + virCgroupPtr group, + bool create, ++ pid_t pid, + unsigned int flags) + { + size_t i; + + for (i = 0; i < VIR_CGROUP_BACKEND_TYPE_LAST; i++) { + if (group->backends[i] && +- group->backends[i]->makeGroup(parent, group, create, flags) < 0) { ++ group->backends[i]->makeGroup(parent, group, create, pid, flags) < 0) { + virCgroupRemove(group); + return -1; + } +@@ -857,8 +858,8 @@ virCgroupNewPartition(const char *path, + goto cleanup; + + if (parent) { +- if (virCgroupMakeGroup(parent, *group, create, VIR_CGROUP_NONE) < 0) +- goto cleanup; ++ if (virCgroupMakeGroup(parent, *group, create, -1, VIR_CGROUP_NONE) < 0) ++ return -1; + } + + ret = 0; +@@ -924,7 +925,7 @@ virCgroupNewDomainPartition(virCgroupPtr partition, + * a group for driver, is to avoid overhead to track + * cumulative usage that we don't need. + */ +- if (virCgroupMakeGroup(partition, *group, create, ++ if (virCgroupMakeGroup(partition, *group, create, -1, + VIR_CGROUP_MEM_HIERACHY) < 0) { + virCgroupFree(group); + return -1; +@@ -978,7 +979,7 @@ virCgroupNewThread(virCgroupPtr domain, + if (virCgroupNew(-1, name, domain, controllers, group) < 0) + return -1; + +- if (virCgroupMakeGroup(domain, *group, create, VIR_CGROUP_THREAD) < 0) { ++ if (virCgroupMakeGroup(domain, *group, create, -1, VIR_CGROUP_THREAD) < 0) { + virCgroupFree(group); + return -1; + } +@@ -1065,7 +1066,7 @@ virCgroupEnableMissingControllers(char *path, + &tmp) < 0) + goto cleanup; + +- if (virCgroupMakeGroup(parent, tmp, true, VIR_CGROUP_SYSTEMD) < 0) { ++ if (virCgroupMakeGroup(parent, tmp, true, -1, VIR_CGROUP_SYSTEMD) < 0) { + virCgroupFree(&tmp); + goto cleanup; + } +diff --git a/src/util/vircgroupbackend.h b/src/util/vircgroupbackend.h +index e12a2e8b9d..ac7b3ae517 100644 +--- a/src/util/vircgroupbackend.h ++++ b/src/util/vircgroupbackend.h +@@ -119,6 +119,7 @@ typedef int + (*virCgroupMakeGroupCB)(virCgroupPtr parent, + virCgroupPtr group, + bool create, ++ pid_t pid, + unsigned int flags); + + typedef int +diff --git a/src/util/vircgroupv1.c b/src/util/vircgroupv1.c +index 09165ece4d..eb2b611cee 100644 +--- a/src/util/vircgroupv1.c ++++ b/src/util/vircgroupv1.c +@@ -601,6 +601,7 @@ static int + virCgroupV1MakeGroup(virCgroupPtr parent, + virCgroupPtr group, + bool create, ++ pid_t pid G_GNUC_UNUSED, + unsigned int flags) + { + size_t i; +diff --git a/src/util/vircgroupv2.c b/src/util/vircgroupv2.c +index 8fe4894a9e..5e19ed8332 100644 +--- a/src/util/vircgroupv2.c ++++ b/src/util/vircgroupv2.c +@@ -398,10 +398,17 @@ virCgroupV2EnableController(virCgroupPtr group, + } + + ++static int ++virCgroupV2AddTask(virCgroupPtr group, ++ pid_t pid, ++ unsigned int flags); ++ ++ + static int + virCgroupV2MakeGroup(virCgroupPtr parent, + virCgroupPtr group, + bool create, ++ pid_t pid, + unsigned int flags) + { + g_autofree char *path = NULL; +@@ -449,6 +456,12 @@ virCgroupV2MakeGroup(virCgroupPtr parent, + } + } else { + size_t i; ++ ++ if (pid > 0) { ++ if (virCgroupV2AddTask(group, pid, VIR_CGROUP_TASK_PROCESS) < 0) ++ return -1; ++ } ++ + for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++) { + int rc; + +-- +2.30.0 + diff --git a/SOURCES/libvirt-vircgroupv2-properly-detect-placement-of-running-VM.patch b/SOURCES/libvirt-vircgroupv2-properly-detect-placement-of-running-VM.patch new file mode 100644 index 0000000..799b56b --- /dev/null +++ b/SOURCES/libvirt-vircgroupv2-properly-detect-placement-of-running-VM.patch @@ -0,0 +1,88 @@ +From 9cf56b5a0d1394fef10afdd763dc8005457bbaf5 Mon Sep 17 00:00:00 2001 +Message-Id: <9cf56b5a0d1394fef10afdd763dc8005457bbaf5@dist-git> +From: Pavel Hrdina +Date: Fri, 19 Feb 2021 13:33:51 +0100 +Subject: [PATCH] vircgroupv2: properly detect placement of running VM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When libvirtd starts a VM it internally stores a path to the main +cgroup. When we restart libvirtd we should get to the same state. + +When we start a VM on host with systemd the cgroup is created for us and +the process is already placed into that cgroup and we detect the path +created by systemd using /proc/$PID/cgroup. After that we create +sub-cgroups and move all threads there. + +Once libvirtd is restarted we again detect the cgroup path using +/proc/$PID/cgroup, but in this case we will get a different path because +the main thread was moved to a "emulator" cgroup. + +Instead of ignoring the "emulator" directory when validating cgroups +remove it completely when detecting cgroup otherwise cgroups will not +work properly when libvirtd is restarted. + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit 902c6644a8ec292789d561b3188e576c37a86872) + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463 + +Signed-off-by: Pavel Hrdina +Message-Id: <10fb6b61cbb4f9caf8e8ba7706ec01d1da41fc67.1613737828.git.phrdina@redhat.com> +Reviewed-by: Ján Tomko +--- + src/util/vircgroupv2.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/src/util/vircgroupv2.c b/src/util/vircgroupv2.c +index 92ae3ec839..4682a6a920 100644 +--- a/src/util/vircgroupv2.c ++++ b/src/util/vircgroupv2.c +@@ -121,12 +121,6 @@ virCgroupV2ValidateMachineGroup(virCgroupPtr group, + if (!(tmp = strrchr(group->unified.placement, '/'))) + return false; + +- if (STREQ(tmp, "/emulator")) { +- *tmp = '\0'; +- +- if (!(tmp = strrchr(group->unified.placement, '/'))) +- return false; +- } + tmp++; + + if (STRNEQ(tmp, partmachinename) && +@@ -197,6 +191,9 @@ virCgroupV2DetectPlacement(virCgroupPtr group, + const char *controllers, + const char *selfpath) + { ++ g_autofree char *placement = g_strdup(selfpath); ++ char *tmp = NULL; ++ + if (group->unified.placement) + return 0; + +@@ -207,12 +204,18 @@ virCgroupV2DetectPlacement(virCgroupPtr group, + if (STRNEQ(controllers, "")) + return 0; + ++ /* Running VM will have the main thread placed in emulator cgroup ++ * but we need to get the main cgroup. */ ++ tmp = g_strrstr(placement, "/emulator"); ++ if (tmp) ++ *tmp = '\0'; ++ + /* + * selfpath == "/" + path="" -> "/" + * selfpath == "/libvirt.service" + path == "" -> "/libvirt.service" + * selfpath == "/libvirt.service" + path == "foo" -> "/libvirt.service/foo" + */ +- group->unified.placement = g_strdup_printf("%s%s%s", selfpath, ++ group->unified.placement = g_strdup_printf("%s%s%s", placement, + (STREQ(selfpath, "/") || STREQ(path, "") ? "" : "/"), path); + + return 0; +-- +2.30.0 + diff --git a/SOURCES/libvirt-virsystemd-export-virSystemdHasMachined.patch b/SOURCES/libvirt-virsystemd-export-virSystemdHasMachined.patch new file mode 100644 index 0000000..df82c03 --- /dev/null +++ b/SOURCES/libvirt-virsystemd-export-virSystemdHasMachined.patch @@ -0,0 +1,65 @@ +From c8fb30409d501e5d9299ac7c08c43917b199a72b Mon Sep 17 00:00:00 2001 +Message-Id: +From: Pavel Hrdina +Date: Fri, 19 Feb 2021 13:33:52 +0100 +Subject: [PATCH] virsystemd: export virSystemdHasMachined +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit a51147d9065217d9087449b4e601e3294c0a22cf) + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463 + +Signed-off-by: Pavel Hrdina +Message-Id: <9a861adc0dc51679d7178e464255c80465247333.1613737828.git.phrdina@redhat.com> +Reviewed-by: Ján Tomko +--- + src/libvirt_private.syms | 1 + + src/util/virsystemd.c | 2 +- + src/util/virsystemd.h | 2 ++ + 3 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index 9d87e2a27b..a869d1f7a4 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -3243,6 +3243,7 @@ virSystemdGetActivation; + virSystemdGetMachineNameByPID; + virSystemdHasLogind; + virSystemdHasLogindResetCachedValue; ++virSystemdHasMachined; + virSystemdHasMachinedResetCachedValue; + virSystemdMakeScopeName; + virSystemdMakeSliceName; +diff --git a/src/util/virsystemd.c b/src/util/virsystemd.c +index 96d43e5440..ca708cd1bd 100644 +--- a/src/util/virsystemd.c ++++ b/src/util/virsystemd.c +@@ -153,7 +153,7 @@ void virSystemdHasLogindResetCachedValue(void) + * -1 = error + * 0 = machine1 is available + */ +-static int ++int + virSystemdHasMachined(void) + { + int ret; +diff --git a/src/util/virsystemd.h b/src/util/virsystemd.h +index dfea75948b..9ce16b7de1 100644 +--- a/src/util/virsystemd.h ++++ b/src/util/virsystemd.h +@@ -57,6 +57,8 @@ int virSystemdTerminateMachine(const char *name); + + void virSystemdNotifyStartup(void); + ++int virSystemdHasMachined(void); ++ + int virSystemdHasLogind(void); + + int virSystemdCanSuspend(bool *result); +-- +2.30.0 + diff --git a/SOURCES/libvirt-virsystemd-introduce-virSystemdGetMachineByPID.patch b/SOURCES/libvirt-virsystemd-introduce-virSystemdGetMachineByPID.patch new file mode 100644 index 0000000..c7242c1 --- /dev/null +++ b/SOURCES/libvirt-virsystemd-introduce-virSystemdGetMachineByPID.patch @@ -0,0 +1,102 @@ +From a3a5c16f04d044502eecedbef6043bce79043df9 Mon Sep 17 00:00:00 2001 +Message-Id: +From: Pavel Hrdina +Date: Fri, 19 Feb 2021 13:33:53 +0100 +Subject: [PATCH] virsystemd: introduce virSystemdGetMachineByPID +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit 385704d5a4e1c02c21fb5779fa5067cf0d8ab56c) + +Conflicts: + src/util/virsystemd.c + - missing upstream glib dbus rewrite + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463 + +Signed-off-by: Pavel Hrdina +Message-Id: <7de7eae45f139e79c45731263924ae078f3e33c5.1613737828.git.phrdina@redhat.com> +Reviewed-by: Ján Tomko +--- + src/util/virsystemd.c | 46 +++++++++++++++++++++++++++++++++---------- + 1 file changed, 36 insertions(+), 10 deletions(-) + +diff --git a/src/util/virsystemd.c b/src/util/virsystemd.c +index ca708cd1bd..394eb13f38 100644 +--- a/src/util/virsystemd.c ++++ b/src/util/virsystemd.c +@@ -200,19 +200,24 @@ virSystemdHasLogind(void) + } + + +-char * +-virSystemdGetMachineNameByPID(pid_t pid) ++/** ++ * virSystemdGetMachineByPID: ++ * @conn: dbus connection ++ * @pid: pid of running VM ++ * ++ * Returns dbus object path to VM registered with machined. ++ * On error returns NULL. ++ */ ++static char * ++virSystemdGetMachineByPID(DBusConnection *conn, ++ pid_t pid) + { +- DBusConnection *conn; + DBusMessage *reply = NULL; +- char *name = NULL, *object = NULL; ++ char *object = NULL; + + if (virSystemdHasMachined() < 0) + goto cleanup; + +- if (!(conn = virDBusGetSystemBus())) +- goto cleanup; +- + if (virDBusCallMethod(conn, &reply, NULL, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", +@@ -224,12 +229,33 @@ virSystemdGetMachineNameByPID(pid_t pid) + if (virDBusMessageDecode(reply, "o", &object) < 0) + goto cleanup; + +- virDBusMessageUnref(reply); +- reply = NULL; +- + VIR_DEBUG("Domain with pid %lld has object path '%s'", + (long long) pid, object); + ++ cleanup: ++ virDBusMessageUnref(reply); ++ ++ return object; ++} ++ ++ ++char * ++virSystemdGetMachineNameByPID(pid_t pid) ++{ ++ DBusConnection *conn; ++ DBusMessage *reply = NULL; ++ char *name = NULL, *object = NULL; ++ ++ if (virSystemdHasMachined() < 0) ++ goto cleanup; ++ ++ if (!(conn = virDBusGetSystemBus())) ++ goto cleanup; ++ ++ object = virSystemdGetMachineByPID(conn, pid); ++ if (!object) ++ goto cleanup; ++ + if (virDBusCallMethod(conn, &reply, NULL, + "org.freedesktop.machine1", + object, +-- +2.30.0 + diff --git a/SOURCES/libvirt-virsystemd-introduce-virSystemdGetMachineUnitByPID.patch b/SOURCES/libvirt-virsystemd-introduce-virSystemdGetMachineUnitByPID.patch new file mode 100644 index 0000000..5918571 --- /dev/null +++ b/SOURCES/libvirt-virsystemd-introduce-virSystemdGetMachineUnitByPID.patch @@ -0,0 +1,205 @@ +From 9ec1193393c48198fd05b795bcce0d607b45d4ee Mon Sep 17 00:00:00 2001 +Message-Id: <9ec1193393c48198fd05b795bcce0d607b45d4ee@dist-git> +From: Pavel Hrdina +Date: Fri, 19 Feb 2021 13:33:54 +0100 +Subject: [PATCH] virsystemd: introduce virSystemdGetMachineUnitByPID +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(cherry picked from commit d3fb774b1ed548c0338b3338a87094dafea32aa2) + +Conflicts: + src/util/virsystemd.c + tests/virsystemdtest.c + - missing upstream glib dbus rewrite + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463 + +Signed-off-by: Pavel Hrdina +Message-Id: <28be8d962cde455d215fe9ee09fbdcc4145e931f.1613737828.git.phrdina@redhat.com> +Reviewed-by: Ján Tomko +--- + src/libvirt_private.syms | 1 + + src/util/virsystemd.c | 48 ++++++++++++++++++++++++++++++++ + src/util/virsystemd.h | 2 ++ + tests/virsystemdtest.c | 59 ++++++++++++++++++++++++++++++++++------ + 4 files changed, 101 insertions(+), 9 deletions(-) + +diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms +index a869d1f7a4..af6f32fb1e 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -3241,6 +3241,7 @@ virSystemdCanSuspend; + virSystemdCreateMachine; + virSystemdGetActivation; + virSystemdGetMachineNameByPID; ++virSystemdGetMachineUnitByPID; + virSystemdHasLogind; + virSystemdHasLogindResetCachedValue; + virSystemdHasMachined; +diff --git a/src/util/virsystemd.c b/src/util/virsystemd.c +index 394eb13f38..0b8e21ae46 100644 +--- a/src/util/virsystemd.c ++++ b/src/util/virsystemd.c +@@ -280,6 +280,54 @@ virSystemdGetMachineNameByPID(pid_t pid) + } + + ++/** ++ * virSystemdGetMachineUnitByPID: ++ * @pid: pid of running VM ++ * ++ * Returns systemd Unit name of a running VM registered with machined. ++ * On error returns NULL. ++ */ ++char * ++virSystemdGetMachineUnitByPID(pid_t pid) ++{ ++ DBusConnection *conn; ++ DBusMessage *reply = NULL; ++ char *unit = NULL, *object = NULL; ++ ++ if (virSystemdHasMachined() < 0) ++ goto cleanup; ++ ++ if (!(conn = virDBusGetSystemBus())) ++ goto cleanup; ++ ++ object = virSystemdGetMachineByPID(conn, pid); ++ if (!object) ++ goto cleanup; ++ ++ if (virDBusCallMethod(conn, &reply, NULL, ++ "org.freedesktop.machine1", ++ object, ++ "org.freedesktop.DBus.Properties", ++ "Get", ++ "ss", ++ "org.freedesktop.machine1.Machine", ++ "Unit") < 0) ++ goto cleanup; ++ ++ if (virDBusMessageDecode(reply, "v", "s", &unit) < 0) ++ goto cleanup; ++ ++ VIR_DEBUG("Domain with pid %lld has unit name '%s'", ++ (long long) pid, unit); ++ ++ cleanup: ++ VIR_FREE(object); ++ virDBusMessageUnref(reply); ++ ++ return unit; ++} ++ ++ + /** + * virSystemdCreateMachine: + * @name: driver unique name of the machine +diff --git a/src/util/virsystemd.h b/src/util/virsystemd.h +index 9ce16b7de1..cd329c49f9 100644 +--- a/src/util/virsystemd.h ++++ b/src/util/virsystemd.h +@@ -69,6 +69,8 @@ int virSystemdCanHybridSleep(bool *result); + + char *virSystemdGetMachineNameByPID(pid_t pid); + ++char *virSystemdGetMachineUnitByPID(pid_t pid); ++ + int virSystemdGetActivation(virSystemdActivationMap *map, + size_t nmap, + virSystemdActivationPtr *act); +diff --git a/tests/virsystemdtest.c b/tests/virsystemdtest.c +index eb510b40e4..475bf8debc 100644 +--- a/tests/virsystemdtest.c ++++ b/tests/virsystemdtest.c +@@ -69,19 +69,42 @@ VIR_MOCK_WRAP_RET_ARGS(dbus_connection_send_with_reply_and_block, + &object_path)) + goto error; + } else if (STREQ(member, "Get")) { +- const char *name = "qemu-demo"; ++ const char *name = NULL; ++ char *iface = NULL; ++ char *prop = NULL; + DBusMessageIter iter; + DBusMessageIter sub; + +- dbus_message_iter_init_append(reply, &iter); +- dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, +- "s", &sub); +- +- if (!dbus_message_iter_append_basic(&sub, +- DBUS_TYPE_STRING, +- &name)) ++ if (virDBusMessageDecode(message, "ss", &iface, &prop) < 0) + goto error; +- dbus_message_iter_close_container(&iter, &sub); ++ ++ VIR_FREE(iface); ++ ++ if (STREQ(prop, "Name")) { ++ name = "qemu-demo"; ++ } else if (STREQ(prop, "Unit")) { ++ name = "machine-qemu-demo.scope"; ++ } else { ++ dbus_set_error_const(error, ++ "org.freedesktop.systemd.badthing", ++ "Unknown machine property"); ++ } ++ ++ VIR_FREE(prop); ++ ++ if (name) { ++ dbus_message_iter_init_append(reply, &iter); ++ ++ dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, ++ "s", &sub); ++ ++ if (!dbus_message_iter_append_basic(&sub, ++ DBUS_TYPE_STRING, ++ &name)) ++ goto error; ++ ++ dbus_message_iter_close_container(&iter, &sub); ++ } + } + } + } else if (STREQ(service, "org.freedesktop.login1")) { +@@ -376,6 +399,23 @@ testGetMachineName(const void *opaque G_GNUC_UNUSED) + } + + ++static int ++testGetMachineUnit(const void *opaque G_GNUC_UNUSED) ++{ ++ g_autofree char *tmp = virSystemdGetMachineUnitByPID(1234); ++ ++ if (!tmp) { ++ fprintf(stderr, "%s", "Failed to create get machine unit\n"); ++ return -1; ++ } ++ ++ if (STREQ(tmp, "machine-qemu-demo.scope")) ++ return 0; ++ ++ return -1; ++} ++ ++ + struct testNameData { + const char *name; + const char *expected; +@@ -698,6 +738,7 @@ mymain(void) + DO_TEST("Test create bad systemd ", testCreateBadSystemd); + DO_TEST("Test create with network ", testCreateNetwork); + DO_TEST("Test getting machine name ", testGetMachineName); ++ DO_TEST("Test getting machine unit ", testGetMachineUnit); + + # define TEST_SCOPE(_name, unitname, _legacy) \ + do { \ +-- +2.30.0 + diff --git a/SPECS/libvirt.spec b/SPECS/libvirt.spec index 2dd83ea..d49212a 100644 --- a/SPECS/libvirt.spec +++ b/SPECS/libvirt.spec @@ -219,7 +219,7 @@ Summary: Library providing a simple virtualization API Name: libvirt Version: 6.0.0 -Release: 34%{?dist}%{?extra_release} +Release: 37%{?dist}%{?extra_release} License: LGPLv2+ URL: https://libvirt.org/ @@ -733,6 +733,45 @@ Patch501: libvirt-vircgroup-fix-cpu-quota-maximum-limit.patch Patch502: libvirt-util-add-virNetDevGetPhysPortName.patch Patch503: libvirt-util-avoid-manual-VIR_FREE-of-a-g_autofree-pointer-in-virPCIGetName.patch Patch504: libvirt-util-Add-phys_port_name-support-on-virPCIGetNetName.patch +Patch505: libvirt-vircgroupv2-properly-detect-placement-of-running-VM.patch +Patch506: libvirt-virsystemd-export-virSystemdHasMachined.patch +Patch507: libvirt-virsystemd-introduce-virSystemdGetMachineByPID.patch +Patch508: libvirt-virsystemd-introduce-virSystemdGetMachineUnitByPID.patch +Patch509: libvirt-vircgroup-use-DBus-call-to-systemd-for-some-APIs.patch +Patch510: libvirt-vircgroupv1-refactor-virCgroupV1DetectPlacement.patch +Patch511: libvirt-vircgroupv2-move-task-into-cgroup-before-enabling-controllers.patch +Patch512: libvirt-vircgroup-introduce-virCgroupV1Exists-and-virCgroupV2Exists.patch +Patch513: libvirt-vircgroup-introduce-nested-cgroup-to-properly-work-with-systemd.patch +Patch514: libvirt-tests-add-cgroup-nested-tests.patch +Patch515: libvirt-vircgroup-correctly-free-nested-virCgroupPtr.patch +Patch516: libvirt-qemu-Add-virtio-related-options-to-vsock.patch +Patch517: libvirt-domain_validate-use-defines-for-cpu-period-and-quota-limits.patch +Patch518: libvirt-docs-use-proper-cpu-quota-value-in-our-documentation.patch +Patch519: libvirt-vircgroup-enforce-range-limit-for-cpu.shares.patch +Patch520: libvirt-cgroup-use-virCgroupSetCpuShares-instead-of-virCgroupSetupCpuShares.patch +Patch521: libvirt-cpumap-Add-support-for-ibrs-CPU-feature.patch +Patch522: libvirt-cpumap-Add-support-for-svme-addr-check-CPU-feature.patch +Patch523: libvirt-cpu_map-Add-EPYC-Milan-x86-CPU-model.patch +Patch524: libvirt-cpu_map-Install-x86_EPYC-Milan.xml.patch +Patch525: libvirt-cpu_map-Fix-spelling-of-svme-addr-chk-feature.patch +Patch526: libvirt-network-make-it-safe-to-call-networkSetupPrivateChains-multiple-times.patch +Patch527: libvirt-network-force-re-creation-of-iptables-private-chains-on-firewalld-restart.patch +Patch528: libvirt-hostdev-Update-mdev-pointer-reference-after-checking-device-type.patch +Patch529: libvirt-hostdev-mdev-Lookup-mdevs-by-sysfs-path-rather-than-mdev-struct.patch +Patch530: libvirt-qemu_firmware-don-t-error-out-for-unknown-firmware-features.patch +Patch531: libvirt-docs-improve-description-of-secure-attribute-for-loader-element.patch +Patch532: libvirt-conf-introduce-virDomainDefParseBootInitOptions.patch +Patch533: libvirt-conf-introduce-virDomainDefParseBootKernelOptions.patch +Patch534: libvirt-conf-introduce-virDomainDefParseBootFirmwareOptions.patch +Patch535: libvirt-conf-introduce-virDomainDefParseBootLoaderOptions.patch +Patch536: libvirt-conf-introduce-virDomainDefParseBootAcpiOptions.patch +Patch537: libvirt-conf-use-switch-in-virDomainDefParseBootOptions.patch +Patch538: libvirt-conf-introduce-support-for-firmware-auto-selection-feature-filtering.patch +Patch539: libvirt-qemu-implement-support-for-firmware-auto-selection-feature-filtering.patch +Patch540: libvirt-domain_conf-Don-t-leak-def-os.firmwareFeatures.patch +Patch541: libvirt-conf-remove-duplicated-firmware-type-attribute.patch +Patch542: libvirt-security-fix-SELinux-label-generation-logic.patch +Patch543: libvirt-storage_driver-Unlock-object-on-ACL-fail-in-storagePoolLookupByTargetPath.patch Requires: libvirt-daemon = %{version}-%{release} Requires: libvirt-daemon-config-network = %{version}-%{release} @@ -2509,6 +2548,51 @@ exit 0 %changelog +* Fri Aug 6 2021 Jiri Denemark - 6.0.0-37 +- security: fix SELinux label generation logic (CVE-2021-3631) +- storage_driver: Unlock object on ACL fail in storagePoolLookupByTargetPath (CVE-2021-3667) + +* Tue Jun 1 2021 Jiri Denemark - 6.0.0-36 +- network: make it safe to call networkSetupPrivateChains() multiple times (rhbz#1942805) +- network: force re-creation of iptables private chains on firewalld restart (rhbz#1942805) +- hostdev: Update mdev pointer reference after checking device type (rhbz#1940449) +- hostdev: mdev: Lookup mdevs by sysfs path rather than mdev struct (rhbz#1940449) +- qemu_firmware: don't error out for unknown firmware features (rhbz#1961562) +- docs: improve description of secure attribute for loader element (rhbz#1929357) +- conf: introduce virDomainDefParseBootInitOptions (rhbz#1929357) +- conf: introduce virDomainDefParseBootKernelOptions (rhbz#1929357) +- conf: introduce virDomainDefParseBootFirmwareOptions (rhbz#1929357) +- conf: introduce virDomainDefParseBootLoaderOptions (rhbz#1929357) +- conf: introduce virDomainDefParseBootAcpiOptions (rhbz#1929357) +- conf: use switch in virDomainDefParseBootOptions (rhbz#1929357) +- conf: introduce support for firmware auto-selection feature filtering (rhbz#1929357) +- qemu: implement support for firmware auto-selection feature filtering (rhbz#1929357) +- domain_conf: Don't leak def->os.firmwareFeatures (rhbz#1929357) +- conf: remove duplicated firmware type attribute (rhbz#1929357) + +* Thu Mar 4 2021 Jiri Denemark - 6.0.0-35 +- vircgroupv2: properly detect placement of running VM (rhbz#1798463) +- virsystemd: export virSystemdHasMachined (rhbz#1798463) +- virsystemd: introduce virSystemdGetMachineByPID (rhbz#1798463) +- virsystemd: introduce virSystemdGetMachineUnitByPID (rhbz#1798463) +- vircgroup: use DBus call to systemd for some APIs (rhbz#1798463) +- vircgroupv1: refactor virCgroupV1DetectPlacement (rhbz#1798463) +- vircgroupv2: move task into cgroup before enabling controllers (rhbz#1798463) +- vircgroup: introduce virCgroupV1Exists and virCgroupV2Exists (rhbz#1798463) +- vircgroup: introduce nested cgroup to properly work with systemd (rhbz#1798463) +- tests: add cgroup nested tests (rhbz#1798463) +- vircgroup: correctly free nested virCgroupPtr (rhbz#1798463) +- qemu: Add virtio related options to vsock (rhbz#1931548) +- domain_validate: use defines for cpu period and quota limits (rhbz#1798463) +- docs: use proper cpu quota value in our documentation (rhbz#1798463) +- vircgroup: enforce range limit for cpu.shares (rhbz#1798463) +- cgroup: use virCgroupSetCpuShares instead of virCgroupSetupCpuShares (rhbz#1798463) +- cpumap: Add support for ibrs CPU feature (rhbz#1926864) +- cpumap: Add support for svme-addr-check CPU feature (rhbz#1926864) +- cpu_map: Add EPYC-Milan x86 CPU model (rhbz#1926864) +- cpu_map: Install x86_EPYC-Milan.xml (rhbz#1926864) +- cpu_map: Fix spelling of svme-addr-chk feature (rhbz#1926864) + * Mon Feb 1 2021 Jiri Denemark - 6.0.0-34 - qemu: move cgroup cpu period and quota defines to vircgroup.h (rhbz#1915733) - vircgroupv1: use defines for cpu period and quota limits (rhbz#1915733)