[libvirt] [PATCH v3 0/5] PCI Multifunction hotplug/unplug, part 1

changes in v3: - rebased after all PCI test changes went to master. - a couple of patches were dropped due to redundancy with what Michal already pushed upstream. - patches 3 and 5 were already R-b by Michal in v2. Hi, In this new version I'm sending what was left to fix after Michal pushed his "Drop KVM assignment" series, which ended up having redundancy of fixes with the previous version. This is the first part of the feature discussed at [1]. These patches are mostly cleanup and fixes, thus it is beneficial to have them upstream right away. The whole feature can be checked out at [2]. All patches survives unit testing. The feature was stress tested with hundreds of consecutive hotplug/unplugs of a Broadcom BCM5719 multifunction network card in a guest running in a Power 8 server. Hopefully I'll find a suitable x86 env to stress test the feature there too. [1] https://www.redhat.com/archives/libvir-list/2019-June/msg00703.html [2] https://github.com/danielhb/libvirt/tree/multifunction_latest Daniel Henrique Barboza (2): virpcimock.c: mock /dev/vfio virpcimock.c: simplify getrealpath() usage Shivaprasad G Bhat (3): virpcimock: Mock the SRIOV Virtual functions tests: Add test case for QEMU pci-hostdev hotplug tests: Add a baseline test for multifunction pci device use case src/util/virprocess.h | 2 +- tests/Makefile.am | 7 + tests/qemuhotplugtest.c | 40 ++- .../qemuhotplug-hostdev-pci.xml | 6 + .../qemuhotplug-base-live+hostdev-pci.xml | 58 +++++ ...uhotplug-pseries-base-live+hostdev-pci.xml | 51 ++++ .../qemuhotplug-pseries-base-live.xml | 43 ++++ .../hostdev-pci-multifunction.args | 35 +++ .../hostdev-pci-multifunction.xml | 59 +++++ .../hostdev-vfio-multidomain.args | 2 +- .../hostdev-vfio-multidomain.xml | 2 +- tests/qemuxml2argvdata/hostdev-vfio.args | 2 +- tests/qemuxml2argvdata/hostdev-vfio.xml | 2 +- tests/qemuxml2argvdata/net-hostdev-fail.xml | 2 +- tests/qemuxml2argvdata/net-hostdev-vfio.args | 2 +- tests/qemuxml2argvdata/net-hostdev-vfio.xml | 2 +- tests/qemuxml2argvtest.c | 3 + .../hostdev-pci-multifunction.xml | 79 ++++++ tests/qemuxml2xmloutdata/hostdev-vfio.xml | 2 +- tests/qemuxml2xmloutdata/net-hostdev-vfio.xml | 2 +- tests/qemuxml2xmltest.c | 1 + tests/virpcimock.c | 232 +++++++++++++++--- tests/virpcitestdata/0000-06-12.0.config | Bin 0 -> 256 bytes tests/virpcitestdata/0000-06-12.1.config | Bin 0 -> 256 bytes tests/virpcitestdata/0000-06-12.2.config | Bin 0 -> 256 bytes tests/virprocessmock.c | 28 +++ 26 files changed, 611 insertions(+), 51 deletions(-) create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-hostdev-pci.xml create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-base-live+hostdev-pci.xml create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+hostdev-pci.xml create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live.xml create mode 100644 tests/qemuxml2argvdata/hostdev-pci-multifunction.args create mode 100644 tests/qemuxml2argvdata/hostdev-pci-multifunction.xml create mode 100644 tests/qemuxml2xmloutdata/hostdev-pci-multifunction.xml create mode 100644 tests/virpcitestdata/0000-06-12.0.config create mode 100644 tests/virpcitestdata/0000-06-12.1.config create mode 100644 tests/virpcitestdata/0000-06-12.2.config create mode 100644 tests/virprocessmock.c -- 2.21.0

