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 <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <a7f8e3c0ce4bc22eccbaa25a434d5e72e74d8a65.1614858616.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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 <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <631e05bc5363abb3e48d8b652a806324801cce16.1621599207.git.phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+---
+ 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 @@
+         <code>ESX</code> and <code>VMWare</code> hypervisor drivers, however,
+         the <code>i686</code> arch will always be chosen even on an
+         <code>x86_64</code> host. <span class="since">Since 0.0.1</span></dd>
++      <dt><a id="elementFirmware"><code>firmware</code></a></dt>
++      <dd>
++        <p><span class="since">Since 7.2.0 QEMU/KVM only</span></p>
++        <p>
++          When used together with <code>firmware</code> attribute of
++          <code>os</code> element the <code>type</code> attribute must
++          have the same value.
++        </p>
++        <p>
++          List of mandatory attributes:
++          <ul>
++            <li>
++              <code>type</code> (accepted values are <code>bios</code>
++              and <code>efi</code>) same as the <code>firmware</code>
++              attribute of <code>os</code> element.
++            </li>
++          </ul>
++        </p>
++        <p>
++          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
++          <code>feature</code> elements. Libvirt will take into consideration
++          only the listed features and ignore the rest when selecting the firmware.
++
++          <dl>
++            <dt><code>feature</code></dt>
++            <dd>
++              The list of mandatory attributes:
++
++              <ul>
++                <li>
++                  <code>enabled</code> (accepted values are <code>yes</code>
++                  and <code>no</code>) is used to tell libvirt if the feature
++                  must be enabled or not in the automatically selected firmware
++                </li>
++                <li>
++                  <code>name</code> the name of the feature, the list of the features:
++                  <ul>
++                    <li>
++                      <code>enrolled-keys</code> 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.
++                    </li>
++                    <li>
++                      <code>secure-boot</code> whether the firmware implements
++                      UEFI Secure boot feature.
++                    </li>
++                  </ul>
++                </li>
++              </ul>
++            </dd>
++          </dl>
++        </p>
++      </dd>
+       <dt><a id="elementLoader"><code>loader</code></a></dt>
+       <dd>The optional <code>loader</code> 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 @@
+           </attribute>
+         </optional>
+         <ref name="ostypehvm"/>
++        <optional>
++          <element name="firmware">
++            <attribute name="type">
++              <choice>
++                <value>bios</value>
++                <value>efi</value>
++              </choice>
++            </attribute>
++            <zeroOrMore>
++              <element name="feature">
++                <attribute name="enabled">
++                  <ref name="virYesNo"/>
++                </attribute>
++                <attribute name="name">
++                  <choice>
++                    <value>enrolled-keys</value>
++                    <value>secure-boot</value>
++                  </choice>
++                </attribute>
++              </element>
++            </zeroOrMore>
++          </element>
++        </optional>
+         <optional>
+           <element name="loader">
+             <optional>
+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
+  * <mirror> 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</type>\n",
+                           virDomainOSTypeToString(def->os.type));
+ 
++    if (def->os.firmware) {
++        virBufferAsprintf(buf, "<firmware type='%s'",
++                          virDomainOsDefFirmwareTypeToString(def->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, "<feature enabled='%s' name='%s'/>\n",
++                                  virTristateBoolTypeToString(def->os.firmwareFeatures[i]),
++                                  virDomainOsDefFirmwareFeatureTypeToString(i));
++            }
++
++            virBufferAdjustIndent(buf, -2);
++
++            virBufferAddLit(buf, "</firmware>\n");
++        } else {
++            virBufferAddLit(buf, "/>\n");
++        }
++    }
++
+     virBufferEscapeString(buf, "<init>%s</init>\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 @@
++<domain type='kvm'>
++  <name>fedora</name>
++  <uuid>63840878-0deb-4095-97e6-fc444d9bc9fa</uuid>
++  <memory unit='KiB'>8192</memory>
++  <currentMemory unit='KiB'>8192</currentMemory>
++  <vcpu placement='static'>1</vcpu>
++  <os firmware='efi'>
++    <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
++    <firmware type='bios'/>
++    <loader secure='no'/>
++    <nvram>/var/lib/libvirt/qemu/nvram/fedora_VARS.fd</nvram>
++    <boot dev='hd'/>
++    <bootmenu enable='yes'/>
++  </os>
++  <features>
++    <acpi/>
++    <apic/>
++    <pae/>
++  </features>
++  <clock offset='utc'/>
++  <on_poweroff>destroy</on_poweroff>
++  <on_reboot>restart</on_reboot>
++  <on_crash>restart</on_crash>
++  <devices>
++    <emulator>/usr/bin/qemu-system-x86_64</emulator>
++    <memballoon model='none'/>
++  </devices>
++</domain>
+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 @@
+   <vcpu placement='static'>1</vcpu>
+   <os firmware='efi'>
+     <type arch='aarch64' machine='virt-4.0'>hvm</type>
++    <firmware type='efi'/>
+     <kernel>/aarch64.kernel</kernel>
+     <initrd>/aarch64.initrd</initrd>
+     <cmdline>earlyprintk console=ttyAMA0,115200n8 rw root=/dev/vda rootwait</cmdline>
+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 @@
+   <vcpu placement='static'>1</vcpu>
+   <os firmware='bios'>
+     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
++    <firmware type='bios'/>
+     <loader secure='no'/>
+     <nvram>/var/lib/libvirt/qemu/nvram/fedora_VARS.fd</nvram>
+     <boot dev='hd'/>
+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 @@
+   <vcpu placement='static'>1</vcpu>
+   <os firmware='efi'>
+     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
++    <firmware type='efi'/>
+     <loader secure='yes'/>
+     <nvram>/var/lib/libvirt/qemu/nvram/fedora_VARS.fd</nvram>
+     <boot dev='hd'/>
+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 @@
+   <vcpu placement='static'>1</vcpu>
+   <os firmware='efi'>
+     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
++    <firmware type='efi'/>
+     <loader secure='no'/>
+     <nvram>/var/lib/libvirt/qemu/nvram/fedora_VARS.fd</nvram>
+     <boot dev='hd'/>
+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 @@
+   <vcpu placement='static'>1</vcpu>
+   <os firmware='efi'>
+     <type arch='i686'>hvm</type>
++    <firmware type='efi'/>
+   </os>
+   <clock offset='utc'/>
+   <on_poweroff>destroy</on_poweroff>
+-- 
+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 <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <5fb7ee0165340ff517b3f7f16ddc542813ac385d.1621599207.git.phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+---
+ 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 <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(cherry picked from commit bcf97abfc6b45694f0d789ae2bdf87c8d082fddf)
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1929357
+
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+Message-Id: <9a090d9f2a43b261ed1b6db608779a01a7594f4a.1621599207.git.phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+---
+ 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: <adafaa880b67f1025c64515352e5e851daa62ae9@dist-git>
+From: Pavel Hrdina <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <cb7f11437bdbc14b0791645c39c963118d0f9806.1621599207.git.phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+---
+ 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 <initarg> 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 <initenv> 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 <initarg> 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 <initenv name='%s'> 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 <initenv> element"));
+-                return -1;
+-            }
+ 
+-            if (!nodes[i]->children ||
+-                !nodes[i]->children->content) {
+-                virReportError(VIR_ERR_XML_ERROR,
+-                               _("No value supplied for <initenv name='%s'> 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: <a62075772680bd30ced25d7177048ab26db8ea09@dist-git>
+From: Pavel Hrdina <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(cherry picked from commit bf9b3f8e573092cc98ea647f25cf116e22bbfe3c)
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1929357
+
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+Message-Id: <936428a5fa6d4104361ac8080639a55111c14965.1621599207.git.phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+---
+ 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 <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <e9d0f563b055b415deb7718d33f7661a797a48f1.1621599207.git.phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+---
+ 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?= <berrange@redhat.com>
+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
+
+  <os firmware='efi'>
+    <firmware type='efi'>
+      <feature enabled='no' name='enrolled-keys'/>
+    </firmware>
+  </os>
+
+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:
+
+  <os firmware='efi'>
+    <firmware>
+      <feature enabled='no' name='enrolled-keys'/>
+    </firmware>
+  </os>
+
+which also means that we don't need to emit the empty element
+<firmware type='efi'/> for all existing configs too.
+
+Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
+Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <299fd16fc3ce632bf25ca55cc4bb65a225437d61.1621599207.git.phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+---
+ 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 @@
+       <dt><a id="elementFirmware"><code>firmware</code></a></dt>
+       <dd>
+         <p><span class="since">Since 7.2.0 QEMU/KVM only</span></p>
+-        <p>
+-          When used together with <code>firmware</code> attribute of
+-          <code>os</code> element the <code>type</code> attribute must
+-          have the same value.
+-        </p>
+-        <p>
+-          List of mandatory attributes:
+-          <ul>
+-            <li>
+-              <code>type</code> (accepted values are <code>bios</code>
+-              and <code>efi</code>) same as the <code>firmware</code>
+-              attribute of <code>os</code> element.
+-            </li>
+-          </ul>
+-        </p>
+         <p>
+           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 @@
+         <ref name="ostypehvm"/>
+         <optional>
+           <element name="firmware">
+-            <attribute name="type">
+-              <choice>
+-                <value>bios</value>
+-                <value>efi</value>
+-              </choice>
+-            </attribute>
+-            <zeroOrMore>
++            <oneOrMore>
+               <element name="feature">
+                 <attribute name="enabled">
+                   <ref name="virYesNo"/>
+@@ -288,7 +282,7 @@
+                   </choice>
+                 </attribute>
+               </element>
+-            </zeroOrMore>
++            </oneOrMore>
+           </element>
+         </optional>
+         <optional>
+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</type>\n",
+                           virDomainOSTypeToString(def->os.type));
+ 
+-    if (def->os.firmware) {
+-        virBufferAsprintf(buf, "<firmware type='%s'",
+-                          virDomainOsDefFirmwareTypeToString(def->os.firmware));
+-
+-        if (def->os.firmwareFeatures) {
+-            virBufferAddLit(buf, ">\n");
+-
+-            virBufferAdjustIndent(buf, 2);
++    if (def->os.firmwareFeatures) {
++        virBufferAddLit(buf, "<firmware>\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, "<feature enabled='%s' name='%s'/>\n",
+-                                  virTristateBoolTypeToString(def->os.firmwareFeatures[i]),
+-                                  virDomainOsDefFirmwareFeatureTypeToString(i));
+-            }
++            virBufferAsprintf(buf, "<feature enabled='%s' name='%s'/>\n",
++                              virTristateBoolTypeToString(def->os.firmwareFeatures[i]),
++                              virDomainOsDefFirmwareFeatureTypeToString(i));
++        }
+ 
+-            virBufferAdjustIndent(buf, -2);
++        virBufferAdjustIndent(buf, -2);
+ 
+-            virBufferAddLit(buf, "</firmware>\n");
+-        } else {
+-            virBufferAddLit(buf, "/>\n");
+-        }
++        virBufferAddLit(buf, "</firmware>\n");
+     }
+ 
+     virBufferEscapeString(buf, "<init>%s</init>\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 @@
+   <vcpu placement='static'>1</vcpu>
+   <os firmware='efi'>
+     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
+-    <firmware type='efi'>
++    <firmware>
+       <feature enabled='no' name='enrolled-keys'/>
+     </firmware>
+     <boot dev='hd'/>
+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 @@
+-<domain type='kvm'>
+-  <name>fedora</name>
+-  <uuid>63840878-0deb-4095-97e6-fc444d9bc9fa</uuid>
+-  <memory unit='KiB'>8192</memory>
+-  <currentMemory unit='KiB'>8192</currentMemory>
+-  <vcpu placement='static'>1</vcpu>
+-  <os firmware='efi'>
+-    <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
+-    <firmware type='bios'/>
+-    <loader secure='no'/>
+-    <nvram>/var/lib/libvirt/qemu/nvram/fedora_VARS.fd</nvram>
+-    <boot dev='hd'/>
+-    <bootmenu enable='yes'/>
+-  </os>
+-  <features>
+-    <acpi/>
+-    <apic/>
+-    <pae/>
+-  </features>
+-  <clock offset='utc'/>
+-  <on_poweroff>destroy</on_poweroff>
+-  <on_reboot>restart</on_reboot>
+-  <on_crash>restart</on_crash>
+-  <devices>
+-    <emulator>/usr/bin/qemu-system-x86_64</emulator>
+-    <memballoon model='none'/>
+-  </devices>
+-</domain>
+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 @@
+   <vcpu placement='static'>1</vcpu>
+   <os firmware='efi'>
+     <type arch='aarch64' machine='virt-4.0'>hvm</type>
+-    <firmware type='efi'/>
+     <kernel>/aarch64.kernel</kernel>
+     <initrd>/aarch64.initrd</initrd>
+     <cmdline>earlyprintk console=ttyAMA0,115200n8 rw root=/dev/vda rootwait</cmdline>
+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 @@
+   <vcpu placement='static'>1</vcpu>
+   <os firmware='bios'>
+     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
+-    <firmware type='bios'/>
+     <loader secure='no'/>
+     <nvram>/var/lib/libvirt/qemu/nvram/fedora_VARS.fd</nvram>
+     <boot dev='hd'/>
+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 @@
+   <vcpu placement='static'>1</vcpu>
+   <os firmware='efi'>
+     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
+-    <firmware type='efi'/>
+     <loader secure='yes'/>
+     <nvram>/var/lib/libvirt/qemu/nvram/fedora_VARS.fd</nvram>
+     <boot dev='hd'/>
+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 @@
+   <vcpu placement='static'>1</vcpu>
+   <os firmware='efi'>
+     <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
+-    <firmware type='efi'/>
+     <loader secure='no'/>
+     <nvram>/var/lib/libvirt/qemu/nvram/fedora_VARS.fd</nvram>
+     <boot dev='hd'/>
+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 @@
+   <vcpu placement='static'>1</vcpu>
+   <os firmware='efi'>
+     <type arch='i686'>hvm</type>
+-    <firmware type='efi'/>
+   </os>
+   <clock offset='utc'/>
+   <on_poweroff>destroy</on_poweroff>
+-- 
+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 <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(cherry picked from commit 6330be1ba3af5c4d2150fe2b831f7bc5d87c6d2a)
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1929357
+
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+Message-Id: <900c870b1720688123ed7b69850548ae308ea9a8.1621599207.git.phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+---
+ 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: <b5716d1b191eb52cd88d7b94cb9bf0186f3e427b@dist-git>
+From: Jiri Denemark <jdenemar@redhat.com>
+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 <jdenemar@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+(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 <jdenemar@redhat.com>
+Message-Id: <715abc0f90faafb7daa193dd24bad65046c36de0.1614766279.git.jdenemar@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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 @@
+     <include filename="x86_EPYC.xml"/>
+     <include filename="x86_EPYC-IBPB.xml"/>
+     <include filename="x86_EPYC-Rome.xml"/>
++    <include filename='x86_EPYC-Milan.xml'/>
+ 
+     <!-- Hygon CPU models -->
+     <include filename="x86_Dhyana.xml"/>
+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 @@
++<cpus>
++  <model name='EPYC-Milan'>
++    <decode host='on' guest='on'/>
++    <signature family='25' model='1'/>
++    <vendor name='AMD'/>
++    <feature name='3dnowprefetch'/>
++    <feature name='abm'/>
++    <feature name='adx'/>
++    <feature name='aes'/>
++    <feature name='amd-ssbd'/>
++    <feature name='amd-stibp'/>
++    <feature name='apic'/>
++    <feature name='arat'/>
++    <feature name='avx'/>
++    <feature name='avx2'/>
++    <feature name='bmi1'/>
++    <feature name='bmi2'/>
++    <feature name='clflush'/>
++    <feature name='clflushopt'/>
++    <feature name='clwb'/>
++    <feature name='clzero'/>
++    <feature name='cmov'/>
++    <feature name='cr8legacy'/>
++    <feature name='cx16'/>
++    <feature name='cx8'/>
++    <feature name='de'/>
++    <feature name='erms'/>
++    <feature name='f16c'/>
++    <feature name='fma'/>
++    <feature name='fpu'/>
++    <feature name='fsgsbase'/>
++    <feature name='fsrm'/>
++    <feature name='fxsr'/>
++    <feature name='fxsr_opt'/>
++    <feature name='ibpb'/>
++    <feature name='ibrs'/>
++    <feature name='invpcid'/>
++    <feature name='lahf_lm'/>
++    <feature name='lm'/>
++    <feature name='mca'/>
++    <feature name='mce'/>
++    <feature name='misalignsse'/>
++    <feature name='mmx'/>
++    <feature name='mmxext'/>
++    <feature name='movbe'/>
++    <feature name='msr'/>
++    <feature name='mtrr'/>
++    <feature name='npt'/>
++    <feature name='nrip-save'/>
++    <feature name='nx'/>
++    <feature name='osvw'/>
++    <feature name='pae'/>
++    <feature name='pat'/>
++    <feature name='pcid'/>
++    <feature name='pclmuldq'/>
++    <feature name='pdpe1gb'/>
++    <feature name='perfctr_core'/>
++    <feature name='pge'/>
++    <feature name='pku'/>
++    <feature name='pni'/>
++    <feature name='popcnt'/>
++    <feature name='pse'/>
++    <feature name='pse36'/>
++    <feature name='rdpid'/>
++    <feature name='rdrand'/>
++    <feature name='rdseed'/>
++    <feature name='rdtscp'/>
++    <feature name='sep'/>
++    <feature name='sha-ni'/>
++    <feature name='smap'/>
++    <feature name='smep'/>
++    <feature name='sse'/>
++    <feature name='sse2'/>
++    <feature name='sse4.1'/>
++    <feature name='sse4.2'/>
++    <feature name='sse4a'/>
++    <feature name='ssse3'/>
++    <feature name='svm'/>
++    <feature name='svme-addr-check'/>
++    <feature name='syscall'/>
++    <feature name='tsc'/>
++    <feature name='umip'/>
++    <feature name='vme'/>
++    <feature name='wbnoinvd'/>
++    <feature name='xgetbv1'/>
++    <feature name='xsave'/>
++    <feature name='xsavec'/>
++    <feature name='xsaveerptr'/>
++    <feature name='xsaveopt'/>
++    <feature name='xsaves'/>
++  </model>
++</cpus>
+-- 
+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: <a7fb45c4e5a807a7b437a91cfc96c8c811351578@dist-git>
+From: Jiri Denemark <jdenemar@redhat.com>
+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 <jdenemar@redhat.com>
+Reviewed-by: Tim Wiederhake <twiederh@redhat.com>
+(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 <jdenemar@redhat.com>
+Message-Id: <75071287f9fc55f4bec82916726fcb8f31c1e014.1614847231.git.jdenemar@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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 @@
+     <feature name='sse4a'/>
+     <feature name='ssse3'/>
+     <feature name='svm'/>
+-    <feature name='svme-addr-check'/>
++    <feature name='svme-addr-chk'/>
+     <feature name='syscall'/>
+     <feature name='tsc'/>
+     <feature name='umip'/>
+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 @@
+   <feature name='pfthreshold'>
+     <cpuid eax_in='0x8000000a' edx='0x00001000'/>
+   </feature>
+-  <feature name='svme-addr-check'>
++  <feature name='svme-addr-chk'>
+     <cpuid eax_in='0x8000000a' edx='0x10000000'/>
+   </feature>
+ 
+-- 
+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 <jdenemar@redhat.com>
+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 <jdenemar@redhat.com>
+Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
+(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 <jdenemar@redhat.com>
+Message-Id: <77cf69a7222fd9fc5ef0f1c25f0534090c29865f.1614766279.git.jdenemar@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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: <bb9f39342d4ea6b76b67378f514f52a9627206b9@dist-git>
+From: Tim Wiederhake <twiederh@redhat.com>
+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 <twiederh@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+(cherry picked from commit 5c17a7ba41670f3182186c06e621995b5d03fc95)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1926864
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+Message-Id: <0aee3baa35e04f56e3c95bb2f60c8a17d7806e7a.1614766279.git.jdenemar@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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 @@
+   <feature name='ibpb'>
+     <cpuid eax_in='0x80000008' ebx='0x00001000'/>
+   </feature>
++  <feature name='ibrs'>
++    <cpuid eax_in='0x80000008' ebx='0x00004000'/>
++  </feature>
+   <feature name='amd-stibp'>
+     <cpuid eax_in='0x80000008' ebx='0x00008000'/>
+   </feature>
+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 @@
+   <feature policy='require' name='topoext'/>
+   <feature policy='require' name='perfctr_nb'/>
+   <feature policy='require' name='invtsc'/>
++  <feature policy='require' name='ibrs'/>
+   <feature policy='require' name='amd-ssbd'/>
+   <feature policy='require' name='lbrv'/>
+   <feature policy='require' name='svm-lock'/>
+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 @@
+   <feature name='topoext'/>
+   <feature name='perfctr_nb'/>
+   <feature name='invtsc'/>
++  <feature name='ibrs'/>
+   <feature name='amd-ssbd'/>
+   <feature name='lbrv'/>
+   <feature name='svm-lock'/>
+-- 
+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 <twiederh@redhat.com>
+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 <twiederh@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+(cherry picked from commit 5ac6ab2fde63881d3c5cc7372a0d0e59618feb55)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1926864
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+Message-Id: <aa154754f76021b9f61788944f6c329c6088cf77.1614766279.git.jdenemar@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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 @@
+   <feature name='pfthreshold'>
+     <cpuid eax_in='0x8000000a' edx='0x00001000'/>
+   </feature>
++  <feature name='svme-addr-check'>
++    <cpuid eax_in='0x8000000a' edx='0x10000000'/>
++  </feature>
+ 
+   <!-- IA32_ARCH_CAPABILITIES features -->
+   <feature name='rdctl-no'>
+-- 
+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 <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Kashyap Chamarthy <kchamart@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <e2c4f2faa7f2a525b4d3ea5608a1b305cf18712b.1621599207.git.phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+---
+ 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, <code>type</code> should be
+         <code>pflash</code>. Moreover, some firmwares may
+         implement the Secure boot feature. Attribute
+-        <code>secure</code> can be used then to control it.
++        <code>secure</code> 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.
+         <span class="since">Since 2.1.0</span></dd>
+       <dt><code>nvram</code></dt>
+       <dd>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: <c9113d8cd9d68c932175ea63b634fc5cb7e51ef2@dist-git>
+From: Pavel Hrdina <phrdina@redhat.com>
+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 <d505b8af58912ae1e1a211fabc9995b19bd40828> changed the cpu quota
+value that reflects what kernel allows but did not update our
+documentation.
+
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <ba20be50c3bde1668cb214253e5ef8f212fc062b.1614858616.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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 <code>quota</code> 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.
+         <span class="since">Only QEMU driver support since 0.9.4, LXC since
+@@ -894,7 +894,7 @@
+         domain. A domain with <code>global_quota</code> 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 <code>global_quota</code>
++        [1000, 17592186044415] or less than 0. A <code>global_quota</code>
+         with value 0 means no value.
+         <span class="since">Only QEMU driver support since 1.3.3</span>
+       </dd>
+@@ -915,7 +915,7 @@
+         excluding vCPUs). A domain with <code>emulator_quota</code> 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.
+         <span class="since">Only QEMU driver support since 0.10.0</span>
+       </dd>
+@@ -937,7 +937,7 @@
+         <code>iothread_quota</code> 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 <code>iothread_quota</code>
++        [1000, 17592186044415] or less than 0. An <code>iothread_quota</code>
+         with value 0 means no value. You can use this feature to ensure that
+         all IOThreads run at the same speed.
+         <span class="since">Only QEMU driver support since 2.1.0</span>
+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 @@
+   <define name="cpuquota">
+     <data type="long">
+       <param name="pattern">-?[0-9]+</param>
+-      <param name="maxInclusive">18446744073709551</param>
++      <param name="maxInclusive">17592186044415</param>
+       <param name='minInclusive'>-1</param>
+     </data>
+   </define>
+-- 
+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 <mprivozn@redhat.com>
+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 <mprivozn@redhat.com>
+Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <82f4beea71e682c43ec10370d5a43a608d1cb411.1621599207.git.phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+---
+ 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 <phrdina@redhat.com>
+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 <bc760f4d7c4f964fadcb2a73e126b0053e7a9b06> and
+<98a09ca48ed4fc011abf2aa290e02ce1b8f1bb5f> fixed the code to use
+defines instead of magic numbers but missed this place.
+
+Following commit <ed1ba69f5a8132f8c1e73d2a1f142d70de0b564a> 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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <63a44700876e2bd59f276fcd8395abaff011b4c1.1614858616.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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: <bad40f7148a5849e84e9cdc341ff1fa03dc94fc6@dist-git>
+From: Thomas Huth <thuth@redhat.com>
+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 <eskultet@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+(cherry picked from commit 964738cff3d949d90fc5c3317a2618fcd8d217b4)
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1940449
+Signed-off-by: Thomas Huth <thuth@redhat.com>
+Message-Id: <20210511121028.304070-2-thuth@redhat.com>
+Reviewed-by: Erik Skultety <eskultet@redhat.com>
+---
+ 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 <thuth@redhat.com>
+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 <path> is in use by
+driver QEMU, domain <name>"
+
+Fixes: https://gitlab.com/libvirt/libvirt/-/issues/119
+
+Signed-off-by: Erik Skultety <eskultet@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+(cherry picked from commit 49cb59778a4e6c2d04bb9383a9d97fbbc83f9fce)
+Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1940449
+Signed-off-by: Thomas Huth <thuth@redhat.com>
+Message-Id: <20210511121028.304070-3-thuth@redhat.com>
+Reviewed-by: Erik Skultety <eskultet@redhat.com>
+---
+ 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 <laine@redhat.com>
+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 <laine@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+(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 <laine@redhat.com>
+Message-Id: <20210415032534.723202-3-laine@redhat.com>
+Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
+---
+ 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 <config.h>
+ 
+ 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 <laine@redhat.com>
+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 <laine@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+(cherry picked from commit de110f110fb917a31b9f33ad8e4b3c1d3284766a)
+
+https://bugzilla.redhat.com/1942805
+
+Message-Id: <20210415032534.723202-2-laine@redhat.com>
+Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
+---
+ 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 <fiuczy@linux.ibm.com>
+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:
+
+ <vsock model='virtio'>
+   <cid auto='no' address='3'/>
+   <driver iommu='on'/>
+ </vsock>
+
+Signed-off-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+---
+ 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
+     <code>auto</code> is set to <code>yes</code>, libvirt
+     will assign a free CID automatically on domain startup.
+-    <span class="since">Since 4.4.0</span></p>
++    <span class="since">Since 4.4.0</span>
++    The optional <code>driver</code> element allows to specify virtio options, see
++    <a href="#elementsVirtio">Virtio-specific options</a> for more details.
++    <span class="since">Since 7.1.0</span></p>
+ 
+ <pre>
+ ...
+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 @@
+         <optional>
+           <ref name="alias"/>
+         </optional>
++        <optional>
++          <element name="driver">
++            <ref name="virtioOptions"/>
++          </element>
++        </optional>
+       </interleave>
+     </element>
+   </define>
+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 @@
++<domain type='qemu'>
++  <name>QEMUGuest1</name>
++  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
++  <memory unit='KiB'>219136</memory>
++  <currentMemory unit='KiB'>219136</currentMemory>
++  <vcpu placement='static'>1</vcpu>
++  <os>
++    <type arch='s390x' machine='s390-ccw-virtio'>hvm</type>
++    <boot dev='hd'/>
++  </os>
++  <cpu mode='custom' match='exact' check='none'>
++    <model fallback='forbid'>qemu</model>
++  </cpu>
++  <clock offset='utc'/>
++  <on_poweroff>destroy</on_poweroff>
++  <on_reboot>restart</on_reboot>
++  <on_crash>destroy</on_crash>
++  <devices>
++    <emulator>/usr/bin/qemu-system-s390x</emulator>
++    <disk type='block' device='disk'>
++      <driver name='qemu' type='raw'/>
++      <source dev='/dev/HostVG/QEMUGuest1'/>
++      <target dev='hda' bus='virtio'/>
++      <address type='ccw' cssid='0xfe' ssid='0x0' devno='0x0000'/>
++    </disk>
++    <controller type='pci' index='0' model='pci-root'/>
++    <memballoon model='virtio'>
++      <address type='ccw' cssid='0xfe' ssid='0x0' devno='0x0001'/>
++    </memballoon>
++    <panic model='s390'/>
++    <vsock model='virtio'>
++      <cid auto='no' address='4'/>
++      <address type='ccw' cssid='0xfe' ssid='0x0' devno='0x0002'/>
++      <driver iommu='on'/>
++    </vsock>
++  </devices>
++</domain>
+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: <d1c5d166a891a2abf408a5879b95bded23b45825@dist-git>
+From: Pavel Hrdina <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <de1971688ed4bf1556d669973e60de6e3c76b4c1.1621599207.git.phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+---
+ 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 @@
++<domain type='kvm'>
++  <name>fedora</name>
++  <uuid>63840878-0deb-4095-97e6-fc444d9bc9fa</uuid>
++  <memory unit='KiB'>8192</memory>
++  <currentMemory unit='KiB'>8192</currentMemory>
++  <vcpu placement='static'>1</vcpu>
++  <os firmware='efi'>
++    <type arch='x86_64' machine='pc-q35-4.0'>hvm</type>
++    <firmware type='efi'>
++      <feature enabled='no' name='enrolled-keys'/>
++    </firmware>
++    <boot dev='hd'/>
++  </os>
++  <features>
++    <acpi/>
++    <apic/>
++    <pae/>
++  </features>
++  <cpu mode='custom' match='exact' check='none'>
++    <model fallback='forbid'>qemu64</model>
++  </cpu>
++  <clock offset='utc'/>
++  <on_poweroff>destroy</on_poweroff>
++  <on_reboot>restart</on_reboot>
++  <on_crash>destroy</on_crash>
++  <devices>
++    <emulator>/usr/bin/qemu-system-x86_64</emulator>
++    <controller type='pci' index='0' model='pcie-root'/>
++    <controller type='pci' index='1' model='pcie-root-port'>
++      <model name='pcie-root-port'/>
++      <target chassis='1' port='0x8'/>
++      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/>
++    </controller>
++    <controller type='pci' index='2' model='pcie-root-port'>
++      <model name='pcie-root-port'/>
++      <target chassis='2' port='0x9'/>
++      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
++    </controller>
++    <controller type='usb' index='0' model='qemu-xhci'>
++      <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
++    </controller>
++    <controller type='sata' index='0'>
++      <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/>
++    </controller>
++    <input type='mouse' bus='ps2'/>
++    <input type='keyboard' bus='ps2'/>
++    <memballoon model='none'/>
++  </devices>
++</domain>
+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: <c8ede44db2e94444e5a8ee38e21eda2b42717879@dist-git>
+From: Pavel Hrdina <phrdina@redhat.com>
+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 <lersek@redhat.com>
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+Reviewed-by: Peter Krempa <pkrempa@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+(cherry picked from commit 61d95a1073833ec4323c1ef28e71e913c55aa7b9)
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1961562
+
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+Message-Id: <8989d70d49d8a720532a8c25e3e73d9b3bf2a495.1621342722.git.phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+---
+ 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?= <berrange@redhat.com>
+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 <pkrempa@redhat.com>
+Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
+(cherry picked from commit 15073504dbb624d3f6c911e85557019d3620fdb2)
+Message-Id: <38c6a7b570b8eb2114d9f1ff0c84a8346e01472f.1627476632.git.pkrempa@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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: <b794a0e4e657defe9a491eb20adf61eafa443ca3@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+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 <pkrempa@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(cherry picked from commit 447f69dec47e1b0bd15ecd7cd49a9fd3b050fb87)
+CVE-2021-3667
+Message-Id: <a398ad51fa2db3697d91711134d28d3e07536bfc.1627476632.git.pkrempa@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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: <c94691d796682d951ffa8fb3a4fcb985aae17d9b@dist-git>
+From: Pavel Hrdina <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <abf8f7673bd59c6e3d9b596cf9a86029b1f1e9c1.1613737828.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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 <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Daniel Henrique Barboza <danielhb413@gmail.com>
+(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 <phrdina@redhat.com>
+Message-Id: <bc2f0207bc684ca81c45b6234a7aaba5227867d7.1613737828.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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: <c82c32f60579d148f37064e5156e857fa3c84c2f@dist-git>
+From: Pavel Hrdina <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <79b9ef9f98b3ab35061f8c4e4acf7b6861d28055.1614858616.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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].
+         <span class="since">Since 0.9.0</span>
+       </dd>
+       <dt><code>period</code></dt>
+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 <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <51312c8b520e4ed794f8cd8a77b77c228387bb15.1613737828.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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
+     </pre>
+ 
++    <p>
++      Prior libvirt 7.1.0 the topology doesn't have extra
++      <code>libvirt</code> directory.
++    </p>
++
+     <h3><a id="currentLayoutGeneric">Non-systemd cgroups layout</a></h3>
+ 
+     <p>
+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: <f835b834d7922bed1ccda35885e42ab7c3f4a70f@dist-git>
+From: Pavel Hrdina <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(cherry picked from commit badc2bcc7398d8c0a739998a80411ddebf129512)
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463
+
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+Message-Id: <14297ed923f0f23cc52506e61e637c8f45e331ee.1613737828.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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 <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <5d22d307112333f1da565cb642ea9001a7b8b55b.1613737828.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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: <a88996cc6c72a6f7fd034c0890747c54cc377484@dist-git>
+From: Pavel Hrdina <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(cherry picked from commit 5f56dd7c83493f14a471bb9e33415b04329a08bf)
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463
+
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+Message-Id: <ce477880853d3a9988389789611b68c458834600.1613737828.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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 <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <85d34403caacb571cb78539d5c4f56eee9484d57.1613737828.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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 <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(cherry picked from commit 902c6644a8ec292789d561b3188e576c37a86872)
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463
+
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+Message-Id: <10fb6b61cbb4f9caf8e8ba7706ec01d1da41fc67.1613737828.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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: <c8fb30409d501e5d9299ac7c08c43917b199a72b@dist-git>
+From: Pavel Hrdina <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(cherry picked from commit a51147d9065217d9087449b4e601e3294c0a22cf)
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1798463
+
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+Message-Id: <9a861adc0dc51679d7178e464255c80465247333.1613737828.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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: <a3a5c16f04d044502eecedbef6043bce79043df9@dist-git>
+From: Pavel Hrdina <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <7de7eae45f139e79c45731263924ae078f3e33c5.1613737828.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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 <phrdina@redhat.com>
+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 <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(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 <phrdina@redhat.com>
+Message-Id: <28be8d962cde455d215fe9ee09fbdcc4145e931f.1613737828.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ 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 <jdenemar@redhat.com> - 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 <jdenemar@redhat.com> - 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 <jdenemar@redhat.com> - 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 <jdenemar@redhat.com> - 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)