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..7a633e8 --- /dev/null +++ b/SOURCES/libvirt-domain_conf-Make-virDomainDeviceFindSCSIController-accept-virDomainDeviceDriveAddress-struct.patch @@ -0,0 +1,102 @@ +From 0c063a84897d357af0c1d04ec70deee47f97a3a1 Mon Sep 17 00:00:00 2001 +Message-Id: <0c063a84897d357af0c1d04ec70deee47f97a3a1@dist-git> +From: Michal Privoznik +Date: Mon, 28 Oct 2019 14:02:22 +0100 +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=1766086 + +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 637d971e21..3bc603b48c 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]; + } + +@@ -18565,7 +18565,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 0989368e7c..934850b28d 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..471b3d5 --- /dev/null +++ b/SOURCES/libvirt-domain_conf-Relax-SCSI-addr-used-check.patch @@ -0,0 +1,102 @@ +From 99a886eeddb5d208871d149e720b13365cc6d261 Mon Sep 17 00:00:00 2001 +Message-Id: <99a886eeddb5d208871d149e720b13365cc6d261@dist-git> +From: Michal Privoznik +Date: Mon, 28 Oct 2019 14:02:23 +0100 +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=1766086 + +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.7 branch. + +Signed-off-by: Michal Privoznik +Message-Id: <1408596266780329bf02f2537aeb4eae3aa589cf.1572267657.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 3bc603b48c..f0e948d80a 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-test-Introduce-virnetdevopenvswitchtest.patch b/SOURCES/libvirt-test-Introduce-virnetdevopenvswitchtest.patch new file mode 100644 index 0000000..69a4dd0 --- /dev/null +++ b/SOURCES/libvirt-test-Introduce-virnetdevopenvswitchtest.patch @@ -0,0 +1,362 @@ +From 4654a9aba4691204f083d6742940437cca0d87b9 Mon Sep 17 00:00:00 2001 +Message-Id: <4654a9aba4691204f083d6742940437cca0d87b9@dist-git> +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 +https://bugzilla.redhat.com/show_bug.cgi?id=1760470 + +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 bf99930802..ac34ea0290 100644 +--- a/src/libvirt_private.syms ++++ b/src/libvirt_private.syms +@@ -2400,6 +2400,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..c10fbc5 --- /dev/null +++ b/SOURCES/libvirt-util-Avoid-possible-error-in-virCommandMassClose.patch @@ -0,0 +1,45 @@ +From 6f186e44c26abd373c927215a0aba4f5892bcd32 Mon Sep 17 00:00:00 2001 +Message-Id: <6f186e44c26abd373c927215a0aba4f5892bcd32@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 +https://bugzilla.redhat.com/show_bug.cgi?id=1760470 + +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..7c50a31 --- /dev/null +++ b/SOURCES/libvirt-util-command-Ignore-bitmap-errors-when-enumerating-file-descriptors-to-close.patch @@ -0,0 +1,60 @@ +From a84a200ecb3867645f051e5c09826facf34786e0 Mon Sep 17 00:00:00 2001 +Message-Id: +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 +https://bugzilla.redhat.com/show_bug.cgi?id=1760470 + +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..242fa48 --- /dev/null +++ b/SOURCES/libvirt-virCommand-use-procfs-to-learn-opened-FDs.patch @@ -0,0 +1,146 @@ +From bff0534793ef6097fda6806b40c016f2757cabec 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 +https://bugzilla.redhat.com/show_bug.cgi?id=1760470 + +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..4cbdce3 --- /dev/null +++ b/SOURCES/libvirt-virNetDevOpenvswitchInterfaceStats-Optimize-for-speed.patch @@ -0,0 +1,188 @@ +From 0a75670e62729ab806f23b10df8556a540d4479d Mon Sep 17 00:00:00 2001 +Message-Id: <0a75670e62729ab806f23b10df8556a540d4479d@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 +https://bugzilla.redhat.com/show_bug.cgi?id=1760470 + +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..8a6afe5 --- /dev/null +++ b/SOURCES/libvirt-vircommand-Separate-mass-FD-closing-into-a-function.patch @@ -0,0 +1,112 @@ +From 307d9f2713d86653375d719020698d858d5c753d Mon Sep 17 00:00:00 2001 +Message-Id: <307d9f2713d86653375d719020698d858d5c753d@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 +https://bugzilla.redhat.com/show_bug.cgi?id=1760470 + +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 9c264b5..a30e97a 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: 23%{?dist}.1%{?extra_release} +Release: 23%{?dist}.3%{?extra_release} License: LGPLv2+ URL: https://libvirt.org/ @@ -590,6 +590,14 @@ Patch324: libvirt-qemu-Pass-correct-qemuCaps-to-virDomainDefPostParse.patch Patch325: libvirt-qemu-Pass-correct-qemuCaps-to-virDomainDefParseNode.patch Patch326: libvirt-qemu-Pass-correct-qemuCaps-to-virDomainDeviceDefPostParse.patch Patch327: libvirt-qemu-Fix-crash-on-incoming-migration.patch +Patch328: libvirt-virNetDevOpenvswitchInterfaceStats-Optimize-for-speed.patch +Patch329: libvirt-test-Introduce-virnetdevopenvswitchtest.patch +Patch330: libvirt-vircommand-Separate-mass-FD-closing-into-a-function.patch +Patch331: libvirt-virCommand-use-procfs-to-learn-opened-FDs.patch +Patch332: libvirt-util-command-Ignore-bitmap-errors-when-enumerating-file-descriptors-to-close.patch +Patch333: libvirt-util-Avoid-possible-error-in-virCommandMassClose.patch +Patch334: libvirt-domain_conf-Make-virDomainDeviceFindSCSIController-accept-virDomainDeviceDriveAddress-struct.patch +Patch335: libvirt-domain_conf-Relax-SCSI-addr-used-check.patch Requires: libvirt-daemon = %{version}-%{release} Requires: libvirt-daemon-config-network = %{version}-%{release} @@ -2491,6 +2499,18 @@ exit 0 %changelog +* Mon Oct 28 2019 Jiri Denemark - 4.5.0-23.el7_7.3 +- domain_conf: Make virDomainDeviceFindSCSIController accept virDomainDeviceDriveAddress struct (rhbz#1766086) +- domain_conf: Relax SCSI addr used check (rhbz#1766086) + +* Mon Oct 14 2019 Jiri Denemark - 4.5.0-23.el7_7.2 +- virNetDevOpenvswitchInterfaceStats: Optimize for speed (rhbz#1760470) +- test: Introduce virnetdevopenvswitchtest (rhbz#1760470) +- vircommand: Separate mass FD closing into a function (rhbz#1760470) +- virCommand: use procfs to learn opened FDs (rhbz#1760470) +- util: command: Ignore bitmap errors when enumerating file descriptors to close (rhbz#1760470) +- util: Avoid possible error in virCommandMassClose (rhbz#1760470) + * Fri Aug 16 2019 Jiri Denemark - 4.5.0-23.el7_7.1 - qemu: Pass qemuCaps to qemuDomainDefCopy (rhbz#1742023) - qemu: Pass qemuCaps to qemuDomainDefFormatBufInternal (rhbz#1742023)