This patch adds mock of the /dev/vfio path, needed for proper implementation of the support for multifunction/multiple devices per iommu groups. To do that, the existing bind and unbind operations were adapted to operate with the mocked filesystem as well. Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- tests/virpcimock.c | 159 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 143 insertions(+), 16 deletions(-) diff --git a/tests/virpcimock.c b/tests/virpcimock.c index a5045ed97c..e9440e7910 100644 --- a/tests/virpcimock.c +++ b/tests/virpcimock.c @@ -47,6 +47,7 @@ char *fakerootdir; # define SYSFS_PCI_PREFIX "/sys/bus/pci/" + # define STDERR(...) \ fprintf(stderr, "%s %zu: ", __FUNCTION__, (size_t) __LINE__); \ fprintf(stderr, __VA_ARGS__); \ @@ -105,6 +106,11 @@ struct pciDriver { size_t len; /* @len is used for both @vendor and @device */ }; +struct pciIommuGroup { + int iommu; + size_t nDevicesBoundToVFIO; /* Indicates the devices in the group */ +}; + struct pciDeviceAddress { unsigned int domain; unsigned int bus; @@ -133,6 +139,9 @@ size_t nPCIDevices = 0; struct pciDriver **pciDrivers = NULL; size_t nPCIDrivers = 0; +struct pciIommuGroup **pciIommuGroups = NULL; +size_t npciIommuGroups = 0; + struct fdCallback *callbacks = NULL; size_t nCallbacks = 0; @@ -254,6 +263,15 @@ getrealpath(char **newpath, errno = ENOMEM; return -1; } + } else if (STRPREFIX(path, "/sys/kernel/") || + STRPREFIX(path, "/dev/vfio/")) { + + if (virAsprintfQuiet(newpath, "%s/%s", + fakerootdir, + path) < 0) { + errno = ENOMEM; + return -1; + } } else { if (VIR_STRDUP_QUIET(*newpath, path) < 0) return -1; @@ -389,8 +407,10 @@ static void pci_device_create_iommu(const struct pciDevice *dev, const char *devid) { + struct pciIommuGroup *iommuGroup; VIR_AUTOFREE(char *) iommuPath = NULL; char tmp[256]; + size_t i; if (virAsprintfQuiet(&iommuPath, "%s/sys/kernel/iommu_groups/%d/devices/", fakerootdir, dev->iommuGroup) < 0) @@ -406,6 +426,23 @@ pci_device_create_iommu(const struct pciDevice *dev, } make_symlink(iommuPath, devid, tmp); + + /* pci_device_create_iommu can be called more than one for the + * same iommuGroup. Bail out here if the iommuGroup was already + * created beforehand. */ + for (i = 0; i < npciIommuGroups; i++) + if (pciIommuGroups[i]->iommu == dev->iommuGroup) + return; + + if (VIR_ALLOC_QUIET(iommuGroup) < 0) + ABORT_OOM(); + + iommuGroup->iommu = dev->iommuGroup; + iommuGroup->nDevicesBoundToVFIO = 0; /* No device bound to VFIO by default */ + + if (VIR_APPEND_ELEMENT_QUIET(pciIommuGroups, npciIommuGroups, + iommuGroup) < 0) + ABORT_OOM(); } @@ -558,6 +595,77 @@ pci_device_autobind(struct pciDevice *dev) return pci_driver_bind(driver, dev); } +static int +pci_vfio_release_iommu(struct pciDevice *device) +{ + VIR_AUTOFREE(char *) vfiopath = NULL; + int ret = -1; + size_t i = 0; + + for (i = 0; i < npciIommuGroups; i++) { + if (pciIommuGroups[i]->iommu == device->iommuGroup) { + + if (pciIommuGroups[i]->nDevicesBoundToVFIO == 0) { + ret = 0; + goto cleanup; + } + + pciIommuGroups[i]->nDevicesBoundToVFIO--; + + if (!pciIommuGroups[i]->nDevicesBoundToVFIO) { + + if (virAsprintfQuiet(&vfiopath, "%s/dev/vfio/%d", + fakerootdir, + device->iommuGroup) < 0) { + errno = ENOMEM; + goto cleanup; + } + + if (unlink(vfiopath) < 0) + goto cleanup; + } + break; + } + } + + ret = 0; + + cleanup: + return ret; +} + +static int +pci_vfio_lock_iommu(struct pciDevice *device) +{ + VIR_AUTOFREE(char *) vfiopath = NULL; + int ret = -1; + size_t i = 0; + int fd = -1; + + for (i = 0; i < npciIommuGroups; i++) { + if (pciIommuGroups[i]->iommu == device->iommuGroup) { + if (!pciIommuGroups[i]->nDevicesBoundToVFIO) { + if (virAsprintfQuiet(&vfiopath, "%s/dev/vfio/%d", + fakerootdir, + device->iommuGroup) < 0) { + errno = ENOMEM; + goto cleanup; + } + if ((fd = real_open(vfiopath, O_CREAT)) < 0) + goto cleanup; + + pciIommuGroups[i]->nDevicesBoundToVFIO++; + } + break; + } + } + + ret = 0; + + cleanup: + real_close(fd); + return ret; +} /* * PCI Driver functions @@ -719,6 +827,10 @@ pci_driver_bind(struct pciDriver *driver, if (symlink(devpath, driverpath) < 0) return -1; + if (STREQ(driver->name, "vfio-pci")) + if (pci_vfio_lock_iommu(dev) < 0) + return -1; + dev->driver = driver; return 0; } @@ -749,6 +861,10 @@ pci_driver_unbind(struct pciDriver *driver, unlink(driverpath) < 0) return -1; + if (STREQ(driver->name, "vfio-pci")) + if (pci_vfio_release_iommu(dev) < 0) + return -1; + dev->driver = NULL; return 0; } @@ -865,6 +981,15 @@ init_env(void) make_dir(tmp, "drivers"); make_file(tmp, "drivers_probe", NULL, -1); + /* Create /dev/vfio/ dir and /dev/vfio/vfio file */ + if (virAsprintfQuiet(&tmp, "%s/dev/vfio", fakerootdir) < 0) + ABORT_OOM(); + + if (virFileMakePath(tmp) < 0) + ABORT("Unable to create: %s", tmp); + + make_file(tmp, "vfio", NULL, -1); + # define MAKE_PCI_DRIVER(name, ...) \ pci_driver_new(name, __VA_ARGS__, -1, -1) @@ -872,29 +997,31 @@ init_env(void) MAKE_PCI_DRIVER("i915", 0x8086, 0x0046, 0x8086, 0x0047); MAKE_PCI_DRIVER("vfio-pci", -1, -1); -# define MAKE_PCI_DEVICE(Id, Vendor, Device, ...) \ +# define MAKE_PCI_DEVICE(Id, Vendor, Device, IommuGroup, ...) \ do { \ struct pciDevice dev = {.vendor = Vendor, \ - .device = Device, __VA_ARGS__}; \ + .device = Device, \ + .iommuGroup = IommuGroup, __VA_ARGS__}; \ if (pci_address_parse(&dev.addr, Id) < 0) \ ABORT("Unable to parse PCI address " Id); \ pci_device_new_from_stub(&dev); \ } while (0) - MAKE_PCI_DEVICE("0000:00:00.0", 0x8086, 0x0044); - MAKE_PCI_DEVICE("0000:00:01.0", 0x8086, 0x0044); - MAKE_PCI_DEVICE("0000:00:02.0", 0x8086, 0x0046); - MAKE_PCI_DEVICE("0000:00:03.0", 0x8086, 0x0048); - MAKE_PCI_DEVICE("0001:00:00.0", 0x1014, 0x03b9, .klass = 0x060400); - MAKE_PCI_DEVICE("0001:01:00.0", 0x8086, 0x105e, .iommuGroup = 0); - MAKE_PCI_DEVICE("0001:01:00.1", 0x8086, 0x105e, .iommuGroup = 0); - MAKE_PCI_DEVICE("0005:80:00.0", 0x10b5, 0x8112, .klass = 0x060400); - MAKE_PCI_DEVICE("0005:90:01.0", 0x1033, 0x0035, .iommuGroup = 1); - MAKE_PCI_DEVICE("0005:90:01.1", 0x1033, 0x0035, .iommuGroup = 1); - MAKE_PCI_DEVICE("0005:90:01.2", 0x1033, 0x00e0, .iommuGroup = 1); - MAKE_PCI_DEVICE("0000:0a:01.0", 0x8086, 0x0047); - MAKE_PCI_DEVICE("0000:0a:02.0", 0x8286, 0x0048); - MAKE_PCI_DEVICE("0000:0a:03.0", 0x8386, 0x0048); + MAKE_PCI_DEVICE("0000:00:00.0", 0x8086, 0x0044, 0); + MAKE_PCI_DEVICE("0000:00:01.0", 0x8086, 0x0044, 1); + MAKE_PCI_DEVICE("0000:00:02.0", 0x8086, 0x0046, 2); + MAKE_PCI_DEVICE("0000:00:03.0", 0x8086, 0x0048, 3); + MAKE_PCI_DEVICE("0001:00:00.0", 0x1014, 0x03b9, 4, .klass = 0x060400); + MAKE_PCI_DEVICE("0001:01:00.0", 0x8086, 0x105e, 5); + MAKE_PCI_DEVICE("0001:01:00.1", 0x8086, 0x105e, 5); + MAKE_PCI_DEVICE("0005:80:00.0", 0x10b5, 0x8112, 6, .klass = 0x060400); + MAKE_PCI_DEVICE("0005:90:01.0", 0x1033, 0x0035, 7); + MAKE_PCI_DEVICE("0005:90:01.1", 0x1033, 0x0035, 7); + MAKE_PCI_DEVICE("0005:90:01.2", 0x1033, 0x00e0, 7); + MAKE_PCI_DEVICE("0005:90:01.3", 0x1033, 0x00e0, 7); + MAKE_PCI_DEVICE("0000:0a:01.0", 0x8086, 0x0047, 8); + MAKE_PCI_DEVICE("0000:0a:02.0", 0x8286, 0x0048, 8); + MAKE_PCI_DEVICE("0000:0a:03.0", 0x8386, 0x0048, 8); } -- 2.21.0

