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 +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 +Message-Id: +Reviewed-by: Michal Privoznik +--- + 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?= +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 +https://bugzilla.redhat.com/show_bug.cgi?id=1801139 +Message-Id: +Reviewed-by: Andrea Bolognani +--- + 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 +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 +Message-Id: <1f6fa49bd2fec4e3b144cb8c1a27a9d0456c9431.1570709916.git.mprivozn@redhat.com> +Reviewed-by: Jiri Denemark +--- + 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 +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 +Message-Id: +Reviewed-by: Jiri Denemark +--- + 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 +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 +Message-Id: <36bac569fd66de8dcbec73085016b16a0371dfe6.1570536610.git.mprivozn@redhat.com> +Reviewed-by: Jiri Denemark +--- + 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 +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 +Message-Id: <3c722bc2e0627583f26111441f37027c256878c7.1570536610.git.mprivozn@redhat.com> +Reviewed-by: Jiri Denemark +--- + 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: +From: Michal Privoznik +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 +Message-Id: <354b68e431cc5179ab57895536afebc0d68b2a4b.1570536610.git.mprivozn@redhat.com> +Reviewed-by: Jiri Denemark +--- + 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 +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 +Reviewed-by: Michal Privoznik +(cherry picked from commit 7e490cdad6364c82b326d5d9251826c757e8f77b) +Message-Id: <20190926220526.12970-1-laine@redhat.com> +Reviewed-by: Jiri Denemark +--- + 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 +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 +Reviewed-by: Daniel P. Berrangé +(cherry picked from commit 9cddc6e8ee9d9ce62dd20a6317c3148f4cd1c0e9) + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1741782 + +Signed-off-by: Michal Privoznik +Message-Id: +Reviewed-by: Jiri Denemark +--- + 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: +From: Michal Privoznik +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 +Reviewed-by: Daniel P. Berrangé +(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 +Message-Id: <9e70aa28937fa3ea1bbeb792f848b2be2a6ae2e7.1571899509.git.mprivozn@redhat.com> +Reviewed-by: Jiri Denemark +--- + 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: +From: Jiang Kun +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 +Reviewed-by: Michal Privoznik +(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 +Message-Id: +Reviewed-by: Andrea Bolognani +--- + 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: +From: Pavel Hrdina +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é +Signed-off-by: Pavel Hrdina +(cherry picked from commit 3379193f1c73a7be6bd797a3cf790e6960195d3a) + +Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1766475 + +Signed-off-by: Pavel Hrdina +Message-Id: <22531b7498d6fc2609c654d6efab9e5b2eac3819.1575014076.git.phrdina@redhat.com> +Reviewed-by: Ján Tomko +--- + 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 +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 +Reviewed-by: Daniel P. Berrangé +(cherry picked from commit 9a4e4b942df0474503e7524ea427351a46c0eabe) + +https://bugzilla.redhat.com/show_bug.cgi?id=1771204 + +Signed-off-by: Ján Tomko +Message-Id: <963a2cb9ac181322394bc475b200b8fc65e1245a.1575472548.git.jtomko@redhat.com> +Reviewed-by: Andrea Bolognani +--- + 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 +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/. + +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é +Signed-off-by: Christian Ehrhardt +(cherry picked from commit be2ca0444728edd12a000653d3693d68a5c9102f) + +https://bugzilla.redhat.com/show_bug.cgi?id=1771204 + +Signed-off-by: Ján Tomko +Message-Id: <6d18f7131fe022cb2ee4613ad4c58faefa9d574c.1575472548.git.jtomko@redhat.com> +Reviewed-by: Andrea Bolognani +--- + 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 +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 +Reviewed-by: Ján Tomko +(cherry picked from commit bd04d63ad97c21b6955710e6473a502f49816a3c) + +https://bugzilla.redhat.com/show_bug.cgi?id=1791886 + +Signed-off-by: Jiri Denemark +Message-Id: <9b32d5af0dd1d3bf7108abc426dc4d6ceeaa84f8.1579193220.git.jdenemar@redhat.com> +Reviewed-by: Ján Tomko +--- + 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 +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 +Reviewed-by: Daniel P. Berrangé +(cherry picked from commit cdd8a6690ee3fa4b4b8ca1d4531924bd33be136a) +Signed-off-by: Michal Privoznik +Message-Id: <058a9025fdcb817d3334e6c5a7c6a4fe1e95e761.1574256841.git.mprivozn@redhat.com> +Reviewed-by: Jiri Denemark +--- + 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: +From: Pavel Hrdina +Date: Mon, 25 Nov 2019 11:02:21 +0100 +Subject: [PATCH] qemu_process: fix starting VMs if machine group has limited + cpuset.cpus + +Commit 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: + +Signed-off-by: Pavel Hrdina +Reviewed-by: Michal Privoznik +(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 +Message-Id: <86eec31e53a4d061e098919d145e6a89cc8740c4.1574676123.git.phrdina@redhat.com> +Reviewed-by: Jiri Denemark +--- + 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: +From: Michal Privoznik +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 +Reviewed-by: Ján Tomko +(cherry picked from commit cc34260f5a8715d208ee45a6ebaa79e5264cbe68) + +https://bugzilla.redhat.com/show_bug.cgi?id=1759904 + +Signed-off-by: Michal Privoznik +Message-Id: +Reviewed-by: Jiri Denemark +--- + 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 ++ * . ++ */ ++ ++#include ++ ++#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 +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 +ACKed-by: Peter Krempa +(cherry picked from commit 6ae4f4a4ceb123417b732e869d53099983ae8d3f) + +https://bugzilla.redhat.com/show_bug.cgi?id=1759904 + +Signed-off-by: Michal Privoznik +Message-Id: <69ca4c7bcf0e3c7588fad50d68dbf75180109b31.1570623892.git.mprivozn@redhat.com> +Reviewed-by: Jiri Denemark +--- + 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 +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 +Reviewed-by: Michal Privoznik +(cherry picked from commit 728343983787cbd4d7ae8fa2007a157bb140f02a) + +https://bugzilla.redhat.com/show_bug.cgi?id=1759904 + +Signed-off-by: Michal Privoznik +Message-Id: <30a3508e2903b58e695d467844f6d84cd008a0d9.1570623892.git.mprivozn@redhat.com> +Reviewed-by: Jiri Denemark +--- + 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: +From: Michal Privoznik +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 +Reviewed-by: Ján Tomko +(cherry picked from commit 432faf259b696043ee5d7e8f657d855419a9a3fa) + +https://bugzilla.redhat.com/show_bug.cgi?id=1759904 + +Signed-off-by: Michal Privoznik +Message-Id: +Reviewed-by: Jiri Denemark +--- + 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 +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 +Reviewed-by: Ján Tomko +(cherry picked from commit c297eab52599c91a4cb26b66dbdfe9d07c3142d3) + +https://bugzilla.redhat.com/show_bug.cgi?id=1759904 + +Signed-off-by: Michal Privoznik +Message-Id: <9904d3bee93a9e103012d088b77999f023acaa2b.1570623892.git.mprivozn@redhat.com> +Reviewed-by: Jiri Denemark +--- + 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 +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 +Reviewed-by: Ján Tomko +(cherry picked from commit c1a9bfbbba48fea44fdfbe532e084c5323c9c9b3) + +https://bugzilla.redhat.com/show_bug.cgi?id=1759904 + +Signed-off-by: Michal Privoznik +Message-Id: <0198a865d008ec9fb80376062049e05522413d3e.1570623892.git.mprivozn@redhat.com> +Reviewed-by: Jiri Denemark +--- + 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 - 4.5.0-33 +- RHEL: qemuCheckUnprivSGIO: use @sysfs_path to get unpriv_sgio (rhbz#1801139) + +* Thu Jan 30 2020 Jiri Denemark - 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 - 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 - 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 - 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 - 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 - 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 - 4.5.0-26 - conf: make arg to virDomainNetGetActualVirtPortProfile() a const (rhbz#1502754) - qemu: move runtime netdev validation into a separate function (rhbz#1502754)