diff --git a/SOURCES/libvirt-RHEL-qemu-Enable-virt-ssbd-for-host-model-with-old-QEMU.patch b/SOURCES/libvirt-RHEL-qemu-Enable-virt-ssbd-for-host-model-with-old-QEMU.patch
new file mode 100644
index 0000000..a0bc853
--- /dev/null
+++ b/SOURCES/libvirt-RHEL-qemu-Enable-virt-ssbd-for-host-model-with-old-QEMU.patch
@@ -0,0 +1,71 @@
+From 6244ce5a6ff5121fff9aaffe1689912955af6372 Mon Sep 17 00:00:00 2001
+Message-Id: <6244ce5a6ff5121fff9aaffe1689912955af6372@dist-git>
+From: Jiri Denemark <jdenemar@redhat.com>
+Date: Fri, 29 Nov 2019 19:14:36 +0100
+Subject: [PATCH] RHEL: qemu: Enable virt-ssbd for host-model with old QEMU
+
+RHEL-only hack for qemu-kvm-1.5.3-*
+
+RHEL version of QEMU in contrast to qemu-kvm-rhev does not support
+reporting what CPU features can be enabled on current host and thus we
+have no idea whether virt-ssbd can be enabled or not. We will just
+blindly enable it when starting a domain with host-model CPU on old
+QEMU, detect whether it was actually enabled once QEMU starts and update
+the live XML accordingly.
+
+We just need to make sure qemu-kvm is new enough (at least 1.5.3-158) to
+support virt-ssbd otherwise QEMU would fail to start complaining about
+unknown feature. Luckily, such qemu-kvm was already present in RHEL-7.6.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1745181
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+Message-Id: <ed6ce8fd56f059d856fed2774a3186882af3cf06.1575051264.git.jdenemar@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+---
+ libvirt.spec.in         |  1 +
+ src/qemu/qemu_process.c | 14 ++++++++++++++
+ 2 files changed, 15 insertions(+)
+
+diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
+index 4a2864af27..0add197af5 100644
+--- a/src/qemu/qemu_process.c
++++ b/src/qemu/qemu_process.c
+@@ -5780,6 +5780,7 @@ qemuProcessUpdateGuestCPU(virDomainDefPtr def,
+                           unsigned int flags)
+ {
+     int ret = -1;
++    bool host_model = false;
+ 
+     if (!def->cpu)
+         return 0;
+@@ -5826,6 +5827,8 @@ qemuProcessUpdateGuestCPU(virDomainDefPtr def,
+                       def->cpu, true) < 0)
+         return -1;
+ 
++    host_model = def->cpu->mode == VIR_CPU_MODE_HOST_MODEL;
++
+     if (virCPUUpdate(def->os.arch, def->cpu,
+                      virQEMUCapsGetHostModel(qemuCaps, def->virtType,
+                                              VIR_QEMU_CAPS_HOST_CPU_MIGRATABLE)) < 0)
+@@ -5835,6 +5838,17 @@ qemuProcessUpdateGuestCPU(virDomainDefPtr def,
+                         virQEMUCapsGetCPUDefinitions(qemuCaps, def->virtType)) < 0)
+         goto cleanup;
+ 
++    if (host_model &&
++        ARCH_IS_X86(def->os.arch) &&
++        caps->host.cpu &&
++        STREQ_NULLABLE(caps->host.cpu->vendor, "AMD")) {
++        virCPUDefPtr hostCPU;
++        hostCPU = virQEMUCapsGetHostModel(qemuCaps, def->virtType,
++                                         VIR_QEMU_CAPS_HOST_CPU_REPORTED);
++        if (hostCPU->fallback == VIR_CPU_FALLBACK_ALLOW)
++            virCPUDefUpdateFeature(def->cpu, "virt-ssbd", VIR_CPU_FEATURE_REQUIRE);
++    }
++
+     def->cpu->fallback = VIR_CPU_FALLBACK_FORBID;
+     ret = 0;
+ 
+-- 
+2.24.0
+
diff --git a/SOURCES/libvirt-RHEL-qemuCheckUnprivSGIO-use-sysfs_path-to-get-unpriv_sgio.patch b/SOURCES/libvirt-RHEL-qemuCheckUnprivSGIO-use-sysfs_path-to-get-unpriv_sgio.patch
new file mode 100644
index 0000000..052b2b5
--- /dev/null
+++ b/SOURCES/libvirt-RHEL-qemuCheckUnprivSGIO-use-sysfs_path-to-get-unpriv_sgio.patch
@@ -0,0 +1,40 @@
+From 0f85e65a6d4ce41d05464129fddb3d28171519b2 Mon Sep 17 00:00:00 2001
+Message-Id: <0f85e65a6d4ce41d05464129fddb3d28171519b2@dist-git>
+From: =?UTF-8?q?J=C3=A1n=20Tomko?= <jtomko@redhat.com>
+Date: Tue, 11 Feb 2020 03:15:00 +0100
+Subject: [PATCH] RHEL: qemuCheckUnprivSGIO: use @sysfs_path to get unpriv_sgio
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Downstream commit 65f4ff0e2c9a968b7ec65c8d751d4055cc212628
+  RHEL: qemuSetUnprivSGIO: Actually use calculated
+    @sysfs_path to set unpriv_sgio
+removed the device_path -> sysfs_path conversion from
+both virGetDeviceUnprivSGIO and virSetDeviceUnprivSGIO,
+but only adjusted one of the callers.
+
+Signed-off-by: Ján Tomko <jtomko@redhat.com>
+https://bugzilla.redhat.com/show_bug.cgi?id=1801139
+Message-Id: <f4d7764bb8eecd133b2afa3727b8299622e9359b.1581387247.git.jtomko@redhat.com>
+Reviewed-by: Andrea Bolognani <abologna@redhat.com>
+---
+ src/qemu/qemu_conf.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
+index 5788354444..a86e340013 100644
+--- a/src/qemu/qemu_conf.c
++++ b/src/qemu/qemu_conf.c
+@@ -1255,7 +1255,7 @@ qemuCheckUnprivSGIO(virHashTablePtr sharedDevices,
+         goto cleanup;
+     }
+ 
+-    if (virGetDeviceUnprivSGIO(device_path, &val) < 0)
++    if (virGetDeviceUnprivSGIO(sysfs_path, &val) < 0)
+         goto cleanup;
+ 
+     /* Error message on failure needs to be handled in caller
+-- 
+2.25.0
+
diff --git a/SOURCES/libvirt-RHEL-qemuSetUnprivSGIO-Actually-use-calculated-sysfs_path-to-set-unpriv_sgio.patch b/SOURCES/libvirt-RHEL-qemuSetUnprivSGIO-Actually-use-calculated-sysfs_path-to-set-unpriv_sgio.patch
new file mode 100644
index 0000000..3c9dd48
--- /dev/null
+++ b/SOURCES/libvirt-RHEL-qemuSetUnprivSGIO-Actually-use-calculated-sysfs_path-to-set-unpriv_sgio.patch
@@ -0,0 +1,169 @@
+From 65f4ff0e2c9a968b7ec65c8d751d4055cc212628 Mon Sep 17 00:00:00 2001
+Message-Id: <65f4ff0e2c9a968b7ec65c8d751d4055cc212628@dist-git>
+From: Michal Privoznik <mprivozn@redhat.com>
+Date: Thu, 10 Oct 2019 14:20:58 +0200
+Subject: [PATCH] RHEL: qemuSetUnprivSGIO: Actually use calculated @sysfs_path
+ to set unpriv_sgio
+
+In previous commits I've attempted to make qemuSetUnprivSGIO()
+construct a generic enough path for SCSI devices to set
+unpriv_sgio. However, virSetDeviceUnprivSGIO() does not care
+about that - it constructs the path on it's own again. This is
+suboptimal in either case - we already have the path constructed.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1754241
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Message-Id: <1f6fa49bd2fec4e3b144cb8c1a27a9d0456c9431.1570709916.git.mprivozn@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/qemu/qemu_conf.c |  8 +++-----
+ src/util/virutil.c   | 24 ++++++------------------
+ src/util/virutil.h   |  2 --
+ 3 files changed, 9 insertions(+), 25 deletions(-)
+
+diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
+index 5636277888..5788354444 100644
+--- a/src/qemu/qemu_conf.c
++++ b/src/qemu/qemu_conf.c
+@@ -1255,7 +1255,7 @@ qemuCheckUnprivSGIO(virHashTablePtr sharedDevices,
+         goto cleanup;
+     }
+ 
+-    if (virGetDeviceUnprivSGIO(device_path, NULL, &val) < 0)
++    if (virGetDeviceUnprivSGIO(device_path, &val) < 0)
+         goto cleanup;
+ 
+     /* Error message on failure needs to be handled in caller
+@@ -1648,7 +1648,6 @@ qemuSetUnprivSGIO(virDomainDeviceDefPtr dev)
+     virDomainDiskDefPtr disk = NULL;
+     virDomainHostdevDefPtr hostdev = NULL;
+     char *sysfs_path = NULL;
+-    const char *path = NULL;
+     int val = 0;
+     int ret = -1;
+ 
+@@ -1657,13 +1656,12 @@ qemuSetUnprivSGIO(virDomainDeviceDefPtr dev)
+      */
+     if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
+         disk = dev->data.disk;
++        const char *path = virDomainDiskGetSource(disk);
+ 
+         if (disk->device != VIR_DOMAIN_DISK_DEVICE_LUN ||
+             !virStorageSourceIsBlockLocal(disk->src))
+             return 0;
+ 
+-        path = virDomainDiskGetSource(disk);
+-
+         if (!(sysfs_path = virGetUnprivSGIOSysfsPath(path, NULL)))
+             goto cleanup;
+ 
+@@ -1703,7 +1701,7 @@ qemuSetUnprivSGIO(virDomainDeviceDefPtr dev)
+      * virSetDeviceUnprivSGIO, to report an error for unsupported unpriv_sgio.
+      */
+     if ((virFileExists(sysfs_path) || val == 1) &&
+-        virSetDeviceUnprivSGIO(path, NULL, val) < 0)
++        virSetDeviceUnprivSGIO(sysfs_path, val) < 0)
+         goto cleanup;
+ 
+     ret = 0;
+diff --git a/src/util/virutil.c b/src/util/virutil.c
+index fb2a95041a..fd70df120b 100644
+--- a/src/util/virutil.c
++++ b/src/util/virutil.c
+@@ -1715,18 +1715,13 @@ virGetUnprivSGIOSysfsPath(const char *path,
+ 
+ int
+ virSetDeviceUnprivSGIO(const char *path,
+-                       const char *sysfs_dir,
+                        int unpriv_sgio)
+ {
+-    char *sysfs_path = NULL;
+     char *val = NULL;
+     int ret = -1;
+     int rc;
+ 
+-    if (!(sysfs_path = virGetUnprivSGIOSysfsPath(path, sysfs_dir)))
+-        return -1;
+-
+-    if (!virFileExists(sysfs_path)) {
++    if (!virFileExists(path)) {
+         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                        _("unpriv_sgio is not supported by this kernel"));
+         goto cleanup;
+@@ -1735,38 +1730,32 @@ virSetDeviceUnprivSGIO(const char *path,
+     if (virAsprintf(&val, "%d", unpriv_sgio) < 0)
+         goto cleanup;
+ 
+-    if ((rc = virFileWriteStr(sysfs_path, val, 0)) < 0) {
+-        virReportSystemError(-rc, _("failed to set %s"), sysfs_path);
++    if ((rc = virFileWriteStr(path, val, 0)) < 0) {
++        virReportSystemError(-rc, _("failed to set %s"), path);
+         goto cleanup;
+     }
+ 
+     ret = 0;
+  cleanup:
+-    VIR_FREE(sysfs_path);
+     VIR_FREE(val);
+     return ret;
+ }
+ 
+ int
+ virGetDeviceUnprivSGIO(const char *path,
+-                       const char *sysfs_dir,
+                        int *unpriv_sgio)
+ {
+-    char *sysfs_path = NULL;
+     char *buf = NULL;
+     char *tmp = NULL;
+     int ret = -1;
+ 
+-    if (!(sysfs_path = virGetUnprivSGIOSysfsPath(path, sysfs_dir)))
+-        return -1;
+-
+-    if (!virFileExists(sysfs_path)) {
++    if (!virFileExists(path)) {
+         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                        _("unpriv_sgio is not supported by this kernel"));
+         goto cleanup;
+     }
+ 
+-    if (virFileReadAll(sysfs_path, 1024, &buf) < 0)
++    if (virFileReadAll(path, 1024, &buf) < 0)
+         goto cleanup;
+ 
+     if ((tmp = strchr(buf, '\n')))
+@@ -1774,13 +1763,12 @@ virGetDeviceUnprivSGIO(const char *path,
+ 
+     if (virStrToLong_i(buf, NULL, 10, unpriv_sgio) < 0) {
+         virReportError(VIR_ERR_INTERNAL_ERROR,
+-                       _("failed to parse value of %s"), sysfs_path);
++                       _("failed to parse value of %s"), path);
+         goto cleanup;
+     }
+ 
+     ret = 0;
+  cleanup:
+-    VIR_FREE(sysfs_path);
+     VIR_FREE(buf);
+     return ret;
+ }
+diff --git a/src/util/virutil.h b/src/util/virutil.h
+index abbbb7101e..b0ee8329e2 100644
+--- a/src/util/virutil.h
++++ b/src/util/virutil.h
+@@ -160,10 +160,8 @@ int virGetDeviceID(const char *path,
+                    int *maj,
+                    int *min);
+ int virSetDeviceUnprivSGIO(const char *path,
+-                           const char *sysfs_dir,
+                            int unpriv_sgio);
+ int virGetDeviceUnprivSGIO(const char *path,
+-                           const char *sysfs_dir,
+                            int *unpriv_sgio);
+ char *virGetUnprivSGIOSysfsPath(const char *path,
+                                 const char *sysfs_dir);
+-- 
+2.23.0
+
diff --git a/SOURCES/libvirt-RHEL-virscsi-Check-device-type-before-getting-it-s-dev-node-name.patch b/SOURCES/libvirt-RHEL-virscsi-Check-device-type-before-getting-it-s-dev-node-name.patch
new file mode 100644
index 0000000..7263d4f
--- /dev/null
+++ b/SOURCES/libvirt-RHEL-virscsi-Check-device-type-before-getting-it-s-dev-node-name.patch
@@ -0,0 +1,231 @@
+From 2cb3950bd3540f1f5f6ffaf93116556a92f2ab8c Mon Sep 17 00:00:00 2001
+Message-Id: <2cb3950bd3540f1f5f6ffaf93116556a92f2ab8c@dist-git>
+From: Michal Privoznik <mprivozn@redhat.com>
+Date: Tue, 8 Oct 2019 14:14:19 +0200
+Subject: [PATCH] RHEL: virscsi: Check device type before getting it's /dev
+ node name
+
+Not all SCSI devices are block devices, therefore
+/sys/bus/scsi/devices/X:X:X:X/block/ directory does not always
+exist. Check if the SCSI device is a block device beforehand.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1754241
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Message-Id: <b10a213ba1f4a091474d2e78d38878aa11a1e451.1570536610.git.mprivozn@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/util/virscsi.c             | 149 ++++++++++++++++++++++++++++++---
+ tests/virscsidata/0-0-0-0/type |   1 +
+ tests/virscsidata/1-0-0-0/type |   1 +
+ 3 files changed, 138 insertions(+), 13 deletions(-)
+ create mode 100644 tests/virscsidata/0-0-0-0/type
+ create mode 100644 tests/virscsidata/1-0-0-0/type
+
+diff --git a/src/util/virscsi.c b/src/util/virscsi.c
+index b51103a86d..af908107d9 100644
+--- a/src/util/virscsi.c
++++ b/src/util/virscsi.c
+@@ -56,6 +56,32 @@ struct _virUsedByInfo {
+ };
+ typedef struct _virUsedByInfo *virUsedByInfoPtr;
+ 
++
++/* Keep in sync with scsi/scsi_proto.h */
++typedef enum {
++    VIR_SCSI_DEVICE_TYPE_NONE = -1,
++    VIR_SCSI_DEVICE_TYPE_DISK = 0x00,
++    VIR_SCSI_DEVICE_TYPE_TAPE = 0x01,
++    VIR_SCSI_DEVICE_TYPE_PRINTER = 0x02,
++    VIR_SCSI_DEVICE_TYPE_PROCESSOR = 0x03,
++    VIR_SCSI_DEVICE_TYPE_WORM = 0x04,
++    VIR_SCSI_DEVICE_TYPE_ROM = 0x05,
++    VIR_SCSI_DEVICE_TYPE_SCANNER = 0x06,
++    VIR_SCSI_DEVICE_TYPE_MOD = 0x07,
++    VIR_SCSI_DEVICE_TYPE_MEDIUM_CHANGER = 0x08,
++    VIR_SCSI_DEVICE_TYPE_COMM = 0x09,
++    VIR_SCSI_DEVICE_TYPE_RAID = 0x0c,
++    VIR_SCSI_DEVICE_TYPE_ENCLOSURE = 0x0d,
++    VIR_SCSI_DEVICE_TYPE_RBC = 0x0e,
++    VIR_SCSI_DEVICE_TYPE_OSD = 0x11,
++    VIR_SCSI_DEVICE_TYPE_ZBC = 0x14,
++    VIR_SCSI_DEVICE_TYPE_WLUN = 0x1e,
++    VIR_SCSI_DEVICE_TYPE_NO_LUN = 0x7f,
++
++    VIR_SCSI_DEVICE_TYPE_LAST,
++} virSCSIDeviceType;
++
++
+ struct _virSCSIDevice {
+     unsigned int adapter;
+     unsigned int bus;
+@@ -143,6 +169,86 @@ virSCSIDeviceGetSgName(const char *sysfs_prefix,
+     return sg;
+ }
+ 
++
++static int
++virSCSIDeviceGetType(const char *prefix,
++                     unsigned int adapter,
++                     unsigned int bus,
++                     unsigned int target,
++                     unsigned long long unit,
++                     virSCSIDeviceType *type)
++{
++    int intType;
++
++    if (virFileReadValueInt(&intType,
++                            "%s/%d:%u:%u:%llu/type",
++                            prefix, adapter, bus, target, unit) < 0)
++        return -1;
++
++    switch (intType) {
++    case VIR_SCSI_DEVICE_TYPE_DISK:
++    case VIR_SCSI_DEVICE_TYPE_TAPE:
++    case VIR_SCSI_DEVICE_TYPE_PRINTER:
++    case VIR_SCSI_DEVICE_TYPE_PROCESSOR:
++    case VIR_SCSI_DEVICE_TYPE_WORM:
++    case VIR_SCSI_DEVICE_TYPE_ROM:
++    case VIR_SCSI_DEVICE_TYPE_SCANNER:
++    case VIR_SCSI_DEVICE_TYPE_MOD:
++    case VIR_SCSI_DEVICE_TYPE_MEDIUM_CHANGER:
++    case VIR_SCSI_DEVICE_TYPE_COMM:
++    case VIR_SCSI_DEVICE_TYPE_RAID:
++    case VIR_SCSI_DEVICE_TYPE_ENCLOSURE:
++    case VIR_SCSI_DEVICE_TYPE_RBC:
++    case VIR_SCSI_DEVICE_TYPE_OSD:
++    case VIR_SCSI_DEVICE_TYPE_ZBC:
++    case VIR_SCSI_DEVICE_TYPE_WLUN:
++    case VIR_SCSI_DEVICE_TYPE_NO_LUN:
++        *type = intType;
++        break;
++
++    default:
++        virReportError(VIR_ERR_INTERNAL_ERROR,
++                       _("unknown SCSI device type: %x"),
++                       intType);
++        return -1;
++    }
++
++    return 0;
++}
++
++
++static char *
++virSCSIDeviceGetDevNameBlock(const char *prefix,
++                             unsigned int adapter,
++                             unsigned int bus,
++                             unsigned int target,
++                             unsigned long long unit)
++{
++    DIR *dir = NULL;
++    struct dirent *entry;
++    char *path = NULL;
++    char *name = NULL;
++
++    if (virAsprintf(&path,
++                    "%s/%d:%u:%u:%llu/block",
++                    prefix, adapter, bus, target, unit) < 0)
++        return NULL;
++
++    if (virDirOpen(&dir, path) < 0)
++        goto cleanup;
++
++    while (virDirRead(dir, &entry, path) > 0) {
++        ignore_value(VIR_STRDUP(name, entry->d_name));
++        break;
++    }
++
++ cleanup:
++    VIR_DIR_CLOSE(dir);
++    VIR_FREE(path);
++    return name;
++}
++
++
+ /* Returns device name (e.g. "sdc") on success, or NULL
+  * on failure.
+  */
+@@ -153,35 +259,52 @@ virSCSIDeviceGetDevName(const char *sysfs_prefix,
+                         unsigned int target,
+                         unsigned long long unit)
+ {
+-    DIR *dir = NULL;
+-    struct dirent *entry;
+-    char *path = NULL;
+     char *name = NULL;
+     unsigned int adapter_id;
++    virSCSIDeviceType type;
+     const char *prefix = sysfs_prefix ? sysfs_prefix : SYSFS_SCSI_DEVICES;
+ 
+     if (virSCSIDeviceGetAdapterId(adapter, &adapter_id) < 0)
+         return NULL;
+ 
+-    if (virAsprintf(&path,
+-                    "%s/%d:%u:%u:%llu/block",
+-                    prefix, adapter_id, bus, target, unit) < 0)
++    if (virSCSIDeviceGetType(prefix, adapter_id,
++                             bus, target, unit, &type) < 0)
+         return NULL;
+ 
+-    if (virDirOpen(&dir, path) < 0)
+-        goto cleanup;
++    switch (type) {
++    case VIR_SCSI_DEVICE_TYPE_DISK:
++        name = virSCSIDeviceGetDevNameBlock(prefix, adapter_id, bus, target, unit);
++        break;
+ 
+-    while (virDirRead(dir, &entry, path) > 0) {
+-        ignore_value(VIR_STRDUP(name, entry->d_name));
++    case VIR_SCSI_DEVICE_TYPE_TAPE:
++    case VIR_SCSI_DEVICE_TYPE_PRINTER:
++    case VIR_SCSI_DEVICE_TYPE_PROCESSOR:
++    case VIR_SCSI_DEVICE_TYPE_WORM:
++    case VIR_SCSI_DEVICE_TYPE_ROM:
++    case VIR_SCSI_DEVICE_TYPE_SCANNER:
++    case VIR_SCSI_DEVICE_TYPE_MOD:
++    case VIR_SCSI_DEVICE_TYPE_MEDIUM_CHANGER:
++    case VIR_SCSI_DEVICE_TYPE_COMM:
++    case VIR_SCSI_DEVICE_TYPE_RAID:
++    case VIR_SCSI_DEVICE_TYPE_ENCLOSURE:
++    case VIR_SCSI_DEVICE_TYPE_RBC:
++    case VIR_SCSI_DEVICE_TYPE_OSD:
++    case VIR_SCSI_DEVICE_TYPE_ZBC:
++    case VIR_SCSI_DEVICE_TYPE_WLUN:
++    case VIR_SCSI_DEVICE_TYPE_NO_LUN:
++    case VIR_SCSI_DEVICE_TYPE_NONE:
++    case VIR_SCSI_DEVICE_TYPE_LAST:
++    default:
++        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
++                       _("unsupported SCSI device type: %x"),
++                       type);
+         break;
+     }
+ 
+- cleanup:
+-    VIR_DIR_CLOSE(dir);
+-    VIR_FREE(path);
+     return name;
+ }
+ 
++
+ virSCSIDevicePtr
+ virSCSIDeviceNew(const char *sysfs_prefix,
+                  const char *adapter,
+diff --git a/tests/virscsidata/0-0-0-0/type b/tests/virscsidata/0-0-0-0/type
+new file mode 100644
+index 0000000000..573541ac97
+--- /dev/null
++++ b/tests/virscsidata/0-0-0-0/type
+@@ -0,0 +1 @@
++0
+diff --git a/tests/virscsidata/1-0-0-0/type b/tests/virscsidata/1-0-0-0/type
+new file mode 100644
+index 0000000000..573541ac97
+--- /dev/null
++++ b/tests/virscsidata/1-0-0-0/type
+@@ -0,0 +1 @@
++0
+-- 
+2.23.0
+
diff --git a/SOURCES/libvirt-RHEL-virscsi-Introduce-and-use-virSCSIDeviceGetUnprivSGIOSysfsPath.patch b/SOURCES/libvirt-RHEL-virscsi-Introduce-and-use-virSCSIDeviceGetUnprivSGIOSysfsPath.patch
new file mode 100644
index 0000000..7f363d1
--- /dev/null
+++ b/SOURCES/libvirt-RHEL-virscsi-Introduce-and-use-virSCSIDeviceGetUnprivSGIOSysfsPath.patch
@@ -0,0 +1,147 @@
+From 1f219561662a850309e4c19418167fc1d33a8cf7 Mon Sep 17 00:00:00 2001
+Message-Id: <1f219561662a850309e4c19418167fc1d33a8cf7@dist-git>
+From: Michal Privoznik <mprivozn@redhat.com>
+Date: Tue, 8 Oct 2019 14:14:21 +0200
+Subject: [PATCH] RHEL: virscsi: Introduce and use
+ virSCSIDeviceGetUnprivSGIOSysfsPath()
+
+When constructing a path to the 'unpriv_sgio' file of given SCSI
+device we don't need to go through /dev/* and major() + minor()
+path. The generated path points to
+/sys/dev/block/MAJ:MIN/queue/unpriv_sgio which is wrong if the
+SCSI device in question is not a block device. We can generate a
+different path: /sys/bus/scsi/devices/X:X:X:X/unpriv_sgio where
+the file is directly accessible regardless of the SCSI device
+type.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1754241
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Message-Id: <36bac569fd66de8dcbec73085016b16a0371dfe6.1570536610.git.mprivozn@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/libvirt_private.syms |  1 +
+ src/qemu/qemu_conf.c     | 19 +++++++++++--------
+ src/util/virscsi.c       | 21 +++++++++++++++++++++
+ src/util/virscsi.h       |  5 +++++
+ 4 files changed, 38 insertions(+), 8 deletions(-)
+
+diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
+index b213e5764b..1bc43293fd 100644
+--- a/src/libvirt_private.syms
++++ b/src/libvirt_private.syms
+@@ -2704,6 +2704,7 @@ virSCSIDeviceGetSgName;
+ virSCSIDeviceGetShareable;
+ virSCSIDeviceGetTarget;
+ virSCSIDeviceGetUnit;
++virSCSIDeviceGetUnprivSGIOSysfsPath;
+ virSCSIDeviceIsAvailable;
+ virSCSIDeviceListAdd;
+ virSCSIDeviceListCount;
+diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
+index a81298326f..5636277888 100644
+--- a/src/qemu/qemu_conf.c
++++ b/src/qemu/qemu_conf.c
+@@ -1648,7 +1648,6 @@ qemuSetUnprivSGIO(virDomainDeviceDefPtr dev)
+     virDomainDiskDefPtr disk = NULL;
+     virDomainHostdevDefPtr hostdev = NULL;
+     char *sysfs_path = NULL;
+-    char *hostdev_path = NULL;
+     const char *path = NULL;
+     int val = 0;
+     int ret = -1;
+@@ -1664,24 +1663,29 @@ qemuSetUnprivSGIO(virDomainDeviceDefPtr dev)
+             return 0;
+ 
+         path = virDomainDiskGetSource(disk);
++
++        if (!(sysfs_path = virGetUnprivSGIOSysfsPath(path, NULL)))
++            goto cleanup;
++
+     } else if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV) {
+         hostdev = dev->data.hostdev;
++        virDomainHostdevSubsysSCSIPtr scsisrc = &hostdev->source.subsys.u.scsi;
++        virDomainHostdevSubsysSCSIHostPtr scsihostsrc = &scsisrc->u.host;
+ 
+         if (hostdev->source.subsys.u.scsi.protocol ==
+             VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI)
+             return 0;
+ 
+-        if (!(hostdev_path = qemuGetHostdevPath(hostdev)))
++        if (!(sysfs_path = virSCSIDeviceGetUnprivSGIOSysfsPath(NULL,
++                                                               scsihostsrc->adapter,
++                                                               scsihostsrc->bus,
++                                                               scsihostsrc->target,
++                                                               scsihostsrc->unit)))
+             goto cleanup;
+-
+-        path = hostdev_path;
+     } else {
+         return 0;
+     }
+ 
+-    if (!(sysfs_path = virGetUnprivSGIOSysfsPath(path, NULL)))
+-        goto cleanup;
+-
+     /* By default, filter the SG_IO commands, i.e. set unpriv_sgio to 0.  */
+     if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
+         if (disk->sgio == VIR_DOMAIN_DEVICE_SGIO_UNFILTERED)
+@@ -1705,7 +1709,6 @@ qemuSetUnprivSGIO(virDomainDeviceDefPtr dev)
+     ret = 0;
+ 
+  cleanup:
+-    VIR_FREE(hostdev_path);
+     VIR_FREE(sysfs_path);
+     return ret;
+ }
+diff --git a/src/util/virscsi.c b/src/util/virscsi.c
+index 6c3fd8a562..5aab43fc88 100644
+--- a/src/util/virscsi.c
++++ b/src/util/virscsi.c
+@@ -342,6 +342,27 @@ virSCSIDeviceGetDevName(const char *sysfs_prefix,
+ }
+ 
+ 
++char *
++virSCSIDeviceGetUnprivSGIOSysfsPath(const char *sysfs_prefix,
++                                    const char *adapter,
++                                    unsigned int bus,
++                                    unsigned int target,
++                                    unsigned long long unit)
++{
++    char *path = NULL;
++    unsigned int adapter_id;
++    const char *prefix = sysfs_prefix ? sysfs_prefix : SYSFS_SCSI_DEVICES;
++
++    if (virSCSIDeviceGetAdapterId(adapter, &adapter_id) < 0)
++        return NULL;
++
++    ignore_value(virAsprintf(&path,
++                             "%s/%d:%u:%u:%llu/unpriv_sgio",
++                             prefix, adapter_id, bus, target, unit));
++    return path;
++}
++
++
+ virSCSIDevicePtr
+ virSCSIDeviceNew(const char *sysfs_prefix,
+                  const char *adapter,
+diff --git a/src/util/virscsi.h b/src/util/virscsi.h
+index 9f8b3ecf1e..5dea2a9f5d 100644
+--- a/src/util/virscsi.h
++++ b/src/util/virscsi.h
+@@ -43,6 +43,11 @@ char *virSCSIDeviceGetDevName(const char *sysfs_prefix,
+                               unsigned int bus,
+                               unsigned int target,
+                               unsigned long long unit);
++char *virSCSIDeviceGetUnprivSGIOSysfsPath(const char *sysfs_prefix,
++                                          const char *adapter,
++                                          unsigned int bus,
++                                          unsigned int target,
++                                          unsigned long long unit);
+ 
+ virSCSIDevicePtr virSCSIDeviceNew(const char *sysfs_prefix,
+                                   const char *adapter,
+-- 
+2.23.0
+
diff --git a/SOURCES/libvirt-RHEL-virscsi-Support-TAPEs-in-virSCSIDeviceGetDevName.patch b/SOURCES/libvirt-RHEL-virscsi-Support-TAPEs-in-virSCSIDeviceGetDevName.patch
new file mode 100644
index 0000000..fe9aba5
--- /dev/null
+++ b/SOURCES/libvirt-RHEL-virscsi-Support-TAPEs-in-virSCSIDeviceGetDevName.patch
@@ -0,0 +1,218 @@
+From 227bf0ec28c4ace3b90d383393a9e93c3c0c727c Mon Sep 17 00:00:00 2001
+Message-Id: <227bf0ec28c4ace3b90d383393a9e93c3c0c727c@dist-git>
+From: Michal Privoznik <mprivozn@redhat.com>
+Date: Tue, 8 Oct 2019 14:14:20 +0200
+Subject: [PATCH] RHEL: virscsi: Support TAPEs in virSCSIDeviceGetDevName()
+
+If the SCSI device we want to get /dev node name for is TAPE
+device we need to look at 'tape' symlink in the sysfs dir
+corresponding to the device.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1754241
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Message-Id: <3c722bc2e0627583f26111441f37027c256878c7.1570536610.git.mprivozn@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/util/virscsi.c                          | 37 ++++++++++++++++++++
+ tests/virscsidata/2-0-0-0/model             |  1 +
+ tests/virscsidata/2-0-0-0/scsi_tape/st0/dev |  1 +
+ tests/virscsidata/2-0-0-0/sg3/dev           |  1 +
+ tests/virscsidata/2-0-0-0/tape              |  1 +
+ tests/virscsidata/2-0-0-0/type              |  1 +
+ tests/virscsidata/2-0-0-0/vendor            |  1 +
+ tests/virscsidata/sg3                       |  0
+ tests/virscsitest.c                         | 38 ++++++++++++++++++---
+ 9 files changed, 76 insertions(+), 5 deletions(-)
+ create mode 100644 tests/virscsidata/2-0-0-0/model
+ create mode 100644 tests/virscsidata/2-0-0-0/scsi_tape/st0/dev
+ create mode 100644 tests/virscsidata/2-0-0-0/sg3/dev
+ create mode 120000 tests/virscsidata/2-0-0-0/tape
+ create mode 100644 tests/virscsidata/2-0-0-0/type
+ create mode 100644 tests/virscsidata/2-0-0-0/vendor
+ create mode 100644 tests/virscsidata/sg3
+
+diff --git a/src/util/virscsi.c b/src/util/virscsi.c
+index af908107d9..6c3fd8a562 100644
+--- a/src/util/virscsi.c
++++ b/src/util/virscsi.c
+@@ -42,6 +42,7 @@
+ #include "virutil.h"
+ #include "virstring.h"
+ #include "virerror.h"
++#include "dirname.h"
+ 
+ #define SYSFS_SCSI_DEVICES "/sys/bus/scsi/devices"
+ 
+@@ -249,6 +250,39 @@ virSCSIDeviceGetDevNameBlock(const char *prefix,
+ }
+ 
+ 
++static char *
++virSCSIDeviceGetDevNameTape(const char *prefix,
++                            unsigned int adapter,
++                            unsigned int bus,
++                            unsigned int target,
++                            unsigned long long unit)
++{
++    char *path = NULL;
++    char *resolvedPath = NULL;
++    char *name = NULL;
++
++    if (virAsprintf(&path,
++                    "%s/%d:%u:%u:%llu/tape",
++                    prefix, adapter, bus, target, unit) < 0)
++        return NULL;
++
++    if (virFileReadLink(path, &resolvedPath) < 0) {
++        virReportSystemError(errno,
++                             _("Unable to read link: %s"),
++                             path);
++        goto cleanup;
++    }
++
++    if (VIR_STRDUP(name, last_component(resolvedPath)) < 0)
++        goto cleanup;
++
++ cleanup:
++    VIR_FREE(resolvedPath);
++    VIR_FREE(path);
++    return name;
++}
++
++
+ /* Returns device name (e.g. "sdc") on success, or NULL
+  * on failure.
+  */
+@@ -277,6 +311,9 @@ virSCSIDeviceGetDevName(const char *sysfs_prefix,
+         break;
+ 
+     case VIR_SCSI_DEVICE_TYPE_TAPE:
++        name = virSCSIDeviceGetDevNameTape(prefix, adapter_id, bus, target, unit);
++        break;
++
+     case VIR_SCSI_DEVICE_TYPE_PRINTER:
+     case VIR_SCSI_DEVICE_TYPE_PROCESSOR:
+     case VIR_SCSI_DEVICE_TYPE_WORM:
+diff --git a/tests/virscsidata/2-0-0-0/model b/tests/virscsidata/2-0-0-0/model
+new file mode 100644
+index 0000000000..d2ab4715c3
+--- /dev/null
++++ b/tests/virscsidata/2-0-0-0/model
+@@ -0,0 +1 @@
++scsi_debug
+diff --git a/tests/virscsidata/2-0-0-0/scsi_tape/st0/dev b/tests/virscsidata/2-0-0-0/scsi_tape/st0/dev
+new file mode 100644
+index 0000000000..3dd777e840
+--- /dev/null
++++ b/tests/virscsidata/2-0-0-0/scsi_tape/st0/dev
+@@ -0,0 +1 @@
++9:0
+diff --git a/tests/virscsidata/2-0-0-0/sg3/dev b/tests/virscsidata/2-0-0-0/sg3/dev
+new file mode 100644
+index 0000000000..b369a59b3e
+--- /dev/null
++++ b/tests/virscsidata/2-0-0-0/sg3/dev
+@@ -0,0 +1 @@
++21:3
+diff --git a/tests/virscsidata/2-0-0-0/tape b/tests/virscsidata/2-0-0-0/tape
+new file mode 120000
+index 0000000000..6ca7f77539
+--- /dev/null
++++ b/tests/virscsidata/2-0-0-0/tape
+@@ -0,0 +1 @@
++scsi_tape/st0
+\ No newline at end of file
+diff --git a/tests/virscsidata/2-0-0-0/type b/tests/virscsidata/2-0-0-0/type
+new file mode 100644
+index 0000000000..d00491fd7e
+--- /dev/null
++++ b/tests/virscsidata/2-0-0-0/type
+@@ -0,0 +1 @@
++1
+diff --git a/tests/virscsidata/2-0-0-0/vendor b/tests/virscsidata/2-0-0-0/vendor
+new file mode 100644
+index 0000000000..9b075671ea
+--- /dev/null
++++ b/tests/virscsidata/2-0-0-0/vendor
+@@ -0,0 +1 @@
++Linux
+diff --git a/tests/virscsidata/sg3 b/tests/virscsidata/sg3
+new file mode 100644
+index 0000000000..e69de29bb2
+diff --git a/tests/virscsitest.c b/tests/virscsitest.c
+index 1215adbfab..880fa22ca8 100644
+--- a/tests/virscsitest.c
++++ b/tests/virscsitest.c
+@@ -36,18 +36,34 @@ VIR_LOG_INIT("tests.scsitest");
+ static const char *abs_top_srcdir;
+ static char *virscsi_prefix;
+ 
++typedef struct {
++    const char *adapter;
++    unsigned int bus;
++    unsigned int target;
++    unsigned int unit;
++    const char *expectedName;
++} testGetDevNameData;
++
+ static int
+-test1(const void *data ATTRIBUTE_UNUSED)
++testGetDevName(const void *opaque)
+ {
++    const testGetDevNameData *data = opaque;
+     char *name = NULL;
+     int ret = -1;
+ 
+     if (!(name = virSCSIDeviceGetDevName(virscsi_prefix,
+-                                         "scsi_host1", 0, 0, 0)))
++                                         data->adapter,
++                                         data->bus,
++                                         data->target,
++                                         data->unit)))
+         return -1;
+ 
+-    if (STRNEQ(name, "sdh"))
++    if (STRNEQ(name, data->expectedName)) {
++        fprintf(stderr,
++                "SCSI dev name mismatch, expected %s got %s",
++                data->expectedName, name);
+         goto cleanup;
++    }
+ 
+     ret = 0;
+  cleanup:
+@@ -225,7 +241,9 @@ mymain(void)
+ 
+     CREATE_SYMLINK("0-0-0-0", "0:0:0:0");
+     CREATE_SYMLINK("1-0-0-0", "1:0:0:0");
++    CREATE_SYMLINK("2-0-0-0", "2:0:0:0");
+     CREATE_SYMLINK("sg0", "sg0");
++    CREATE_SYMLINK("sg3", "sg3");
+     CREATE_SYMLINK("sg8", "sg8");
+ 
+     VIR_FREE(virscsi_prefix);
+@@ -235,8 +253,18 @@ mymain(void)
+         goto cleanup;
+     }
+ 
+-    if (virTestRun("test1", test1, NULL) < 0)
+-        ret = -1;
++#define TEST_GET_DEV_NAME(adapter, bus, target, unit, expectedName) \
++    do { \
++        testGetDevNameData data = {adapter, bus, target, unit, expectedName}; \
++        if (virTestRun("test getDevname " expectedName, \
++                       testGetDevName, &data) < 0) \
++            ret = -1; \
++    } while (0)
++
++    TEST_GET_DEV_NAME("scsi_host0", 0, 0, 0, "sda");
++    TEST_GET_DEV_NAME("scsi_host1", 0, 0, 0, "sdh");
++    TEST_GET_DEV_NAME("scsi_host2", 0, 0, 0, "st0");
++
+     if (virTestRun("test2", test2, NULL) < 0)
+         ret = -1;
+ 
+-- 
+2.23.0
+
diff --git a/SOURCES/libvirt-RHEL-virutil-Accept-non-block-devices-in-virGetDeviceID.patch b/SOURCES/libvirt-RHEL-virutil-Accept-non-block-devices-in-virGetDeviceID.patch
new file mode 100644
index 0000000..8e4de4d
--- /dev/null
+++ b/SOURCES/libvirt-RHEL-virutil-Accept-non-block-devices-in-virGetDeviceID.patch
@@ -0,0 +1,36 @@
+From a87147a0bb1bf52cb0646e5776bce19fdc51d80d Mon Sep 17 00:00:00 2001
+Message-Id: <a87147a0bb1bf52cb0646e5776bce19fdc51d80d@dist-git>
+From: Michal Privoznik <mprivozn@redhat.com>
+Date: Tue, 8 Oct 2019 14:14:22 +0200
+Subject: [PATCH] RHEL: virutil: Accept non-block devices in virGetDeviceID()
+
+If a caller wants to learn major or minor number for a device,
+let them. There's no need to check if the device is a block
+device here.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1754241
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Message-Id: <354b68e431cc5179ab57895536afebc0d68b2a4b.1570536610.git.mprivozn@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/util/virutil.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/src/util/virutil.c b/src/util/virutil.c
+index b25d2a5ca4..fb2a95041a 100644
+--- a/src/util/virutil.c
++++ b/src/util/virutil.c
+@@ -1672,9 +1672,6 @@ virGetDeviceID(const char *path, int *maj, int *min)
+     if (stat(path, &sb) < 0)
+         return -errno;
+ 
+-    if (!S_ISBLK(sb.st_mode))
+-        return -EINVAL;
+-
+     if (maj)
+         *maj = major(sb.st_rdev);
+     if (min)
+-- 
+2.23.0
+
diff --git a/SOURCES/libvirt-conf-utility-function-to-update-entry-in-def-nets-array.patch b/SOURCES/libvirt-conf-utility-function-to-update-entry-in-def-nets-array.patch
new file mode 100644
index 0000000..c524c73
--- /dev/null
+++ b/SOURCES/libvirt-conf-utility-function-to-update-entry-in-def-nets-array.patch
@@ -0,0 +1,150 @@
+From 9bf517748d9fed50a0bee163625f119b25fdb0ea Mon Sep 17 00:00:00 2001
+Message-Id: <9bf517748d9fed50a0bee163625f119b25fdb0ea@dist-git>
+From: Laine Stump <laine@redhat.com>
+Date: Thu, 26 Sep 2019 18:05:26 -0400
+Subject: [PATCH] conf: utility function to update entry in def->nets array
+
+A virDomainNetDef object in a domain's nets array might contain a
+virDomainHostdevDef, and when this is the case, the domain's hostdevs
+array will also have a pointer to this embedded hostdev (this is done
+so that internal functions that need to perform some operation on all
+hostdevs won't leave out the type='hostdev' network interfaces).
+
+When a network device was updated with virDomainUpdateDeviceFlags(),
+we were replacing the entry in the nets array (and free'ing the
+original) but forgetting about the pointer in the hostdevs array
+(which would then point to the now-free'd hostdev contained in the old
+net object.) This often resulted in a libvirtd crash.
+
+The solution is to add a function, virDomainNetUpdate(), called by
+qemuDomainUpdateDeviceConfig(), that updates the hostdevs array
+appropriately along with the nets array.
+
+Resolves: https://bugzilla.redhat.com/1558934
+
+Signed-off-by: Laine Stump <laine@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(cherry picked from commit 7e490cdad6364c82b326d5d9251826c757e8f77b)
+Message-Id: <20190926220526.12970-1-laine@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/conf/domain_conf.c   | 41 ++++++++++++++++++++++++++++++++++++++++
+ src/conf/domain_conf.h   |  1 +
+ src/libvirt_private.syms |  1 +
+ src/lxc/lxc_driver.c     |  6 ++++--
+ src/qemu/qemu_driver.c   |  6 ++++--
+ 5 files changed, 51 insertions(+), 4 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 0352fad245..60f426df04 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -17119,6 +17119,47 @@ virDomainNetRemove(virDomainDefPtr def, size_t i)
+     return net;
+ }
+ 
++
++int
++virDomainNetUpdate(virDomainDefPtr def,
++                   size_t netidx,
++                   virDomainNetDefPtr newnet)
++{
++    size_t hostdevidx;
++    virDomainNetDefPtr oldnet = def->nets[netidx];
++    virDomainHostdevDefPtr oldhostdev = virDomainNetGetActualHostdev(oldnet);
++    virDomainHostdevDefPtr newhostdev = virDomainNetGetActualHostdev(newnet);
++
++    /*
++     * if newnet or oldnet has a valid hostdev*, we need to update the
++     * hostdevs list
++     */
++    if (oldhostdev) {
++        for (hostdevidx = 0; hostdevidx < def->nhostdevs; hostdevidx++) {
++            if (def->hostdevs[hostdevidx] == oldhostdev)
++                break;
++        }
++    }
++
++    if (oldhostdev && hostdevidx < def->nhostdevs) {
++        if (newhostdev) {
++            /* update existing entry in def->hostdevs */
++            def->hostdevs[hostdevidx] = newhostdev;
++        } else {
++            /* delete oldhostdev from def->hostdevs */
++            virDomainHostdevRemove(def, hostdevidx);
++        }
++    } else if (newhostdev) {
++        /* add newhostdev to end of def->hostdevs */
++        if (VIR_APPEND_ELEMENT(def->hostdevs, def->nhostdevs, newhostdev) < 0)
++            return -1;
++    }
++
++    def->nets[netidx] = newnet;
++    return 0;
++}
++
++
+ int virDomainControllerInsert(virDomainDefPtr def,
+                               virDomainControllerDefPtr controller)
+ {
+diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
+index 1c4556cecd..ef8f061ae2 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -3168,6 +3168,7 @@ virDomainNetDefPtr virDomainNetFind(virDomainDefPtr def, const char *device);
+ virDomainNetDefPtr virDomainNetFindByName(virDomainDefPtr def, const char *ifname);
+ bool virDomainHasNet(virDomainDefPtr def, virDomainNetDefPtr net);
+ int virDomainNetInsert(virDomainDefPtr def, virDomainNetDefPtr net);
++int virDomainNetUpdate(virDomainDefPtr def, size_t netidx, virDomainNetDefPtr newnet);
+ virDomainNetDefPtr virDomainNetRemove(virDomainDefPtr def, size_t i);
+ void virDomainNetRemoveHostdev(virDomainDefPtr def, virDomainNetDefPtr net);
+ 
+diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
+index 9b5e1350f0..b213e5764b 100644
+--- a/src/libvirt_private.syms
++++ b/src/libvirt_private.syms
+@@ -476,6 +476,7 @@ virDomainNetSetDeviceImpl;
+ virDomainNetTypeFromString;
+ virDomainNetTypeSharesHostView;
+ virDomainNetTypeToString;
++virDomainNetUpdate;
+ virDomainNostateReasonTypeFromString;
+ virDomainNostateReasonTypeToString;
+ virDomainObjAssignDef;
+diff --git a/src/lxc/lxc_driver.c b/src/lxc/lxc_driver.c
+index 5978183e7f..0f2ef47bb5 100644
+--- a/src/lxc/lxc_driver.c
++++ b/src/lxc/lxc_driver.c
+@@ -3526,8 +3526,10 @@ lxcDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
+                                          false) < 0)
+             return -1;
+ 
+-        virDomainNetDefFree(vmdef->nets[idx]);
+-        vmdef->nets[idx] = net;
++        if (virDomainNetUpdate(vmdef, idx, net) < 0)
++            return -1;
++
++        virDomainNetDefFree(oldDev.data.net);
+         dev->data.net = NULL;
+         ret = 0;
+ 
+diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
+index d95c97928d..2852b96edd 100644
+--- a/src/qemu/qemu_driver.c
++++ b/src/qemu/qemu_driver.c
+@@ -8341,8 +8341,10 @@ qemuDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
+                                          false) < 0)
+             return -1;
+ 
+-        virDomainNetDefFree(vmdef->nets[pos]);
+-        vmdef->nets[pos] = net;
++        if (virDomainNetUpdate(vmdef, pos, net))
++            return -1;
++
++        virDomainNetDefFree(oldDev.data.net);
+         dev->data.net = NULL;
+         break;
+ 
+-- 
+2.23.0
+
diff --git a/SOURCES/libvirt-domain_conf-Make-virDomainDeviceFindSCSIController-accept-virDomainDeviceDriveAddress-struct.patch b/SOURCES/libvirt-domain_conf-Make-virDomainDeviceFindSCSIController-accept-virDomainDeviceDriveAddress-struct.patch
new file mode 100644
index 0000000..d820fba
--- /dev/null
+++ b/SOURCES/libvirt-domain_conf-Make-virDomainDeviceFindSCSIController-accept-virDomainDeviceDriveAddress-struct.patch
@@ -0,0 +1,102 @@
+From 62bd04e98582005d38a17850afbd25465015ae1b Mon Sep 17 00:00:00 2001
+Message-Id: <62bd04e98582005d38a17850afbd25465015ae1b@dist-git>
+From: Michal Privoznik <mprivozn@redhat.com>
+Date: Thu, 24 Oct 2019 08:45:49 +0200
+Subject: [PATCH] domain_conf: Make virDomainDeviceFindSCSIController accept
+ virDomainDeviceDriveAddress struct
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+So far, the virDomainDeviceFindSCSIController() takes
+virDomainDeviceInfo structure which is an overkill. It assumes
+that the passed structure is type of
+VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE which is not obvious.
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+(cherry picked from commit 9cddc6e8ee9d9ce62dd20a6317c3148f4cd1c0e9)
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1741782
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Message-Id: <ee6d546175c25f26c3f95fd5bc4de47be66ae603.1571899509.git.mprivozn@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/conf/domain_conf.c         | 6 +++---
+ src/conf/domain_conf.h         | 2 +-
+ src/qemu/qemu_domain_address.c | 2 +-
+ src/vbox/vbox_common.c         | 2 +-
+ 4 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 60f426df04..333d9836c1 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -8235,13 +8235,13 @@ virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
+ 
+ virDomainControllerDefPtr
+ virDomainDeviceFindSCSIController(const virDomainDef *def,
+-                                  virDomainDeviceInfoPtr info)
++                                  const virDomainDeviceDriveAddress *addr)
+ {
+     size_t i;
+ 
+     for (i = 0; i < def->ncontrollers; i++) {
+         if (def->controllers[i]->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
+-            def->controllers[i]->idx == info->addr.drive.controller)
++            def->controllers[i]->idx == addr->controller)
+             return def->controllers[i];
+     }
+ 
+@@ -18606,7 +18606,7 @@ virDomainDefMaybeAddHostdevSCSIcontroller(virDomainDefPtr def)
+              * So let's grab the model from it and update the model we're
+              * going to add as long as this one isn't undefined. The premise
+              * being keeping the same controller model for all SCSI hostdevs. */
+-            cont = virDomainDeviceFindSCSIController(def, hostdev->info);
++            cont = virDomainDeviceFindSCSIController(def, &hostdev->info->addr.drive);
+             if (cont && cont->model != -1)
+                 newModel = cont->model;
+         }
+diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
+index ef8f061ae2..5eb9b257a7 100644
+--- a/src/conf/domain_conf.h
++++ b/src/conf/domain_conf.h
+@@ -2866,7 +2866,7 @@ int virDomainDiskGetFormat(virDomainDiskDefPtr def);
+ void virDomainDiskSetFormat(virDomainDiskDefPtr def, int format);
+ virDomainControllerDefPtr
+ virDomainDeviceFindSCSIController(const virDomainDef *def,
+-                                  virDomainDeviceInfoPtr info);
++                                  const virDomainDeviceDriveAddress *addr);
+ virDomainDiskDefPtr virDomainDiskFindByBusAndDst(virDomainDefPtr def,
+                                                  int bus,
+                                                  char *dst);
+diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
+index 0cb5af4a87..4f0278d348 100644
+--- a/src/qemu/qemu_domain_address.c
++++ b/src/qemu/qemu_domain_address.c
+@@ -113,7 +113,7 @@ qemuDomainFindSCSIControllerModel(const virDomainDef *def,
+ {
+     virDomainControllerDefPtr cont;
+ 
+-    if (!(cont = virDomainDeviceFindSCSIController(def, info))) {
++    if (!(cont = virDomainDeviceFindSCSIController(def, &info->addr.drive))) {
+         virReportError(VIR_ERR_INTERNAL_ERROR,
+                        _("unable to find a SCSI controller for idx=%d"),
+                        info->addr.drive.controller);
+diff --git a/src/vbox/vbox_common.c b/src/vbox/vbox_common.c
+index eed7c83913..fe3c3ab2aa 100644
+--- a/src/vbox/vbox_common.c
++++ b/src/vbox/vbox_common.c
+@@ -1118,7 +1118,7 @@ vboxAttachDrives(virDomainDefPtr def, vboxDriverPtr data, IMachine *machine)
+         case VIR_DOMAIN_DISK_BUS_SCSI:
+             VBOX_UTF8_TO_UTF16(VBOX_CONTROLLER_SCSI_NAME, &storageCtlName);
+ 
+-            cont = virDomainDeviceFindSCSIController(def, &disk->info);
++            cont = virDomainDeviceFindSCSIController(def, &disk->info.addr.drive);
+             if (cont && cont->model == VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068) {
+                 VBOX_UTF16_FREE(storageCtlName);
+                 VBOX_UTF8_TO_UTF16(VBOX_CONTROLLER_SAS_NAME, &storageCtlName);
+-- 
+2.23.0
+
diff --git a/SOURCES/libvirt-domain_conf-Relax-SCSI-addr-used-check.patch b/SOURCES/libvirt-domain_conf-Relax-SCSI-addr-used-check.patch
new file mode 100644
index 0000000..e79f4eb
--- /dev/null
+++ b/SOURCES/libvirt-domain_conf-Relax-SCSI-addr-used-check.patch
@@ -0,0 +1,102 @@
+From dfc8270c27d1eaad36b85d6eab8f912b5bd7e334 Mon Sep 17 00:00:00 2001
+Message-Id: <dfc8270c27d1eaad36b85d6eab8f912b5bd7e334@dist-git>
+From: Michal Privoznik <mprivozn@redhat.com>
+Date: Thu, 24 Oct 2019 08:45:50 +0200
+Subject: [PATCH] domain_conf: Relax SCSI addr used check
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+In domain_conf.c we have virDomainSCSIDriveAddressIsUsed()
+function which returns true or false if given drive address is
+already in use for given domain config or not. However, it also
+takes a shortcut and returns true (meaning address in use) if the
+unit number equals 7. This is because for some controllers this
+is reserved address. The limitation comes mostly from vmware and
+applies to lsilogic, buslogic, spapr-vscsi and vmpvscsi models.
+On the other hand, we were not checking for the maximum unit
+number (aka LUN number) which is also relevant and differs from
+model to model.
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+(cherry picked from commit c8007fdc5d2ce43fec2753cda60fb4963f55abd5)
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1741782
+
+I had to drop
+VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_TRANSITIONAL and
+VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_NON_TRANSITIONAL from
+virDomainSCSIDriveAddressIsUsed() because those don't exist in
+RHEL-7.8 branch.
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Message-Id: <9e70aa28937fa3ea1bbeb792f848b2be2a6ae2e7.1571899509.git.mprivozn@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/conf/domain_conf.c | 49 +++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 44 insertions(+), 5 deletions(-)
+
+diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
+index 333d9836c1..8bd527cfa1 100644
+--- a/src/conf/domain_conf.c
++++ b/src/conf/domain_conf.c
+@@ -4407,11 +4407,50 @@ bool
+ virDomainSCSIDriveAddressIsUsed(const virDomainDef *def,
+                                 const virDomainDeviceDriveAddress *addr)
+ {
+-    /* In current implementation, the maximum unit number of a controller
+-     * is either 16 or 7 (narrow SCSI bus), and if the maximum unit number
+-     * is 16, the controller itself is on unit 7 */
+-    if (addr->unit == 7)
+-        return true;
++    const virDomainControllerDef *cont;
++
++    cont = virDomainDeviceFindSCSIController(def, addr);
++    if (cont) {
++        int max = -1;
++        int reserved = -1;
++
++        /* Different controllers have different limits. These limits here are
++         * taken from QEMU source code, but nevertheless they should apply to
++         * other hypervisors too. */
++        switch ((virDomainControllerModelSCSI) cont->model) {
++        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VIRTIO_SCSI:
++            max = 16383;
++            break;
++        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_IBMVSCSI:
++            max = 31;
++            reserved = 7;
++            break;
++        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1068:
++            max = 1;
++            break;
++        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSISAS1078:
++            max = 255;
++            break;
++        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LSILOGIC:
++            reserved = 7;
++            break;
++        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_VMPVSCSI:
++            reserved = 7;
++            break;
++        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_BUSLOGIC:
++            reserved = 7;
++            break;
++        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_DEFAULT:
++        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_AUTO:
++        case VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST:
++            break;
++        }
++
++        if (max != -1 && addr->unit >= max)
++            return true;
++        if (reserved != -1 && addr->unit == reserved)
++            return true;
++    }
+ 
+     if (virDomainDriveAddressIsUsedByDisk(def, VIR_DOMAIN_DISK_BUS_SCSI,
+                                           addr) ||
+-- 
+2.23.0
+
diff --git a/SOURCES/libvirt-node_device_conf-Don-t-leak-physical_function-in-virNodeDeviceGetPCISRIOVCaps.patch b/SOURCES/libvirt-node_device_conf-Don-t-leak-physical_function-in-virNodeDeviceGetPCISRIOVCaps.patch
new file mode 100644
index 0000000..3555b27
--- /dev/null
+++ b/SOURCES/libvirt-node_device_conf-Don-t-leak-physical_function-in-virNodeDeviceGetPCISRIOVCaps.patch
@@ -0,0 +1,44 @@
+From f05fe59ebbdfc07d738b393c18f951925dd3814d Mon Sep 17 00:00:00 2001
+Message-Id: <f05fe59ebbdfc07d738b393c18f951925dd3814d@dist-git>
+From: Jiang Kun <jiang.kun2@zte.com.cn>
+Date: Mon, 20 Jan 2020 08:51:25 +0100
+Subject: [PATCH] node_device_conf: Don't leak @physical_function in
+ virNodeDeviceGetPCISRIOVCaps
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The pci_dev->physical_function is rewritten in
+virPCIGetPhysicalFunction() to a newly allocated pointer.
+Therefore, we must free the old one to avoid memleak.
+
+Signed-off-by: Jiang kun <jiang.kun2@zte.com.cn>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(cherry picked from commit 38816336a5026623d0a49988c6681b1323c79f09)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1792831
+https://bugzilla.redhat.com/show_bug.cgi?id=1793575
+https://bugzilla.redhat.com/show_bug.cgi?id=1793576
+
+Signed-off-by: Ján Tomko <jtomko@redhat.com>
+Message-Id: <e0b84a11167f2d4f8e3fa1401959d907921c6df5.1579506302.git.jtomko@redhat.com>
+Reviewed-by: Andrea Bolognani <abologna@redhat.com>
+---
+ src/conf/node_device_conf.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/conf/node_device_conf.c b/src/conf/node_device_conf.c
+index fd8f4e4a94..7f5afee41e 100644
+--- a/src/conf/node_device_conf.c
++++ b/src/conf/node_device_conf.c
+@@ -2689,6 +2689,7 @@ virNodeDeviceGetPCISRIOVCaps(const char *sysfsPath,
+     for (i = 0; i < pci_dev->num_virtual_functions; i++)
+        VIR_FREE(pci_dev->virtual_functions[i]);
+     VIR_FREE(pci_dev->virtual_functions);
++    VIR_FREE(pci_dev->physical_function);
+     pci_dev->num_virtual_functions = 0;
+     pci_dev->max_virtual_functions = 0;
+     pci_dev->flags &= ~VIR_NODE_DEV_CAP_FLAG_PCI_VIRTUAL_FUNCTION;
+-- 
+2.25.0
+
diff --git a/SOURCES/libvirt-nwfilter-Remove-redundant-check-if-object-exists.patch b/SOURCES/libvirt-nwfilter-Remove-redundant-check-if-object-exists.patch
new file mode 100644
index 0000000..1faf408
--- /dev/null
+++ b/SOURCES/libvirt-nwfilter-Remove-redundant-check-if-object-exists.patch
@@ -0,0 +1,48 @@
+From fb8458440bb6c36a04400f83595da821dd445039 Mon Sep 17 00:00:00 2001
+Message-Id: <fb8458440bb6c36a04400f83595da821dd445039@dist-git>
+From: Pavel Hrdina <phrdina@redhat.com>
+Date: Fri, 29 Nov 2019 08:54:55 +0100
+Subject: [PATCH] nwfilter: Remove redundant check if object exists
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The same check is done by virNWFilterBindingObjListAdd().  The main
+issue with the current code is that if the object already exists we
+would leak 'def' because 'obj' would be set and the cleanup code frees
+'def' only if 'obj' is NULL.
+
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+(cherry picked from commit 3379193f1c73a7be6bd797a3cf790e6960195d3a)
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1766475
+
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+Message-Id: <22531b7498d6fc2609c654d6efab9e5b2eac3819.1575014076.git.phrdina@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ src/nwfilter/nwfilter_driver.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+diff --git a/src/nwfilter/nwfilter_driver.c b/src/nwfilter/nwfilter_driver.c
+index ed34586105..ac3a964388 100644
+--- a/src/nwfilter/nwfilter_driver.c
++++ b/src/nwfilter/nwfilter_driver.c
+@@ -752,13 +752,6 @@ nwfilterBindingCreateXML(virConnectPtr conn,
+     if (virNWFilterBindingCreateXMLEnsureACL(conn, def) < 0)
+         goto cleanup;
+ 
+-    obj = virNWFilterBindingObjListFindByPortDev(driver->bindings, def->portdevname);
+-    if (obj) {
+-        virReportError(VIR_ERR_INTERNAL_ERROR,
+-                       _("Filter already present for NIC %s"), def->portdevname);
+-        goto cleanup;
+-    }
+-
+     obj = virNWFilterBindingObjListAdd(driver->bindings,
+                                        def);
+     if (!obj)
+-- 
+2.24.0
+
diff --git a/SOURCES/libvirt-process-wait-longer-5-30s-on-hard-shutdown.patch b/SOURCES/libvirt-process-wait-longer-5-30s-on-hard-shutdown.patch
new file mode 100644
index 0000000..1fe1ddd
--- /dev/null
+++ b/SOURCES/libvirt-process-wait-longer-5-30s-on-hard-shutdown.patch
@@ -0,0 +1,56 @@
+From 744c445c2b259649afd0f8c715e30d7ae51b35b0 Mon Sep 17 00:00:00 2001
+Message-Id: <744c445c2b259649afd0f8c715e30d7ae51b35b0@dist-git>
+From: Christian Ehrhardt <christian.ehrhardt@canonical.com>
+Date: Wed, 4 Dec 2019 16:18:14 +0100
+Subject: [PATCH] process: wait longer 5->30s on hard shutdown
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+In cases where virProcessKillPainfully already reailizes that
+SIGTERM wasn't enough we are partially on a bad path already.
+Maybe the system is overloaded or having serious trouble to free and
+reap resources in time.
+
+In those case give the SIGKILL that was sent after 10 seconds some more
+time to take effect if force was set (only then we are falling back to
+SIGKILL anyway).
+
+Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+(cherry picked from commit 9a4e4b942df0474503e7524ea427351a46c0eabe)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1771204
+
+Signed-off-by: Ján Tomko <jtomko@redhat.com>
+Message-Id: <963a2cb9ac181322394bc475b200b8fc65e1245a.1575472548.git.jtomko@redhat.com>
+Reviewed-by: Andrea Bolognani <abologna@redhat.com>
+---
+ src/util/virprocess.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/util/virprocess.c b/src/util/virprocess.c
+index 297c96a8e5..1085e6cd5d 100644
+--- a/src/util/virprocess.c
++++ b/src/util/virprocess.c
+@@ -354,7 +354,7 @@ virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay)
+     size_t i;
+     int ret = -1;
+     /* This is in 1/5th seconds since polling is on a 0.2s interval */
+-    unsigned int polldelay = 75 + (extradelay*5);
++    unsigned int polldelay = (force ? 200 : 75) + (extradelay*5);
+     const char *signame = "TERM";
+ 
+     VIR_DEBUG("vpid=%lld force=%d extradelay=%u",
+@@ -363,7 +363,7 @@ virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay)
+     /* This loop sends SIGTERM, then waits a few iterations (10 seconds)
+      * to see if it dies. If the process still hasn't exited, and
+      * @force is requested, a SIGKILL will be sent, and this will
+-     * wait up to 5 seconds more for the process to exit before
++     * wait up to 30 seconds more for the process to exit before
+      * returning.
+      *
+      * An extra delay can be passed by the caller for cases that are
+-- 
+2.24.0
+
diff --git a/SOURCES/libvirt-process-wait-longer-on-kill-per-assigned-Hostdev.patch b/SOURCES/libvirt-process-wait-longer-on-kill-per-assigned-Hostdev.patch
new file mode 100644
index 0000000..a5515f7
--- /dev/null
+++ b/SOURCES/libvirt-process-wait-longer-on-kill-per-assigned-Hostdev.patch
@@ -0,0 +1,138 @@
+From 3e06f98a83d5f23c345a71e48115659a83f673b5 Mon Sep 17 00:00:00 2001
+Message-Id: <3e06f98a83d5f23c345a71e48115659a83f673b5@dist-git>
+From: Christian Ehrhardt <christian.ehrhardt@canonical.com>
+Date: Wed, 4 Dec 2019 16:18:13 +0100
+Subject: [PATCH] process: wait longer on kill per assigned Hostdev
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It was found that in cases with host devices virProcessKillPainfully
+might be able to send signal zero to the target PID for quite a while
+with the process already being gone from /proc/<PID>.
+
+That is due to cleanup and reset of devices which might include a
+secondary bus reset that on top of the actions taken has a 1s delay
+to let the bus settle. Due to that guests with plenty of Host devices
+could easily exceed the default timeouts.
+
+To solve that, this adds an extra delay of 2s per hostdev that is associated
+to a VM.
+
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+Signed-off-by: Christian Ehrhardt <christian.ehrhardt@canonical.com>
+(cherry picked from commit be2ca0444728edd12a000653d3693d68a5c9102f)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1771204
+
+Signed-off-by: Ján Tomko <jtomko@redhat.com>
+Message-Id: <6d18f7131fe022cb2ee4613ad4c58faefa9d574c.1575472548.git.jtomko@redhat.com>
+Reviewed-by: Andrea Bolognani <abologna@redhat.com>
+---
+ src/libvirt_private.syms |  1 +
+ src/qemu/qemu_process.c  |  7 +++++--
+ src/util/virprocess.c    | 20 +++++++++++++++++---
+ src/util/virprocess.h    |  3 +++
+ 4 files changed, 26 insertions(+), 5 deletions(-)
+
+diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
+index 53dbce7cfe..2a3950fd35 100644
+--- a/src/libvirt_private.syms
++++ b/src/libvirt_private.syms
+@@ -2623,6 +2623,7 @@ virProcessGetPids;
+ virProcessGetStartTime;
+ virProcessKill;
+ virProcessKillPainfully;
++virProcessKillPainfullyDelay;
+ virProcessNamespaceAvailable;
+ virProcessRunInMountNamespace;
+ virProcessSchedPolicyTypeFromString;
+diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
+index 0add197af5..d813c59c0d 100644
+--- a/src/qemu/qemu_process.c
++++ b/src/qemu/qemu_process.c
+@@ -6937,8 +6937,11 @@ qemuProcessKill(virDomainObjPtr vm, unsigned int flags)
+         return 0;
+     }
+ 
+-    ret = virProcessKillPainfully(vm->pid,
+-                                  !!(flags & VIR_QEMU_PROCESS_KILL_FORCE));
++    /* Request an extra delay of two seconds per current nhostdevs
++     * to be safe against stalls by the kernel freeing up the resources */
++    ret = virProcessKillPainfullyDelay(vm->pid,
++                                       !!(flags & VIR_QEMU_PROCESS_KILL_FORCE),
++                                       vm->def->nhostdevs * 2);
+ 
+     return ret;
+ }
+diff --git a/src/util/virprocess.c b/src/util/virprocess.c
+index f92b0dce37..297c96a8e5 100644
+--- a/src/util/virprocess.c
++++ b/src/util/virprocess.c
+@@ -344,15 +344,21 @@ int virProcessKill(pid_t pid, int sig)
+  * Returns 0 if it was killed gracefully, 1 if it
+  * was killed forcibly, -1 if it is still alive,
+  * or another error occurred.
++ *
++ * Callers can proide an extra delay in seconds to
++ * wait longer than the default.
+  */
+ int
+-virProcessKillPainfully(pid_t pid, bool force)
++virProcessKillPainfullyDelay(pid_t pid, bool force, unsigned int extradelay)
+ {
+     size_t i;
+     int ret = -1;
++    /* This is in 1/5th seconds since polling is on a 0.2s interval */
++    unsigned int polldelay = 75 + (extradelay*5);
+     const char *signame = "TERM";
+ 
+-    VIR_DEBUG("vpid=%lld force=%d", (long long)pid, force);
++    VIR_DEBUG("vpid=%lld force=%d extradelay=%u",
++              (long long)pid, force, extradelay);
+ 
+     /* This loop sends SIGTERM, then waits a few iterations (10 seconds)
+      * to see if it dies. If the process still hasn't exited, and
+@@ -360,9 +366,12 @@ virProcessKillPainfully(pid_t pid, bool force)
+      * wait up to 5 seconds more for the process to exit before
+      * returning.
+      *
++     * An extra delay can be passed by the caller for cases that are
++     * expected to clean up slower than usual.
++     *
+      * Note that setting @force could result in dataloss for the process.
+      */
+-    for (i = 0; i < 75; i++) {
++    for (i = 0; i < polldelay; i++) {
+         int signum;
+         if (i == 0) {
+             signum = SIGTERM; /* kindly suggest it should exit */
+@@ -405,6 +414,11 @@ virProcessKillPainfully(pid_t pid, bool force)
+ }
+ 
+ 
++int virProcessKillPainfully(pid_t pid, bool force)
++{
++    return virProcessKillPainfullyDelay(pid, force, 0);
++}
++
+ #if HAVE_SCHED_GETAFFINITY
+ 
+ int virProcessSetAffinity(pid_t pid, virBitmapPtr map)
+diff --git a/src/util/virprocess.h b/src/util/virprocess.h
+index 3c5a882772..5faa0892fe 100644
+--- a/src/util/virprocess.h
++++ b/src/util/virprocess.h
+@@ -55,6 +55,9 @@ virProcessWait(pid_t pid, int *exitstatus, bool raw)
+ int virProcessKill(pid_t pid, int sig);
+ 
+ int virProcessKillPainfully(pid_t pid, bool force);
++int virProcessKillPainfullyDelay(pid_t pid,
++                                 bool force,
++                                 unsigned int extradelay);
+ 
+ int virProcessSetAffinity(pid_t pid, virBitmapPtr map);
+ 
+-- 
+2.24.0
+
diff --git a/SOURCES/libvirt-qemu-Don-t-emit-SUSPENDED_POSTCOPY-event-on-destination.patch b/SOURCES/libvirt-qemu-Don-t-emit-SUSPENDED_POSTCOPY-event-on-destination.patch
new file mode 100644
index 0000000..26f7c77
--- /dev/null
+++ b/SOURCES/libvirt-qemu-Don-t-emit-SUSPENDED_POSTCOPY-event-on-destination.patch
@@ -0,0 +1,53 @@
+From 1099f7c0e8741dd232d0f4568d2925cd791c6b69 Mon Sep 17 00:00:00 2001
+Message-Id: <1099f7c0e8741dd232d0f4568d2925cd791c6b69@dist-git>
+From: Jiri Denemark <jdenemar@redhat.com>
+Date: Thu, 16 Jan 2020 19:57:53 +0100
+Subject: [PATCH] qemu: Don't emit SUSPENDED_POSTCOPY event on destination
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When pause-before-switchover QEMU capability is enabled, we get STOP
+event before MIGRATION event with postcopy-active state. To properly
+handle post-copy migration and emit correct events commit
+v4.10.0-rc1-4-geca9d21e6c added a hack to
+qemuProcessHandleMigrationStatus which translates the paused state
+reason to VIR_DOMAIN_PAUSED_POSTCOPY and emits
+VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY event when migration state changes
+to post-copy.
+
+However, the code was effective on both sides of migration resulting in
+a confusing VIR_DOMAIN_EVENT_SUSPENDED_POSTCOPY event on the destination
+host, where entering post-copy mode is already properly advertised by
+VIR_DOMAIN_EVENT_RESUMED_POSTCOPY event.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1791458
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+(cherry picked from commit bd04d63ad97c21b6955710e6473a502f49816a3c)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1791886
+
+Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
+Message-Id: <9b32d5af0dd1d3bf7108abc426dc4d6ceeaa84f8.1579193220.git.jdenemar@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+---
+ src/qemu/qemu_process.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
+index d813c59c0d..7a7fc8f205 100644
+--- a/src/qemu/qemu_process.c
++++ b/src/qemu/qemu_process.c
+@@ -1546,6 +1546,7 @@ qemuProcessHandleMigrationStatus(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+     virDomainObjBroadcast(vm);
+ 
+     if (status == QEMU_MONITOR_MIGRATION_STATUS_POSTCOPY &&
++        priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT &&
+         virDomainObjGetState(vm, &reason) == VIR_DOMAIN_PAUSED &&
+         reason == VIR_DOMAIN_PAUSED_MIGRATION) {
+         VIR_DEBUG("Correcting paused state reason for domain %s to %s",
+-- 
+2.25.0
+
diff --git a/SOURCES/libvirt-qemu-Forcibly-mknod-even-if-it-exists.patch b/SOURCES/libvirt-qemu-Forcibly-mknod-even-if-it-exists.patch
new file mode 100644
index 0000000..d02ac6d
--- /dev/null
+++ b/SOURCES/libvirt-qemu-Forcibly-mknod-even-if-it-exists.patch
@@ -0,0 +1,95 @@
+From 29a17260cc1875640e62f63bfe7fa9661dc9fe70 Mon Sep 17 00:00:00 2001
+Message-Id: <29a17260cc1875640e62f63bfe7fa9661dc9fe70@dist-git>
+From: Michal Privoznik <mprivozn@redhat.com>
+Date: Wed, 20 Nov 2019 14:34:11 +0100
+Subject: [PATCH] qemu: Forcibly mknod() even if it exists
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Another weird bug appeared concerning qemu namespaces. Basically
+the problem is as follows:
+
+1) Issue an API that causes libvirt to create a node in domain's
+   namespace, say /dev/nvme0n1 with 8:0 as major:minor (the API can
+   be attach-disk for instance). Or simply create the node from a
+   console by hand.
+
+2) Detach the disk from qemu.
+
+3) Do something that makes /dev/nvme0n1 change it's minor number.
+
+4) Try to attach the disk again.
+
+The problem is, in a few cases - like disk-detach - we don't
+remove the corresponding /dev node from the mount namespace
+(because it may be used by some other disk's backing chain). But
+this creates a problem, because if the node changes its MAJ:MIN
+numbers we don't propagate the change into the domain's
+namespace. We do plain mknod() and ignore EEXIST which obviously
+is not enough because it doesn't guarantee that the node has
+updated MAJ:MIN pair.
+
+Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1752978
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
+(cherry picked from commit cdd8a6690ee3fa4b4b8ca1d4531924bd33be136a)
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Message-Id: <058a9025fdcb817d3334e6c5a7c6a4fe1e95e761.1574256841.git.mprivozn@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/qemu/qemu_domain.c | 25 +++++++++----------------
+ 1 file changed, 9 insertions(+), 16 deletions(-)
+
+diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
+index e7d7a3baeb..3c67769771 100644
+--- a/src/qemu/qemu_domain.c
++++ b/src/qemu/qemu_domain.c
+@@ -11191,16 +11191,14 @@ qemuDomainCreateDeviceRecursive(const char *device,
+                                             allow_noent, ttl - 1) < 0)
+             goto cleanup;
+     } else if (isDev) {
+-        if (create &&
+-            mknod(devicePath, sb.st_mode, sb.st_rdev) < 0) {
+-            if (errno == EEXIST) {
+-                ret = 0;
+-            } else {
++        if (create) {
++            unlink(devicePath);
++            if (mknod(devicePath, sb.st_mode, sb.st_rdev) < 0) {
+                 virReportSystemError(errno,
+                                      _("Failed to make device %s"),
+                                      devicePath);
++                goto cleanup;
+             }
+-            goto cleanup;
+         }
+     } else if (isReg) {
+         if (create &&
+@@ -11969,17 +11967,12 @@ qemuDomainAttachDeviceMknodHelper(pid_t pid ATTRIBUTE_UNUSED,
+     } else if (isDev) {
+         VIR_DEBUG("Creating dev %s (%d,%d)",
+                   data->file, major(data->sb.st_rdev), minor(data->sb.st_rdev));
++        unlink(data->file);
+         if (mknod(data->file, data->sb.st_mode, data->sb.st_rdev) < 0) {
+-            /* Because we are not removing devices on hotunplug, or
+-             * we might be creating part of backing chain that
+-             * already exist due to a different disk plugged to
+-             * domain, accept EEXIST. */
+-            if (errno != EEXIST) {
+-                virReportSystemError(errno,
+-                                     _("Unable to create device %s"),
+-                                     data->file);
+-                goto cleanup;
+-            }
++            virReportSystemError(errno,
++                                 _("Unable to create device %s"),
++                                 data->file);
++            goto cleanup;
+         } else {
+             delDevice = true;
+         }
+-- 
+2.24.0
+
diff --git a/SOURCES/libvirt-qemu_process-fix-starting-VMs-if-machine-group-has-limited-cpuset.cpus.patch b/SOURCES/libvirt-qemu_process-fix-starting-VMs-if-machine-group-has-limited-cpuset.cpus.patch
new file mode 100644
index 0000000..2656a60
--- /dev/null
+++ b/SOURCES/libvirt-qemu_process-fix-starting-VMs-if-machine-group-has-limited-cpuset.cpus.patch
@@ -0,0 +1,72 @@
+From ba8699bf038f3fe588cc0e40bf484260c08e6f48 Mon Sep 17 00:00:00 2001
+Message-Id: <ba8699bf038f3fe588cc0e40bf484260c08e6f48@dist-git>
+From: Pavel Hrdina <phrdina@redhat.com>
+Date: Mon, 25 Nov 2019 11:02:21 +0100
+Subject: [PATCH] qemu_process: fix starting VMs if machine group has limited
+ cpuset.cpus
+
+Commit <f136b83139c63f20de0df3285d9e82df2fb97bfc> reworked process
+affinity setting but did not take cgroups into account which introduced
+an issue when starting VM with custom cpuset.cpus for the whole machine
+group.
+
+If the machine group is limited to some pCPUs libvirt should not try to
+set a VM to run on all pCPUs as it will result in permission denied when
+writing to cpuset.cpus.
+
+To fix this the affinity has to be set separately from cgroups cpuset.
+
+Resolves: <https://bugzilla.redhat.com/show_bug.cgi?id=1746517>
+
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(cherry picked from commit 4c0398b5284d14c55eca51095673b6fadbbd85fb)
+
+Conflicts:
+    src/qemu/qemu_process.c - upstream commit that introduced this
+            issue was modified to not use VIR_AUTOFREE
+
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+Message-Id: <86eec31e53a4d061e098919d145e6a89cc8740c4.1574676123.git.phrdina@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/qemu/qemu_process.c | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
+index 307098cd63..4a2864af27 100644
+--- a/src/qemu/qemu_process.c
++++ b/src/qemu/qemu_process.c
+@@ -2476,6 +2476,7 @@ qemuProcessSetupPid(virDomainObjPtr vm,
+     virDomainNumatuneMemMode mem_mode;
+     virCgroupPtr cgroup = NULL;
+     virBitmapPtr use_cpumask = NULL;
++    virBitmapPtr afinity_cpumask = NULL;
+     virBitmapPtr hostcpumap = NULL;
+     char *mem_mask = NULL;
+     int ret = -1;
+@@ -2501,7 +2502,7 @@ qemuProcessSetupPid(virDomainObjPtr vm,
+          * its config file */
+         if (qemuProcessGetAllCpuAffinity(&hostcpumap) < 0)
+             goto cleanup;
+-        use_cpumask = hostcpumap;
++        afinity_cpumask = hostcpumap;
+     }
+ 
+     /*
+@@ -2542,8 +2543,11 @@ qemuProcessSetupPid(virDomainObjPtr vm,
+ 
+     }
+ 
++    if (!afinity_cpumask)
++        afinity_cpumask = use_cpumask;
++
+     /* Setup legacy affinity. */
+-    if (use_cpumask && virProcessSetAffinity(pid, use_cpumask) < 0)
++    if (afinity_cpumask && virProcessSetAffinity(pid, afinity_cpumask) < 0)
+         goto cleanup;
+ 
+     /* Set scheduler type and priority. */
+-- 
+2.24.0
+
diff --git a/SOURCES/libvirt-test-Introduce-virnetdevopenvswitchtest.patch b/SOURCES/libvirt-test-Introduce-virnetdevopenvswitchtest.patch
new file mode 100644
index 0000000..7523ed0
--- /dev/null
+++ b/SOURCES/libvirt-test-Introduce-virnetdevopenvswitchtest.patch
@@ -0,0 +1,361 @@
+From b08e42e2ea6ba1366d9cb9b58fcca22c68b4281a Mon Sep 17 00:00:00 2001
+Message-Id: <b08e42e2ea6ba1366d9cb9b58fcca22c68b4281a@dist-git>
+From: Michal Privoznik <mprivozn@redhat.com>
+Date: Wed, 9 Oct 2019 14:27:42 +0200
+Subject: [PATCH] test: Introduce virnetdevopenvswitchtest
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Test if our parsing of interface stats as returned by ovs-vsctl
+works as expected. To achieve this without having to mock
+virCommand* I'm separating parsing of stats into a separate
+function.
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+(cherry picked from commit cc34260f5a8715d208ee45a6ebaa79e5264cbe68)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1759904
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Message-Id: <a1ed18fa73eadd5b2a87c0829555771b38a003a7.1570623892.git.mprivozn@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/libvirt_private.syms                   |   1 +
+ src/util/virnetdevopenvswitch.c            |  98 ++++++++++++--------
+ src/util/virnetdevopenvswitch.h            |   4 +
+ tests/Makefile.am                          |  13 ++-
+ tests/virnetdevopenvswitchdata/stats1.json |   1 +
+ tests/virnetdevopenvswitchdata/stats2.json |   1 +
+ tests/virnetdevopenvswitchtest.c           | 101 +++++++++++++++++++++
+ 7 files changed, 181 insertions(+), 38 deletions(-)
+ create mode 100644 tests/virnetdevopenvswitchdata/stats1.json
+ create mode 100644 tests/virnetdevopenvswitchdata/stats2.json
+ create mode 100644 tests/virnetdevopenvswitchtest.c
+
+diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
+index 1bc43293fd..53dbce7cfe 100644
+--- a/src/libvirt_private.syms
++++ b/src/libvirt_private.syms
+@@ -2401,6 +2401,7 @@ virNetDevMidonetUnbindPort;
+ virNetDevOpenvswitchAddPort;
+ virNetDevOpenvswitchGetMigrateData;
+ virNetDevOpenvswitchGetVhostuserIfname;
++virNetDevOpenvswitchInterfaceParseStats;
+ virNetDevOpenvswitchInterfaceStats;
+ virNetDevOpenvswitchRemovePort;
+ virNetDevOpenvswitchSetMigrateData;
+diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c
+index fc92ab2e7f..80da5ad3db 100644
+--- a/src/util/virnetdevopenvswitch.c
++++ b/src/util/virnetdevopenvswitch.c
+@@ -326,50 +326,31 @@ int virNetDevOpenvswitchSetMigrateData(char *migrate, const char *ifname)
+     return ret;
+ }
+ 
++
+ /**
+- * virNetDevOpenvswitchInterfaceStats:
+- * @ifname: the name of the interface
+- * @stats: the retreived domain interface stat
++ * virNetDevOpenvswitchInterfaceParseStats:
++ * @json: Input string in JSON format
++ * @stats: parsed stats
+  *
+- * Retrieves the OVS interfaces stats
++ * For given input string @json parse interface statistics and store them into
++ * @stats.
+  *
+- * Returns 0 in case of success or -1 in case of failure
++ * Returns: 0 on success,
++ *         -1 otherwise (with error reported).
+  */
+ int
+-virNetDevOpenvswitchInterfaceStats(const char *ifname,
+-                                   virDomainInterfaceStatsPtr stats)
++virNetDevOpenvswitchInterfaceParseStats(const char *json,
++                                        virDomainInterfaceStatsPtr stats)
+ {
+-    virCommandPtr cmd = NULL;
+-    VIR_AUTOFREE(char *) output = NULL;
+     virJSONValuePtr jsonStats = NULL;
+     virJSONValuePtr jsonMap = NULL;
+     size_t i;
+     int ret = -1;
+ 
+-    cmd = virCommandNew(OVSVSCTL);
+-    virNetDevOpenvswitchAddTimeout(cmd);
+-    virCommandAddArgList(cmd, "--if-exists", "--format=list", "--data=json",
+-                         "--no-headings", "--columns=statistics", "list",
+-                         "Interface", ifname, NULL);
+-    virCommandSetOutputBuffer(cmd, &output);
+-
+-    /* The above command returns either:
+-     * 1) empty string if @ifname doesn't exist, or
+-     * 2) a JSON array, for instance:
+-     *    ["map",[["collisions",0],["rx_bytes",0],["rx_crc_err",0],["rx_dropped",0],
+-     *    ["rx_errors",0],["rx_frame_err",0],["rx_over_err",0],["rx_packets",0],
+-     *    ["tx_bytes",12406],["tx_dropped",0],["tx_errors",0],["tx_packets",173]]]
+-     */
+-
+-    if (virCommandRun(cmd, NULL) < 0 ||
+-        STREQ_NULLABLE(output, "")) {
+-        /* no ovs-vsctl or interface 'ifname' doesn't exists in ovs */
+-        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+-                       _("Interface not found"));
+-        goto cleanup;
+-    }
++    stats->rx_bytes = stats->rx_packets = stats->rx_errs = stats->rx_drop = -1;
++    stats->tx_bytes = stats->tx_packets = stats->tx_errs = stats->tx_drop = -1;
+ 
+-    if (!(jsonStats = virJSONValueFromString(output)) ||
++    if (!(jsonStats = virJSONValueFromString(json)) ||
+         !virJSONValueIsArray(jsonStats) ||
+         !(jsonMap = virJSONValueArrayGet(jsonStats, 1))) {
+         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+@@ -377,9 +358,6 @@ virNetDevOpenvswitchInterfaceStats(const char *ifname,
+         goto cleanup;
+     }
+ 
+-    stats->rx_bytes = stats->rx_packets = stats->rx_errs = stats->rx_drop = -1;
+-    stats->tx_bytes = stats->tx_packets = stats->tx_errs = stats->tx_drop = -1;
+-
+     for (i = 0; i < virJSONValueArraySize(jsonMap); i++) {
+         virJSONValuePtr item = virJSONValueArrayGet(jsonMap, i);
+         virJSONValuePtr jsonKey;
+@@ -420,6 +398,55 @@ virNetDevOpenvswitchInterfaceStats(const char *ifname,
+         }
+     }
+ 
++    ret = 0;
++ cleanup:
++    virJSONValueFree(jsonStats);
++    return ret;
++}
++
++/**
++ * virNetDevOpenvswitchInterfaceStats:
++ * @ifname: the name of the interface
++ * @stats: the retrieved domain interface stat
++ *
++ * Retrieves the OVS interfaces stats
++ *
++ * Returns 0 in case of success or -1 in case of failure
++ */
++int
++virNetDevOpenvswitchInterfaceStats(const char *ifname,
++                                   virDomainInterfaceStatsPtr stats)
++{
++    virCommandPtr cmd = NULL;
++    VIR_AUTOFREE(char *) output = NULL;
++    int ret = -1;
++
++    cmd = virCommandNew(OVSVSCTL);
++    virNetDevOpenvswitchAddTimeout(cmd);
++    virCommandAddArgList(cmd, "--if-exists", "--format=list", "--data=json",
++                         "--no-headings", "--columns=statistics", "list",
++                         "Interface", ifname, NULL);
++    virCommandSetOutputBuffer(cmd, &output);
++
++    /* The above command returns either:
++     * 1) empty string if @ifname doesn't exist, or
++     * 2) a JSON array, for instance:
++     *    ["map",[["collisions",0],["rx_bytes",0],["rx_crc_err",0],["rx_dropped",0],
++     *    ["rx_errors",0],["rx_frame_err",0],["rx_over_err",0],["rx_packets",0],
++     *    ["tx_bytes",12406],["tx_dropped",0],["tx_errors",0],["tx_packets",173]]]
++     */
++
++    if (virCommandRun(cmd, NULL) < 0 ||
++        STREQ_NULLABLE(output, "")) {
++        /* no ovs-vsctl or interface 'ifname' doesn't exists in ovs */
++        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
++                       _("Interface not found"));
++        return -1;
++    }
++
++    if (virNetDevOpenvswitchInterfaceParseStats(output, stats) < 0)
++        return -1;
++
+     if (stats->rx_bytes == -1 &&
+         stats->rx_packets == -1 &&
+         stats->rx_errs == -1 &&
+@@ -436,7 +463,6 @@ virNetDevOpenvswitchInterfaceStats(const char *ifname,
+     ret = 0;
+ 
+  cleanup:
+-    virJSONValueFree(jsonStats);
+     virCommandFree(cmd);
+     return ret;
+ }
+diff --git a/src/util/virnetdevopenvswitch.h b/src/util/virnetdevopenvswitch.h
+index 6f6e620c22..c1a211dec1 100644
+--- a/src/util/virnetdevopenvswitch.h
++++ b/src/util/virnetdevopenvswitch.h
+@@ -53,6 +53,10 @@ int virNetDevOpenvswitchGetMigrateData(char **migrate, const char *ifname)
+ int virNetDevOpenvswitchSetMigrateData(char *migrate, const char *ifname)
+     ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+ 
++int virNetDevOpenvswitchInterfaceParseStats(const char *json,
++                                            virDomainInterfaceStatsPtr stats)
++    ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
++
+ int virNetDevOpenvswitchInterfaceStats(const char *ifname,
+                                        virDomainInterfaceStatsPtr stats)
+     ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
+diff --git a/tests/Makefile.am b/tests/Makefile.am
+index f871a8a102..8cff413a78 100644
+--- a/tests/Makefile.am
++++ b/tests/Makefile.am
+@@ -158,6 +158,7 @@ EXTRA_DIST = \
+ 	virmock.h \
+ 	virnetdaemondata \
+ 	virnetdevtestdata \
++	virnetdevopenvswitchdata \
+ 	virnwfilterbindingxml2xmldata \
+ 	virpcitestdata \
+ 	virscsidata \
+@@ -1243,9 +1244,17 @@ virmacmaptest_SOURCES = \
+ 	virmacmaptest.c testutils.h testutils.c
+ virmacmaptest_LDADD = $(LDADDS)
+ 
+-test_programs += virmacmaptest
++virnetdevopenvswitchtest_SOURCES = \
++	virnetdevopenvswitchtest.c testutils.h testutils.c
++virnetdevopenvswitchtest_LDADD = $(LDADDS)
++
++test_programs += \
++	virmacmaptest \
++	virnetdevopenvswitchtest
+ else ! WITH_YAJL
+-EXTRA_DIST +=  virmacmaptest.c
++EXTRA_DIST += \
++	virmacmaptest.c \
++	virnetdevopenvswitchtest.c
+ endif ! WITH_YAJL
+ 
+ virnetdevtest_SOURCES = \
+diff --git a/tests/virnetdevopenvswitchdata/stats1.json b/tests/virnetdevopenvswitchdata/stats1.json
+new file mode 100644
+index 0000000000..1138c6271e
+--- /dev/null
++++ b/tests/virnetdevopenvswitchdata/stats1.json
+@@ -0,0 +1 @@
++["map",[["collisions",1],["rx_bytes",2],["rx_crc_err",3],["rx_dropped",4],["rx_errors",5],["rx_frame_err",6],["rx_over_err",7],["rx_packets",8],["tx_bytes",9],["tx_dropped",10],["tx_errors",11],["tx_packets",12]]]
+diff --git a/tests/virnetdevopenvswitchdata/stats2.json b/tests/virnetdevopenvswitchdata/stats2.json
+new file mode 100644
+index 0000000000..d84be7e011
+--- /dev/null
++++ b/tests/virnetdevopenvswitchdata/stats2.json
+@@ -0,0 +1 @@
++["map",[["collisions",0],["rx_bytes",0],["rx_crc_err",0],["rx_dropped",0],["rx_errors",0],["rx_frame_err",0],["rx_over_err",0],["rx_packets",0],["tx_bytes",12406],["tx_dropped",0],["tx_errors",0],["tx_packets",173]]]
+diff --git a/tests/virnetdevopenvswitchtest.c b/tests/virnetdevopenvswitchtest.c
+new file mode 100644
+index 0000000000..f01e77cbba
+--- /dev/null
++++ b/tests/virnetdevopenvswitchtest.c
+@@ -0,0 +1,101 @@
++/*
++ * Copyright (C) 2019 Red Hat, Inc.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library.  If not, see
++ * <http://www.gnu.org/licenses/>.
++ */
++
++#include <config.h>
++
++#include "testutils.h"
++#include "virnetdevopenvswitch.h"
++
++#define VIR_FROM_THIS VIR_FROM_NONE
++
++typedef struct _InterfaceParseStatsData InterfaceParseStatsData;
++struct _InterfaceParseStatsData {
++    const char *filename;
++    const virDomainInterfaceStatsStruct stats;
++};
++
++
++static int
++testInterfaceParseStats(const void *opaque)
++{
++    const InterfaceParseStatsData *data = opaque;
++    VIR_AUTOFREE(char *) filename = NULL;
++    VIR_AUTOFREE(char *) buf = NULL;
++    virDomainInterfaceStatsStruct actual;
++
++    if (virAsprintf(&filename, "%s/virnetdevopenvswitchdata/%s",
++                    abs_srcdir, data->filename) < 0)
++        return -1;
++
++    if (virFileReadAll(filename, 1024, &buf) < 0)
++        return -1;
++
++    if (virNetDevOpenvswitchInterfaceParseStats(buf, &actual) < 0)
++        return -1;
++
++    if (memcmp(&actual, &data->stats, sizeof(actual)) != 0) {
++        fprintf(stderr,
++                "Expected stats: %lld %lld %lld %lld %lld %lld %lld %lld\n"
++                "Actual stats: %lld %lld %lld %lld %lld %lld %lld %lld",
++                data->stats.rx_bytes,
++                data->stats.rx_packets,
++                data->stats.rx_errs,
++                data->stats.rx_drop,
++                data->stats.tx_bytes,
++                data->stats.tx_packets,
++                data->stats.tx_errs,
++                data->stats.tx_drop,
++                actual.rx_bytes,
++                actual.rx_packets,
++                actual.rx_errs,
++                actual.rx_drop,
++                actual.tx_bytes,
++                actual.tx_packets,
++                actual.tx_errs,
++                actual.tx_drop);
++
++        return -1;
++    }
++
++    return 0;
++}
++
++
++static int
++mymain(void)
++{
++    int ret = 0;
++
++#define TEST_INTERFACE_STATS(file, \
++                             rxBytes, rxPackets, rxErrs, rxDrop, \
++                             txBytes, txPackets, txErrs, txDrop) \
++    do { \
++        const InterfaceParseStatsData data = {.filename = file, .stats = { \
++                             rxBytes, rxPackets, rxErrs, rxDrop, \
++                             txBytes, txPackets, txErrs, txDrop}}; \
++        if (virTestRun("Interface stats " file, testInterfaceParseStats, &data) < 0) \
++            ret = -1; \
++    } while (0)
++
++    TEST_INTERFACE_STATS("stats1.json", 9, 12, 11, 10, 2, 8, 5, 4);
++    TEST_INTERFACE_STATS("stats2.json", 12406, 173, 0, 0, 0, 0, 0, 0);
++
++    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
++}
++
++VIR_TEST_MAIN(mymain);
+-- 
+2.23.0
+
diff --git a/SOURCES/libvirt-util-Avoid-possible-error-in-virCommandMassClose.patch b/SOURCES/libvirt-util-Avoid-possible-error-in-virCommandMassClose.patch
new file mode 100644
index 0000000..f289fe9
--- /dev/null
+++ b/SOURCES/libvirt-util-Avoid-possible-error-in-virCommandMassClose.patch
@@ -0,0 +1,44 @@
+From 78713fc280ae0cb18e389ff9ba1eee97eedb7050 Mon Sep 17 00:00:00 2001
+Message-Id: <78713fc280ae0cb18e389ff9ba1eee97eedb7050@dist-git>
+From: John Ferlan <jferlan@redhat.com>
+Date: Wed, 9 Oct 2019 14:27:46 +0200
+Subject: [PATCH] util: Avoid possible error in virCommandMassClose
+
+Avoid the chance that sysconf(_SC_OPEN_MAX) returns -1 and thus
+would cause virBitmapNew would attempt to allocate a very large
+bitmap.
+
+Found by Coverity
+
+Signed-off-by: John Ferlan <jferlan@redhat.com>
+ACKed-by: Peter Krempa <pkrempa@redhat.com>
+(cherry picked from commit 6ae4f4a4ceb123417b732e869d53099983ae8d3f)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1759904
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Message-Id: <69ca4c7bcf0e3c7588fad50d68dbf75180109b31.1570623892.git.mprivozn@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/util/vircommand.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/src/util/vircommand.c b/src/util/vircommand.c
+index 17405ceea4..083a8bbee5 100644
+--- a/src/util/vircommand.c
++++ b/src/util/vircommand.c
+@@ -561,6 +561,11 @@ virCommandMassClose(virCommandPtr cmd,
+      * Therefore we can safely allocate memory here (and transitively call
+      * opendir/readdir) without a deadlock. */
+ 
++    if (openmax < 0) {
++        virReportSystemError(errno, "%s", _("sysconf(_SC_OPEN_MAX) failed"));
++        return -1;
++    }
++
+     if (!(fds = virBitmapNew(openmax)))
+         return -1;
+ 
+-- 
+2.23.0
+
diff --git a/SOURCES/libvirt-util-command-Ignore-bitmap-errors-when-enumerating-file-descriptors-to-close.patch b/SOURCES/libvirt-util-command-Ignore-bitmap-errors-when-enumerating-file-descriptors-to-close.patch
new file mode 100644
index 0000000..8335623
--- /dev/null
+++ b/SOURCES/libvirt-util-command-Ignore-bitmap-errors-when-enumerating-file-descriptors-to-close.patch
@@ -0,0 +1,59 @@
+From 89288ed330ea3afb25547e7809ea1df3d4a857bd Mon Sep 17 00:00:00 2001
+Message-Id: <89288ed330ea3afb25547e7809ea1df3d4a857bd@dist-git>
+From: Peter Krempa <pkrempa@redhat.com>
+Date: Wed, 9 Oct 2019 14:27:45 +0200
+Subject: [PATCH] util: command: Ignore bitmap errors when enumerating file
+ descriptors to close
+
+virCommandMassCloseGetFDsLinux fails when running libvird on valgrind
+with the following message:
+
+libvirt:  error : internal error: unable to set FD as open: 1024
+
+This is because valgrind opens few file descriptors beyond the limit:
+
+65701125 lr-x------. 1 root root 64 Jul 18 14:48 1024 -> /home/pipo/build/libvirt/gcc/src/.libs/libvirtd
+65701126 lrwx------. 1 root root 64 Jul 18 14:48 1025 -> '/tmp/valgrind_proc_3849_cmdline_186612e3 (deleted)'
+65701127 lrwx------. 1 root root 64 Jul 18 14:48 1026 -> '/tmp/valgrind_proc_3849_auxv_186612e3 (deleted)'
+65701128 lrwx------. 1 root root 64 Jul 18 14:48 1027 -> /dev/pts/11
+65701129 lr-x------. 1 root root 64 Jul 18 14:48 1028 -> 'pipe:[65689522]'
+65701130 l-wx------. 1 root root 64 Jul 18 14:48 1029 -> 'pipe:[65689522]'
+65701131 lr-x------. 1 root root 64 Jul 18 14:48 1030 -> /tmp/vgdb-pipe-from-vgdb-to-3849-by-root-on-angien
+
+Ignore bitmap errors in this case since we'd leak those FD's anyways in
+the previous scenario.
+
+Signed-off-by: Peter Krempa <pkrempa@redhat.com>
+Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
+(cherry picked from commit 728343983787cbd4d7ae8fa2007a157bb140f02a)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1759904
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Message-Id: <30a3508e2903b58e695d467844f6d84cd008a0d9.1570623892.git.mprivozn@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/util/vircommand.c | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+diff --git a/src/util/vircommand.c b/src/util/vircommand.c
+index 2d0c987fe2..17405ceea4 100644
+--- a/src/util/vircommand.c
++++ b/src/util/vircommand.c
+@@ -520,12 +520,7 @@ virCommandMassCloseGetFDsLinux(virCommandPtr cmd ATTRIBUTE_UNUSED,
+             goto cleanup;
+         }
+ 
+-        if (virBitmapSetBit(fds, fd) < 0) {
+-            virReportError(VIR_ERR_INTERNAL_ERROR,
+-                           _("unable to set FD as open: %d"),
+-                           fd);
+-            goto cleanup;
+-        }
++        ignore_value(virBitmapSetBit(fds, fd));
+     }
+ 
+     if (rc < 0)
+-- 
+2.23.0
+
diff --git a/SOURCES/libvirt-virCommand-use-procfs-to-learn-opened-FDs.patch b/SOURCES/libvirt-virCommand-use-procfs-to-learn-opened-FDs.patch
new file mode 100644
index 0000000..468a9aa
--- /dev/null
+++ b/SOURCES/libvirt-virCommand-use-procfs-to-learn-opened-FDs.patch
@@ -0,0 +1,145 @@
+From de87d273266404f3d8fc079efda3d325f6031cc5 Mon Sep 17 00:00:00 2001
+Message-Id: <de87d273266404f3d8fc079efda3d325f6031cc5@dist-git>
+From: Michal Privoznik <mprivozn@redhat.com>
+Date: Wed, 9 Oct 2019 14:27:44 +0200
+Subject: [PATCH] virCommand: use procfs to learn opened FDs
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+When spawning a child process, between fork() and exec() we close
+all file descriptors and keep only those the caller wants us to
+pass onto the child. The problem is how we do that. Currently, we
+get the limit of opened files and then iterate through each one
+of them and either close() it or make it survive exec(). This
+approach is suboptimal (although, not that much in default
+configurations where the limit is pretty low - 1024). We have
+/proc where we can learn what FDs we hold open and thus we can
+selectively close only those.
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+(cherry picked from commit 432faf259b696043ee5d7e8f657d855419a9a3fa)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1759904
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Message-Id: <b9a09b65205ad8d2b001a55c329ec36c0e4f3183.1570623892.git.mprivozn@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/util/vircommand.c | 86 +++++++++++++++++++++++++++++++++++++++----
+ 1 file changed, 78 insertions(+), 8 deletions(-)
+
+diff --git a/src/util/vircommand.c b/src/util/vircommand.c
+index 02dbe0fc76..2d0c987fe2 100644
+--- a/src/util/vircommand.c
++++ b/src/util/vircommand.c
+@@ -492,27 +492,97 @@ virExecCommon(virCommandPtr cmd, gid_t *groups, int ngroups)
+     return ret;
+ }
+ 
++# ifdef __linux__
++/* On Linux, we can utilize procfs and read the table of opened
++ * FDs and selectively close only those FDs we don't want to pass
++ * onto child process (well, the one we will exec soon since this
++ * is called from the child). */
++static int
++virCommandMassCloseGetFDsLinux(virCommandPtr cmd ATTRIBUTE_UNUSED,
++                               virBitmapPtr fds)
++{
++    DIR *dp = NULL;
++    struct dirent *entry;
++    const char *dirName = "/proc/self/fd";
++    int rc;
++    int ret = -1;
++
++    if (virDirOpen(&dp, dirName) < 0)
++        return -1;
++
++    while ((rc = virDirRead(dp, &entry, dirName)) > 0) {
++        int fd;
++
++        if (virStrToLong_i(entry->d_name, NULL, 10, &fd) < 0) {
++            virReportError(VIR_ERR_INTERNAL_ERROR,
++                           _("unable to parse FD: %s"),
++                           entry->d_name);
++            goto cleanup;
++        }
++
++        if (virBitmapSetBit(fds, fd) < 0) {
++            virReportError(VIR_ERR_INTERNAL_ERROR,
++                           _("unable to set FD as open: %d"),
++                           fd);
++            goto cleanup;
++        }
++    }
++
++    if (rc < 0)
++        goto cleanup;
++
++    ret = 0;
++ cleanup:
++    VIR_DIR_CLOSE(dp);
++    return ret;
++}
++
++# else /* !__linux__ */
++
++static int
++virCommandMassCloseGetFDsGeneric(virCommandPtr cmd ATTRIBUTE_UNUSED,
++                                 virBitmapPtr fds)
++{
++    virBitmapSetAll(fds);
++    return 0;
++}
++# endif /* !__linux__ */
++
+ static int
+ virCommandMassClose(virCommandPtr cmd,
+                     int childin,
+                     int childout,
+                     int childerr)
+ {
++    VIR_AUTOPTR(virBitmap) fds = NULL;
+     int openmax = sysconf(_SC_OPEN_MAX);
+-    int fd;
+-    int tmpfd;
++    int fd = -1;
+ 
+-    if (openmax < 0) {
+-        virReportSystemError(errno,  "%s",
+-                             _("sysconf(_SC_OPEN_MAX) failed"));
++    /* In general, it is not safe to call malloc() between fork() and exec()
++     * because the child might have forked at the worst possible time, i.e.
++     * when another thread was in malloc() and thus held its lock. That is to
++     * say, POSIX does not mandate malloc() to be async-safe. Fortunately,
++     * glibc developers are aware of this and made malloc() async-safe.
++     * Therefore we can safely allocate memory here (and transitively call
++     * opendir/readdir) without a deadlock. */
++
++    if (!(fds = virBitmapNew(openmax)))
+         return -1;
+-    }
+ 
+-    for (fd = 3; fd < openmax; fd++) {
++# ifdef __linux__
++    if (virCommandMassCloseGetFDsLinux(cmd, fds) < 0)
++        return -1;
++# else
++    if (virCommandMassCloseGetFDsGeneric(cmd, fds) < 0)
++        return -1;
++# endif
++
++    fd = virBitmapNextSetBit(fds, 2);
++    for (; fd >= 0; fd = virBitmapNextSetBit(fds, fd)) {
+         if (fd == childin || fd == childout || fd == childerr)
+             continue;
+         if (!virCommandFDIsSet(cmd, fd)) {
+-            tmpfd = fd;
++            int tmpfd = fd;
+             VIR_MASS_CLOSE(tmpfd);
+         } else if (virSetInherit(fd, true) < 0) {
+             virReportSystemError(errno, _("failed to preserve fd %d"), fd);
+-- 
+2.23.0
+
diff --git a/SOURCES/libvirt-virNetDevOpenvswitchInterfaceStats-Optimize-for-speed.patch b/SOURCES/libvirt-virNetDevOpenvswitchInterfaceStats-Optimize-for-speed.patch
new file mode 100644
index 0000000..a65530d
--- /dev/null
+++ b/SOURCES/libvirt-virNetDevOpenvswitchInterfaceStats-Optimize-for-speed.patch
@@ -0,0 +1,187 @@
+From 5ca75531afd1244898ee7c8d2307857ba8260cba Mon Sep 17 00:00:00 2001
+Message-Id: <5ca75531afd1244898ee7c8d2307857ba8260cba@dist-git>
+From: Michal Privoznik <mprivozn@redhat.com>
+Date: Wed, 9 Oct 2019 14:27:41 +0200
+Subject: [PATCH] virNetDevOpenvswitchInterfaceStats: Optimize for speed
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+We run 'ovs-vsctl' nine times (first to find if interface is
+there and then eight times = for each stats member separately).
+This is very inefficient. I've found a way to run it once and
+with a bit of help from virJSON module we can parse out stats
+we need.
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+(cherry picked from commit c297eab52599c91a4cb26b66dbdfe9d07c3142d3)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1759904
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Message-Id: <9904d3bee93a9e103012d088b77999f023acaa2b.1570623892.git.mprivozn@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/util/virnetdevopenvswitch.c | 119 +++++++++++++++++++++-----------
+ 1 file changed, 78 insertions(+), 41 deletions(-)
+
+diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitch.c
+index f36916a300..fc92ab2e7f 100644
+--- a/src/util/virnetdevopenvswitch.c
++++ b/src/util/virnetdevopenvswitch.c
+@@ -35,6 +35,7 @@
+ #include "virmacaddr.h"
+ #include "virstring.h"
+ #include "virlog.h"
++#include "virjson.h"
+ 
+ #define VIR_FROM_THIS VIR_FROM_NONE
+ 
+@@ -339,58 +340,94 @@ virNetDevOpenvswitchInterfaceStats(const char *ifname,
+                                    virDomainInterfaceStatsPtr stats)
+ {
+     virCommandPtr cmd = NULL;
+-    char *output;
+-    char *tmp;
+-    bool gotStats = false;
++    VIR_AUTOFREE(char *) output = NULL;
++    virJSONValuePtr jsonStats = NULL;
++    virJSONValuePtr jsonMap = NULL;
++    size_t i;
+     int ret = -1;
+ 
+-    /* Just ensure the interface exists in ovs */
+     cmd = virCommandNew(OVSVSCTL);
+     virNetDevOpenvswitchAddTimeout(cmd);
+-    virCommandAddArgList(cmd, "get", "Interface", ifname, "name", NULL);
++    virCommandAddArgList(cmd, "--if-exists", "--format=list", "--data=json",
++                         "--no-headings", "--columns=statistics", "list",
++                         "Interface", ifname, NULL);
+     virCommandSetOutputBuffer(cmd, &output);
+ 
+-    if (virCommandRun(cmd, NULL) < 0) {
++    /* The above command returns either:
++     * 1) empty string if @ifname doesn't exist, or
++     * 2) a JSON array, for instance:
++     *    ["map",[["collisions",0],["rx_bytes",0],["rx_crc_err",0],["rx_dropped",0],
++     *    ["rx_errors",0],["rx_frame_err",0],["rx_over_err",0],["rx_packets",0],
++     *    ["tx_bytes",12406],["tx_dropped",0],["tx_errors",0],["tx_packets",173]]]
++     */
++
++    if (virCommandRun(cmd, NULL) < 0 ||
++        STREQ_NULLABLE(output, "")) {
+         /* no ovs-vsctl or interface 'ifname' doesn't exists in ovs */
+         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("Interface not found"));
+         goto cleanup;
+     }
+ 
+-#define GET_STAT(name, member) \
+-    do { \
+-        VIR_FREE(output); \
+-        virCommandFree(cmd); \
+-        cmd = virCommandNew(OVSVSCTL); \
+-        virNetDevOpenvswitchAddTimeout(cmd); \
+-        virCommandAddArgList(cmd, "--if-exists", "get", "Interface", \
+-                             ifname, "statistics:" name, NULL); \
+-        virCommandSetOutputBuffer(cmd, &output); \
+-        if (virCommandRun(cmd, NULL) < 0 || !output || !*output || *output == '\n') { \
+-            stats->member = -1; \
+-        } else { \
+-            if (virStrToLong_ll(output, &tmp, 10, &stats->member) < 0 || \
+-                *tmp != '\n') { \
+-                virReportError(VIR_ERR_INTERNAL_ERROR, "%s", \
+-                               _("Fail to parse ovs-vsctl output")); \
+-                goto cleanup; \
+-            } \
+-            gotStats = true; \
+-        } \
+-    } while (0)
+-
+-    /* The TX/RX fields appear to be swapped here
+-     * because this is the host view. */
+-    GET_STAT("rx_bytes", tx_bytes);
+-    GET_STAT("rx_packets", tx_packets);
+-    GET_STAT("rx_errors", tx_errs);
+-    GET_STAT("rx_dropped", tx_drop);
+-    GET_STAT("tx_bytes", rx_bytes);
+-    GET_STAT("tx_packets", rx_packets);
+-    GET_STAT("tx_errors", rx_errs);
+-    GET_STAT("tx_dropped", rx_drop);
+-
+-    if (!gotStats) {
++    if (!(jsonStats = virJSONValueFromString(output)) ||
++        !virJSONValueIsArray(jsonStats) ||
++        !(jsonMap = virJSONValueArrayGet(jsonStats, 1))) {
++        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
++                       _("Unable to parse ovs-vsctl output"));
++        goto cleanup;
++    }
++
++    stats->rx_bytes = stats->rx_packets = stats->rx_errs = stats->rx_drop = -1;
++    stats->tx_bytes = stats->tx_packets = stats->tx_errs = stats->tx_drop = -1;
++
++    for (i = 0; i < virJSONValueArraySize(jsonMap); i++) {
++        virJSONValuePtr item = virJSONValueArrayGet(jsonMap, i);
++        virJSONValuePtr jsonKey;
++        virJSONValuePtr jsonVal;
++        const char *key;
++        long long val;
++
++        if (!item ||
++            (!(jsonKey = virJSONValueArrayGet(item, 0))) ||
++            (!(jsonVal = virJSONValueArrayGet(item, 1))) ||
++            (!(key = virJSONValueGetString(jsonKey))) ||
++            (virJSONValueGetNumberLong(jsonVal, &val) < 0)) {
++            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
++                           _("Malformed ovs-vsctl output"));
++            goto cleanup;
++        }
++
++        /* The TX/RX fields appear to be swapped here
++         * because this is the host view. */
++        if (STREQ(key, "rx_bytes")) {
++            stats->tx_bytes = val;
++        } else if (STREQ(key, "rx_packets")) {
++            stats->tx_packets = val;
++        } else if (STREQ(key, "rx_errors")) {
++            stats->tx_errs = val;
++        } else if (STREQ(key, "rx_dropped")) {
++            stats->tx_drop = val;
++        } else if (STREQ(key, "tx_bytes")) {
++            stats->rx_bytes = val;
++        } else if (STREQ(key, "tx_packets")) {
++            stats->rx_packets = val;
++        } else if (STREQ(key, "tx_errors")) {
++            stats->rx_errs = val;
++        } else if (STREQ(key, "tx_dropped")) {
++            stats->rx_drop = val;
++        } else {
++            VIR_DEBUG("Unused ovs-vsctl stat key=%s val=%lld", key, val);
++        }
++    }
++
++    if (stats->rx_bytes == -1 &&
++        stats->rx_packets == -1 &&
++        stats->rx_errs == -1 &&
++        stats->rx_drop == -1 &&
++        stats->tx_bytes == -1 &&
++        stats->tx_packets == -1 &&
++        stats->tx_errs == -1 &&
++        stats->tx_drop == -1) {
+         virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                        _("Interface doesn't have any statistics"));
+         goto cleanup;
+@@ -399,7 +436,7 @@ virNetDevOpenvswitchInterfaceStats(const char *ifname,
+     ret = 0;
+ 
+  cleanup:
+-    VIR_FREE(output);
++    virJSONValueFree(jsonStats);
+     virCommandFree(cmd);
+     return ret;
+ }
+-- 
+2.23.0
+
diff --git a/SOURCES/libvirt-vircommand-Separate-mass-FD-closing-into-a-function.patch b/SOURCES/libvirt-vircommand-Separate-mass-FD-closing-into-a-function.patch
new file mode 100644
index 0000000..c651daf
--- /dev/null
+++ b/SOURCES/libvirt-vircommand-Separate-mass-FD-closing-into-a-function.patch
@@ -0,0 +1,111 @@
+From 42f610677fc7d38d687ec0703b4c7552f922b598 Mon Sep 17 00:00:00 2001
+Message-Id: <42f610677fc7d38d687ec0703b4c7552f922b598@dist-git>
+From: Michal Privoznik <mprivozn@redhat.com>
+Date: Wed, 9 Oct 2019 14:27:43 +0200
+Subject: [PATCH] vircommand: Separate mass FD closing into a function
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+I will optimize this code a bit in the next commit. But for that
+it is better if the code lives in a separate function.
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Reviewed-by: Ján Tomko <jtomko@redhat.com>
+(cherry picked from commit c1a9bfbbba48fea44fdfbe532e084c5323c9c9b3)
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1759904
+
+Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
+Message-Id: <0198a865d008ec9fb80376062049e05522413d3e.1570623892.git.mprivozn@redhat.com>
+Reviewed-by: Jiri Denemark <jdenemar@redhat.com>
+---
+ src/util/vircommand.c | 52 ++++++++++++++++++++++++++++---------------
+ 1 file changed, 34 insertions(+), 18 deletions(-)
+
+diff --git a/src/util/vircommand.c b/src/util/vircommand.c
+index f539bafab6..02dbe0fc76 100644
+--- a/src/util/vircommand.c
++++ b/src/util/vircommand.c
+@@ -492,6 +492,37 @@ virExecCommon(virCommandPtr cmd, gid_t *groups, int ngroups)
+     return ret;
+ }
+ 
++static int
++virCommandMassClose(virCommandPtr cmd,
++                    int childin,
++                    int childout,
++                    int childerr)
++{
++    int openmax = sysconf(_SC_OPEN_MAX);
++    int fd;
++    int tmpfd;
++
++    if (openmax < 0) {
++        virReportSystemError(errno,  "%s",
++                             _("sysconf(_SC_OPEN_MAX) failed"));
++        return -1;
++    }
++
++    for (fd = 3; fd < openmax; fd++) {
++        if (fd == childin || fd == childout || fd == childerr)
++            continue;
++        if (!virCommandFDIsSet(cmd, fd)) {
++            tmpfd = fd;
++            VIR_MASS_CLOSE(tmpfd);
++        } else if (virSetInherit(fd, true) < 0) {
++            virReportSystemError(errno, _("failed to preserve fd %d"), fd);
++            return -1;
++        }
++    }
++
++    return 0;
++}
++
+ /*
+  * virExec:
+  * @cmd virCommandPtr containing all information about the program to
+@@ -501,13 +532,12 @@ static int
+ virExec(virCommandPtr cmd)
+ {
+     pid_t pid;
+-    int null = -1, fd, openmax;
++    int null = -1;
+     int pipeout[2] = {-1, -1};
+     int pipeerr[2] = {-1, -1};
+     int childin = cmd->infd;
+     int childout = -1;
+     int childerr = -1;
+-    int tmpfd;
+     char *binarystr = NULL;
+     const char *binary = NULL;
+     int ret;
+@@ -616,23 +646,9 @@ virExec(virCommandPtr cmd)
+     if (cmd->mask)
+         umask(cmd->mask);
+     ret = EXIT_CANCELED;
+-    openmax = sysconf(_SC_OPEN_MAX);
+-    if (openmax < 0) {
+-        virReportSystemError(errno,  "%s",
+-                             _("sysconf(_SC_OPEN_MAX) failed"));
++
++    if (virCommandMassClose(cmd, childin, childout, childerr) < 0)
+         goto fork_error;
+-    }
+-    for (fd = 3; fd < openmax; fd++) {
+-        if (fd == childin || fd == childout || fd == childerr)
+-            continue;
+-        if (!virCommandFDIsSet(cmd, fd)) {
+-            tmpfd = fd;
+-            VIR_MASS_CLOSE(tmpfd);
+-        } else if (virSetInherit(fd, true) < 0) {
+-            virReportSystemError(errno, _("failed to preserve fd %d"), fd);
+-            goto fork_error;
+-        }
+-    }
+ 
+     if (prepareStdFd(childin, STDIN_FILENO) < 0) {
+         virReportSystemError(errno,
+-- 
+2.23.0
+
diff --git a/SPECS/libvirt.spec b/SPECS/libvirt.spec
index 13dfac1..d68df15 100644
--- a/SPECS/libvirt.spec
+++ b/SPECS/libvirt.spec
@@ -253,7 +253,7 @@
 Summary: Library providing a simple virtualization API
 Name: libvirt
 Version: 4.5.0
-Release: 26%{?dist}%{?extra_release}
+Release: 33%{?dist}%{?extra_release}
 License: LGPLv2+
 URL: https://libvirt.org/
 
@@ -607,6 +607,29 @@ Patch341: libvirt-qemu-Don-t-report-some-ignored-errors-in-qemuDomainGetStatsOne
 Patch342: libvirt-conf-make-arg-to-virDomainNetGetActualVirtPortProfile-a-const.patch
 Patch343: libvirt-qemu-move-runtime-netdev-validation-into-a-separate-function.patch
 Patch344: libvirt-qemu-call-common-NetDef-validation-for-hotplug-and-device-update.patch
+Patch345: libvirt-conf-utility-function-to-update-entry-in-def-nets-array.patch
+Patch346: libvirt-RHEL-virscsi-Check-device-type-before-getting-it-s-dev-node-name.patch
+Patch347: libvirt-RHEL-virscsi-Support-TAPEs-in-virSCSIDeviceGetDevName.patch
+Patch348: libvirt-RHEL-virscsi-Introduce-and-use-virSCSIDeviceGetUnprivSGIOSysfsPath.patch
+Patch349: libvirt-RHEL-virutil-Accept-non-block-devices-in-virGetDeviceID.patch
+Patch350: libvirt-virNetDevOpenvswitchInterfaceStats-Optimize-for-speed.patch
+Patch351: libvirt-test-Introduce-virnetdevopenvswitchtest.patch
+Patch352: libvirt-vircommand-Separate-mass-FD-closing-into-a-function.patch
+Patch353: libvirt-virCommand-use-procfs-to-learn-opened-FDs.patch
+Patch354: libvirt-util-command-Ignore-bitmap-errors-when-enumerating-file-descriptors-to-close.patch
+Patch355: libvirt-util-Avoid-possible-error-in-virCommandMassClose.patch
+Patch356: libvirt-RHEL-qemuSetUnprivSGIO-Actually-use-calculated-sysfs_path-to-set-unpriv_sgio.patch
+Patch357: libvirt-domain_conf-Make-virDomainDeviceFindSCSIController-accept-virDomainDeviceDriveAddress-struct.patch
+Patch358: libvirt-domain_conf-Relax-SCSI-addr-used-check.patch
+Patch359: libvirt-qemu-Forcibly-mknod-even-if-it-exists.patch
+Patch360: libvirt-qemu_process-fix-starting-VMs-if-machine-group-has-limited-cpuset.cpus.patch
+Patch361: libvirt-nwfilter-Remove-redundant-check-if-object-exists.patch
+Patch362: libvirt-RHEL-qemu-Enable-virt-ssbd-for-host-model-with-old-QEMU.patch
+Patch363: libvirt-process-wait-longer-on-kill-per-assigned-Hostdev.patch
+Patch364: libvirt-process-wait-longer-5-30s-on-hard-shutdown.patch
+Patch365: libvirt-qemu-Don-t-emit-SUSPENDED_POSTCOPY-event-on-destination.patch
+Patch366: libvirt-node_device_conf-Don-t-leak-physical_function-in-virNodeDeviceGetPCISRIOVCaps.patch
+Patch367: libvirt-RHEL-qemuCheckUnprivSGIO-use-sysfs_path-to-get-unpriv_sgio.patch
 
 Requires: libvirt-daemon = %{version}-%{release}
 Requires: libvirt-daemon-config-network = %{version}-%{release}
@@ -1137,6 +1160,7 @@ Requires: xz
     %if 0%{?fedora} || 0%{?rhel} > 7
 Requires: systemd-container
     %endif
+Conflicts: qemu-kvm < 10:1.5.3-158
 
 %description daemon-driver-qemu
 The qemu driver plugin for the libvirtd daemon, providing
@@ -2285,7 +2309,7 @@ exit 0
 %config(noreplace) %{_sysconfdir}/libvirt/qemu.conf
 %config(noreplace) %{_sysconfdir}/libvirt/qemu-lockd.conf
 %config(noreplace) %{_sysconfdir}/logrotate.d/libvirtd.qemu
-%ghost %dir %attr(0700, root, root) %{_localstatedir}/run/libvirt/qemu/
+%ghost %dir %{_localstatedir}/run/libvirt/qemu/
 %dir %attr(0751, %{qemu_user}, %{qemu_group}) %{_localstatedir}/lib/libvirt/qemu/
 %dir %attr(0750, %{qemu_user}, %{qemu_group}) %{_localstatedir}/cache/libvirt/qemu/
 %{_datadir}/augeas/lenses/libvirtd_qemu.aug
@@ -2508,6 +2532,44 @@ exit 0
 
 
 %changelog
+* Fri Feb 14 2020 Jiri Denemark <jdenemar@redhat.com> - 4.5.0-33
+- RHEL: qemuCheckUnprivSGIO: use @sysfs_path to get unpriv_sgio (rhbz#1801139)
+
+* Thu Jan 30 2020 Jiri Denemark <jdenemar@redhat.com> - 4.5.0-32
+- qemu: Don't emit SUSPENDED_POSTCOPY event on destination (rhbz#1791886)
+- node_device_conf: Don't leak @physical_function in virNodeDeviceGetPCISRIOVCaps (rhbz#1792831)
+
+* Thu Dec  5 2019 Jiri Denemark <jdenemar@redhat.com> - 4.5.0-31
+- process: wait longer on kill per assigned Hostdev (rhbz#1771204)
+- process: wait longer 5->30s on hard shutdown (rhbz#1771204)
+
+* Wed Dec  4 2019 Jiri Denemark <jdenemar@redhat.com> - 4.5.0-30
+- nwfilter: Remove redundant check if object exists (rhbz#1766475)
+- RHEL: qemu: Enable virt-ssbd for host-model with old QEMU (rhbz#1745181)
+
+* Thu Nov 28 2019 Jiri Denemark <jdenemar@redhat.com> - 4.5.0-29
+- qemu: Forcibly mknod() even if it exists (rhbz#1752978)
+- qemu_process: fix starting VMs if machine group has limited cpuset.cpus (rhbz#1746517)
+
+* Thu Oct 24 2019 Jiri Denemark <jdenemar@redhat.com> - 4.5.0-28
+- domain_conf: Make virDomainDeviceFindSCSIController accept virDomainDeviceDriveAddress struct (rhbz#1741782)
+- domain_conf: Relax SCSI addr used check (rhbz#1741782)
+
+* Thu Oct 10 2019 Jiri Denemark <jdenemar@redhat.com> - 4.5.0-27
+- conf: utility function to update entry in def->nets array (rhbz#1558934)
+- spec: Fix permissions of /var/run/libvirt/qemu (rhbz#1738693)
+- RHEL: virscsi: Check device type before getting it's /dev node name (rhbz#1754241)
+- RHEL: virscsi: Support TAPEs in virSCSIDeviceGetDevName() (rhbz#1754241)
+- RHEL: virscsi: Introduce and use virSCSIDeviceGetUnprivSGIOSysfsPath() (rhbz#1754241)
+- RHEL: virutil: Accept non-block devices in virGetDeviceID() (rhbz#1754241)
+- virNetDevOpenvswitchInterfaceStats: Optimize for speed (rhbz#1759904)
+- test: Introduce virnetdevopenvswitchtest (rhbz#1759904)
+- vircommand: Separate mass FD closing into a function (rhbz#1759904)
+- virCommand: use procfs to learn opened FDs (rhbz#1759904)
+- util: command: Ignore bitmap errors when enumerating file descriptors to close (rhbz#1759904)
+- util: Avoid possible error in virCommandMassClose (rhbz#1759904)
+- RHEL: qemuSetUnprivSGIO: Actually use calculated @sysfs_path to set unpriv_sgio (rhbz#1754241)
+
 * Thu Sep 19 2019 Jiri Denemark <jdenemar@redhat.com> - 4.5.0-26
 - conf: make arg to virDomainNetGetActualVirtPortProfile() a const (rhbz#1502754)
 - qemu: move runtime netdev validation into a separate function (rhbz#1502754)