On 8/29/19 9:18 PM, Daniel Henrique Barboza wrote:
This patch adds mock of the /dev/vfio path, needed for proper implementation of the support for multifunction/multiple devices per iommu groups.
To do that, the existing bind and unbind operations were adapted to operate with the mocked filesystem as well.
Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- tests/virpcimock.c | 159 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 143 insertions(+), 16 deletions(-)
diff --git a/tests/virpcimock.c b/tests/virpcimock.c index a5045ed97c..e9440e7910 100644 --- a/tests/virpcimock.c +++ b/tests/virpcimock.c @@ -47,6 +47,7 @@ char *fakerootdir;
# define SYSFS_PCI_PREFIX "/sys/bus/pci/"
+ # define STDERR(...) \ fprintf(stderr, "%s %zu: ", __FUNCTION__, (size_t) __LINE__); \ fprintf(stderr, __VA_ARGS__); \ @@ -105,6 +106,11 @@ struct pciDriver { size_t len; /* @len is used for both @vendor and @device */ };
+struct pciIommuGroup { + int iommu; + size_t nDevicesBoundToVFIO; /* Indicates the devices in the group */ +}; + struct pciDeviceAddress { unsigned int domain; unsigned int bus; @@ -133,6 +139,9 @@ size_t nPCIDevices = 0; struct pciDriver **pciDrivers = NULL; size_t nPCIDrivers = 0;
+struct pciIommuGroup **pciIommuGroups = NULL; +size_t npciIommuGroups = 0; + struct fdCallback *callbacks = NULL; size_t nCallbacks = 0;
@@ -254,6 +263,15 @@ getrealpath(char **newpath, errno = ENOMEM; return -1; } + } else if (STRPREFIX(path, "/sys/kernel/") || + STRPREFIX(path, "/dev/vfio/")) { + + if (virAsprintfQuiet(newpath, "%s/%s", + fakerootdir, + path) < 0) { + errno = ENOMEM; + return -1; + } } else { if (VIR_STRDUP_QUIET(*newpath, path) < 0) return -1; @@ -389,8 +407,10 @@ static void pci_device_create_iommu(const struct pciDevice *dev, const char *devid) { + struct pciIommuGroup *iommuGroup; VIR_AUTOFREE(char *) iommuPath = NULL; char tmp[256]; + size_t i;
if (virAsprintfQuiet(&iommuPath, "%s/sys/kernel/iommu_groups/%d/devices/", fakerootdir, dev->iommuGroup) < 0) @@ -406,6 +426,23 @@ pci_device_create_iommu(const struct pciDevice *dev, }
make_symlink(iommuPath, devid, tmp); + + /* pci_device_create_iommu can be called more than one for the + * same iommuGroup. Bail out here if the iommuGroup was already + * created beforehand. */ + for (i = 0; i < npciIommuGroups; i++) + if (pciIommuGroups[i]->iommu == dev->iommuGroup) + return; + + if (VIR_ALLOC_QUIET(iommuGroup) < 0) + ABORT_OOM(); + + iommuGroup->iommu = dev->iommuGroup; + iommuGroup->nDevicesBoundToVFIO = 0; /* No device bound to VFIO by default */ + + if (VIR_APPEND_ELEMENT_QUIET(pciIommuGroups, npciIommuGroups, + iommuGroup) < 0) + ABORT_OOM(); }
@@ -558,6 +595,77 @@ pci_device_autobind(struct pciDevice *dev) return pci_driver_bind(driver, dev); }
+static int +pci_vfio_release_iommu(struct pciDevice *device) +{ + VIR_AUTOFREE(char *) vfiopath = NULL; + int ret = -1; + size_t i = 0; + + for (i = 0; i < npciIommuGroups; i++) { + if (pciIommuGroups[i]->iommu == device->iommuGroup) {
I'd use "if (!cond) continue" so that you can save one level of indend.
+ + if (pciIommuGroups[i]->nDevicesBoundToVFIO == 0) { + ret = 0; + goto cleanup; + } + + pciIommuGroups[i]->nDevicesBoundToVFIO--; + + if (!pciIommuGroups[i]->nDevicesBoundToVFIO) { + + if (virAsprintfQuiet(&vfiopath, "%s/dev/vfio/%d", + fakerootdir, + device->iommuGroup) < 0) { + errno = ENOMEM; + goto cleanup; + } + + if (unlink(vfiopath) < 0) + goto cleanup; + } + break; + } + } + + ret = 0; + + cleanup: + return ret;
This cleanup label looks needless to me.
+} + +static int +pci_vfio_lock_iommu(struct pciDevice *device) +{ + VIR_AUTOFREE(char *) vfiopath = NULL; + int ret = -1; + size_t i = 0; + int fd = -1; + + for (i = 0; i < npciIommuGroups; i++) { + if (pciIommuGroups[i]->iommu == device->iommuGroup) { + if (!pciIommuGroups[i]->nDevicesBoundToVFIO) { + if (virAsprintfQuiet(&vfiopath, "%s/dev/vfio/%d", + fakerootdir, + device->iommuGroup) < 0) { + errno = ENOMEM; + goto cleanup; + } + if ((fd = real_open(vfiopath, O_CREAT)) < 0) + goto cleanup; + + pciIommuGroups[i]->nDevicesBoundToVFIO++;
No, This needs to go outside of this if() as it needs to be incremented every time @device falls into iommu group we're processing here.
+ } + break; + } + } + + ret = 0; + + cleanup: + real_close(fd);
close() won't work with fd == -1. It will overwrite any errno we set earlier.
+ return ret; +}
/* * PCI Driver functions @@ -719,6 +827,10 @@ pci_driver_bind(struct pciDriver *driver, if (symlink(devpath, driverpath) < 0) return -1;
+ if (STREQ(driver->name, "vfio-pci")) + if (pci_vfio_lock_iommu(dev) < 0) + return -1; + dev->driver = driver; return 0; } @@ -749,6 +861,10 @@ pci_driver_unbind(struct pciDriver *driver, unlink(driverpath) < 0) return -1;
+ if (STREQ(driver->name, "vfio-pci")) + if (pci_vfio_release_iommu(dev) < 0) + return -1;
These can be joined in one condition.
+ dev->driver = NULL; return 0; } @@ -865,6 +981,15 @@ init_env(void) make_dir(tmp, "drivers"); make_file(tmp, "drivers_probe", NULL, -1);
+ /* Create /dev/vfio/ dir and /dev/vfio/vfio file */ + if (virAsprintfQuiet(&tmp, "%s/dev/vfio", fakerootdir) < 0) + ABORT_OOM();
At this point, before executing virAsprintf() the @tmp variable is allocated, so it must be freed to avoid leaking it. Michal

From: Shivaprasad G Bhat <sbhat@linux.vnet.ibm.com> The softlink to physfn is the way to know if the device is VF or not. So, the patch softlinks 'physfn' to the parent function. The multifunction PCI devices dont have 'physfn' softlinks. The patch adds few Virtual functions to the mock environment and changes the existing VFIO test xmls using the VFs to use the newly added VFs for their use case. Signed-off-by: Shivaprasad G Bhat <sbhat@linux.vnet.ibm.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- .../hostdev-vfio-multidomain.args | 2 +- .../hostdev-vfio-multidomain.xml | 2 +- tests/qemuxml2argvdata/hostdev-vfio.args | 2 +- tests/qemuxml2argvdata/hostdev-vfio.xml | 2 +- tests/qemuxml2argvdata/net-hostdev-fail.xml | 2 +- tests/qemuxml2argvdata/net-hostdev-vfio.args | 2 +- tests/qemuxml2argvdata/net-hostdev-vfio.xml | 2 +- tests/qemuxml2xmloutdata/hostdev-vfio.xml | 2 +- tests/qemuxml2xmloutdata/net-hostdev-vfio.xml | 2 +- tests/virpcimock.c | 19 ++++++++++++++++++ tests/virpcitestdata/0000-06-12.0.config | Bin 0 -> 256 bytes tests/virpcitestdata/0000-06-12.1.config | Bin 0 -> 256 bytes tests/virpcitestdata/0000-06-12.2.config | Bin 0 -> 256 bytes 13 files changed, 28 insertions(+), 9 deletions(-) create mode 100644 tests/virpcitestdata/0000-06-12.0.config create mode 100644 tests/virpcitestdata/0000-06-12.1.config create mode 100644 tests/virpcitestdata/0000-06-12.2.config diff --git a/tests/qemuxml2argvdata/hostdev-vfio-multidomain.args b/tests/qemuxml2argvdata/hostdev-vfio-multidomain.args index d098bff356..959d2a8888 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio-multidomain.args +++ b/tests/qemuxml2argvdata/hostdev-vfio-multidomain.args @@ -27,5 +27,5 @@ server,nowait \ -usb \ -drive file=/dev/HostVG/QEMUGuest2,format=raw,if=none,id=drive-ide0-0-0 \ -device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 \ --device vfio-pci,host=55aa:20:0f.3,id=hostdev0,bus=pci.0,addr=0x3 \ +-device vfio-pci,host=0021:de:1f.1,id=hostdev0,bus=pci.0,addr=0x3 \ -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 diff --git a/tests/qemuxml2argvdata/hostdev-vfio-multidomain.xml b/tests/qemuxml2argvdata/hostdev-vfio-multidomain.xml index 832458125b..7c34b65c7f 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio-multidomain.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio-multidomain.xml @@ -25,7 +25,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x55aa' bus='32' slot='15' function='3'/> + <address domain='0x0021' bus='222' slot='31' function='1'/> </source> </hostdev> <memballoon model='virtio'/> diff --git a/tests/qemuxml2argvdata/hostdev-vfio.args b/tests/qemuxml2argvdata/hostdev-vfio.args index 79654f44bb..f2025afcd4 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio.args +++ b/tests/qemuxml2argvdata/hostdev-vfio.args @@ -27,5 +27,5 @@ server,nowait \ -usb \ -drive file=/dev/HostVG/QEMUGuest2,format=raw,if=none,id=drive-ide0-0-0 \ -device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 \ --device vfio-pci,host=0000:06:12.5,id=hostdev0,bus=pci.0,addr=0x3 \ +-device vfio-pci,host=0000:06:12.1,id=hostdev0,bus=pci.0,addr=0x3 \ -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 diff --git a/tests/qemuxml2argvdata/hostdev-vfio.xml b/tests/qemuxml2argvdata/hostdev-vfio.xml index 4d96b9f732..b2e6c62e7e 100644 --- a/tests/qemuxml2argvdata/hostdev-vfio.xml +++ b/tests/qemuxml2argvdata/hostdev-vfio.xml @@ -27,7 +27,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x06' slot='0x12' function='0x5'/> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> </source> </hostdev> <memballoon model='virtio'/> diff --git a/tests/qemuxml2argvdata/net-hostdev-fail.xml b/tests/qemuxml2argvdata/net-hostdev-fail.xml index c815d68bd9..50b102c658 100644 --- a/tests/qemuxml2argvdata/net-hostdev-fail.xml +++ b/tests/qemuxml2argvdata/net-hostdev-fail.xml @@ -25,7 +25,7 @@ <interface type='hostdev' managed='yes'> <mac address='00:11:22:33:44:55'/> <source> - <address type='pci' domain='0x0000' bus='0x03' slot='0x07' function='0x1'/> + <address type='pci' domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> </source> <model type='virtio'/> <filterref filter='myfilter'/> diff --git a/tests/qemuxml2argvdata/net-hostdev-vfio.args b/tests/qemuxml2argvdata/net-hostdev-vfio.args index aa9e91db82..b0178a81bb 100644 --- a/tests/qemuxml2argvdata/net-hostdev-vfio.args +++ b/tests/qemuxml2argvdata/net-hostdev-vfio.args @@ -27,5 +27,5 @@ server,nowait \ -usb \ -drive file=/dev/HostVG/QEMUGuest1,format=raw,if=none,id=drive-ide0-0-0 \ -device ide-hd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 \ --device vfio-pci,host=0000:03:07.1,id=hostdev0,bus=pci.0,addr=0x3 \ +-device vfio-pci,host=0000:06:12.1,id=hostdev0,bus=pci.0,addr=0x3 \ -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x4 diff --git a/tests/qemuxml2argvdata/net-hostdev-vfio.xml b/tests/qemuxml2argvdata/net-hostdev-vfio.xml index 24034cad8b..aff681c0fb 100644 --- a/tests/qemuxml2argvdata/net-hostdev-vfio.xml +++ b/tests/qemuxml2argvdata/net-hostdev-vfio.xml @@ -26,7 +26,7 @@ <mac address='00:11:22:33:44:55'/> <driver name='vfio'/> <source> - <address type='pci' domain='0x0000' bus='0x03' slot='0x07' function='0x1'/> + <address type='pci' domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> </source> <vlan> <tag id='42'/> diff --git a/tests/qemuxml2xmloutdata/hostdev-vfio.xml b/tests/qemuxml2xmloutdata/hostdev-vfio.xml index 77bd62a129..15a845f4d1 100644 --- a/tests/qemuxml2xmloutdata/hostdev-vfio.xml +++ b/tests/qemuxml2xmloutdata/hostdev-vfio.xml @@ -32,7 +32,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x06' slot='0x12' function='0x5'/> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </hostdev> diff --git a/tests/qemuxml2xmloutdata/net-hostdev-vfio.xml b/tests/qemuxml2xmloutdata/net-hostdev-vfio.xml index 0523cd8d3b..3f057a8249 100644 --- a/tests/qemuxml2xmloutdata/net-hostdev-vfio.xml +++ b/tests/qemuxml2xmloutdata/net-hostdev-vfio.xml @@ -31,7 +31,7 @@ <mac address='00:11:22:33:44:55'/> <driver name='vfio'/> <source> - <address type='pci' domain='0x0000' bus='0x03' slot='0x07' function='0x1'/> + <address type='pci' domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> </source> <vlan> <tag id='42'/> diff --git a/tests/virpcimock.c b/tests/virpcimock.c index e9440e7910..b1651617a6 100644 --- a/tests/virpcimock.c +++ b/tests/virpcimock.c @@ -125,6 +125,7 @@ struct pciDevice { int device; int klass; int iommuGroup; + const char *physfn; struct pciDriver *driver; /* Driver attached. NULL if attached to no driver */ }; @@ -545,6 +546,15 @@ pci_device_new_from_stub(const struct pciDevice *data) make_symlink(devsympath, devid, tmp); + if (dev->physfn) { + if (snprintf(tmp, sizeof(tmp), + "%s%s/devices/%s", fakerootdir, + SYSFS_PCI_PREFIX, dev->physfn) < 0) { + ABORT("@tmp overflow"); + } + make_symlink(devpath, "physfn", tmp); + } + if (pci_device_autobind(dev) < 0) ABORT("Unable to bind: %s", devid); @@ -1022,6 +1032,15 @@ init_env(void) MAKE_PCI_DEVICE("0000:0a:01.0", 0x8086, 0x0047, 8); MAKE_PCI_DEVICE("0000:0a:02.0", 0x8286, 0x0048, 8); MAKE_PCI_DEVICE("0000:0a:03.0", 0x8386, 0x0048, 8); + MAKE_PCI_DEVICE("0000:06:12.0", 0x8086, 0x0047, 9); + MAKE_PCI_DEVICE("0000:06:12.1", 0x8086, 0x0047, 10, + .physfn = "0000:06:12.0"); /* Virtual Function */ + MAKE_PCI_DEVICE("0000:06:12.2", 0x8086, 0x0047, 11, + .physfn = "0000:06:12.0"); /* Virtual Function */ + MAKE_PCI_DEVICE("0021:de:1f.0", 0x8086, 0x0047, 12); + MAKE_PCI_DEVICE("0021:de:1f.1", 0x8086, 0x0047, 13, + .physfn = "0021:de:1f.0"); /* Virtual Function */ + } diff --git a/tests/virpcitestdata/0000-06-12.0.config b/tests/virpcitestdata/0000-06-12.0.config new file mode 100644 index 0000000000000000000000000000000000000000..beee76534041a7020c08ae9ac03d9a349c6ea12e GIT binary patch literal 256 ycmXpOFlAt45MXi^VCG@qU|?VnU}yr8Sb;H6EeJS(Ng%<*sKv;@R0rb@MH&E<&;s)S literal 0 HcmV?d00001 diff --git a/tests/virpcitestdata/0000-06-12.1.config b/tests/virpcitestdata/0000-06-12.1.config new file mode 100644 index 0000000000000000000000000000000000000000..beee76534041a7020c08ae9ac03d9a349c6ea12e GIT binary patch literal 256 ycmXpOFlAt45MXi^VCG@qU|?VnU}yr8Sb;H6EeJS(Ng%<*sKv;@R0rb@MH&E<&;s)S literal 0 HcmV?d00001 diff --git a/tests/virpcitestdata/0000-06-12.2.config b/tests/virpcitestdata/0000-06-12.2.config new file mode 100644 index 0000000000000000000000000000000000000000..beee76534041a7020c08ae9ac03d9a349c6ea12e GIT binary patch literal 256 ycmXpOFlAt45MXi^VCG@qU|?VnU}yr8Sb;H6EeJS(Ng%<*sKv;@R0rb@MH&E<&;s)S literal 0 HcmV?d00001 -- 2.21.0

From: Shivaprasad G Bhat <sbhat@linux.vnet.ibm.com> This patch adds hostdev test cases in qemuhotplugtest.c. Note: the small tweak inside virpcimock.c was needed because the new tests added a code path in which virHostHasIOMMU() (virutil.c) started being called, and the mocked '/sys/kernel/' prefix that is mocked in virpcimock.c wasn't being considered in the opendir() mock. An alternative to avoid these situations in virpcimock.c is implemented in the next patch. Reviewed-by: Michal Privoznik <mprivozn@redhat.com> Signed-off-by: Shivaprasad G Bhat <sbhat@linux.vnet.ibm.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- src/util/virprocess.h | 2 +- tests/Makefile.am | 7 +++ tests/qemuhotplugtest.c | 40 ++++++++++++- .../qemuhotplug-hostdev-pci.xml | 6 ++ .../qemuhotplug-base-live+hostdev-pci.xml | 58 +++++++++++++++++++ ...uhotplug-pseries-base-live+hostdev-pci.xml | 51 ++++++++++++++++ .../qemuhotplug-pseries-base-live.xml | 43 ++++++++++++++ tests/virpcimock.c | 3 +- tests/virprocessmock.c | 28 +++++++++ 9 files changed, 235 insertions(+), 3 deletions(-) create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-hostdev-pci.xml create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-base-live+hostdev-pci.xml create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+hostdev-pci.xml create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live.xml create mode 100644 tests/virprocessmock.c diff --git a/src/util/virprocess.h b/src/util/virprocess.h index 003ba1edf4..4806c592da 100644 --- a/src/util/virprocess.h +++ b/src/util/virprocess.h @@ -75,7 +75,7 @@ int virProcessGetNamespaces(pid_t pid, int virProcessSetNamespaces(size_t nfdlist, int *fdlist); -int virProcessSetMaxMemLock(pid_t pid, unsigned long long bytes); +int virProcessSetMaxMemLock(pid_t pid, unsigned long long bytes) ATTRIBUTE_NOINLINE; int virProcessSetMaxProcesses(pid_t pid, unsigned int procs); int virProcessSetMaxFiles(pid_t pid, unsigned int files); int virProcessSetMaxCoreSize(pid_t pid, unsigned long long bytes); diff --git a/tests/Makefile.am b/tests/Makefile.am index f92710db43..8c343857a5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -216,6 +216,7 @@ test_libraries = libshunload.la \ libvirpcimock.la \ libvirnetdevmock.la \ libvirrandommock.la \ + libvirprocessmock.la \ libvirhostcpumock.la \ libdomaincapsmock.la \ libvirfilecachemock.la \ @@ -1196,6 +1197,12 @@ libvirrandommock_la_SOURCES = \ libvirrandommock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS) libvirrandommock_la_LIBADD = $(MOCKLIBS_LIBS) +libvirprocessmock_la_SOURCES = \ + virprocessmock.c +libvirprocessmock_la_CFLAGS = $(AM_CFLAGS) +libvirprocessmock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS) +libvirprocessmock_la_LIBADD = $(MOCKLIBS_LIBS) + libvirhostcpumock_la_SOURCES = \ virhostcpumock.c libvirhostcpumock_la_LDFLAGS = $(MOCKLIBS_LDFLAGS) diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index b6aad330a9..3c177c6622 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -28,6 +28,7 @@ #include "testutils.h" #include "testutilsqemu.h" #include "testutilsqemuschema.h" +#include "virhostdev.h" #include "virerror.h" #include "virstring.h" #include "virthread.h" @@ -79,6 +80,8 @@ qemuHotplugCreateObjects(virDomainXMLOptionPtr xmlopt, virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM_PLAIN); virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_IVSHMEM_DOORBELL); virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_SCSI_DISK_WWN); + virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_VFIO_PCI); + virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE); if (qemuTestCapsCacheInsert(driver.qemuCapsCache, priv->qemuCaps) < 0) goto cleanup; @@ -130,6 +133,9 @@ testQemuHotplugAttach(virDomainObjPtr vm, case VIR_DOMAIN_DEVICE_WATCHDOG: ret = qemuDomainAttachWatchdog(&driver, vm, dev->data.watchdog); break; + case VIR_DOMAIN_DEVICE_HOSTDEV: + ret = qemuDomainAttachHostDevice(&driver, vm, dev->data.hostdev); + break; default: VIR_TEST_VERBOSE("device type '%s' cannot be attached", virDomainDeviceTypeToString(dev->type)); @@ -151,6 +157,7 @@ testQemuHotplugDetach(virDomainObjPtr vm, case VIR_DOMAIN_DEVICE_CHR: case VIR_DOMAIN_DEVICE_SHMEM: case VIR_DOMAIN_DEVICE_WATCHDOG: + case VIR_DOMAIN_DEVICE_HOSTDEV: ret = qemuDomainDetachDeviceLive(vm, dev, &driver, async); break; default: @@ -578,6 +585,7 @@ testQemuHotplugCpuIndividual(const void *opaque) return ret; } +#define FAKEROOTDIRTEMPLATE abs_builddir "/fakerootdir-XXXXXX" static int @@ -587,6 +595,19 @@ mymain(void) int ret = 0; struct qemuHotplugTestData data = {0}; struct testQemuHotplugCpuParams cpudata; + char *fakerootdir; + + if (VIR_STRDUP_QUIET(fakerootdir, FAKEROOTDIRTEMPLATE) < 0) { + fprintf(stderr, "Out of memory\n"); + abort(); + } + + if (!mkdtemp(fakerootdir)) { + fprintf(stderr, "Cannot create fakerootdir"); + abort(); + } + + setenv("LIBVIRT_FAKE_ROOT_DIR", fakerootdir, 1); #if !WITH_YAJL fputs("libvirt not compiled with JSON support, skipping this test\n", stderr); @@ -621,6 +642,8 @@ mymain(void) if (!driver.lockManager) return EXIT_FAILURE; + driver.hostdevMgr = virHostdevManagerGetDefault(); + /* wait only 100ms for DEVICE_DELETED event */ qemuDomainRemoveDeviceWaitTime = 100; @@ -789,6 +812,15 @@ mymain(void) "human-monitor-command", HMP("OK\\r\\n"), "device_add", QMP_OK); + DO_TEST_ATTACH("base-live", "hostdev-pci", false, true, + "device_add", QMP_OK); + DO_TEST_DETACH("base-live", "hostdev-pci", false, false, + "device_del", QMP_DEVICE_DELETED("hostdev0") QMP_OK); + DO_TEST_ATTACH("pseries-base-live", "hostdev-pci", false, true, + "device_add", QMP_OK); + DO_TEST_DETACH("pseries-base-live", "hostdev-pci", false, false, + "device_del", QMP_DEVICE_DELETED("hostdev0") QMP_OK); + DO_TEST_ATTACH("base-live", "watchdog", false, true, "watchdog-set-action", QMP_OK, "device_add", QMP_OK); @@ -846,9 +878,15 @@ mymain(void) DO_TEST_CPU_INDIVIDUAL("ppc64-modern-individual", "16-22", true, true, true); DO_TEST_CPU_INDIVIDUAL("ppc64-modern-individual", "17", true, true, true); + if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) + virFileDeleteTree(fakerootdir); + VIR_FREE(fakerootdir); + qemuTestDriverFree(&driver); virObjectUnref(data.vm); return (ret == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } -VIR_TEST_MAIN(mymain) +VIR_TEST_MAIN_PRELOAD(mymain, + VIR_TEST_MOCK("virpci"), + VIR_TEST_MOCK("virprocess")); diff --git a/tests/qemuhotplugtestdevices/qemuhotplug-hostdev-pci.xml b/tests/qemuhotplugtestdevices/qemuhotplug-hostdev-pci.xml new file mode 100644 index 0000000000..6f7c99c943 --- /dev/null +++ b/tests/qemuhotplugtestdevices/qemuhotplug-hostdev-pci.xml @@ -0,0 +1,6 @@ +<hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/> + </source> +</hostdev> diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-base-live+hostdev-pci.xml b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+hostdev-pci.xml new file mode 100644 index 0000000000..40dcc33595 --- /dev/null +++ b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+hostdev-pci.xml @@ -0,0 +1,58 @@ +<domain type='kvm' id='7'> + <name>hotplug</name> + <uuid>d091ea82-29e6-2e34-3005-f02617b36e87</uuid> + <memory unit='KiB'>4194304</memory> + <currentMemory unit='KiB'>4194304</currentMemory> + <vcpu placement='static'>4</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <features> + <acpi/> + <apic/> + <pae/> + </features> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>restart</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0'> + <alias name='usb'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <alias name='ide'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='scsi' index='0' model='virtio-scsi'> + <alias name='scsi0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='pci' index='0' model='pci-root'> + <alias name='pci'/> + </controller> + <controller type='virtio-serial' index='0'> + <alias name='virtio-serial0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <input type='mouse' bus='ps2'> + <alias name='input0'/> + </input> + <input type='keyboard' bus='ps2'> + <alias name='input1'/> + </input> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/> + </source> + <alias name='hostdev0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </hostdev> + <memballoon model='none'/> + </devices> + <seclabel type='none' model='none'/> +</domain> diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+hostdev-pci.xml b/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+hostdev-pci.xml new file mode 100644 index 0000000000..483cb5d8f0 --- /dev/null +++ b/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+hostdev-pci.xml @@ -0,0 +1,51 @@ +<domain type='kvm' id='7'> + <name>hotplug</name> + <uuid>d091ea82-29e6-2e34-3005-f02617b36e87</uuid> + <memory unit='KiB'>4194304</memory> + <currentMemory unit='KiB'>4194304</currentMemory> + <vcpu placement='static'>4</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + <alias name='pci.0'/> + </controller> + <controller type='pci' index='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> + <alias name='pci.1'/> + </controller> + <controller type='usb' index='0'> + <alias name='usb'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </controller> + <input type='keyboard' bus='usb'> + <alias name='input0'/> + <address type='usb' bus='0' port='1'/> + </input> + <input type='mouse' bus='usb'> + <alias name='input1'/> + <address type='usb' bus='0' port='2'/> + </input> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/> + </source> + <alias name='hostdev0'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'/> + </hostdev> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> + <seclabel type='none' model='none'/> +</domain> diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live.xml b/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live.xml new file mode 100644 index 0000000000..1dcc35f626 --- /dev/null +++ b/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live.xml @@ -0,0 +1,43 @@ +<domain type='kvm' id='7'> + <name>hotplug</name> + <uuid>d091ea82-29e6-2e34-3005-f02617b36e87</uuid> + <memory unit='KiB'>4194304</memory> + <currentMemory unit='KiB'>4194304</currentMemory> + <vcpu placement='static'>4</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + <alias name='pci.0'/> + </controller> + <controller type='pci' index='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> + <alias name='pci.1'/> + </controller> + <controller type='usb' index='0'> + <alias name='usb'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </controller> + <input type='keyboard' bus='usb'> + <alias name='input0'/> + <address type='usb' bus='0' port='1'/> + </input> + <input type='mouse' bus='usb'> + <alias name='input1'/> + <address type='usb' bus='0' port='2'/> + </input> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> + <seclabel type='none' model='none'/> +</domain> diff --git a/tests/virpcimock.c b/tests/virpcimock.c index b1651617a6..e362121899 100644 --- a/tests/virpcimock.c +++ b/tests/virpcimock.c @@ -1150,7 +1150,8 @@ opendir(const char *path) init_syms(); - if (STRPREFIX(path, SYSFS_PCI_PREFIX) && + if ((STRPREFIX(path, SYSFS_PCI_PREFIX) || + STRPREFIX(path, "/sys/kernel/")) && getrealpath(&newpath, path) < 0) return NULL; diff --git a/tests/virprocessmock.c b/tests/virprocessmock.c new file mode 100644 index 0000000000..79af1e8064 --- /dev/null +++ b/tests/virprocessmock.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2019 Red Hat, Inc. + * Copyright (C) 2019 IBM Corp. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include <config.h> +#include "virprocess.h" + +int +virProcessSetMaxMemLock(pid_t pid ATTRIBUTE_UNUSED, unsigned long long bytes ATTRIBUTE_UNUSED) +{ + return 0; +} -- 2.21.0

Previous patch had to add '/sys/kernel/' prefix in opendir() because the path, which is being mocked, wasn't being considered due to an 'if SYSFS_PCI_PREFIX' guarding the call to getrealpath(). In fact, all current getrealpath() callers are guarding it with a conditional to ensure that the function will never be called with a non-mocked path. In this case, an extra non-NULL verification is needed for the 'newpath' string to use the variable - which is counterintuitive, given that getrealpath() will always write the 'newpath' string in any non-error conditon. However, simply removing the guard of all getrealpath() instances causes an abort in init_env(). This happens because tests will execute access() to non-mocked paths even before the LIBVIRT_FAKE_ROOT_DIR variable is declared in the test files. We don't need 'fakerootdir' to be created at this point though. This patch does the following changes to simplify getrealpath() usage: - getrealpath() will now guard the init_env() call by checking if both fakeroot isn't created and the required path is being mocked. This ensures that we're not failing inside init_env() because we're too early and LIBVIRT_FAKE_ROOT_DIR wasn't defined yet; - remove all conditional guards to call getrealpath() from access(), virMockStatRedirect(), open(), open_2(), opendir() and virFileCanonicalizePath(). As a bonus, remove all ternary conditionals with 'newpath'; - a new 'pathPrefixIsMocked()' helper to aggregate all the prefixes we're mocking, making it easier to add/remove them. If a prefix is added inside this function, we can be sure that all functions are mocking them. Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- tests/virpcimock.c | 63 +++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/tests/virpcimock.c b/tests/virpcimock.c index e362121899..69ee360e4c 100644 --- a/tests/virpcimock.c +++ b/tests/virpcimock.c @@ -45,8 +45,16 @@ static char *(*real_virFileCanonicalizePath)(const char *path); */ char *fakerootdir; +/* To add a new mocked prefix in virpcimock: + * - add the prefix here as a define to make it easier to track what we + * are mocking; + * - add it to the 'pathPrefixIsMocked()' helper; + * - (optional) edit 'getrealpath()' if you need the resulting mocked + * path to be different than <fakerootdir>/path + */ # define SYSFS_PCI_PREFIX "/sys/bus/pci/" - +# define SYSFS_KERNEL_PREFIX "/sys/kernel/" +# define DEV_VFIO_PREFIX "/dev/vfio/" # define STDERR(...) \ fprintf(stderr, "%s %zu: ", __FUNCTION__, (size_t) __LINE__); \ @@ -251,11 +259,20 @@ pci_read_file(const char *path, return ret; } +static bool +pathPrefixIsMocked(const char *path) +{ + return STRPREFIX(path, SYSFS_PCI_PREFIX) || + STRPREFIX(path, SYSFS_KERNEL_PREFIX) || + STRPREFIX(path, DEV_VFIO_PREFIX); +} + static int getrealpath(char **newpath, const char *path) { - init_env(); + if (!fakerootdir && pathPrefixIsMocked(path)) + init_env(); if (STRPREFIX(path, SYSFS_PCI_PREFIX)) { if (virAsprintfQuiet(newpath, "%s/sys/bus/pci/%s", @@ -264,9 +281,7 @@ getrealpath(char **newpath, errno = ENOMEM; return -1; } - } else if (STRPREFIX(path, "/sys/kernel/") || - STRPREFIX(path, "/dev/vfio/")) { - + } else if (pathPrefixIsMocked(path)) { if (virAsprintfQuiet(newpath, "%s/%s", fakerootdir, path) < 0) { @@ -974,9 +989,6 @@ init_env(void) { VIR_AUTOFREE(char *) tmp = NULL; - if (fakerootdir) - return; - if (!(fakerootdir = getenv("LIBVIRT_FAKE_ROOT_DIR"))) ABORT("Missing LIBVIRT_FAKE_ROOT_DIR env variable\n"); @@ -1057,21 +1069,19 @@ access(const char *path, int mode) init_syms(); - if (STRPREFIX(path, SYSFS_PCI_PREFIX) && - getrealpath(&newpath, path) < 0) + if (getrealpath(&newpath, path) < 0) return -1; - return real_access(newpath ? newpath : path, mode); + return real_access(newpath, mode); } static int virMockStatRedirect(const char *path, char **newpath) { - if (STRPREFIX(path, SYSFS_PCI_PREFIX)) { - if (getrealpath(newpath, path) < 0) - return -1; - } + if (getrealpath(newpath, path) < 0) + return -1; + return 0; } @@ -1084,8 +1094,7 @@ open(const char *path, int flags, ...) init_syms(); - if (STRPREFIX(path, SYSFS_PCI_PREFIX) && - getrealpath(&newpath, path) < 0) + if (getrealpath(&newpath, path) < 0) return -1; if (flags & O_CREAT) { @@ -1094,9 +1103,9 @@ open(const char *path, int flags, ...) va_start(ap, flags); mode = (mode_t) va_arg(ap, int); va_end(ap); - ret = real_open(newpath ? newpath : path, flags, mode); + ret = real_open(newpath, flags, mode); } else { - ret = real_open(newpath ? newpath : path, flags); + ret = real_open(newpath, flags); } /* Catch both: /sys/bus/pci/drivers/... and @@ -1125,11 +1134,10 @@ __open_2(const char *path, int flags) init_syms(); - if (STRPREFIX(path, SYSFS_PCI_PREFIX) && - getrealpath(&newpath, path) < 0) + if (getrealpath(&newpath, path) < 0) return -1; - ret = real___open_2(newpath ? newpath : path, flags); + ret = real___open_2(newpath, flags); /* Catch both: /sys/bus/pci/drivers/... and * /sys/bus/pci/device/.../driver/... */ @@ -1150,12 +1158,10 @@ opendir(const char *path) init_syms(); - if ((STRPREFIX(path, SYSFS_PCI_PREFIX) || - STRPREFIX(path, "/sys/kernel/")) && - getrealpath(&newpath, path) < 0) + if (getrealpath(&newpath, path) < 0) return NULL; - return real_opendir(newpath ? newpath : path); + return real_opendir(newpath); } int @@ -1173,11 +1179,10 @@ virFileCanonicalizePath(const char *path) init_syms(); - if (STRPREFIX(path, SYSFS_PCI_PREFIX) && - getrealpath(&newpath, path) < 0) + if (getrealpath(&newpath, path) < 0) return NULL; - return real_virFileCanonicalizePath(newpath ? newpath : path); + return real_virFileCanonicalizePath(newpath); } # include "virmockstathelpers.c" -- 2.21.0

From: Shivaprasad G Bhat <sbhat@linux.vnet.ibm.com> There are already good number of test cases with hostdevices, few have multifunction devices but none having more than one than one multifunction cards. This patch adds a case where there are two multifunction cards and two Virtual functions part of the same XML. 0001:01:00.X & 0005:09:00.X - are Multifunction PCI cards. 0000:06:12.[5|6] - are SRIOV Virtual functions Future commits will improve on automatically detecting the multifunction cards and auto-assinging the addresses appropriately. Reviewed-by: Michal Privoznik <mprivozn@redhat.com> Signed-off-by: Shivaprasad G Bhat <sbhat@linux.vnet.ibm.com> Signed-off-by: Daniel Henrique Barboza <danielhb413@gmail.com> --- .../hostdev-pci-multifunction.args | 35 ++++++++ .../hostdev-pci-multifunction.xml | 59 ++++++++++++++ tests/qemuxml2argvtest.c | 3 + .../hostdev-pci-multifunction.xml | 79 +++++++++++++++++++ tests/qemuxml2xmltest.c | 1 + 5 files changed, 177 insertions(+) create mode 100644 tests/qemuxml2argvdata/hostdev-pci-multifunction.args create mode 100644 tests/qemuxml2argvdata/hostdev-pci-multifunction.xml create mode 100644 tests/qemuxml2xmloutdata/hostdev-pci-multifunction.xml diff --git a/tests/qemuxml2argvdata/hostdev-pci-multifunction.args b/tests/qemuxml2argvdata/hostdev-pci-multifunction.args new file mode 100644 index 0000000000..d8690c010b --- /dev/null +++ b/tests/qemuxml2argvdata/hostdev-pci-multifunction.args @@ -0,0 +1,35 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-delete \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-delete/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-delete/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-delete/.config \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-x86_64 \ +-name delete \ +-S \ +-machine pc,accel=kvm,usb=off,dump-guest-core=off \ +-m 256 \ +-realtime mlock=off \ +-smp 4,sockets=4,cores=1,threads=1 \ +-uuid 583a8e8e-f0ce-4f53-89ab-092862148b25 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-delete/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-usb \ +-device vfio-pci,host=0005:90:01.0,id=hostdev0,bus=pci.0,addr=0x3 \ +-device vfio-pci,host=0001:01:00.1,id=hostdev1,bus=pci.0,addr=0x4 \ +-device vfio-pci,host=0001:01:00.0,id=hostdev2,bus=pci.0,addr=0x5 \ +-device vfio-pci,host=0005:90:01.2,id=hostdev3,bus=pci.0,addr=0x6 \ +-device vfio-pci,host=0005:90:01.3,id=hostdev4,bus=pci.0,addr=0x7 \ +-device vfio-pci,host=0000:06:12.1,id=hostdev5,bus=pci.0,addr=0x8 \ +-device vfio-pci,host=0000:06:12.2,id=hostdev6,bus=pci.0,addr=0x9 \ +-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0xa diff --git a/tests/qemuxml2argvdata/hostdev-pci-multifunction.xml b/tests/qemuxml2argvdata/hostdev-pci-multifunction.xml new file mode 100644 index 0000000000..06c889c64d --- /dev/null +++ b/tests/qemuxml2argvdata/hostdev-pci-multifunction.xml @@ -0,0 +1,59 @@ +<domain type='kvm'> + <name>delete</name> + <uuid>583a8e8e-f0ce-4f53-89ab-092862148b25</uuid> + <memory unit='KiB'>262144</memory> + <vcpu placement='static'>4</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0'/> + <controller type='ide' index='0'/> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> + </source> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/> + </source> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> + </source> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0005' bus='0x90' slot='0x01' function='0x2'/> + </source> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0005' bus='0x90' slot='0x01' function='0x3'/> + </source> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> + </source> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/> + </source> + </hostdev> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 9395cc19a2..d11a31b836 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1317,6 +1317,9 @@ mymain(void) DO_TEST_FAILURE("net-hostdev-fail", QEMU_CAPS_DEVICE_VFIO_PCI); + DO_TEST("hostdev-pci-multifunction", + QEMU_CAPS_KVM, + QEMU_CAPS_DEVICE_VFIO_PCI); DO_TEST("serial-file-log", QEMU_CAPS_CHARDEV_FILE_APPEND, diff --git a/tests/qemuxml2xmloutdata/hostdev-pci-multifunction.xml b/tests/qemuxml2xmloutdata/hostdev-pci-multifunction.xml new file mode 100644 index 0000000000..52ed86e305 --- /dev/null +++ b/tests/qemuxml2xmloutdata/hostdev-pci-multifunction.xml @@ -0,0 +1,79 @@ +<domain type='kvm'> + <name>delete</name> + <uuid>583a8e8e-f0ce-4f53-89ab-092862148b25</uuid> + <memory unit='KiB'>262144</memory> + <currentMemory unit='KiB'>262144</currentMemory> + <vcpu placement='static'>4</vcpu> + <os> + <type arch='x86_64' machine='pc'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <emulator>/usr/bin/qemu-system-x86_64</emulator> + <controller type='usb' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> + </controller> + <controller type='ide' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> + </controller> + <controller type='pci' index='0' model='pci-root'/> + <input type='mouse' bus='ps2'/> + <input type='keyboard' bus='ps2'/> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0005' bus='0x90' slot='0x01' function='0x0'/> + </source> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x1'/> + </source> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> + </source> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0005' bus='0x90' slot='0x01' function='0x2'/> + </source> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0005' bus='0x90' slot='0x01' function='0x3'/> + </source> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x1'/> + </source> + <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> + </hostdev> + <hostdev mode='subsystem' type='pci' managed='yes'> + <driver name='vfio'/> + <source> + <address domain='0x0000' bus='0x06' slot='0x12' function='0x2'/> + </source> + <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> + </hostdev> + <memballoon model='virtio'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + </memballoon> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 5f6a3618cd..c4bc05e679 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -439,6 +439,7 @@ mymain(void) DO_TEST("hostdev-usb-address", NONE); DO_TEST("hostdev-pci-address", NONE); + DO_TEST("hostdev-pci-multifunction", NONE); DO_TEST("hostdev-vfio", NONE); DO_TEST("hostdev-vfio-zpci", QEMU_CAPS_DEVICE_ZPCI, -- 2.21.0

On 8/29/19 9:18 PM, Daniel Henrique Barboza wrote:
changes in v3: - rebased after all PCI test changes went to master. - a couple of patches were dropped due to redundancy with what Michal already pushed upstream. - patches 3 and 5 were already R-b by Michal in v2.
Hi,
In this new version I'm sending what was left to fix after Michal pushed his "Drop KVM assignment" series, which ended up having redundancy of fixes with the previous version.
This is the first part of the feature discussed at [1]. These patches are mostly cleanup and fixes, thus it is beneficial to have them upstream right away.
The whole feature can be checked out at [2]. All patches survives unit testing. The feature was stress tested with hundreds of consecutive hotplug/unplugs of a Broadcom BCM5719 multifunction network card in a guest running in a Power 8 server. Hopefully I'll find a suitable x86 env to stress test the feature there too.
[1] https://www.redhat.com/archives/libvir-list/2019-June/msg00703.html [2] https://github.com/danielhb/libvirt/tree/multifunction_latest
Daniel Henrique Barboza (2): virpcimock.c: mock /dev/vfio virpcimock.c: simplify getrealpath() usage
Shivaprasad G Bhat (3): virpcimock: Mock the SRIOV Virtual functions tests: Add test case for QEMU pci-hostdev hotplug tests: Add a baseline test for multifunction pci device use case
src/util/virprocess.h | 2 +- tests/Makefile.am | 7 + tests/qemuhotplugtest.c | 40 ++- .../qemuhotplug-hostdev-pci.xml | 6 + .../qemuhotplug-base-live+hostdev-pci.xml | 58 +++++ ...uhotplug-pseries-base-live+hostdev-pci.xml | 51 ++++ .../qemuhotplug-pseries-base-live.xml | 43 ++++ .../hostdev-pci-multifunction.args | 35 +++ .../hostdev-pci-multifunction.xml | 59 +++++ .../hostdev-vfio-multidomain.args | 2 +- .../hostdev-vfio-multidomain.xml | 2 +- tests/qemuxml2argvdata/hostdev-vfio.args | 2 +- tests/qemuxml2argvdata/hostdev-vfio.xml | 2 +- tests/qemuxml2argvdata/net-hostdev-fail.xml | 2 +- tests/qemuxml2argvdata/net-hostdev-vfio.args | 2 +- tests/qemuxml2argvdata/net-hostdev-vfio.xml | 2 +- tests/qemuxml2argvtest.c | 3 + .../hostdev-pci-multifunction.xml | 79 ++++++ tests/qemuxml2xmloutdata/hostdev-vfio.xml | 2 +- tests/qemuxml2xmloutdata/net-hostdev-vfio.xml | 2 +- tests/qemuxml2xmltest.c | 1 + tests/virpcimock.c | 232 +++++++++++++++--- tests/virpcitestdata/0000-06-12.0.config | Bin 0 -> 256 bytes tests/virpcitestdata/0000-06-12.1.config | Bin 0 -> 256 bytes tests/virpcitestdata/0000-06-12.2.config | Bin 0 -> 256 bytes tests/virprocessmock.c | 28 +++ 26 files changed, 611 insertions(+), 51 deletions(-) create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-hostdev-pci.xml create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-base-live+hostdev-pci.xml create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+hostdev-pci.xml create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live.xml create mode 100644 tests/qemuxml2argvdata/hostdev-pci-multifunction.args create mode 100644 tests/qemuxml2argvdata/hostdev-pci-multifunction.xml create mode 100644 tests/qemuxml2xmloutdata/hostdev-pci-multifunction.xml create mode 100644 tests/virpcitestdata/0000-06-12.0.config create mode 100644 tests/virpcitestdata/0000-06-12.1.config create mode 100644 tests/virpcitestdata/0000-06-12.2.config create mode 100644 tests/virprocessmock.c
I've fixed 1/5, ACKed all of them and pushed. Michal
participants (2)
-
Daniel Henrique Barboza
-
Michal Privoznik