[libvirt] [PATCH 00/26] Support multiple PHBs for pSeries guests

Book 1: A Journey Begins ======================== These commits merely set the stage for what's coming next. Adventure! Challenges! Friendship! Perhaps even love? 00-03: Trivial cleanups 04-05: Test suite changes that will make implementing future test cases possible; get them out of the way early in order to make patches more straightforward when the time finally comes 06: Simple is beautiful Book 2: From Great POWERs ========================= Our hero faces and overcomes many hardships and by doing so grows as an individual, but something is still amiss. 07-09: Get ready to remove some assumptions... 10: ... and then promptly remove them. Hashtag efficient 11-17: Introduce new characters-I mean, XML elements and attributes and capabilities and all that jazz. Close enough, I say. 18: By now, our hero has acquired amazing powers such as being able to create pSeries guests with multiple PHBs; unfortunately, he still has to rely on his strenght and his strength alone when facing new challenges. Wouldn't it be great if he could get some help? Maybe that's exactly where the story is heading, but we'll have to wait for the next books to find out... 19: Prove to the world that the journey is more important than the destination, yet you still gotta get there at some point Book 3: With a Little Help ========================== Joined by a ragtag group of newfound friends, our hero can push forward knowing that he will always be able to count on their help, and that he'll never again be alone. 20: You can only know how far you've come if you marked your starting point on the map 21-22: The Evil One can only recoil in horror as its minions are banished from the land, one by one. Onwards to the final battle! Book 4: The Parting of the Ways =============================== Every journey must come to an end. The Evil One is at last ready to set in motion its plan to take over the entire land; our hero and his companions are the only obstacles standing in its way. Will they be able to stop impending doom? Maybe, but chances are sure stacked against them. Will knowing this stop them from fighting until their last breath? Of course not. Is the title a Doctor Who reference? You better believe it is! 23-25: More characters join the fray, as the narrative gears up for an epic finale 26: The final battle takes place. Swords will clash, spells will be cast, old friends will fall, and when all is said and done... Well, you didn't really expect me to give away the ending so easily, did you? :) Book 5: ??? =========== Whew, that was quite something, wasn't it? But wait, there's more! The fifth book in this engrossing tetralogy is still being drafted, but is meant to be published along with the rest and provide insights and details that might have escaped even the most attentive reader... Yes, I'm talking about documentation here. Hardcover and paperback editions available. Signed copies can be purchased via mail order. Andrea Bolognani (26): conf: Remove obsolete comment conf: Make virDomainPCIAddressSetGrow() private conf: Tweak virDomainPCIAddressGetNextAddr() signature tests: Update qemumemlock data tests: Mock IOMMU groups conf: Simplify slot allocation qemu: Allow qemuBuildControllerDevStr() to return NULL qemu: Tweak index number checking conf: Move index number checking to drivers qemu: Relax pci-root index requirement for pSeries guests schema: Allow <target index='...'/> conf: Parse and format <target index='...'/> schema: Allow 'spapr-pci-host-bridge' controller model conf: Add 'spapr-pci-host-bridge' controller model qemu: Automatically pick index and model for pci-root controllers qemu: Introduce QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE qemu: Deal with PHB naming convention qemu: Use multiple PHBs for pSeries guests tests: Add tests for pSeries guests with multiple PHBs tests: Add baseline tests for automatic PHB usage qemu: Use PHBs to fill holes in PCI bus numbering qemu: Use PHBs when extending the guest PCI topology conf: Introduce isolation groups schema: Allow <isolationGroup/> conf: Parse and format <isolationGroup/> qemu: Isolate hostdevs on pSeries guests docs/schemas/domaincommon.rng | 12 ++ src/bhyve/bhyve_device.c | 4 +- src/bhyve/bhyve_domain.c | 15 ++ src/conf/device_conf.h | 8 +- src/conf/domain_addr.c | 138 +++++++-------- src/conf/domain_addr.h | 28 +-- src/conf/domain_conf.c | 50 +++++- src/conf/domain_conf.h | 6 + src/libvirt_private.syms | 1 - src/libxl/libxl_domain.c | 14 ++ src/lxc/lxc_domain.c | 14 ++ src/openvz/openvz_driver.c | 14 ++ src/qemu/qemu_capabilities.c | 3 + src/qemu/qemu_capabilities.h | 3 + src/qemu/qemu_command.c | 146 +++++++++++++--- src/qemu/qemu_command.h | 9 +- src/qemu/qemu_domain.c | 14 ++ src/qemu/qemu_domain_address.c | 190 ++++++++++++++++++--- src/qemu/qemu_hotplug.c | 5 +- src/uml/uml_driver.c | 14 ++ src/vz/vz_driver.c | 14 ++ src/xen/xen_driver.c | 14 ++ .../qemuargv2xmldata/qemuargv2xml-pseries-disk.xml | 5 +- .../qemuargv2xml-pseries-nvram.xml | 5 +- tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml | 1 + .../qemumemlock-pc-hardlimit+hostdev.xml | 2 +- .../qemumemlock-pc-hardlimit+locked+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pc-hostdev.xml | 2 +- .../qemumemlock-pc-locked+hostdev.xml | 2 +- .../qemumemlock-pseries-hardlimit+hostdev.xml | 2 +- ...emumemlock-pseries-hardlimit+locked+hostdev.xml | 2 +- .../qemumemlock-pseries-hostdev.xml | 2 +- .../qemumemlock-pseries-locked+hostdev.xml | 2 +- tests/qemumemlocktest.c | 21 ++- .../qemuxml2argv-pseries-hostdev.args | 25 +++ .../qemuxml2argv-pseries-hostdev.xml | 33 ++++ .../qemuxml2argv-pseries-many-buses-1.args | 22 +++ .../qemuxml2argv-pseries-many-buses-1.xml | 20 +++ .../qemuxml2argv-pseries-many-buses-2.args | 22 +++ .../qemuxml2argv-pseries-many-buses-2.xml | 18 ++ .../qemuxml2argv-pseries-many-devices.args | 53 ++++++ .../qemuxml2argv-pseries-many-devices.xml | 49 ++++++ .../qemuxml2argv-pseries-phb-default-missing.args | 22 +++ .../qemuxml2argv-pseries-phb-default-missing.xml | 16 ++ .../qemuxml2argv-pseries-phb-simple.args | 22 +++ .../qemuxml2argv-pseries-phb-simple.xml | 17 ++ tests/qemuxml2argvtest.c | 51 +++++- .../qemuxml2xmlout-panic-pseries.xml | 5 +- .../qemuxml2xmlout-ppc64-usb-controller-legacy.xml | 5 +- .../qemuxml2xmlout-ppc64-usb-controller.xml | 5 +- .../qemuxml2xmlout-pseries-hostdev.xml | 56 ++++++ ...xml => qemuxml2xmlout-pseries-many-buses-1.xml} | 19 ++- ...xml => qemuxml2xmlout-pseries-many-buses-2.xml} | 20 ++- .../qemuxml2xmlout-pseries-many-devices.xml | 125 ++++++++++++++ .../qemuxml2xmlout-pseries-nvram.xml | 5 +- .../qemuxml2xmlout-pseries-panic-missing.xml | 5 +- .../qemuxml2xmlout-pseries-panic-no-address.xml | 5 +- ...qemuxml2xmlout-pseries-phb-default-missing.xml} | 18 +- ...m.xml => qemuxml2xmlout-pseries-phb-simple.xml} | 18 +- tests/qemuxml2xmltest.c | 47 ++++- tests/virpcimock.c | 43 ++++- 61 files changed, 1306 insertions(+), 204 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdev.xml copy tests/qemuxml2xmloutdata/{qemuxml2xmlout-pseries-nvram.xml => qemuxml2xmlout-pseries-many-buses-1.xml} (55%) copy tests/qemuxml2xmloutdata/{qemuxml2xmlout-pseries-nvram.xml => qemuxml2xmlout-pseries-many-buses-2.xml} (54%) create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml copy tests/qemuxml2xmloutdata/{qemuxml2xmlout-pseries-nvram.xml => qemuxml2xmlout-pseries-phb-default-missing.xml} (56%) copy tests/qemuxml2xmloutdata/{qemuxml2xmlout-pseries-nvram.xml => qemuxml2xmlout-pseries-phb-simple.xml} (56%) -- 2.7.5

The virDomainDeviceInfoIsSet() function no longer exists. --- src/conf/device_conf.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index a20de85..58b2c9c 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -134,10 +134,6 @@ struct _virDomainDeviceDimmAddress { typedef struct _virDomainDeviceInfo virDomainDeviceInfo; typedef virDomainDeviceInfo *virDomainDeviceInfoPtr; struct _virDomainDeviceInfo { - /* If adding to this struct, ensure that - * virDomainDeviceInfoIsSet() is updated - * to consider the new fields - */ char *alias; int type; /* virDomainDeviceAddressType */ union { -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
The virDomainDeviceInfoIsSet() function no longer exists. --- src/conf/device_conf.h | 4 ---- 1 file changed, 4 deletions(-)
diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index a20de85..58b2c9c 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -134,10 +134,6 @@ struct _virDomainDeviceDimmAddress { typedef struct _virDomainDeviceInfo virDomainDeviceInfo; typedef virDomainDeviceInfo *virDomainDeviceInfoPtr; struct _virDomainDeviceInfo { - /* If adding to this struct, ensure that - * virDomainDeviceInfoIsSet() is updated - * to consider the new fields - */ char *alias; int type; /* virDomainDeviceAddressType */ union {
Reviewed-by: Laine Stump <laine@laine.org>

There are no external users. --- src/conf/domain_addr.c | 2 +- src/conf/domain_addr.h | 5 ----- src/libvirt_private.syms | 1 - 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 639168e..9c809e8 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -362,7 +362,7 @@ virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus, * 0 = no action performed * >0 = number of buses added */ -int +static int virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr, virDomainPCIConnectFlags flags) diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index f884b8a..efa97ca 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -145,11 +145,6 @@ bool virDomainPCIAddressSlotInUse(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); -int virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs, - virPCIDeviceAddressPtr addr, - virDomainPCIConnectFlags flags) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr, virDomainPCIConnectFlags flags) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 429b095..901cc99 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -113,7 +113,6 @@ virDomainPCIAddressReserveNextAddr; virDomainPCIAddressSetAllMulti; virDomainPCIAddressSetAlloc; virDomainPCIAddressSetFree; -virDomainPCIAddressSetGrow; virDomainPCIAddressSlotInUse; virDomainPCIAddressValidate; virDomainPCIControllerModelToConnectType; -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
There are no external users. --- src/conf/domain_addr.c | 2 +- src/conf/domain_addr.h | 5 ----- src/libvirt_private.syms | 1 - 3 files changed, 1 insertion(+), 7 deletions(-)
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 639168e..9c809e8 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -362,7 +362,7 @@ virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus, * 0 = no action performed * >0 = number of buses added */ -int +static int virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr, virDomainPCIConnectFlags flags) diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index f884b8a..efa97ca 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -145,11 +145,6 @@ bool virDomainPCIAddressSlotInUse(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
-int virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs, - virPCIDeviceAddressPtr addr, - virDomainPCIConnectFlags flags) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr, virDomainPCIConnectFlags flags) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 429b095..901cc99 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -113,7 +113,6 @@ virDomainPCIAddressReserveNextAddr; virDomainPCIAddressSetAllMulti; virDomainPCIAddressSetAlloc; virDomainPCIAddressSetFree; -virDomainPCIAddressSetGrow; virDomainPCIAddressSlotInUse; virDomainPCIAddressValidate; virDomainPCIControllerModelToConnectType;
Reviewed-by: Laine Stump <laine@laine.org> (This *is* the new hot way to say ACK, right?)

On Sun, Jun 11, 2017 at 10:10:39PM -0400, Laine Stump wrote:
Reviewed-by: Laine Stump <laine@laine.org>
(This *is* the new hot way to say ACK, right?)
It is not a replacement (AFAIK only rebels like John and Pavel use it) and it is not an equivalent (with Reviewed-by, I assume the reviewer wants me to make it a part of the commit history). Jan

On Mon, 2017-06-12 at 08:35 +0200, Ján Tomko wrote:
Reviewed-by: Laine Stump <laine@laine.org> (This *is* the new hot way to say ACK, right?) It is not a replacement (AFAIK only rebels like John and Pavel use it) and it is not an equivalent (with Reviewed-by, I assume the reviewer wants me to make it a part of the commit history).
Both ACK and R-B are perfectly acceptable ways to signal the submitter you consider their code suitable for merging. As a project we don't currently mandate or prefer either form, so feel free to use the one you like best :) -- Andrea Bolognani / Red Hat / Virtualization

On 06/12/2017 05:20 AM, Andrea Bolognani wrote:
On Mon, 2017-06-12 at 08:35 +0200, Ján Tomko wrote:
Reviewed-by: Laine Stump <laine@laine.org>
(This *is* the new hot way to say ACK, right?)
It is not a replacement (AFAIK only rebels like John and Pavel use it) and it is not an equivalent (with Reviewed-by, I assume the reviewer wants me to make it a part of the commit history).
Both ACK and R-B are perfectly acceptable ways to signal the submitter you consider their code suitable for merging. As a project we don't currently mandate or prefer either form, so feel free to use the one you like best :)
Yeah, I noticed the discussion awhile back and then noticed that some people had started using it, so wasn't sure if I'd missed some memo about "phasing it in" or something. Personally, I like the ease/brevity of "ACK", and as for having a Reviewed-by as part of the commit history, I have two comments: 1) I don't care much about having *my* reviews documented in the history, but it's sometimes useful to know who the reviewer was when it's someone else (of course others will say the same for patches that *I* review, so... :-) So I'm conflicted. It seems like a good idea but takes more time. Too bad there's not some commit hook that could search the email archives for the message with the ACK for a patch and add a Reviewed-by to the commit automatically...

Move @function after @flags to match other functions in the same module like virDomainPCIAddressReserveNextAddr(). Also move virDomainPCIAddressReserveNextAddr() closer to virDomainPCIAddressReserveAddr() in the header file. --- src/conf/domain_addr.c | 6 +++--- src/conf/domain_addr.h | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 9c809e8..6fd8bfc 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -738,8 +738,8 @@ virDomainPCIAddressFindUnusedFunctionOnBus(virDomainPCIAddressBusPtr bus, static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr next_addr, - int function, - virDomainPCIConnectFlags flags) + virDomainPCIConnectFlags flags, + int function) { /* default to starting the search for a free slot from * the first slot of domain 0 bus 0... @@ -845,7 +845,7 @@ virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, { virPCIDeviceAddress addr; - if (virDomainPCIAddressGetNextAddr(addrs, &addr, function, flags) < 0) + if (virDomainPCIAddressGetNextAddr(addrs, &addr, flags, function) < 0) return -1; if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags, false) < 0) diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index efa97ca..77e19bb 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -150,6 +150,12 @@ int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs, virDomainPCIConnectFlags flags) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +int virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, + virDomainDeviceInfoPtr dev, + virDomainPCIConnectFlags flags, + int function) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + int virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs, virDomainDeviceInfoPtr dev, virDomainPCIConnectFlags flags) @@ -159,12 +165,6 @@ int virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); -int virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, - virDomainDeviceInfoPtr dev, - virDomainPCIConnectFlags flags, - int function) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - void virDomainPCIAddressSetAllMulti(virDomainDefPtr def) ATTRIBUTE_NONNULL(1); -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
Move @function after @flags to match other functions in the same module like virDomainPCIAddressReserveNextAddr().
I might have changed the other functions to put flags last (or maybe not). Anyway, consistency is good. Reviewed-by: Laine Stump <laine@laine.org>
Also move virDomainPCIAddressReserveNextAddr() closer to virDomainPCIAddressReserveAddr() in the header file. --- src/conf/domain_addr.c | 6 +++--- src/conf/domain_addr.h | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 9c809e8..6fd8bfc 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -738,8 +738,8 @@ virDomainPCIAddressFindUnusedFunctionOnBus(virDomainPCIAddressBusPtr bus, static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr next_addr, - int function, - virDomainPCIConnectFlags flags) + virDomainPCIConnectFlags flags, + int function) { /* default to starting the search for a free slot from * the first slot of domain 0 bus 0... @@ -845,7 +845,7 @@ virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, { virPCIDeviceAddress addr;
- if (virDomainPCIAddressGetNextAddr(addrs, &addr, function, flags) < 0) + if (virDomainPCIAddressGetNextAddr(addrs, &addr, flags, function) < 0) return -1;
if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags, false) < 0) diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index efa97ca..77e19bb 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -150,6 +150,12 @@ int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs, virDomainPCIConnectFlags flags) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
+int virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, + virDomainDeviceInfoPtr dev, + virDomainPCIConnectFlags flags, + int function) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + int virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs, virDomainDeviceInfoPtr dev, virDomainPCIConnectFlags flags) @@ -159,12 +165,6 @@ int virDomainPCIAddressReleaseAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
-int virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, - virDomainDeviceInfoPtr dev, - virDomainPCIConnectFlags flags, - int function) - ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); - void virDomainPCIAddressSetAllMulti(virDomainDefPtr def) ATTRIBUTE_NONNULL(1);

Use 0001:01:00.0 instead of 0000:04:02.0 as the source address for the host device. This doesn't change anything at the moment, but it will make a difference later on. --- tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pc-hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml index 5443145..e03f5a5 100644 --- a/tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml @@ -13,7 +13,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml index 8184eef..7070e5a 100644 --- a/tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml @@ -16,7 +16,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pc-hostdev.xml b/tests/qemumemlockdata/qemumemlock-pc-hostdev.xml index 6c058a9..cd517ee 100644 --- a/tests/qemumemlockdata/qemumemlock-pc-hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pc-hostdev.xml @@ -10,7 +10,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml index fbc1dc3..da79cb5 100644 --- a/tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml @@ -13,7 +13,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml index ddd3b47..baf0649 100644 --- a/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml @@ -13,7 +13,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml index 73c28c1..04ae4e9 100644 --- a/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml @@ -16,7 +16,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml b/tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml index daf70a4..a52768c 100644 --- a/tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml @@ -10,7 +10,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml index 74212f1..f5abef0 100644 --- a/tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml @@ -13,7 +13,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
Use 0001:01:00.0 instead of 0000:04:02.0 as the source address for the host device. This doesn't change anything at the moment, but it will make a difference later on.
Now I'm curious - a non-0 domain is *extremely* rare on x86 machines. Is it more normal on PPC? Reviewed-by: Laine Stump <laine@laine.org>
--- tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pc-hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml | 2 +- tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml index 5443145..e03f5a5 100644 --- a/tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pc-hardlimit+hostdev.xml @@ -13,7 +13,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml index 8184eef..7070e5a 100644 --- a/tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pc-hardlimit+locked+hostdev.xml @@ -16,7 +16,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pc-hostdev.xml b/tests/qemumemlockdata/qemumemlock-pc-hostdev.xml index 6c058a9..cd517ee 100644 --- a/tests/qemumemlockdata/qemumemlock-pc-hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pc-hostdev.xml @@ -10,7 +10,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml index fbc1dc3..da79cb5 100644 --- a/tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pc-locked+hostdev.xml @@ -13,7 +13,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml index ddd3b47..baf0649 100644 --- a/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+hostdev.xml @@ -13,7 +13,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml index 73c28c1..04ae4e9 100644 --- a/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pseries-hardlimit+locked+hostdev.xml @@ -16,7 +16,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml b/tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml index daf70a4..a52768c 100644 --- a/tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pseries-hostdev.xml @@ -10,7 +10,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices> diff --git a/tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml b/tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml index 74212f1..f5abef0 100644 --- a/tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml +++ b/tests/qemumemlockdata/qemumemlock-pseries-locked+hostdev.xml @@ -13,7 +13,7 @@ <hostdev mode='subsystem' type='pci' managed='yes'> <driver name='vfio'/> <source> - <address domain='0x0000' bus='0x04' slot='0x02' function='0x0'/> + <address domain='0x0001' bus='0x01' slot='0x00' function='0x0'/> </source> </hostdev> </devices>

On Sun, 2017-06-11 at 22:14 -0400, Laine Stump wrote:
Use 0001:01:00.0 instead of 0000:04:02.0 as the source address for the host device. This doesn't change anything at the moment, but it will make a difference later on. Now I'm curious - a non-0 domain is *extremely* rare on x86 machines. Is it more normal on PPC?
Yup. Most PCI devices have their own PCI domain on POWER hosts and PowerVM guests, and getting libvirt to behave the same way is kind of the whole point of this series :) -- Andrea Bolognani / Red Hat / Virtualization

Later on we're going to need access to information about IOMMU groups for host devices. Implement the support in virpcimock, and start using that mock library in a few QEMU test cases. --- tests/qemumemlocktest.c | 21 ++++++++++++++++++++- tests/qemuxml2argvtest.c | 25 ++++++++++++++++++++++--- tests/qemuxml2xmltest.c | 22 +++++++++++++++++++++- tests/virpcimock.c | 43 +++++++++++++++++++++++++++++++++++++------ 4 files changed, 100 insertions(+), 11 deletions(-) diff --git a/tests/qemumemlocktest.c b/tests/qemumemlocktest.c index 6cf17a4..c0f1dc3 100644 --- a/tests/qemumemlocktest.c +++ b/tests/qemumemlocktest.c @@ -56,11 +56,25 @@ testCompareMemLock(const void *data) return ret; } +# define FAKEROOTDIRTEMPLATE abs_builddir "/fakerootdir-XXXXXX" static int mymain(void) { int ret = 0; + 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); abs_top_srcdir = getenv("abs_top_srcdir"); if (!abs_top_srcdir) @@ -124,12 +138,17 @@ mymain(void) DO_TEST("pseries-hardlimit+locked+hostdev", 2147483648); DO_TEST("pseries-locked+hostdev", VIR_DOMAIN_MEMORY_PARAM_UNLIMITED); + if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) + virFileDeleteTree(fakerootdir); + qemuTestDriverFree(&driver); + VIR_FREE(fakerootdir); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -VIR_TEST_MAIN(mymain) +VIR_TEST_MAIN_PRELOAD(mymain, + abs_builddir "/.libs/virpcimock.so") #else diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index b360185..cc6a8a8 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -534,13 +534,27 @@ testCompareXMLToArgv(const void *data) return ret; } +# define FAKEROOTDIRTEMPLATE abs_builddir "/fakerootdir-XXXXXX" static int mymain(void) { int ret = 0; + char *fakerootdir; bool skipLegacyCPUs = false; + 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); + abs_top_srcdir = getenv("abs_top_srcdir"); if (!abs_top_srcdir) abs_top_srcdir = abs_srcdir "/.."; @@ -2567,15 +2581,20 @@ mymain(void) DO_TEST_PARSE_ERROR("cpu-cache-passthrough3", QEMU_CAPS_KVM); DO_TEST_PARSE_ERROR("cpu-cache-passthrough-l3", QEMU_CAPS_KVM); + if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) + virFileDeleteTree(fakerootdir); + qemuTestDriverFree(&driver); + VIR_FREE(fakerootdir); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } VIR_TEST_MAIN_PRELOAD(mymain, - abs_builddir "/.libs/qemuxml2argvmock.so", - abs_builddir "/.libs/virrandommock.so", - abs_builddir "/.libs/qemucpumock.so") + abs_builddir "/.libs/qemuxml2argvmock.so", + abs_builddir "/.libs/virrandommock.so", + abs_builddir "/.libs/qemucpumock.so", + abs_builddir "/.libs/virpcimock.so") #else diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index fff13e2..3c8dbc4 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -303,14 +303,28 @@ testInfoSet(struct testInfo *info, return -1; } +# define FAKEROOTDIRTEMPLATE abs_builddir "/fakerootdir-XXXXXX" static int mymain(void) { int ret = 0; + char *fakerootdir; struct testInfo info; virQEMUDriverConfigPtr cfg = NULL; + 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); + memset(&info, 0, sizeof(info)); if (qemuTestDriverInit(&driver) < 0) @@ -1137,12 +1151,18 @@ mymain(void) DO_TEST("cpu-check-default-partial", NONE); DO_TEST("cpu-check-default-partial2", NONE); + if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) + virFileDeleteTree(fakerootdir); + qemuTestDriverFree(&driver); + VIR_FREE(fakerootdir); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } -VIR_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/qemuxml2xmlmock.so") +VIR_TEST_MAIN_PRELOAD(mymain, + abs_builddir "/.libs/qemuxml2xmlmock.so", + abs_builddir "/.libs/virpcimock.so") #else diff --git a/tests/virpcimock.c b/tests/virpcimock.c index e9408aa..19b10f4 100644 --- a/tests/virpcimock.c +++ b/tests/virpcimock.c @@ -127,6 +127,7 @@ struct pciDevice { int vendor; int device; int class; + int iommuGroup; struct pciDriver *driver; /* Driver attached. NULL if attached to no driver */ }; @@ -190,6 +191,22 @@ make_file(const char *path, VIR_FREE(filepath); } +static void +make_symlink(const char *path, + const char *name, + const char *target) +{ + char *filepath = NULL; + + if (virAsprintfQuiet(&filepath, "%s/%s", path, name) < 0) + ABORT_OOM(); + + if (symlink(target, filepath) < 0) + ABORT("Unable to create symlink filepath -> target"); + + VIR_FREE(filepath); +} + static int pci_read_file(const char *path, char *buf, @@ -322,7 +339,7 @@ pci_device_new_from_stub(const struct pciDevice *data) char *id; char *c; char *configSrc; - char tmp[32]; + char tmp[256]; struct stat sb; if (VIR_STRDUP_QUIET(id, data->id) < 0) @@ -386,6 +403,20 @@ pci_device_new_from_stub(const struct pciDevice *data) ABORT("@tmp overflow"); make_file(devpath, "class", tmp, -1); + if (snprintf(tmp, sizeof(tmp), + "%s/../../../kernel/iommu_groups/%d", + devpath, dev->iommuGroup) < 0) { + ABORT("@tmp overflow"); + } + if (virFileMakePath(tmp) < 0) + ABORT("Unable to create %s", tmp); + + if (snprintf(tmp, sizeof(tmp), + "../../../kernel/iommu_groups/%d", dev->iommuGroup) < 0) { + ABORT("@tmp overflow"); + } + make_symlink(devpath, "iommu_group", tmp); + if (pci_device_autobind(dev) < 0) ABORT("Unable to bind: %s", data->id); @@ -821,12 +852,12 @@ init_env(void) 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, .class = 0x060400); - MAKE_PCI_DEVICE("0001:01:00.0", 0x8086, 0x105e); - MAKE_PCI_DEVICE("0001:01:00.1", 0x8086, 0x105e); + MAKE_PCI_DEVICE("0001:01:00.0", 0x8086, 0x105e, .iommuGroup = 2); + MAKE_PCI_DEVICE("0001:01:00.1", 0x8086, 0x105e, .iommuGroup = 2); MAKE_PCI_DEVICE("0005:80:00.0", 0x10b5, 0x8112, .class = 0x060400); - MAKE_PCI_DEVICE("0005:90:01.0", 0x1033, 0x0035); - MAKE_PCI_DEVICE("0005:90:01.1", 0x1033, 0x0035); - MAKE_PCI_DEVICE("0005:90:01.2", 0x1033, 0x00e0); + MAKE_PCI_DEVICE("0005:90:01.0", 0x1033, 0x0035, .iommuGroup = 3); + MAKE_PCI_DEVICE("0005:90:01.1", 0x1033, 0x0035, .iommuGroup = 3); + MAKE_PCI_DEVICE("0005:90:01.2", 0x1033, 0x00e0, .iommuGroup = 3); 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); -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
Later on we're going to need access to information about IOMMU groups for host devices. Implement the support in virpcimock, and start using that mock library in a few QEMU test cases. --- tests/qemumemlocktest.c | 21 ++++++++++++++++++++- tests/qemuxml2argvtest.c | 25 ++++++++++++++++++++++--- tests/qemuxml2xmltest.c | 22 +++++++++++++++++++++- tests/virpcimock.c | 43 +++++++++++++++++++++++++++++++++++++------ 4 files changed, 100 insertions(+), 11 deletions(-)
diff --git a/tests/qemumemlocktest.c b/tests/qemumemlocktest.c index 6cf17a4..c0f1dc3 100644 --- a/tests/qemumemlocktest.c +++ b/tests/qemumemlocktest.c @@ -56,11 +56,25 @@ testCompareMemLock(const void *data) return ret; }
+# define FAKEROOTDIRTEMPLATE abs_builddir "/fakerootdir-XXXXXX"
static int mymain(void) { int ret = 0; + 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);
I see all this repetition of boilerplate code and wonder if maybe it should be done in one common place. Not a topic for this series though.
abs_top_srcdir = getenv("abs_top_srcdir"); if (!abs_top_srcdir) @@ -124,12 +138,17 @@ mymain(void) DO_TEST("pseries-hardlimit+locked+hostdev", 2147483648); DO_TEST("pseries-locked+hostdev", VIR_DOMAIN_MEMORY_PARAM_UNLIMITED);
+ if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) + virFileDeleteTree(fakerootdir); + qemuTestDriverFree(&driver); + VIR_FREE(fakerootdir);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; }
-VIR_TEST_MAIN(mymain) +VIR_TEST_MAIN_PRELOAD(mymain, + abs_builddir "/.libs/virpcimock.so")
#else
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index b360185..cc6a8a8 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -534,13 +534,27 @@ testCompareXMLToArgv(const void *data) return ret; }
+# define FAKEROOTDIRTEMPLATE abs_builddir "/fakerootdir-XXXXXX"
static int mymain(void) { int ret = 0; + char *fakerootdir; bool skipLegacyCPUs = false;
+ if (VIR_STRDUP_QUIET(fakerootdir, FAKEROOTDIRTEMPLATE) < 0) { + fprintf(stderr, "Out of memory\n"); + abort();
Any particular reason (other than "that's what everybody else is doing") that you use a combination of fprintf+abort here, but the ABORT macro in other places?
+ } + + if (!mkdtemp(fakerootdir)) { + fprintf(stderr, "Cannot create fakerootdir"); + abort(); + } + + setenv("LIBVIRT_FAKE_ROOT_DIR", fakerootdir, 1); + abs_top_srcdir = getenv("abs_top_srcdir"); if (!abs_top_srcdir) abs_top_srcdir = abs_srcdir "/.."; @@ -2567,15 +2581,20 @@ mymain(void) DO_TEST_PARSE_ERROR("cpu-cache-passthrough3", QEMU_CAPS_KVM); DO_TEST_PARSE_ERROR("cpu-cache-passthrough-l3", QEMU_CAPS_KVM);
+ if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) + virFileDeleteTree(fakerootdir); + qemuTestDriverFree(&driver); + VIR_FREE(fakerootdir);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; }
VIR_TEST_MAIN_PRELOAD(mymain, - abs_builddir "/.libs/qemuxml2argvmock.so", - abs_builddir "/.libs/virrandommock.so", - abs_builddir "/.libs/qemucpumock.so") + abs_builddir "/.libs/qemuxml2argvmock.so", + abs_builddir "/.libs/virrandommock.so", + abs_builddir "/.libs/qemucpumock.so", + abs_builddir "/.libs/virpcimock.so")
#else
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index fff13e2..3c8dbc4 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -303,14 +303,28 @@ testInfoSet(struct testInfo *info, return -1; }
+# define FAKEROOTDIRTEMPLATE abs_builddir "/fakerootdir-XXXXXX"
static int mymain(void) { int ret = 0; + char *fakerootdir; struct testInfo info; virQEMUDriverConfigPtr cfg = NULL;
+ 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); + memset(&info, 0, sizeof(info));
if (qemuTestDriverInit(&driver) < 0) @@ -1137,12 +1151,18 @@ mymain(void) DO_TEST("cpu-check-default-partial", NONE); DO_TEST("cpu-check-default-partial2", NONE);
+ if (getenv("LIBVIRT_SKIP_CLEANUP") == NULL) + virFileDeleteTree(fakerootdir); + qemuTestDriverFree(&driver); + VIR_FREE(fakerootdir);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; }
-VIR_TEST_MAIN_PRELOAD(mymain, abs_builddir "/.libs/qemuxml2xmlmock.so") +VIR_TEST_MAIN_PRELOAD(mymain, + abs_builddir "/.libs/qemuxml2xmlmock.so", + abs_builddir "/.libs/virpcimock.so")
#else
diff --git a/tests/virpcimock.c b/tests/virpcimock.c index e9408aa..19b10f4 100644 --- a/tests/virpcimock.c +++ b/tests/virpcimock.c @@ -127,6 +127,7 @@ struct pciDevice { int vendor; int device; int class; + int iommuGroup; struct pciDriver *driver; /* Driver attached. NULL if attached to no driver */ };
@@ -190,6 +191,22 @@ make_file(const char *path, VIR_FREE(filepath); }
+static void +make_symlink(const char *path, + const char *name, + const char *target) +{ + char *filepath = NULL; + + if (virAsprintfQuiet(&filepath, "%s/%s", path, name) < 0) + ABORT_OOM(); + + if (symlink(target, filepath) < 0) + ABORT("Unable to create symlink filepath -> target"); + + VIR_FREE(filepath); +} + static int pci_read_file(const char *path, char *buf, @@ -322,7 +339,7 @@ pci_device_new_from_stub(const struct pciDevice *data) char *id; char *c; char *configSrc; - char tmp[32]; + char tmp[256]; struct stat sb;
if (VIR_STRDUP_QUIET(id, data->id) < 0) @@ -386,6 +403,20 @@ pci_device_new_from_stub(const struct pciDevice *data) ABORT("@tmp overflow"); make_file(devpath, "class", tmp, -1);
+ if (snprintf(tmp, sizeof(tmp), + "%s/../../../kernel/iommu_groups/%d", + devpath, dev->iommuGroup) < 0) { + ABORT("@tmp overflow"); + } + if (virFileMakePath(tmp) < 0) + ABORT("Unable to create %s", tmp); + + if (snprintf(tmp, sizeof(tmp), + "../../../kernel/iommu_groups/%d", dev->iommuGroup) < 0) { + ABORT("@tmp overflow"); + } + make_symlink(devpath, "iommu_group", tmp); + if (pci_device_autobind(dev) < 0) ABORT("Unable to bind: %s", data->id);
@@ -821,12 +852,12 @@ init_env(void) 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, .class = 0x060400); - MAKE_PCI_DEVICE("0001:01:00.0", 0x8086, 0x105e); - MAKE_PCI_DEVICE("0001:01:00.1", 0x8086, 0x105e); + MAKE_PCI_DEVICE("0001:01:00.0", 0x8086, 0x105e, .iommuGroup = 2); + MAKE_PCI_DEVICE("0001:01:00.1", 0x8086, 0x105e, .iommuGroup = 2); MAKE_PCI_DEVICE("0005:80:00.0", 0x10b5, 0x8112, .class = 0x060400); - MAKE_PCI_DEVICE("0005:90:01.0", 0x1033, 0x0035); - MAKE_PCI_DEVICE("0005:90:01.1", 0x1033, 0x0035); - MAKE_PCI_DEVICE("0005:90:01.2", 0x1033, 0x00e0); + MAKE_PCI_DEVICE("0005:90:01.0", 0x1033, 0x0035, .iommuGroup = 3); + MAKE_PCI_DEVICE("0005:90:01.1", 0x1033, 0x0035, .iommuGroup = 3); + MAKE_PCI_DEVICE("0005:90:01.2", 0x1033, 0x00e0, .iommuGroup = 3); 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);
Reviewed-by: Laine Stump <laine@laine.org> (feel free to include in the commit log or not :-P) (also, I'm assuming that you've run make check && make syntax-check on each patch individually. Otherwise all ACKs are null and void)

The current algorithm for slot allocation tries to be clever and avoid looking at buses / slots more than once unless it's necessary. Unfortunately that makes the code more complex, and it will cause problem later on in some situations unless even more complex code is added. Since the performance gains are going to be pretty modest anyway, we can just get rid of the extra complexity and use a completely straighforward implementation instead. --- src/conf/domain_addr.c | 43 +++++++------------------------------------ src/conf/domain_addr.h | 2 -- 2 files changed, 7 insertions(+), 38 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 6fd8bfc..d173766 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -741,34 +741,26 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, virDomainPCIConnectFlags flags, int function) { - /* default to starting the search for a free slot from - * the first slot of domain 0 bus 0... - */ virPCIDeviceAddress a = { 0 }; - bool found = false; if (addrs->nbuses == 0) { virReportError(VIR_ERR_XML_ERROR, "%s", _("No PCI buses available")); goto error; } - /* ...unless this search is for the exact same type of device as - * last time, then continue the search from the slot where we - * found the previous match (it's possible there will still be a - * function available on that slot). - */ - if (flags == addrs->lastFlags) - a = addrs->lastaddr; - else - a.slot = addrs->buses[0].minSlot; - /* if the caller asks for "any function", give them function 0 */ if (function == -1) a.function = 0; else a.function = function; - while (a.bus < addrs->nbuses) { + /* "Begin at the beginning," the King said, very gravely, "and go on + * till you come to the end: then stop." */ + for (a.bus = 0; a.bus < addrs->nbuses; a.bus++) { + bool found = false; + + a.slot = addrs->buses[a.bus].minSlot; + if (virDomainPCIAddressFindUnusedFunctionOnBus(&addrs->buses[a.bus], &a, function, flags, &found) < 0) { @@ -777,10 +769,6 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, if (found) goto success; - - /* nothing on this bus, go to the next bus */ - if (++a.bus < addrs->nbuses) - a.slot = addrs->buses[a.bus].minSlot; } /* There were no free slots after the last used one */ @@ -791,20 +779,6 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, /* this device will use the first slot of the new bus */ a.slot = addrs->buses[a.bus].minSlot; goto success; - } else if (flags == addrs->lastFlags) { - /* Check the buses from 0 up to the last used one */ - for (a.bus = 0; a.bus <= addrs->lastaddr.bus; a.bus++) { - a.slot = addrs->buses[a.bus].minSlot; - - if (virDomainPCIAddressFindUnusedFunctionOnBus(&addrs->buses[a.bus], - &a, function, - flags, &found) < 0) { - goto error; - } - - if (found) - goto success; - } } virReportError(VIR_ERR_INTERNAL_ERROR, @@ -851,9 +825,6 @@ virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags, false) < 0) return -1; - addrs->lastaddr = addr; - addrs->lastFlags = flags; - if (!addrs->dryRun) { dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; dev->addr.pci = addr; diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 77e19bb..7704061 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -106,8 +106,6 @@ typedef virDomainPCIAddressBus *virDomainPCIAddressBusPtr; struct _virDomainPCIAddressSet { virDomainPCIAddressBus *buses; size_t nbuses; - virPCIDeviceAddress lastaddr; - virDomainPCIConnectFlags lastFlags; bool dryRun; /* on a dry run, new buses are auto-added and addresses aren't saved in device infos */ }; -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
The current algorithm for slot allocation tries to be clever and avoid looking at buses / slots more than once unless it's necessary. Unfortunately that makes the code more complex, and it will cause problem later on in some situations unless even more complex code is added.
Since the performance gains are going to be pretty modest anyway, we can just get rid of the extra complexity and use a completely straighforward implementation instead. ---
From looking at the current git blame you might assume that I had something to do with this optimization, but actually it was there before I got involved with PCI address allocation - I only preserved that behavior. So I have no quarrel with simplifying it as you've done.
I guess the only concern I might have would be if the new algorithm ended up give out a different address in some case (just in case someone using transient domains with no pre-assigned PCI addresses was expecting address stability), but I can't think of any way that would happen, and the fact that the unit tests all pass indicates that it isn't happening. Reviewed-by: Laine Stump <laine@laine.org>
src/conf/domain_addr.c | 43 +++++++------------------------------------ src/conf/domain_addr.h | 2 -- 2 files changed, 7 insertions(+), 38 deletions(-)
diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index 6fd8bfc..d173766 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -741,34 +741,26 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, virDomainPCIConnectFlags flags, int function) { - /* default to starting the search for a free slot from - * the first slot of domain 0 bus 0... - */ virPCIDeviceAddress a = { 0 }; - bool found = false;
if (addrs->nbuses == 0) { virReportError(VIR_ERR_XML_ERROR, "%s", _("No PCI buses available")); goto error; }
- /* ...unless this search is for the exact same type of device as - * last time, then continue the search from the slot where we - * found the previous match (it's possible there will still be a - * function available on that slot). - */ - if (flags == addrs->lastFlags) - a = addrs->lastaddr; - else - a.slot = addrs->buses[0].minSlot; - /* if the caller asks for "any function", give them function 0 */ if (function == -1) a.function = 0; else a.function = function;
- while (a.bus < addrs->nbuses) { + /* "Begin at the beginning," the King said, very gravely, "and go on + * till you come to the end: then stop." */ + for (a.bus = 0; a.bus < addrs->nbuses; a.bus++) { + bool found = false; + + a.slot = addrs->buses[a.bus].minSlot; + if (virDomainPCIAddressFindUnusedFunctionOnBus(&addrs->buses[a.bus], &a, function, flags, &found) < 0) { @@ -777,10 +769,6 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs,
if (found) goto success; - - /* nothing on this bus, go to the next bus */ - if (++a.bus < addrs->nbuses) - a.slot = addrs->buses[a.bus].minSlot; }
/* There were no free slots after the last used one */ @@ -791,20 +779,6 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, /* this device will use the first slot of the new bus */ a.slot = addrs->buses[a.bus].minSlot; goto success; - } else if (flags == addrs->lastFlags) { - /* Check the buses from 0 up to the last used one */ - for (a.bus = 0; a.bus <= addrs->lastaddr.bus; a.bus++) { - a.slot = addrs->buses[a.bus].minSlot; - - if (virDomainPCIAddressFindUnusedFunctionOnBus(&addrs->buses[a.bus], - &a, function, - flags, &found) < 0) { - goto error; - } - - if (found) - goto success; - } }
virReportError(VIR_ERR_INTERNAL_ERROR, @@ -851,9 +825,6 @@ virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags, false) < 0) return -1;
- addrs->lastaddr = addr; - addrs->lastFlags = flags; - if (!addrs->dryRun) { dev->type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; dev->addr.pci = addr; diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 77e19bb..7704061 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -106,8 +106,6 @@ typedef virDomainPCIAddressBus *virDomainPCIAddressBusPtr; struct _virDomainPCIAddressSet { virDomainPCIAddressBus *buses; size_t nbuses; - virPCIDeviceAddress lastaddr; - virDomainPCIConnectFlags lastFlags; bool dryRun; /* on a dry run, new buses are auto-added and addresses aren't saved in device infos */ };

We will soon need to be able to return a NULL pointer without the caller considering that an error: to make it possible, change the return type to int and use an out parameter for the string instead. Add some documentation for the function as well. --- src/qemu/qemu_command.c | 53 ++++++++++++++++++++++++++++++++++++------------- src/qemu/qemu_command.h | 9 +++++---- src/qemu/qemu_hotplug.c | 5 ++++- 3 files changed, 48 insertions(+), 19 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 015af10..a0403bf 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -2664,10 +2664,31 @@ qemuCheckSCSIControllerIOThreads(const virDomainDef *domainDef, } -char * +/** + * qemuBuildControllerDevStr: + * @domainDef: domain definition + * @def: controller definition + * @qemuCaps: QEMU binary capabilities + * @devstr: device string + * @nusbcontroller: number of USB controllers + * + * Turn @def into a description of the controller that QEMU will understand, + * to be used either on the command line or through the monitor. + * + * The description will be returned in @devstr and can be NULL, eg. when + * passing in one of the built-in controllers. The returned string must be + * freed by the caller. + * + * The number pointed to by @nusbcontroller will be increased by one every + * time the description for a USB controller has been generated successfully. + * + * Returns: 0 on success, <0 on failure + */ +int qemuBuildControllerDevStr(const virDomainDef *domainDef, virDomainControllerDefPtr def, virQEMUCapsPtr qemuCaps, + char **devstr, int *nusbcontroller) { virBuffer buf = VIR_BUFFER_INITIALIZER; @@ -2676,11 +2697,11 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, if (!qemuCheckCCWS390AddressSupport(domainDef, def->info, qemuCaps, "controller")) - return NULL; + return -1; if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) { if ((qemuDomainSetSCSIControllerModel(domainDef, qemuCaps, &model)) < 0) - return NULL; + return -1; } if (!(def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI && @@ -2688,22 +2709,22 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, if (def->queues) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("'queues' is only supported by virtio-scsi controller")); - return NULL; + return -1; } if (def->cmd_per_lun) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("'cmd_per_lun' is only supported by virtio-scsi controller")); - return NULL; + return -1; } if (def->max_sectors) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("'max_sectors' is only supported by virtio-scsi controller")); - return NULL; + return -1; } if (def->ioeventfd) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("'ioeventfd' is only supported by virtio-scsi controller")); - return NULL; + return -1; } } @@ -3114,11 +3135,12 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, if (virBufferCheckError(&buf) < 0) goto error; - return virBufferContentAndReset(&buf); + *devstr = virBufferContentAndReset(&buf); + return 0; error: virBufferFreeAndReset(&buf); - return NULL; + return -1; } @@ -3213,12 +3235,15 @@ qemuBuildControllerDevCommandLine(virCommandPtr cmd, continue; } - virCommandAddArg(cmd, "-device"); - if (!(devstr = qemuBuildControllerDevStr(def, cont, qemuCaps, - &usbcontroller))) + if (qemuBuildControllerDevStr(def, cont, qemuCaps, + &devstr, &usbcontroller) < 0) return -1; - virCommandAddArg(cmd, devstr); - VIR_FREE(devstr); + + if (devstr) { + virCommandAddArg(cmd, "-device"); + virCommandAddArg(cmd, devstr); + VIR_FREE(devstr); + } } } diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 09cb00e..9a2ab29 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -118,10 +118,11 @@ char *qemuBuildDriveDevStr(const virDomainDef *def, virQEMUCapsPtr qemuCaps); /* Current, best practice */ -char *qemuBuildControllerDevStr(const virDomainDef *domainDef, - virDomainControllerDefPtr def, - virQEMUCapsPtr qemuCaps, - int *nusbcontroller); +int qemuBuildControllerDevStr(const virDomainDef *domainDef, + virDomainControllerDefPtr def, + virQEMUCapsPtr qemuCaps, + char **devstr, + int *nusbcontroller); int qemuBuildMemoryBackendStr(virJSONValuePtr *backendProps, const char **backendType, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 4a7d997..f910012 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -523,7 +523,10 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver, if (qemuAssignDeviceControllerAlias(vm->def, priv->qemuCaps, controller) < 0) goto cleanup; - if (!(devstr = qemuBuildControllerDevStr(vm->def, controller, priv->qemuCaps, NULL))) + if (qemuBuildControllerDevStr(vm->def, controller, priv->qemuCaps, &devstr, NULL) < 0) + goto cleanup; + + if (!devstr) goto cleanup; if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers+1) < 0) -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
We will soon need to be able to return a NULL pointer without the caller considering that an error: to make it possible, change the return type to int and use an out parameter for the string instead.
Add some documentation for the function as well. --- src/qemu/qemu_command.c | 53 ++++++++++++++++++++++++++++++++++++------------- src/qemu/qemu_command.h | 9 +++++---- src/qemu/qemu_hotplug.c | 5 ++++- 3 files changed, 48 insertions(+), 19 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 015af10..a0403bf 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -2664,10 +2664,31 @@ qemuCheckSCSIControllerIOThreads(const virDomainDef *domainDef, }
-char * +/** + * qemuBuildControllerDevStr: + * @domainDef: domain definition + * @def: controller definition + * @qemuCaps: QEMU binary capabilities + * @devstr: device string + * @nusbcontroller: number of USB controllers + * + * Turn @def into a description of the controller that QEMU will understand, + * to be used either on the command line or through the monitor. + * + * The description will be returned in @devstr and can be NULL, eg. when + * passing in one of the built-in controllers. The returned string must be + * freed by the caller. + * + * The number pointed to by @nusbcontroller will be increased by one every + * time the description for a USB controller has been generated successfully. + * + * Returns: 0 on success, <0 on failure + */ +int qemuBuildControllerDevStr(const virDomainDef *domainDef, virDomainControllerDefPtr def, virQEMUCapsPtr qemuCaps, + char **devstr, int *nusbcontroller) { virBuffer buf = VIR_BUFFER_INITIALIZER;
Maybe initialize *devstr to NULL in case the caller hasn't? Reviewed-by: Laine Stump <laine@laine.org>
@@ -2676,11 +2697,11 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef,
if (!qemuCheckCCWS390AddressSupport(domainDef, def->info, qemuCaps, "controller")) - return NULL; + return -1;
if (def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI) { if ((qemuDomainSetSCSIControllerModel(domainDef, qemuCaps, &model)) < 0) - return NULL; + return -1; }
if (!(def->type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI && @@ -2688,22 +2709,22 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, if (def->queues) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("'queues' is only supported by virtio-scsi controller")); - return NULL; + return -1; } if (def->cmd_per_lun) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("'cmd_per_lun' is only supported by virtio-scsi controller")); - return NULL; + return -1; } if (def->max_sectors) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("'max_sectors' is only supported by virtio-scsi controller")); - return NULL; + return -1; } if (def->ioeventfd) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("'ioeventfd' is only supported by virtio-scsi controller")); - return NULL; + return -1; } }
@@ -3114,11 +3135,12 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, if (virBufferCheckError(&buf) < 0) goto error;
- return virBufferContentAndReset(&buf); + *devstr = virBufferContentAndReset(&buf); + return 0;
error: virBufferFreeAndReset(&buf); - return NULL; + return -1; }
@@ -3213,12 +3235,15 @@ qemuBuildControllerDevCommandLine(virCommandPtr cmd, continue; }
- virCommandAddArg(cmd, "-device"); - if (!(devstr = qemuBuildControllerDevStr(def, cont, qemuCaps, - &usbcontroller))) + if (qemuBuildControllerDevStr(def, cont, qemuCaps, + &devstr, &usbcontroller) < 0) return -1; - virCommandAddArg(cmd, devstr); - VIR_FREE(devstr); + + if (devstr) { + virCommandAddArg(cmd, "-device"); + virCommandAddArg(cmd, devstr); + VIR_FREE(devstr); + } } }
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 09cb00e..9a2ab29 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -118,10 +118,11 @@ char *qemuBuildDriveDevStr(const virDomainDef *def, virQEMUCapsPtr qemuCaps);
/* Current, best practice */ -char *qemuBuildControllerDevStr(const virDomainDef *domainDef, - virDomainControllerDefPtr def, - virQEMUCapsPtr qemuCaps, - int *nusbcontroller); +int qemuBuildControllerDevStr(const virDomainDef *domainDef, + virDomainControllerDefPtr def, + virQEMUCapsPtr qemuCaps, + char **devstr, + int *nusbcontroller);
int qemuBuildMemoryBackendStr(virJSONValuePtr *backendProps, const char **backendType, diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 4a7d997..f910012 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -523,7 +523,10 @@ int qemuDomainAttachControllerDevice(virQEMUDriverPtr driver, if (qemuAssignDeviceControllerAlias(vm->def, priv->qemuCaps, controller) < 0) goto cleanup;
- if (!(devstr = qemuBuildControllerDevStr(vm->def, controller, priv->qemuCaps, NULL))) + if (qemuBuildControllerDevStr(vm->def, controller, priv->qemuCaps, &devstr, NULL) < 0) + goto cleanup; + + if (!devstr) goto cleanup;
if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers+1) < 0)

Moving the check and rewriting it this way doesn't alter the current behavior, but will allow us to special-case pci-root down the line. --- src/qemu/qemu_command.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index a0403bf..082ffa9 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -2828,6 +2828,26 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, case VIR_DOMAIN_CONTROLLER_TYPE_PCI: switch ((virDomainControllerModelPCI) def->model) { case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE: + case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS: + if (def->idx == 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("index for pci controllers of model '%s' must be > 0"), + virDomainControllerModelPCITypeToString(def->model)); + goto error; + } + break; + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST: + break; + } + switch ((virDomainControllerModelPCI) def->model) { + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE: if (def->opts.pciopts.modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE || def->opts.pciopts.chassisNr == -1) { @@ -3086,12 +3106,6 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, _("wrong function called")); goto error; } - if (def->idx == 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("index for pci controllers of model '%s' must be > 0"), - virDomainControllerModelPCITypeToString(def->model)); - goto error; - } break; case VIR_DOMAIN_CONTROLLER_TYPE_IDE: -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
Moving the check and rewriting it this way doesn't alter the current behavior, but will allow us to special-case pci-root down the line.
But this function should never be called for a controller with model='pci-root'?
--- src/qemu/qemu_command.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index a0403bf..082ffa9 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -2828,6 +2828,26 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, case VIR_DOMAIN_CONTROLLER_TYPE_PCI: switch ((virDomainControllerModelPCI) def->model) { case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE: + case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_DOWNSTREAM_PORT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_EXPANDER_BUS: + if (def->idx == 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("index for pci controllers of model '%s' must be > 0"), + virDomainControllerModelPCITypeToString(def->model)); + goto error; + } + break; + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST: + break; + } + switch ((virDomainControllerModelPCI) def->model) { + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE: if (def->opts.pciopts.modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE || def->opts.pciopts.chassisNr == -1) { @@ -3086,12 +3106,6 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, _("wrong function called")); goto error; } - if (def->idx == 0) { - virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("index for pci controllers of model '%s' must be > 0"), - virDomainControllerModelPCITypeToString(def->model)); - goto error; - } break;
case VIR_DOMAIN_CONTROLLER_TYPE_IDE:

On Mon, 2017-06-12 at 22:02 -0400, Laine Stump wrote:
Moving the check and rewriting it this way doesn't alter the current behavior, but will allow us to special-case pci-root down the line.
But this function should never be called for a controller with model='pci-root'?
<spoilers> It will, later on ;) </spoilers> -- Andrea Bolognani / Red Hat / Virtualization

On 06/13/2017 06:22 AM, Andrea Bolognani wrote:
On Mon, 2017-06-12 at 22:02 -0400, Laine Stump wrote:
Moving the check and rewriting it this way doesn't alter the current behavior, but will allow us to special-case pci-root down the line.
But this function should never be called for a controller with model='pci-root'?
<spoilers> It will, later on ;) </spoilers>
Right. My brain is *slowly* waking up. So ACK, or Reviewed-by: Laine Stump <laine@laine.org> if you prefer. (Looking back at that function, it could be made a lot more compact by combining all the different models' checks for modelName != NONE as well. Again, that's irrelevant to your patches).

pSeries guests will soon be allowed to have multiple PHBs (pci-root controllers), which of course means that all but one of them will have a non-zero index; hence, we'll need to relax the current check. However, right now the check is performed in the conf module, which is generic rather than tied to the QEMU driver, and where we don't have information such as the guest machine type available. To make this change of behavior possible down the line, we need to move the check from the XML parser to the driver. Unfortunately, this means duplicating code :( --- src/bhyve/bhyve_domain.c | 15 +++++++++++++++ src/conf/domain_conf.c | 6 ------ src/libxl/libxl_domain.c | 14 ++++++++++++++ src/lxc/lxc_domain.c | 14 ++++++++++++++ src/openvz/openvz_driver.c | 14 ++++++++++++++ src/qemu/qemu_domain.c | 9 +++++++++ src/uml/uml_driver.c | 14 ++++++++++++++ src/vz/vz_driver.c | 14 ++++++++++++++ src/xen/xen_driver.c | 14 ++++++++++++++ 9 files changed, 108 insertions(+), 6 deletions(-) diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c index 76b4fac..05c1508 100644 --- a/src/bhyve/bhyve_domain.c +++ b/src/bhyve/bhyve_domain.c @@ -122,6 +122,21 @@ bhyveDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, bhyveDomainDiskDefAssignAddress(driver, disk, def) < 0) return -1; } + + if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; } diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index c7e20b8..d5dff8e 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -9059,12 +9059,6 @@ virDomainControllerDefParseXML(xmlNodePtr node, "have an address")); goto error; } - if (def->idx > 0) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("pci-root and pcie-root controllers " - "should have index 0")); - goto error; - } if ((rc = virDomainParseScaledValue("./pcihole64", NULL, ctxt, &bytes, 1024, 1024ULL * ULONG_MAX, false)) < 0) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 256cf1d..59ef2fb 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -379,6 +379,20 @@ libxlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW); } + if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; } diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c index 3a7404f..a50f6fe 100644 --- a/src/lxc/lxc_domain.c +++ b/src/lxc/lxc_domain.c @@ -389,6 +389,20 @@ virLXCDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE) dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_LXC; + if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; } diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 9c4a196..058d830 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -127,6 +127,20 @@ openvzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, return -1; } + if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; } diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 0a85ee9..18512cb 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3404,6 +3404,15 @@ qemuDomainControllerDefPostParse(virDomainControllerDefPtr cont, break; case VIR_DOMAIN_CONTROLLER_TYPE_PCI: + if ((cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS && !qemuDomainIsI440FX(def)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 03edc89..d9df3c5 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -426,6 +426,20 @@ umlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, return -1; } + if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; } diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index ef7b453..e988e7c 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -283,6 +283,20 @@ vzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, VIR_STRDUP(dev->data.net->model, "e1000") < 0) return -1; + if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; } diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 4d14089..b681764 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -362,6 +362,20 @@ xenDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, } } + if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; } -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
pSeries guests will soon be allowed to have multiple PHBs (pci-root controllers), which of course means that all but one of them will have a non-zero index; hence, we'll need to relax the current check.
However, right now the check is performed in the conf module, which is generic rather than tied to the QEMU driver, and where we don't have information such as the guest machine type available.
To make this change of behavior possible down the line, we need to move the check from the XML parser to the driver. Unfortunately, this means duplicating code :(\
Maybe instead we should just eliminate this check (since the pSeries case shows that it's an invalid assumption). And since the index is really just something used internally by libvirt, we really don't even need to verify that one of the pci controllers has index=0. All we *really* care about is that there is at least one "root" PCI bus, and that no device includes a bus# in its PCI address that isn't represented by the index in one of the PCI controllers. (But for the purposes of this patch, I think we can just remove the validation in conf and not worry about adding it elsewhere).
--- src/bhyve/bhyve_domain.c | 15 +++++++++++++++ src/conf/domain_conf.c | 6 ------ src/libxl/libxl_domain.c | 14 ++++++++++++++ src/lxc/lxc_domain.c | 14 ++++++++++++++ src/openvz/openvz_driver.c | 14 ++++++++++++++ src/qemu/qemu_domain.c | 9 +++++++++ src/uml/uml_driver.c | 14 ++++++++++++++ src/vz/vz_driver.c | 14 ++++++++++++++ src/xen/xen_driver.c | 14 ++++++++++++++ 9 files changed, 108 insertions(+), 6 deletions(-)
diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c index 76b4fac..05c1508 100644 --- a/src/bhyve/bhyve_domain.c +++ b/src/bhyve/bhyve_domain.c @@ -122,6 +122,21 @@ bhyveDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, bhyveDomainDiskDefAssignAddress(driver, disk, def) < 0) return -1; } + + if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; }
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index c7e20b8..d5dff8e 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -9059,12 +9059,6 @@ virDomainControllerDefParseXML(xmlNodePtr node, "have an address")); goto error; } - if (def->idx > 0) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("pci-root and pcie-root controllers " - "should have index 0")); - goto error; - } if ((rc = virDomainParseScaledValue("./pcihole64", NULL, ctxt, &bytes, 1024, 1024ULL * ULONG_MAX, false)) < 0) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 256cf1d..59ef2fb 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -379,6 +379,20 @@ libxlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW); }
+ if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; }
diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c index 3a7404f..a50f6fe 100644 --- a/src/lxc/lxc_domain.c +++ b/src/lxc/lxc_domain.c @@ -389,6 +389,20 @@ virLXCDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE) dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_LXC;
+ if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; }
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 9c4a196..058d830 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -127,6 +127,20 @@ openvzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, return -1; }
+ if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; }
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 0a85ee9..18512cb 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3404,6 +3404,15 @@ qemuDomainControllerDefPostParse(virDomainControllerDefPtr cont, break;
case VIR_DOMAIN_CONTROLLER_TYPE_PCI: + if ((cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS && !qemuDomainIsI440FX(def)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 03edc89..d9df3c5 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -426,6 +426,20 @@ umlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, return -1; }
+ if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; }
diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index ef7b453..e988e7c 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -283,6 +283,20 @@ vzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, VIR_STRDUP(dev->data.net->model, "e1000") < 0) return -1;
+ if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; }
diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 4d14089..b681764 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -362,6 +362,20 @@ xenDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, } }
+ if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; }

On 06/12/2017 10:08 PM, Laine Stump wrote:
On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
pSeries guests will soon be allowed to have multiple PHBs (pci-root controllers), which of course means that all but one of them will have a non-zero index; hence, we'll need to relax the current check.
However, right now the check is performed in the conf module, which is generic rather than tied to the QEMU driver, and where we don't have information such as the guest machine type available.
To make this change of behavior possible down the line, we need to move the check from the XML parser to the driver. Unfortunately, this means duplicating code :(\
Maybe instead we should just eliminate this check (since the pSeries case shows that it's an invalid assumption). And since the index is really just something used internally by libvirt, we really don't even need to verify that one of the pci controllers has index=0. All we *really* care about is that there is at least one "root" PCI bus, and that no device includes a bus# in its PCI address that isn't represented by the index in one of the PCI controllers.
(But for the purposes of this patch, I think we can just remove the validation in conf and not worry about adding it elsewhere).\\
After looking at the next patch, I may have changed my mind. If we remove the validation here, then we would still have to add in validation when the commandline is generated. But I suppose it's better to give an error at domain definition time rather than domain runtime, so this makes sense. I don't think all of those drivers actually use PCI controllers though, do they? (Look for which ones actually call the functions to assign PCI addresses).
--- src/bhyve/bhyve_domain.c | 15 +++++++++++++++ src/conf/domain_conf.c | 6 ------ src/libxl/libxl_domain.c | 14 ++++++++++++++ src/lxc/lxc_domain.c | 14 ++++++++++++++ src/openvz/openvz_driver.c | 14 ++++++++++++++ src/qemu/qemu_domain.c | 9 +++++++++ src/uml/uml_driver.c | 14 ++++++++++++++ src/vz/vz_driver.c | 14 ++++++++++++++ src/xen/xen_driver.c | 14 ++++++++++++++ 9 files changed, 108 insertions(+), 6 deletions(-)
diff --git a/src/bhyve/bhyve_domain.c b/src/bhyve/bhyve_domain.c index 76b4fac..05c1508 100644 --- a/src/bhyve/bhyve_domain.c +++ b/src/bhyve/bhyve_domain.c @@ -122,6 +122,21 @@ bhyveDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, bhyveDomainDiskDefAssignAddress(driver, disk, def) < 0) return -1; } + + if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; }
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index c7e20b8..d5dff8e 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -9059,12 +9059,6 @@ virDomainControllerDefParseXML(xmlNodePtr node, "have an address")); goto error; } - if (def->idx > 0) { - virReportError(VIR_ERR_XML_ERROR, "%s", - _("pci-root and pcie-root controllers " - "should have index 0")); - goto error; - } if ((rc = virDomainParseScaledValue("./pcihole64", NULL, ctxt, &bytes, 1024, 1024ULL * ULONG_MAX, false)) < 0) diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c index 256cf1d..59ef2fb 100644 --- a/src/libxl/libxl_domain.c +++ b/src/libxl/libxl_domain.c @@ -379,6 +379,20 @@ libxlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW); }
+ if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; }
diff --git a/src/lxc/lxc_domain.c b/src/lxc/lxc_domain.c index 3a7404f..a50f6fe 100644 --- a/src/lxc/lxc_domain.c +++ b/src/lxc/lxc_domain.c @@ -389,6 +389,20 @@ virLXCDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE) dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_LXC;
+ if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; }
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c index 9c4a196..058d830 100644 --- a/src/openvz/openvz_driver.c +++ b/src/openvz/openvz_driver.c @@ -127,6 +127,20 @@ openvzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, return -1; }
+ if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; }
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 0a85ee9..18512cb 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3404,6 +3404,15 @@ qemuDomainControllerDefPostParse(virDomainControllerDefPtr cont, break;
case VIR_DOMAIN_CONTROLLER_TYPE_PCI: + if ((cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_EXPANDER_BUS && !qemuDomainIsI440FX(def)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", diff --git a/src/uml/uml_driver.c b/src/uml/uml_driver.c index 03edc89..d9df3c5 100644 --- a/src/uml/uml_driver.c +++ b/src/uml/uml_driver.c @@ -426,6 +426,20 @@ umlDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, return -1; }
+ if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; }
diff --git a/src/vz/vz_driver.c b/src/vz/vz_driver.c index ef7b453..e988e7c 100644 --- a/src/vz/vz_driver.c +++ b/src/vz/vz_driver.c @@ -283,6 +283,20 @@ vzDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, VIR_STRDUP(dev->data.net->model, "e1000") < 0) return -1;
+ if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; }
diff --git a/src/xen/xen_driver.c b/src/xen/xen_driver.c index 4d14089..b681764 100644 --- a/src/xen/xen_driver.c +++ b/src/xen/xen_driver.c @@ -362,6 +362,20 @@ xenDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, } }
+ if (dev->type == VIR_DOMAIN_DEVICE_CONTROLLER) { + virDomainControllerDefPtr cont = dev->data.controller; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("pci-root and pcie-root controllers " + "should have index 0")); + return -1; + } + } + return 0; }
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On 06/12/2017 10:14 PM, Laine Stump wrote:
On 06/12/2017 10:08 PM, Laine Stump wrote:
On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
pSeries guests will soon be allowed to have multiple PHBs (pci-root controllers), which of course means that all but one of them will have a non-zero index; hence, we'll need to relax the current check.
However, right now the check is performed in the conf module, which is generic rather than tied to the QEMU driver, and where we don't have information such as the guest machine type available.
To make this change of behavior possible down the line, we need to move the check from the XML parser to the driver. Unfortunately, this means duplicating code :(\
Maybe instead we should just eliminate this check (since the pSeries case shows that it's an invalid assumption). And since the index is really just something used internally by libvirt, we really don't even need to verify that one of the pci controllers has index=0. All we *really* care about is that there is at least one "root" PCI bus, and that no device includes a bus# in its PCI address that isn't represented by the index in one of the PCI controllers.
(But for the purposes of this patch, I think we can just remove the validation in conf and not worry about adding it elsewhere).\\
After looking at the next patch, I may have changed my mind. If we remove the validation here, then we would still have to add in validation when the commandline is generated. But I suppose it's better to give an error at domain definition time rather than domain runtime, so this makes sense. I don't think all of those drivers actually use PCI controllers though, do they? (Look for which ones actually call the functions to assign PCI addresses).
Refreshing my memory by looking at the code - I think only the qemu driver and bhyve driver assign PCI addresses (they're certainly the only ones that use VIR_DOMAIN_CONTROLLER_TYPE_PCI or VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT, or call virDomainPCIAddressReserveNextAddr()). So I'm fairly certain you only need to add the check in those two drivers. (Additionally, bhyve only supports pci-root, not pcie-root - see src/bhyve/bhyve_command.c:509) So, ACK if you remove the extra checks in all the other drivers aside from qemu and bhyve.

pSeries guests will soon be allowed to have multiple PHBs (pci-root controllers), meaning the current check on the controller index no longer applies to them. --- src/qemu/qemu_domain.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 18512cb..7dc90fd 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3404,9 +3404,14 @@ qemuDomainControllerDefPostParse(virDomainControllerDefPtr cont, break; case VIR_DOMAIN_CONTROLLER_TYPE_PCI: - if ((cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || - cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && - cont->idx != 0) { + + /* pSeries guests can have multiple pci-root controllers, + * but other machine types only support a single one */ + if (!qemuDomainIsPSeries(def) && + cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { virReportError(VIR_ERR_XML_ERROR, "%s", _("pci-root and pcie-root controllers " "should have index 0")); -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
pSeries guests will soon be allowed to have multiple PHBs (pci-root controllers), meaning the current check on the controller index no longer applies to them. --- src/qemu/qemu_domain.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 18512cb..7dc90fd 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -3404,9 +3404,14 @@ qemuDomainControllerDefPostParse(virDomainControllerDefPtr cont, break;
case VIR_DOMAIN_CONTROLLER_TYPE_PCI: - if ((cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || - cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && - cont->idx != 0) { + + /* pSeries guests can have multiple pci-root controllers, + * but other machine types only support a single one */ + if (!qemuDomainIsPSeries(def) && + cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) && + cont->idx != 0) { virReportError(VIR_ERR_XML_ERROR, "%s", _("pci-root and pcie-root controllers " "should have index 0"));
Reviewed-by: Laine Stump <laine@laine.org>

--- docs/schemas/domaincommon.rng | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 4d9f8d1..cff595b 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1996,6 +1996,11 @@ </attribute> </optional> <optional> + <attribute name='index'> + <ref name='uint8'/> + </attribute> + </optional> + <optional> <element name='node'> <ref name='unsignedInt'/> </element> -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
--- docs/schemas/domaincommon.rng | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 4d9f8d1..cff595b 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1996,6 +1996,11 @@ </attribute> </optional> <optional> + <attribute name='index'> + <ref name='uint8'/> + </attribute> + </optional> + <optional> <element name='node'> <ref name='unsignedInt'/> </element>
I always just put the schema changes in the same patch as the parser/formatter changes (along with documentation in formatdomain.html.in - I know you said in your epic synopsis that you have documentation patches planned, but in the past we've required an addition to format*.html.in before ACKing any patch that added to the parser/formatter/schema).

On Tue, 2017-06-13 at 17:53 -0400, Laine Stump wrote:
I always just put the schema changes in the same patch as theA parser/formatter changes (along with documentation in formatdomain.html.in - I know you said in your epic synopsis that you have documentation patches planned, but in the past we've required an addition to format*.html.in before ACKing any patch that added to the parser/formatter/schema).
Sure, I can have it all squashed together in a single commit in v2 if you prefer it that way. -- Andrea Bolognani / Red Hat / Virtualization

--- src/conf/domain_conf.c | 24 ++++++++++++++++++++++++ src/conf/domain_conf.h | 1 + 2 files changed, 25 insertions(+) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index d5dff8e..deb0dce 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1803,6 +1803,7 @@ virDomainControllerDefNew(virDomainControllerType type) def->opts.pciopts.chassis = -1; def->opts.pciopts.port = -1; def->opts.pciopts.busNr = -1; + def->opts.pciopts.idx = -1; def->opts.pciopts.numaNode = -1; break; case VIR_DOMAIN_CONTROLLER_TYPE_IDE: @@ -8909,6 +8910,7 @@ virDomainControllerDefParseXML(xmlNodePtr node, goto error; } def->idx = idxVal; + VIR_FREE(idx); } cur = node->children; @@ -8940,6 +8942,7 @@ virDomainControllerDefParseXML(xmlNodePtr node, chassis = virXMLPropString(cur, "chassis"); port = virXMLPropString(cur, "port"); busNr = virXMLPropString(cur, "busNr"); + idx = virXMLPropString(cur, "index"); processedTarget = true; } } @@ -9155,6 +9158,23 @@ virDomainControllerDefParseXML(xmlNodePtr node, goto error; } } + if (idx) { + if (virStrToLong_i(idx, NULL, 0, + &def->opts.pciopts.idx) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Invalid index '%s' in PCI controller"), + idx); + goto error; + } + if (def->opts.pciopts.idx < 0 || + def->opts.pciopts.idx > 31) { + virReportError(VIR_ERR_XML_ERROR, + _("PCI controller index '%s' out of range " + "- must be 0-31"), + idx); + goto error; + } + } if (numaNode >= 0) def->opts.pciopts.numaNode = numaNode; break; @@ -21413,6 +21433,7 @@ virDomainControllerDefFormat(virBufferPtr buf, def->opts.pciopts.chassis != -1 || def->opts.pciopts.port != -1 || def->opts.pciopts.busNr != -1 || + def->opts.pciopts.idx != -1 || def->opts.pciopts.numaNode != -1) pciTarget = true; break; @@ -21453,6 +21474,9 @@ virDomainControllerDefFormat(virBufferPtr buf, if (def->opts.pciopts.busNr != -1) virBufferAsprintf(buf, " busNr='%d'", def->opts.pciopts.busNr); + if (def->opts.pciopts.idx != -1) + virBufferAsprintf(buf, " index='%d'", + def->opts.pciopts.idx); if (def->opts.pciopts.numaNode == -1) { virBufferAddLit(buf, "/>\n"); } else { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 83e0672..5a21289 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -780,6 +780,7 @@ struct _virDomainPCIControllerOpts { int chassis; int port; int busNr; /* used by pci-expander-bus, -1 == unspecified */ + int idx; /* used by spapr-pci-host-bridge, -1 == unspecified */ /* numaNode is a *subelement* of target (to match existing * item in memory target config) -1 == unspecified */ -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
--- src/conf/domain_conf.c | 24 ++++++++++++++++++++++++ src/conf/domain_conf.h | 1 + 2 files changed, 25 insertions(+)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index d5dff8e..deb0dce 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1803,6 +1803,7 @@ virDomainControllerDefNew(virDomainControllerType type) def->opts.pciopts.chassis = -1; def->opts.pciopts.port = -1; def->opts.pciopts.busNr = -1; + def->opts.pciopts.idx = -1; def->opts.pciopts.numaNode = -1; break; case VIR_DOMAIN_CONTROLLER_TYPE_IDE: @@ -8909,6 +8910,7 @@ virDomainControllerDefParseXML(xmlNodePtr node, goto error; } def->idx = idxVal; + VIR_FREE(idx); }
cur = node->children; @@ -8940,6 +8942,7 @@ virDomainControllerDefParseXML(xmlNodePtr node, chassis = virXMLPropString(cur, "chassis"); port = virXMLPropString(cur, "port"); busNr = virXMLPropString(cur, "busNr"); + idx = virXMLPropString(cur, "index"); processedTarget = true; } } @@ -9155,6 +9158,23 @@ virDomainControllerDefParseXML(xmlNodePtr node, goto error; } } + if (idx) { + if (virStrToLong_i(idx, NULL, 0, + &def->opts.pciopts.idx) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Invalid index '%s' in PCI controller"),
You should probably say "target index" to differentiate it from the toplevel index.
+ idx); + goto error; + } + if (def->opts.pciopts.idx < 0 || + def->opts.pciopts.idx > 31) { + virReportError(VIR_ERR_XML_ERROR, + _("PCI controller index '%s' out of range " + "- must be 0-31"),
Same here. Other than that, what about an xml2xml test case? (as well as combining with the previous patch, and adding a sentence to formatdomain.html.in)
+ idx); + goto error; + } + } if (numaNode >= 0) def->opts.pciopts.numaNode = numaNode; break; @@ -21413,6 +21433,7 @@ virDomainControllerDefFormat(virBufferPtr buf, def->opts.pciopts.chassis != -1 || def->opts.pciopts.port != -1 || def->opts.pciopts.busNr != -1 || + def->opts.pciopts.idx != -1 || def->opts.pciopts.numaNode != -1) pciTarget = true; break; @@ -21453,6 +21474,9 @@ virDomainControllerDefFormat(virBufferPtr buf, if (def->opts.pciopts.busNr != -1) virBufferAsprintf(buf, " busNr='%d'", def->opts.pciopts.busNr); + if (def->opts.pciopts.idx != -1) + virBufferAsprintf(buf, " index='%d'", + def->opts.pciopts.idx); if (def->opts.pciopts.numaNode == -1) { virBufferAddLit(buf, "/>\n"); } else { diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 83e0672..5a21289 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -780,6 +780,7 @@ struct _virDomainPCIControllerOpts { int chassis; int port; int busNr; /* used by pci-expander-bus, -1 == unspecified */ + int idx; /* used by spapr-pci-host-bridge, -1 == unspecified */ /* numaNode is a *subelement* of target (to match existing * item in memory target config) -1 == unspecified */

On Tue, 2017-06-13 at 17:59 -0400, Laine Stump wrote:
@@ -9155,6 +9158,23 @@ virDomainControllerDefParseXML(xmlNodePtr node, goto error; } } + if (idx) { + if (virStrToLong_i(idx, NULL, 0, + &def->opts.pciopts.idx) < 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Invalid index '%s' in PCI controller"), You should probably say "target index" to differentiate it from the toplevel index.
I agree and was in fact planning to change it just the way you suggested, I just forgot O:-)
Other than that, what about an xml2xml test case? (as well as combining with the previous patch, and adding a sentence to formatdomain.html.in)
Test cases (both argv2xml and xml2xml) are added in patch 19/26, that is, after adding the code that fills in the target index automatically. I'd prefer keeping it that way so that they excercise the entire functionality at once. -- Andrea Bolognani / Red Hat / Virtualization

--- docs/schemas/domaincommon.rng | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index cff595b..d565a0b 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1953,6 +1953,8 @@ <element name="model"> <attribute name="name"> <choice> + <!-- implementations of 'pci-root' --> + <value>spapr-pci-host-bridge</value> <!-- implementations of 'pci-bridge' --> <value>pci-bridge</value> <!-- implementations of 'dmi-to-pci-bridge' --> -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
--- docs/schemas/domaincommon.rng | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index cff595b..d565a0b 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -1953,6 +1953,8 @@ <element name="model"> <attribute name="name"> <choice> + <!-- implementations of 'pci-root' --> + <value>spapr-pci-host-bridge</value> <!-- implementations of 'pci-bridge' --> <value>pci-bridge</value> <!-- implementations of 'dmi-to-pci-bridge' -->
As with 11/26 and 12/26 - ACK to 13 & 14/26, but combined, and with a sentence added to formatdomain.html.in *and* an xml2xml test case. (and I assume the validation to disallow this model name for anything other than pci-root is in a later patch?

On Tue, 2017-06-13 at 21:39 -0400, Laine Stump wrote:
(and I assume the validation to disallow this model name for anything other than pci-root is in a later patch?
It's actually already in place: qemuBuildControllerDevStr() contains whitelist-style checks that only allow eg. ioh3420 or pcie-root-port to be used as model names for a PCIe Root Ports, so the new model name will automatically be rejected. -- Andrea Bolognani / Red Hat / Virtualization

Adding it to the virDomainControllerPCIModelName enumeration is enough for existing code to handle it, so parsing and formatting will work without further tweaking. --- src/conf/domain_conf.c | 1 + src/conf/domain_conf.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index deb0dce..10998ea 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -343,6 +343,7 @@ VIR_ENUM_IMPL(virDomainControllerPCIModelName, "pxb", "pxb-pcie", "pcie-root-port", + "spapr-pci-host-bridge", ); VIR_ENUM_IMPL(virDomainControllerModelSCSI, VIR_DOMAIN_CONTROLLER_MODEL_SCSI_LAST, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 5a21289..244977a 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -705,6 +705,7 @@ typedef enum { VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB, VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB_PCIE, VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PCIE_ROOT_PORT, + VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE, VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_LAST } virDomainControllerPCIModelName; -- 2.7.5

pSeries guests will soon need the new information; luckily, we can figure it out automatically most of the time, so users won't have to bother with it. --- src/qemu/qemu_domain_address.c | 57 +++++++++++++++++++++- .../qemuargv2xmldata/qemuargv2xml-pseries-disk.xml | 5 +- .../qemuargv2xml-pseries-nvram.xml | 5 +- .../qemuxml2xmlout-panic-pseries.xml | 5 +- .../qemuxml2xmlout-ppc64-usb-controller-legacy.xml | 5 +- .../qemuxml2xmlout-ppc64-usb-controller.xml | 5 +- .../qemuxml2xmlout-pseries-nvram.xml | 5 +- .../qemuxml2xmlout-pseries-panic-missing.xml | 5 +- .../qemuxml2xmlout-pseries-panic-no-address.xml | 5 +- 9 files changed, 87 insertions(+), 10 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 2106b34..d46f8f7 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1856,6 +1856,7 @@ qemuDomainSupportsPCI(virDomainDefPtr def, static void qemuDomainPCIControllerSetDefaultModelName(virDomainControllerDefPtr cont, + virDomainDefPtr def, virQEMUCapsPtr qemuCaps) { int *modelName = &cont->opts.pciopts.modelName; @@ -1892,6 +1893,9 @@ qemuDomainPCIControllerSetDefaultModelName(virDomainControllerDefPtr cont, *modelName = VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB_PCIE; break; case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: + if (qemuDomainIsPSeries(def)) + *modelName = VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE; + break; case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST: break; @@ -1900,6 +1904,30 @@ qemuDomainPCIControllerSetDefaultModelName(virDomainControllerDefPtr cont, static int +qemuDomainAddressFindNewIndex(virDomainDefPtr def) +{ + int ret = 1; + size_t i; + + for (i = 0; i < def->ncontrollers; i++) { + virDomainControllerDefPtr cont = def->controllers[i]; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) { + if (cont->opts.pciopts.idx >= ret) + ret = cont->opts.pciopts.idx + 1; + } + } + + /* 0 is reserved for the implicit PHB, whereas anything lower + * than 0 or higher than 31 is invalid */ + if (ret > 31) + ret = -1; + + return ret; +} + + +static int qemuDomainAddressFindNewBusNr(virDomainDefPtr def) { /* Try to find a nice default for busNr for a new pci-expander-bus. @@ -2159,7 +2187,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, * device in qemu) for any controller that doesn't yet * have it set. */ - qemuDomainPCIControllerSetDefaultModelName(cont, qemuCaps); + qemuDomainPCIControllerSetDefaultModelName(cont, def, qemuCaps); /* set defaults for any other auto-generated config * options for this controller that haven't been @@ -2196,9 +2224,34 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, goto cleanup; } break; + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: + if (!qemuDomainIsPSeries(def)) + break; + if (options->idx == -1) { + if (cont->idx == 0) { + /* The pcie-root controller with controller index 0 + * must always be assigned target index 0, because + * it represents the implicit PHB which is treated + * differently than all other PHBs */ + options->idx = 0; + } else { + /* For all other PHBs the target index doesn't need + * to match the controller index or have any + * particular value, really */ + options->idx = qemuDomainAddressFindNewIndex(def); + } + } + if (options->idx == -1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("No valid index is available to " + "auto-assign to bus %d. Must be " + "manually assigned"), + addr->bus); + goto cleanup; + } + break; case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE: case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT: - case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST: break; diff --git a/tests/qemuargv2xmldata/qemuargv2xml-pseries-disk.xml b/tests/qemuargv2xmldata/qemuargv2xml-pseries-disk.xml index 1bad8ee..601d0f7 100644 --- a/tests/qemuargv2xmldata/qemuargv2xml-pseries-disk.xml +++ b/tests/qemuargv2xmldata/qemuargv2xml-pseries-disk.xml @@ -30,7 +30,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <controller type='scsi' index='0'> <address type='spapr-vio' reg='0x2000'/> </controller> diff --git a/tests/qemuargv2xmldata/qemuargv2xml-pseries-nvram.xml b/tests/qemuargv2xmldata/qemuargv2xml-pseries-nvram.xml index 7e9f864..7787847 100644 --- a/tests/qemuargv2xmldata/qemuargv2xml-pseries-nvram.xml +++ b/tests/qemuargv2xmldata/qemuargv2xml-pseries-nvram.xml @@ -17,7 +17,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <memballoon model='none'/> <nvram> <address type='spapr-vio' reg='0x4000'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-panic-pseries.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-panic-pseries.xml index 1ed11ce..7fb49fe 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-panic-pseries.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-panic-pseries.xml @@ -17,7 +17,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <serial type='pty'> <target port='0'/> <address type='spapr-vio' reg='0x30000000'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller-legacy.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller-legacy.xml index b7bde24..673b81d 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller-legacy.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller-legacy.xml @@ -22,7 +22,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <memballoon model='virtio'> <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </memballoon> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller.xml index 82aaaca..68995a9 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller.xml @@ -22,7 +22,10 @@ <controller type='usb' index='0' model='pci-ohci'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <memballoon model='virtio'> <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </memballoon> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-nvram.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-nvram.xml index 713f31c..f89b23b 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-nvram.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-nvram.xml @@ -17,7 +17,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <memballoon model='none'/> <nvram> <address type='spapr-vio' reg='0x4000'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-missing.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-missing.xml index 1ed11ce..7fb49fe 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-missing.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-missing.xml @@ -17,7 +17,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <serial type='pty'> <target port='0'/> <address type='spapr-vio' reg='0x30000000'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-no-address.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-no-address.xml index 1ed11ce..7fb49fe 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-no-address.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-no-address.xml @@ -17,7 +17,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <serial type='pty'> <target port='0'/> <address type='spapr-vio' reg='0x30000000'/> -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
pSeries guests will soon need the new information; luckily, we can figure it out automatically most of the time, so users won't have to bother with it. --- src/qemu/qemu_domain_address.c | 57 +++++++++++++++++++++- .../qemuargv2xmldata/qemuargv2xml-pseries-disk.xml | 5 +- .../qemuargv2xml-pseries-nvram.xml | 5 +- .../qemuxml2xmlout-panic-pseries.xml | 5 +- .../qemuxml2xmlout-ppc64-usb-controller-legacy.xml | 5 +- .../qemuxml2xmlout-ppc64-usb-controller.xml | 5 +- .../qemuxml2xmlout-pseries-nvram.xml | 5 +- .../qemuxml2xmlout-pseries-panic-missing.xml | 5 +- .../qemuxml2xmlout-pseries-panic-no-address.xml | 5 +- 9 files changed, 87 insertions(+), 10 deletions(-)
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 2106b34..d46f8f7 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1856,6 +1856,7 @@ qemuDomainSupportsPCI(virDomainDefPtr def,
static void qemuDomainPCIControllerSetDefaultModelName(virDomainControllerDefPtr cont, + virDomainDefPtr def, virQEMUCapsPtr qemuCaps) { int *modelName = &cont->opts.pciopts.modelName; @@ -1892,6 +1893,9 @@ qemuDomainPCIControllerSetDefaultModelName(virDomainControllerDefPtr cont, *modelName = VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB_PCIE; break; case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: + if (qemuDomainIsPSeries(def)) + *modelName = VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE; + break;
Just to verify - *all* the pci-roots on pSeries will be spapr-pci-host-bridge, even the first one?
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST: break; @@ -1900,6 +1904,30 @@ qemuDomainPCIControllerSetDefaultModelName(virDomainControllerDefPtr cont,
static int +qemuDomainAddressFindNewIndex(virDomainDefPtr def)
To help avoid confusion between the target index and the index at the toplevel, can we call this qemuDomainAddressFindNewTargetIndex()? (yeah, I know that's really long)
+{ + int ret = 1; + size_t i; + + for (i = 0; i < def->ncontrollers; i++) { + virDomainControllerDefPtr cont = def->controllers[i]; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) { + if (cont->opts.pciopts.idx >= ret) + ret = cont->opts.pciopts.idx + 1; + }
I know it would be idiotic to do so, but what if someone removed one of the pci-root controllers, and then later added a new one? You'd end up with an unused index where the earlier one was removed (and it would never be filled in). Maybe you should instead start at 0, and scan all the existing controllers for 0, then for 1, then for 2, etc, until you find the lowest target index value that isn't used.
+ } + + /* 0 is reserved for the implicit PHB, whereas anything lower + * than 0 or higher than 31 is invalid */ + if (ret > 31) + ret = -1; + + return ret; +} + + +static int qemuDomainAddressFindNewBusNr(virDomainDefPtr def) { /* Try to find a nice default for busNr for a new pci-expander-bus. @@ -2159,7 +2187,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, * device in qemu) for any controller that doesn't yet * have it set. */ - qemuDomainPCIControllerSetDefaultModelName(cont, qemuCaps); + qemuDomainPCIControllerSetDefaultModelName(cont, def, qemuCaps);
/* set defaults for any other auto-generated config * options for this controller that haven't been @@ -2196,9 +2224,34 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, goto cleanup; } break; + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: + if (!qemuDomainIsPSeries(def)) + break; + if (options->idx == -1) { + if (cont->idx == 0) { + /* The pcie-root controller with controller index 0
*really* unimportant, but I think the above should say "pci-root" rather than "pcie-root" :-)
+ * must always be assigned target index 0, because + * it represents the implicit PHB which is treated + * differently than all other PHBs */ + options->idx = 0; + } else { + /* For all other PHBs the target index doesn't need + * to match the controller index or have any + * particular value, really */
How is it used then? Just directly put on qemu commandline? And it's allowed to have gaps in the index numbers of the PHBs?
+ options->idx = qemuDomainAddressFindNewIndex(def); + } + } + if (options->idx == -1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("No valid index is available to " + "auto-assign to bus %d. Must be " + "manually assigned"),
I guess if you checked for unused indexes inside the limits of currently used indexes (as I suggested above) then the part about "Must be manually assigned" wouldn't be true - if we couldn't find an unused index, then that's the end of it; there's no possible value to manually assign either.
+ addr->bus); + goto cleanup; + } + break; case VIR_DOMAIN_CONTROLLER_MODEL_DMI_TO_PCI_BRIDGE: case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_SWITCH_UPSTREAM_PORT: - case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST: break; diff --git a/tests/qemuargv2xmldata/qemuargv2xml-pseries-disk.xml b/tests/qemuargv2xmldata/qemuargv2xml-pseries-disk.xml index 1bad8ee..601d0f7 100644 --- a/tests/qemuargv2xmldata/qemuargv2xml-pseries-disk.xml +++ b/tests/qemuargv2xmldata/qemuargv2xml-pseries-disk.xml @@ -30,7 +30,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <controller type='scsi' index='0'> <address type='spapr-vio' reg='0x2000'/> </controller> diff --git a/tests/qemuargv2xmldata/qemuargv2xml-pseries-nvram.xml b/tests/qemuargv2xmldata/qemuargv2xml-pseries-nvram.xml index 7e9f864..7787847 100644 --- a/tests/qemuargv2xmldata/qemuargv2xml-pseries-nvram.xml +++ b/tests/qemuargv2xmldata/qemuargv2xml-pseries-nvram.xml @@ -17,7 +17,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <memballoon model='none'/> <nvram> <address type='spapr-vio' reg='0x4000'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-panic-pseries.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-panic-pseries.xml index 1ed11ce..7fb49fe 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-panic-pseries.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-panic-pseries.xml @@ -17,7 +17,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <serial type='pty'> <target port='0'/> <address type='spapr-vio' reg='0x30000000'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller-legacy.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller-legacy.xml index b7bde24..673b81d 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller-legacy.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller-legacy.xml @@ -22,7 +22,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <memballoon model='virtio'> <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </memballoon> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller.xml index 82aaaca..68995a9 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-ppc64-usb-controller.xml @@ -22,7 +22,10 @@ <controller type='usb' index='0' model='pci-ohci'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <memballoon model='virtio'> <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </memballoon> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-nvram.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-nvram.xml index 713f31c..f89b23b 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-nvram.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-nvram.xml @@ -17,7 +17,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <memballoon model='none'/> <nvram> <address type='spapr-vio' reg='0x4000'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-missing.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-missing.xml index 1ed11ce..7fb49fe 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-missing.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-missing.xml @@ -17,7 +17,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <serial type='pty'> <target port='0'/> <address type='spapr-vio' reg='0x30000000'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-no-address.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-no-address.xml index 1ed11ce..7fb49fe 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-no-address.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-panic-no-address.xml @@ -17,7 +17,10 @@ <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> - <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> <serial type='pty'> <target port='0'/> <address type='spapr-vio' reg='0x30000000'/>

On Tue, 2017-06-13 at 21:52 -0400, Laine Stump wrote:
@@ -1856,6 +1856,7 @@ qemuDomainSupportsPCI(virDomainDefPtr def, static void qemuDomainPCIControllerSetDefaultModelName(virDomainControllerDefPtr cont, + virDomainDefPtr def, virQEMUCapsPtr qemuCaps) { int *modelName = &cont->opts.pciopts.modelName; @@ -1892,6 +1893,9 @@ qemuDomainPCIControllerSetDefaultModelName(virDomainControllerDefPtr cont, *modelName = VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_PXB_PCIE; break; case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: + if (qemuDomainIsPSeries(def)) + *modelName = VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE; + break; Just to verify - *all* the pci-roots on pSeries will be spapr-pci-host-bridge, even the first one?
Yup.
case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST: break; @@ -1900,6 +1904,30 @@ qemuDomainPCIControllerSetDefaultModelName(virDomainControllerDefPtr cont, static int +qemuDomainAddressFindNewIndex(virDomainDefPtr def) To help avoid confusion between the target index and the index at the toplevel, can we call this qemuDomainAddressFindNewTargetIndex()? (yeah, I know that's really long)
Sure.
+{ + int ret = 1; + size_t i; + + for (i = 0; i < def->ncontrollers; i++) { + virDomainControllerDefPtr cont = def->controllers[i]; + + if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI) { + if (cont->opts.pciopts.idx >= ret) + ret = cont->opts.pciopts.idx + 1; + } I know it would be idiotic to do so, but what if someone removed one of the pci-root controllers, and then later added a new one? You'd end up with an unused index where the earlier one was removed (and it would never be filled in). Maybe you should instead start at 0, and scan all the existing controllers for 0, then for 1, then for 2, etc, until you find the lowest target index value that isn't used.
Zero is going to be used for the default PHB, so I'd have to start from one instead. But I like the idea :)
@@ -2196,9 +2224,34 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, goto cleanup; } break; + case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: + if (!qemuDomainIsPSeries(def)) + break; + if (options->idx == -1) { + if (cont->idx == 0) { + /* The pcie-root controller with controller index 0 *really* unimportant, but I think the above should say "pci-root" rather than "pcie-root" :-)
It's not unimportant! Comments that disagree with the code can cause a lot of confusion. Good catch :)
+ * must always be assigned target index 0, because + * it represents the implicit PHB which is treated + * differently than all other PHBs */ + options->idx = 0; + } else { + /* For all other PHBs the target index doesn't need + * to match the controller index or have any + * particular value, really */ How is it used then? Just directly put on qemu commandline? And it's allowed to have gaps in the index numbers of the PHBs?
Yes to both. I can't think of a single sensible reason why you'd want to have gaps, but it's a valid configuration.
+ options->idx = qemuDomainAddressFindNewIndex(def); + } + } + if (options->idx == -1) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("No valid index is available to " + "auto-assign to bus %d. Must be " + "manually assigned"), I guess if you checked for unused indexes inside the limits of currently used indexes (as I suggested above) then the part about "Must be manually assigned" wouldn't be true - if we couldn't find an unused index, then that's the end of it; there's no possible value to manually assign either.
Indeed. I just realized I'm not making sure user-assigned target indexes are contained in the allowed range either, so I'll add that as well. -- Andrea Bolognani / Red Hat / Virtualization

This new capability can be used to detect whether a QEMU binary supports the spapr-pci-host-bridge controller. --- src/qemu/qemu_capabilities.c | 3 +++ src/qemu/qemu_capabilities.h | 3 +++ tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml | 1 + 3 files changed, 7 insertions(+) diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 7ea8505..3efa3ad 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -372,6 +372,8 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, "intel-iommu.intremap", "intel-iommu.caching-mode", "intel-iommu.eim", + + "spapr-pci-host-bridge", /* 260 */ ); @@ -1621,6 +1623,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { { "nvdimm", QEMU_CAPS_DEVICE_NVDIMM }, { "pcie-root-port", QEMU_CAPS_DEVICE_PCIE_ROOT_PORT }, { "qemu-xhci", QEMU_CAPS_DEVICE_QEMU_XHCI }, + { "spapr-pci-host-bridge", QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE }, }; static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsVirtioBalloon[] = { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index eba9814..d07ba0e 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -411,6 +411,9 @@ typedef enum { QEMU_CAPS_INTEL_IOMMU_CACHING_MODE, /* intel-iommu.caching-mode */ QEMU_CAPS_INTEL_IOMMU_EIM, /* intel-iommu.eim */ + /* 260 */ + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, /* -device spapr-pci-host-bridge */ + QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags; diff --git a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml index 425992f..7fa652a 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml @@ -164,6 +164,7 @@ <flag name='query-named-block-nodes'/> <flag name='kernel-irqchip'/> <flag name='kernel-irqchip.split'/> + <flag name='spapr-pci-host-bridge'/> <version>2006000</version> <kvmVersion>0</kvmVersion> <package></package> -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
This new capability can be used to detect whether a QEMU binary supports the spapr-pci-host-bridge controller. --- src/qemu/qemu_capabilities.c | 3 +++ src/qemu/qemu_capabilities.h | 3 +++ tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml | 1 + 3 files changed, 7 insertions(+)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 7ea8505..3efa3ad 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -372,6 +372,8 @@ VIR_ENUM_IMPL(virQEMUCaps, QEMU_CAPS_LAST, "intel-iommu.intremap", "intel-iommu.caching-mode", "intel-iommu.eim", + + "spapr-pci-host-bridge", /* 260 */ );
@@ -1621,6 +1623,7 @@ struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = { { "nvdimm", QEMU_CAPS_DEVICE_NVDIMM }, { "pcie-root-port", QEMU_CAPS_DEVICE_PCIE_ROOT_PORT }, { "qemu-xhci", QEMU_CAPS_DEVICE_QEMU_XHCI }, + { "spapr-pci-host-bridge", QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE }, };
static struct virQEMUCapsStringFlags virQEMUCapsObjectPropsVirtioBalloon[] = { diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index eba9814..d07ba0e 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -411,6 +411,9 @@ typedef enum { QEMU_CAPS_INTEL_IOMMU_CACHING_MODE, /* intel-iommu.caching-mode */ QEMU_CAPS_INTEL_IOMMU_EIM, /* intel-iommu.eim */
+ /* 260 */ + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, /* -device spapr-pci-host-bridge */ + QEMU_CAPS_LAST /* this must always be the last item */ } virQEMUCapsFlags;
diff --git a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml index 425992f..7fa652a 100644 --- a/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml +++ b/tests/qemucapabilitiesdata/caps_2.6.0.ppc64le.xml @@ -164,6 +164,7 @@ <flag name='query-named-block-nodes'/> <flag name='kernel-irqchip'/> <flag name='kernel-irqchip.split'/> + <flag name='spapr-pci-host-bridge'/> <version>2006000</version> <kvmVersion>0</kvmVersion> <package></package>
Reviewed-by: Laine Stump <laine@laine.org>

Usually, a controller with alias 'x' will create a bus with the same name; however, the bus created by a PHBs with alias 'x' will be named 'x.0' instead, so we need to account for that. As an exception to the exception, the implicit PHB that's added automatically to every pSeries guest creates the 'pci.0' bus. --- src/qemu/qemu_command.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 082ffa9..1bc3093 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -301,6 +301,9 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, int ret = -1; char *devStr = NULL; const char *contAlias = NULL; + virDomainControllerModelPCI contModel; + virDomainControllerPCIModelName contModelName; + int contIndex; if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { size_t i; @@ -313,6 +316,9 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && cont->idx == info->addr.pci.bus) { contAlias = cont->info.alias; + contModel = cont->model; + contModelName = cont->opts.pciopts.modelName; + contIndex = cont->opts.pciopts.idx; if (!contAlias) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Device alias was not set for PCI " @@ -348,7 +354,19 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, } } - virBufferAsprintf(buf, ",bus=%s", contAlias); + if (contModel == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT && + contModelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE && + contIndex > 0) { + /* The PCI bus created by a spapr-pci-host-bridge device with + * alias 'x' will be called 'x.0' rather than 'x'; however, + * this does not apply to the implicit PHB in a pSeries guest, + * which always has the hardcoded name 'pci.0' */ + virBufferAsprintf(buf, ",bus=%s.0", contAlias); + } else { + /* For all other controllers, the bus name matches the alias + * of the corresponding controller */ + virBufferAsprintf(buf, ",bus=%s", contAlias); + } if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_ON) virBufferAddLit(buf, ",multifunction=on"); -- 2.7.5

On 06/02/2017 12:07 PM, Andrea Bolognani wrote:
Usually, a controller with alias 'x' will create a bus with the same name; however, the bus created by a PHBs with alias 'x' will be named 'x.0' instead, so we need to account for that.
This doesn't make sense to me. My recollection (without going through the code again) is that for PCI controllers, the alias for pci-root is "pci.0" as long as the qemu binary supports multiple PCI controllers (otherwise it is just "pci"), and the alias is pcie.0 for pcie-root, then all other PCI controllers have the alias (i.e. value of "contAlias" in this function) of pci.x (where "x" is the index of the controller). What you're saying here doesn't match that. Unless you're saying that the PHBs will have aliases named something like "pci.1.0" (which isn't what I see in the test cases in 19/26). I guess I need time to digest why this is necessary. Based on my memory, it should have worked properly already...
As an exception to the exception, the implicit PHB that's added automatically to every pSeries guest creates the 'pci.0' bus. --- src/qemu/qemu_command.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 082ffa9..1bc3093 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -301,6 +301,9 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, int ret = -1; char *devStr = NULL; const char *contAlias = NULL; + virDomainControllerModelPCI contModel; + virDomainControllerPCIModelName contModelName; + int contIndex;
if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) { size_t i; @@ -313,6 +316,9 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && cont->idx == info->addr.pci.bus) { contAlias = cont->info.alias; + contModel = cont->model; + contModelName = cont->opts.pciopts.modelName; + contIndex = cont->opts.pciopts.idx; if (!contAlias) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Device alias was not set for PCI " @@ -348,7 +354,19 @@ qemuBuildDeviceAddressStr(virBufferPtr buf, } }
- virBufferAsprintf(buf, ",bus=%s", contAlias); + if (contModel == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT && + contModelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE && + contIndex > 0) { + /* The PCI bus created by a spapr-pci-host-bridge device with + * alias 'x' will be called 'x.0' rather than 'x'; however, + * this does not apply to the implicit PHB in a pSeries guest, + * which always has the hardcoded name 'pci.0' */ + virBufferAsprintf(buf, ",bus=%s.0", contAlias); + } else { + /* For all other controllers, the bus name matches the alias + * of the corresponding controller */ + virBufferAsprintf(buf, ",bus=%s", contAlias); + }
if (info->addr.pci.multi == VIR_TRISTATE_SWITCH_ON) virBufferAddLit(buf, ",multifunction=on");

On Tue, 2017-06-13 at 22:10 -0400, Laine Stump wrote:
Usually, a controller with alias 'x' will create a bus with the same name; however, the bus created by a PHBs with alias 'x' will be named 'x.0' instead, so we need to account for that. This doesn't make sense to me. My recollection (without going through the code again) is that for PCI controllers, the alias for pci-root is "pci.0" as long as the qemu binary supports multiple PCI controllers (otherwise it is just "pci"), and the alias is pcie.0 for pcie-root, then all other PCI controllers have the alias (i.e. value of "contAlias" in this function) of pci.x (where "x" is the index of the controller).
That's correct.
What you're saying here doesn't match that. Unless you're saying that the PHBs will have aliases named something like "pci.1.0" (which isn't what I see in the test cases in 19/26).
So here's the subtle bit: for all PCI controllers *except* spapr-pci-host-brigde, the bus name for a controller will match the controller alias, so you'll have -device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 -device virtio-scsi-pci,id=scsi0,bus=pci.1,addr=0x1 spapr-pci-host-bridge will behave slightly differently, in that a controller with alias x will create a bus with name x.0, so you'll have to use -device spapr-pci-host-bridge,index=1,id=pci.1 -device virtio-scsi-pci,id=scsi0,bus=pci.1.0,addr=0x1 instead. To add to the fun, the implicit PHB (despite being an instance of the same device) will create a bus named pci.0 just like you'd expect. Hence this patch :) You can see this in action in patch 22/26; later patches will also move more devices to separate PHBs, so by the end of the series there will be a bunch of test cases covering this behavior. -- Andrea Bolognani / Red Hat / Virtualization

Additional PHBs (pci-root controllers) will be created for the guest using the spapr-pci-host-bridge QEMU device, if available; the implicit default PHB, while present in the guest configuration, will be skipped. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1431193 --- src/qemu/qemu_command.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 1bc3093..b0b6c85 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3118,6 +3118,40 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, def->opts.pciopts.numaNode); break; case VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT: + if (def->opts.pciopts.modelName == VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_NONE || + def->opts.pciopts.idx == -1) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("autogenerated pci-root options not set")); + goto error; + } + + /* Skip the implicit one */ + if (def->opts.pciopts.idx == 0) + goto done; + + modelName = virDomainControllerPCIModelNameTypeToString(def->opts.pciopts.modelName); + if (!modelName) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown pci-root model name value %d"), + def->opts.pciopts.modelName); + goto error; + } + if (def->opts.pciopts.modelName != VIR_DOMAIN_CONTROLLER_PCI_MODEL_NAME_SPAPR_PCI_HOST_BRIDGE) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("PCI controller model name '%s' is not valid for a pci-root"), + modelName); + goto error; + } + if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("the spapr-pci-host-bridge controller " + "is not supported in this QEMU binary")); + goto error; + } + virBufferAsprintf(&buf, "%s,index=%d,id=%s", + modelName, def->opts.pciopts.idx, + def->info.alias); + break; case VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT: case VIR_DOMAIN_CONTROLLER_MODEL_PCI_LAST: virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -3167,6 +3201,7 @@ qemuBuildControllerDevStr(const virDomainDef *domainDef, if (virBufferCheckError(&buf) < 0) goto error; + done: *devstr = virBufferContentAndReset(&buf); return 0; @@ -3224,10 +3259,16 @@ qemuBuildControllerDevCommandLine(virCommandPtr cmd, continue; } - /* skip pci-root/pcie-root */ + /* skip pcie-root */ if (cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && - (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT || - cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT)) + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) + continue; + + /* Skip pci-root, except for pSeries guests (which actually + * support more than one PCI Host Bridge per guest) */ + if (!qemuDomainIsPSeries(def) && + cont->type == VIR_DOMAIN_CONTROLLER_TYPE_PCI && + cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT) continue; /* first SATA controller on Q35 machines is implicit */ -- 2.7.5

--- .../qemuxml2argv-pseries-phb-default-missing.args | 22 +++++++++++++++ .../qemuxml2argv-pseries-phb-default-missing.xml | 16 +++++++++++ .../qemuxml2argv-pseries-phb-simple.args | 22 +++++++++++++++ .../qemuxml2argv-pseries-phb-simple.xml | 17 +++++++++++ tests/qemuxml2argvtest.c | 8 ++++++ .../qemuxml2xmlout-pseries-phb-default-missing.xml | 33 ++++++++++++++++++++++ .../qemuxml2xmlout-pseries-phb-simple.xml | 33 ++++++++++++++++++++++ tests/qemuxml2xmltest.c | 7 +++++ 8 files changed, 158 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-default-missing.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-simple.xml diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.args new file mode 100644 index 0000000..009f5a8 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.args @@ -0,0 +1,22 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-ppc64 \ +-name QEMUGuest1 \ +-S \ +-M pseries \ +-m 512 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \ +-nographic \ +-nodefconfig \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-boot c \ +-device spapr-pci-host-bridge,index=1,id=pci.1 \ +-device spapr-pci-host-bridge,index=2,id=pci.2 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.xml new file mode 100644 index 0000000..d0b45bf --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-default-missing.xml @@ -0,0 +1,16 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <controller type='pci' index='1' model='pci-root'/> + <controller type='pci' index='2' model='pci-root'/> + <controller type='usb' model='none'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.args new file mode 100644 index 0000000..009f5a8 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.args @@ -0,0 +1,22 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-ppc64 \ +-name QEMUGuest1 \ +-S \ +-M pseries \ +-m 512 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \ +-nographic \ +-nodefconfig \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-QEMUGuest1/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-boot c \ +-device spapr-pci-host-bridge,index=1,id=pci.1 \ +-device spapr-pci-host-bridge,index=2,id=pci.2 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.xml new file mode 100644 index 0000000..b1c6ff3 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-phb-simple.xml @@ -0,0 +1,17 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <controller type='pci' model='pci-root'/> + <controller type='pci' model='pci-root'/> + <controller type='pci' model='pci-root'/> + <controller type='usb' model='none'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index cc6a8a8..9996960 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1695,6 +1695,14 @@ mymain(void) QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); DO_TEST_FAILURE("pseries-panic-address", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG); + + DO_TEST("pseries-phb-simple", + QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_CHARDEV, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE); + DO_TEST("pseries-phb-default-missing", + QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_CHARDEV, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE); + DO_TEST("disk-ide-drive-split", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_IDE_CD); diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-default-missing.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-default-missing.xml new file mode 100644 index 0000000..62708b4 --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-default-missing.xml @@ -0,0 +1,33 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</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='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> + </controller> + <controller type='pci' index='2' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='2'/> + </controller> + <controller type='usb' index='0' model='none'/> + <controller type='pci' index='0' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='0'/> + </controller> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-simple.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-simple.xml new file mode 100644 index 0000000..2c1e64e --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-phb-simple.xml @@ -0,0 +1,33 @@ +<domain type='qemu'> + <name>QEMUGuest1</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</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'/> + </controller> + <controller type='pci' index='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> + </controller> + <controller type='pci' index='2' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='2'/> + </controller> + <controller type='usb' index='0' model='none'/> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 3c8dbc4..549543a 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -670,6 +670,13 @@ mymain(void) DO_TEST("pseries-panic-missing", NONE); DO_TEST("pseries-panic-no-address", NONE); + DO_TEST("pseries-phb-simple", + QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_CHARDEV, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE); + DO_TEST("pseries-phb-default-missing", + QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_CHARDEV, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE); + DO_TEST("balloon-device-auto", NONE); DO_TEST("balloon-device-period", NONE); DO_TEST("channel-virtio-auto", NONE); -- 2.7.5

These tests demonstrate that, while it's now possible for the user to create PHB explicitly and manually assign devices to them, libvirt still defaults to extending the guest PCI topology using PCI bridges and making suboptimal device placement choices. The next few commits will improve on these behaviors and the tests outputs will automatically be updated to reflect this. --- .../qemuxml2argv-pseries-hostdev.args | 23 ++++ .../qemuxml2argv-pseries-hostdev.xml | 33 ++++++ .../qemuxml2argv-pseries-many-buses-1.args | 22 ++++ .../qemuxml2argv-pseries-many-buses-1.xml | 20 ++++ .../qemuxml2argv-pseries-many-buses-2.args | 22 ++++ .../qemuxml2argv-pseries-many-buses-2.xml | 18 +++ .../qemuxml2argv-pseries-many-devices.args | 53 +++++++++ .../qemuxml2argv-pseries-many-devices.xml | 49 ++++++++ tests/qemuxml2argvtest.c | 21 ++++ .../qemuxml2xmlout-pseries-hostdev.xml | 46 ++++++++ .../qemuxml2xmlout-pseries-many-buses-1.xml | 33 ++++++ .../qemuxml2xmlout-pseries-many-buses-2.xml | 34 ++++++ .../qemuxml2xmlout-pseries-many-devices.xml | 126 +++++++++++++++++++++ tests/qemuxml2xmltest.c | 21 ++++ 14 files changed, 521 insertions(+) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.xml create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdev.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml create mode 100644 tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.args new file mode 100644 index 0000000..dbd2964 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.args @@ -0,0 +1,23 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-ppc64 \ +-name guest \ +-S \ +-M pseries \ +-m 512 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \ +-nographic \ +-nodefconfig \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-guest/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-boot c \ +-device vfio-pci,host=0001:01:00.0,id=hostdev0,bus=pci.0,addr=0x1 \ +-device vfio-pci,host=0005:90:01.2,id=hostdev1,bus=pci.0,addr=0x2 \ +-device vfio-pci,host=0001:01:00.1,id=hostdev2,bus=pci.0,addr=0x3 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.xml new file mode 100644 index 0000000..2aa6ffc --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.xml @@ -0,0 +1,33 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <controller type='pci' model='pci-root'/> + <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='0x0001' bus='0x01' slot='0x00' function='0x1'/> + </source> + </hostdev> + <controller type='usb' model='none'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args new file mode 100644 index 0000000..bf78fc1 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args @@ -0,0 +1,22 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-ppc64 \ +-name guest \ +-S \ +-M pseries \ +-m 512 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \ +-nographic \ +-nodefconfig \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-guest/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-boot c \ +-device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.1,addr=0x1 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.xml new file mode 100644 index 0000000..8755409 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.xml @@ -0,0 +1,20 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <controller type='pci' model='pci-root'/> + <!-- The SCSI controller is plugged into PCI bus 1, but since said bus + is not present in the configuration libvirt will have to add it --> + <controller type='scsi' model='virtio-scsi'> + <address type='pci' bus='1' slot='1'/> + </controller> + <controller type='usb' model='none'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args new file mode 100644 index 0000000..1cb5831 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args @@ -0,0 +1,22 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-ppc64 \ +-name guest \ +-S \ +-M pseries \ +-m 512 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \ +-nographic \ +-nodefconfig \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-guest/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-boot c \ +-device spapr-pci-host-bridge,index=1,id=pci.2 \ +-device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.xml new file mode 100644 index 0000000..7065626 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.xml @@ -0,0 +1,18 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <!-- PCI buses 0 and 2 are present in the configuration, libvirt will + have to fill in the blanks and add bus 1 --> + <controller type='pci' index='0' model='pci-root'/> + <controller type='pci' index='2' model='pci-root'/> + <controller type='usb' model='none'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args new file mode 100644 index 0000000..1db4533 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args @@ -0,0 +1,53 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/home/test \ +USER=test \ +LOGNAME=test \ +QEMU_AUDIO_DRV=none \ +/usr/bin/qemu-system-ppc64 \ +-name guest \ +-S \ +-M pseries \ +-m 512 \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid 1ccfd97d-5eb4-478a-bbe6-88d254c16db7 \ +-nographic \ +-nodefconfig \ +-nodefaults \ +-chardev socket,id=charmonitor,path=/tmp/lib/domain--1-guest/monitor.sock,\ +server,nowait \ +-mon chardev=charmonitor,id=monitor,mode=readline \ +-boot c \ +-device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x2 \ +-device virtio-scsi-pci,id=scsi1,bus=pci.0,addr=0x3 \ +-device virtio-scsi-pci,id=scsi2,bus=pci.0,addr=0x4 \ +-device virtio-scsi-pci,id=scsi3,bus=pci.0,addr=0x5 \ +-device virtio-scsi-pci,id=scsi4,bus=pci.0,addr=0x6 \ +-device virtio-scsi-pci,id=scsi5,bus=pci.0,addr=0x7 \ +-device virtio-scsi-pci,id=scsi6,bus=pci.0,addr=0x8 \ +-device virtio-scsi-pci,id=scsi7,bus=pci.0,addr=0x9 \ +-device virtio-scsi-pci,id=scsi8,bus=pci.0,addr=0xa \ +-device virtio-scsi-pci,id=scsi9,bus=pci.0,addr=0xb \ +-device virtio-scsi-pci,id=scsi10,bus=pci.0,addr=0xc \ +-device virtio-scsi-pci,id=scsi11,bus=pci.0,addr=0xd \ +-device virtio-scsi-pci,id=scsi12,bus=pci.0,addr=0xe \ +-device virtio-scsi-pci,id=scsi13,bus=pci.0,addr=0xf \ +-device virtio-scsi-pci,id=scsi14,bus=pci.0,addr=0x10 \ +-device virtio-scsi-pci,id=scsi15,bus=pci.0,addr=0x11 \ +-device virtio-scsi-pci,id=scsi16,bus=pci.0,addr=0x12 \ +-device virtio-scsi-pci,id=scsi17,bus=pci.0,addr=0x13 \ +-device virtio-scsi-pci,id=scsi18,bus=pci.0,addr=0x14 \ +-device virtio-scsi-pci,id=scsi19,bus=pci.0,addr=0x15 \ +-device virtio-scsi-pci,id=scsi20,bus=pci.0,addr=0x16 \ +-device virtio-scsi-pci,id=scsi21,bus=pci.0,addr=0x17 \ +-device virtio-scsi-pci,id=scsi22,bus=pci.0,addr=0x18 \ +-device virtio-scsi-pci,id=scsi23,bus=pci.0,addr=0x19 \ +-device virtio-scsi-pci,id=scsi24,bus=pci.0,addr=0x1a \ +-device virtio-scsi-pci,id=scsi25,bus=pci.0,addr=0x1b \ +-device virtio-scsi-pci,id=scsi26,bus=pci.0,addr=0x1c \ +-device virtio-scsi-pci,id=scsi27,bus=pci.0,addr=0x1d \ +-device virtio-scsi-pci,id=scsi28,bus=pci.0,addr=0x1e \ +-device virtio-scsi-pci,id=scsi29,bus=pci.0,addr=0x1f \ +-device virtio-scsi-pci,id=scsi30,bus=pci.1,addr=0x1 \ +-device virtio-scsi-pci,id=scsi31,bus=pci.1,addr=0x2 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.xml b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.xml new file mode 100644 index 0000000..9a3ead3 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.xml @@ -0,0 +1,49 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='ppc64' machine='pseries'>hvm</type> + </os> + <devices> + <emulator>/usr/bin/qemu-system-ppc64</emulator> + <controller type='pci' model='pci-root'/> + <!-- pci-root has 31 slots and there are 32 SCSI controllers here, so + libvirt will automatically add at least one more PCI controller --> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='scsi' model='virtio-scsi'/> + <controller type='usb' model='none'/> + <memballoon model='none'/> + </devices> +</domain> diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 9996960..4e46825 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1703,6 +1703,27 @@ mymain(void) QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE); + DO_TEST("pseries-many-devices", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI); + DO_TEST("pseries-many-buses-1", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI); + DO_TEST("pseries-many-buses-2", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI); + DO_TEST("pseries-hostdev", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_HOST_PCI_MULTIDOMAIN, + QEMU_CAPS_DEVICE_VFIO_PCI); + DO_TEST("disk-ide-drive-split", QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_IDE_CD); diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdev.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdev.xml new file mode 100644 index 0000000..a00c09c --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdev.xml @@ -0,0 +1,46 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</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'/> + </controller> + <controller type='usb' index='0' model='none'/> + <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='0x01' 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='0x02' 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='0x03' function='0x0'/> + </hostdev> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml new file mode 100644 index 0000000..010a3be --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml @@ -0,0 +1,33 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</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'/> + </controller> + <controller type='scsi' index='0' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'/> + </controller> + <controller type='usb' index='0' model='none'/> + <controller type='pci' index='1' model='pci-bridge'> + <model name='pci-bridge'/> + <target chassisNr='1'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </controller> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml new file mode 100644 index 0000000..75dfabf --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml @@ -0,0 +1,34 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</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'/> + </controller> + <controller type='pci' index='2' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> + </controller> + <controller type='usb' index='0' model='none'/> + <controller type='pci' index='1' model='pci-bridge'> + <model name='pci-bridge'/> + <target chassisNr='1'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </controller> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml new file mode 100644 index 0000000..336373b --- /dev/null +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml @@ -0,0 +1,126 @@ +<domain type='qemu'> + <name>guest</name> + <uuid>1ccfd97d-5eb4-478a-bbe6-88d254c16db7</uuid> + <memory unit='KiB'>524288</memory> + <currentMemory unit='KiB'>524288</currentMemory> + <vcpu placement='static'>1</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'/> + </controller> + <controller type='scsi' index='0' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <controller type='scsi' index='1' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </controller> + <controller type='scsi' index='2' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </controller> + <controller type='scsi' index='3' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + </controller> + <controller type='scsi' index='4' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + </controller> + <controller type='scsi' index='5' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + </controller> + <controller type='scsi' index='6' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> + </controller> + <controller type='scsi' index='7' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> + </controller> + <controller type='scsi' index='8' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + </controller> + <controller type='scsi' index='9' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> + </controller> + <controller type='scsi' index='10' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> + </controller> + <controller type='scsi' index='11' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/> + </controller> + <controller type='scsi' index='12' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/> + </controller> + <controller type='scsi' index='13' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0f' function='0x0'/> + </controller> + <controller type='scsi' index='14' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x10' function='0x0'/> + </controller> + <controller type='scsi' index='15' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x11' function='0x0'/> + </controller> + <controller type='scsi' index='16' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x12' function='0x0'/> + </controller> + <controller type='scsi' index='17' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x13' function='0x0'/> + </controller> + <controller type='scsi' index='18' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x14' function='0x0'/> + </controller> + <controller type='scsi' index='19' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x15' function='0x0'/> + </controller> + <controller type='scsi' index='20' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x16' function='0x0'/> + </controller> + <controller type='scsi' index='21' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x17' function='0x0'/> + </controller> + <controller type='scsi' index='22' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x18' function='0x0'/> + </controller> + <controller type='scsi' index='23' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x19' function='0x0'/> + </controller> + <controller type='scsi' index='24' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1a' function='0x0'/> + </controller> + <controller type='scsi' index='25' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/> + </controller> + <controller type='scsi' index='26' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1c' function='0x0'/> + </controller> + <controller type='scsi' index='27' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x0'/> + </controller> + <controller type='scsi' index='28' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> + </controller> + <controller type='scsi' index='29' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x0'/> + </controller> + <controller type='scsi' index='30' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'/> + </controller> + <controller type='scsi' index='31' model='virtio-scsi'> + <address type='pci' domain='0x0000' bus='0x01' slot='0x02' function='0x0'/> + </controller> + <controller type='usb' index='0' model='none'/> + <controller type='pci' index='1' model='pci-bridge'> + <model name='pci-bridge'/> + <target chassisNr='1'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + </controller> + <memballoon model='none'/> + <panic model='pseries'/> + </devices> +</domain> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 549543a..8cbada1 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -677,6 +677,27 @@ mymain(void) QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE); + DO_TEST("pseries-many-devices", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI); + DO_TEST("pseries-many-buses-1", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI); + DO_TEST("pseries-many-buses-2", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_DEVICE_PCI_BRIDGE, + QEMU_CAPS_VIRTIO_SCSI); + DO_TEST("pseries-hostdev", + QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, + QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, + QEMU_CAPS_HOST_PCI_MULTIDOMAIN, + QEMU_CAPS_DEVICE_VFIO_PCI); + DO_TEST("balloon-device-auto", NONE); DO_TEST("balloon-device-period", NONE); DO_TEST("channel-virtio-auto", NONE); -- 2.7.5

PCI bus has to be numbered sequentially, and no index can be missing, so libvirt will fill in the blanks automatically for the user. Up until now, it has done so using either pci-bridge, for machine types based on legacy PCI, or pcie-root-port, for machine types based on PCI Express. Neither choice is good for pSeries guests, where PHBs (pci-root) should be used instead. --- src/qemu/qemu_domain_address.c | 16 +++++++++++++--- .../qemuxml2argv-pseries-many-buses-2.args | 2 +- tests/qemuxml2argvtest.c | 1 - .../qemuxml2xmlout-pseries-many-buses-2.xml | 7 +++---- tests/qemuxml2xmltest.c | 1 - 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index d46f8f7..9585fe5 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1092,10 +1092,14 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, * that don't yet have a corresponding controller in the domain * config. */ - if (hasPCIeRoot) + if (qemuDomainIsPSeries(def)) { + /* pSeries guests should use PHBs (pci-root controllers) */ + defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT; + } else if (hasPCIeRoot) { defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT_PORT; - else + } else { defaultModel = VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE; + } for (i = 1; i < addrs->nbuses; i++) { @@ -2144,7 +2148,13 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, dev.data.controller = def->controllers[contIndex]; /* set connect flags so it will be properly addressed */ qemuDomainFillDevicePCIConnectFlags(def, &dev, qemuCaps, driver); - if (qemuDomainPCIAddressReserveNextAddr(addrs, + + /* Reserve an address for the controller. pci-root and pcie-root + * controllers don't plug into any other PCI controller, hence + * they should skip this step */ + if (bus->model != VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT && + bus->model != VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT && + qemuDomainPCIAddressReserveNextAddr(addrs, &dev.data.controller->info) < 0) { goto cleanup; } diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args index 1cb5831..13fed02 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-2.args @@ -19,4 +19,4 @@ server,nowait \ -mon chardev=charmonitor,id=monitor,mode=readline \ -boot c \ -device spapr-pci-host-bridge,index=1,id=pci.2 \ --device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 +-device spapr-pci-host-bridge,index=2,id=pci.1 diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 4e46825..7a6acd5 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1716,7 +1716,6 @@ mymain(void) DO_TEST("pseries-many-buses-2", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI); DO_TEST("pseries-hostdev", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml index 75dfabf..14f3e36 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-2.xml @@ -23,10 +23,9 @@ <target index='1'/> </controller> <controller type='usb' index='0' model='none'/> - <controller type='pci' index='1' model='pci-bridge'> - <model name='pci-bridge'/> - <target chassisNr='1'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + <controller type='pci' index='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='2'/> </controller> <memballoon model='none'/> <panic model='pseries'/> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index 8cbada1..b75807c 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -690,7 +690,6 @@ mymain(void) DO_TEST("pseries-many-buses-2", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI); DO_TEST("pseries-hostdev", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, -- 2.7.5

When looking for slots suitable for a PCI device, libvirt might need to add an extra PCI controller: for pSeries guests, we want that extra controller to be a PHB (pci-root) rather than a PCI bridge. --- Better viewed with 'git diff -w'. src/conf/domain_addr.c | 56 +++++++++-------- src/conf/domain_addr.h | 2 + src/qemu/qemu_domain_address.c | 4 ++ .../qemuxml2argv-pseries-many-buses-1.args | 4 +- .../qemuxml2argv-pseries-many-devices.args | 66 ++++++++++---------- tests/qemuxml2argvtest.c | 2 - .../qemuxml2xmlout-pseries-many-buses-1.xml | 7 +-- .../qemuxml2xmlout-pseries-many-devices.xml | 71 +++++++++++----------- tests/qemuxml2xmltest.c | 2 - 9 files changed, 110 insertions(+), 104 deletions(-) diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index d173766..e6a6399 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -383,33 +383,39 @@ virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs, */ if (flags & VIR_PCI_CONNECT_TYPE_PCI_DEVICE) { - model = VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE; + if (addrs->multipleRootsSupported) { + /* Use a pci-root controller to expand the guest's PCI + * topology if it supports having more than one */ + model = VIR_DOMAIN_CONTROLLER_MODEL_PCI_ROOT; + } else { + model = VIR_DOMAIN_CONTROLLER_MODEL_PCI_BRIDGE; - /* if there aren't yet any buses that will accept a - * pci-bridge, and the caller is asking for one, we'll need to - * add a dmi-to-pci-bridge first. - */ - needDMIToPCIBridge = true; - for (i = 0; i < addrs->nbuses; i++) { - if (addrs->buses[i].flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) { - needDMIToPCIBridge = false; - break; - } - } - if (needDMIToPCIBridge && add == 1) { - /* We need to add a single pci-bridge to provide the bus - * our legacy PCI device will be plugged into; however, we - * have also determined that there isn't yet any proper - * place to connect that pci-bridge we're about to add (on - * a system with pcie-root, that "proper place" would be a - * dmi-to-pci-bridge". So, to give the pci-bridge a place - * to connect, we increase the count of buses to add, - * while also incrementing the bus number in the address - * for the device (since the pci-bridge will now be at an - * index 1 higher than the caller had anticipated). + /* if there aren't yet any buses that will accept a + * pci-bridge, and the caller is asking for one, we'll need to + * add a dmi-to-pci-bridge first. */ - add++; - addr->bus++; + needDMIToPCIBridge = true; + for (i = 0; i < addrs->nbuses; i++) { + if (addrs->buses[i].flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE) { + needDMIToPCIBridge = false; + break; + } + } + if (needDMIToPCIBridge && add == 1) { + /* We need to add a single pci-bridge to provide the bus + * our legacy PCI device will be plugged into; however, we + * have also determined that there isn't yet any proper + * place to connect that pci-bridge we're about to add (on + * a system with pcie-root, that "proper place" would be a + * dmi-to-pci-bridge". So, to give the pci-bridge a place + * to connect, we increase the count of buses to add, + * while also incrementing the bus number in the address + * for the device (since the pci-bridge will now be at an + * index 1 higher than the caller had anticipated). + */ + add++; + addr->bus++; + } } } else if (flags & VIR_PCI_CONNECT_TYPE_PCI_BRIDGE && addrs->buses[0].model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) { diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 7704061..1849d2b 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -108,6 +108,8 @@ struct _virDomainPCIAddressSet { size_t nbuses; bool dryRun; /* on a dry run, new buses are auto-added and addresses aren't saved in device infos */ + /* If true, the guest can have multiple pci-root controllers */ + bool multipleRootsSupported; }; typedef struct _virDomainPCIAddressSet virDomainPCIAddressSet; typedef virDomainPCIAddressSet *virDomainPCIAddressSetPtr; diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 9585fe5..08773c0 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1056,6 +1056,10 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, addrs->dryRun = dryRun; + /* pSeries domains support multiple pci-root controllers */ + if (qemuDomainIsPSeries(def)) + addrs->multipleRootsSupported = true; + for (i = 0; i < def->ncontrollers; i++) { virDomainControllerDefPtr cont = def->controllers[i]; size_t idx = cont->idx; diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args index bf78fc1..eb5ccbd 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-buses-1.args @@ -18,5 +18,5 @@ QEMU_AUDIO_DRV=none \ server,nowait \ -mon chardev=charmonitor,id=monitor,mode=readline \ -boot c \ --device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 \ --device virtio-scsi-pci,id=scsi0,bus=pci.1,addr=0x1 +-device spapr-pci-host-bridge,index=1,id=pci.1 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.1.0,addr=0x1 diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args index 1db4533..f20bc52 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-many-devices.args @@ -18,36 +18,36 @@ QEMU_AUDIO_DRV=none \ server,nowait \ -mon chardev=charmonitor,id=monitor,mode=readline \ -boot c \ --device pci-bridge,chassis_nr=1,id=pci.1,bus=pci.0,addr=0x1 \ --device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x2 \ --device virtio-scsi-pci,id=scsi1,bus=pci.0,addr=0x3 \ --device virtio-scsi-pci,id=scsi2,bus=pci.0,addr=0x4 \ --device virtio-scsi-pci,id=scsi3,bus=pci.0,addr=0x5 \ --device virtio-scsi-pci,id=scsi4,bus=pci.0,addr=0x6 \ --device virtio-scsi-pci,id=scsi5,bus=pci.0,addr=0x7 \ --device virtio-scsi-pci,id=scsi6,bus=pci.0,addr=0x8 \ --device virtio-scsi-pci,id=scsi7,bus=pci.0,addr=0x9 \ --device virtio-scsi-pci,id=scsi8,bus=pci.0,addr=0xa \ --device virtio-scsi-pci,id=scsi9,bus=pci.0,addr=0xb \ --device virtio-scsi-pci,id=scsi10,bus=pci.0,addr=0xc \ --device virtio-scsi-pci,id=scsi11,bus=pci.0,addr=0xd \ --device virtio-scsi-pci,id=scsi12,bus=pci.0,addr=0xe \ --device virtio-scsi-pci,id=scsi13,bus=pci.0,addr=0xf \ --device virtio-scsi-pci,id=scsi14,bus=pci.0,addr=0x10 \ --device virtio-scsi-pci,id=scsi15,bus=pci.0,addr=0x11 \ --device virtio-scsi-pci,id=scsi16,bus=pci.0,addr=0x12 \ --device virtio-scsi-pci,id=scsi17,bus=pci.0,addr=0x13 \ --device virtio-scsi-pci,id=scsi18,bus=pci.0,addr=0x14 \ --device virtio-scsi-pci,id=scsi19,bus=pci.0,addr=0x15 \ --device virtio-scsi-pci,id=scsi20,bus=pci.0,addr=0x16 \ --device virtio-scsi-pci,id=scsi21,bus=pci.0,addr=0x17 \ --device virtio-scsi-pci,id=scsi22,bus=pci.0,addr=0x18 \ --device virtio-scsi-pci,id=scsi23,bus=pci.0,addr=0x19 \ --device virtio-scsi-pci,id=scsi24,bus=pci.0,addr=0x1a \ --device virtio-scsi-pci,id=scsi25,bus=pci.0,addr=0x1b \ --device virtio-scsi-pci,id=scsi26,bus=pci.0,addr=0x1c \ --device virtio-scsi-pci,id=scsi27,bus=pci.0,addr=0x1d \ --device virtio-scsi-pci,id=scsi28,bus=pci.0,addr=0x1e \ --device virtio-scsi-pci,id=scsi29,bus=pci.0,addr=0x1f \ --device virtio-scsi-pci,id=scsi30,bus=pci.1,addr=0x1 \ --device virtio-scsi-pci,id=scsi31,bus=pci.1,addr=0x2 +-device spapr-pci-host-bridge,index=1,id=pci.1 \ +-device virtio-scsi-pci,id=scsi0,bus=pci.0,addr=0x1 \ +-device virtio-scsi-pci,id=scsi1,bus=pci.0,addr=0x2 \ +-device virtio-scsi-pci,id=scsi2,bus=pci.0,addr=0x3 \ +-device virtio-scsi-pci,id=scsi3,bus=pci.0,addr=0x4 \ +-device virtio-scsi-pci,id=scsi4,bus=pci.0,addr=0x5 \ +-device virtio-scsi-pci,id=scsi5,bus=pci.0,addr=0x6 \ +-device virtio-scsi-pci,id=scsi6,bus=pci.0,addr=0x7 \ +-device virtio-scsi-pci,id=scsi7,bus=pci.0,addr=0x8 \ +-device virtio-scsi-pci,id=scsi8,bus=pci.0,addr=0x9 \ +-device virtio-scsi-pci,id=scsi9,bus=pci.0,addr=0xa \ +-device virtio-scsi-pci,id=scsi10,bus=pci.0,addr=0xb \ +-device virtio-scsi-pci,id=scsi11,bus=pci.0,addr=0xc \ +-device virtio-scsi-pci,id=scsi12,bus=pci.0,addr=0xd \ +-device virtio-scsi-pci,id=scsi13,bus=pci.0,addr=0xe \ +-device virtio-scsi-pci,id=scsi14,bus=pci.0,addr=0xf \ +-device virtio-scsi-pci,id=scsi15,bus=pci.0,addr=0x10 \ +-device virtio-scsi-pci,id=scsi16,bus=pci.0,addr=0x11 \ +-device virtio-scsi-pci,id=scsi17,bus=pci.0,addr=0x12 \ +-device virtio-scsi-pci,id=scsi18,bus=pci.0,addr=0x13 \ +-device virtio-scsi-pci,id=scsi19,bus=pci.0,addr=0x14 \ +-device virtio-scsi-pci,id=scsi20,bus=pci.0,addr=0x15 \ +-device virtio-scsi-pci,id=scsi21,bus=pci.0,addr=0x16 \ +-device virtio-scsi-pci,id=scsi22,bus=pci.0,addr=0x17 \ +-device virtio-scsi-pci,id=scsi23,bus=pci.0,addr=0x18 \ +-device virtio-scsi-pci,id=scsi24,bus=pci.0,addr=0x19 \ +-device virtio-scsi-pci,id=scsi25,bus=pci.0,addr=0x1a \ +-device virtio-scsi-pci,id=scsi26,bus=pci.0,addr=0x1b \ +-device virtio-scsi-pci,id=scsi27,bus=pci.0,addr=0x1c \ +-device virtio-scsi-pci,id=scsi28,bus=pci.0,addr=0x1d \ +-device virtio-scsi-pci,id=scsi29,bus=pci.0,addr=0x1e \ +-device virtio-scsi-pci,id=scsi30,bus=pci.0,addr=0x1f \ +-device virtio-scsi-pci,id=scsi31,bus=pci.1.0,addr=0x1 diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 7a6acd5..296c93b 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1706,12 +1706,10 @@ mymain(void) DO_TEST("pseries-many-devices", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI); DO_TEST("pseries-many-buses-1", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI); DO_TEST("pseries-many-buses-2", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml index 010a3be..1b2845d 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-buses-1.xml @@ -22,10 +22,9 @@ <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'/> </controller> <controller type='usb' index='0' model='none'/> - <controller type='pci' index='1' model='pci-bridge'> - <model name='pci-bridge'/> - <target chassisNr='1'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + <controller type='pci' index='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> </controller> <memballoon model='none'/> <panic model='pseries'/> diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml index 336373b..5a78590 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-many-devices.xml @@ -19,106 +19,105 @@ <target index='0'/> </controller> <controller type='scsi' index='0' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> </controller> <controller type='scsi' index='1' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> </controller> <controller type='scsi' index='2' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </controller> <controller type='scsi' index='3' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> </controller> <controller type='scsi' index='4' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> </controller> <controller type='scsi' index='5' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </controller> <controller type='scsi' index='6' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> </controller> <controller type='scsi' index='7' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> </controller> <controller type='scsi' index='8' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> </controller> <controller type='scsi' index='9' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> </controller> <controller type='scsi' index='10' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0b' function='0x0'/> </controller> <controller type='scsi' index='11' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0c' function='0x0'/> </controller> <controller type='scsi' index='12' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0d' function='0x0'/> </controller> <controller type='scsi' index='13' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x0f' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/> </controller> <controller type='scsi' index='14' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x10' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x0f' function='0x0'/> </controller> <controller type='scsi' index='15' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x11' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x10' function='0x0'/> </controller> <controller type='scsi' index='16' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x12' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x11' function='0x0'/> </controller> <controller type='scsi' index='17' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x13' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x12' function='0x0'/> </controller> <controller type='scsi' index='18' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x14' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x13' function='0x0'/> </controller> <controller type='scsi' index='19' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x15' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x14' function='0x0'/> </controller> <controller type='scsi' index='20' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x16' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x15' function='0x0'/> </controller> <controller type='scsi' index='21' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x17' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x16' function='0x0'/> </controller> <controller type='scsi' index='22' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x18' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x17' function='0x0'/> </controller> <controller type='scsi' index='23' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x19' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x18' function='0x0'/> </controller> <controller type='scsi' index='24' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1a' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x19' function='0x0'/> </controller> <controller type='scsi' index='25' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1a' function='0x0'/> </controller> <controller type='scsi' index='26' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1c' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/> </controller> <controller type='scsi' index='27' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1c' function='0x0'/> </controller> <controller type='scsi' index='28' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x0'/> </controller> <controller type='scsi' index='29' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1e' function='0x0'/> </controller> <controller type='scsi' index='30' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x0'/> </controller> <controller type='scsi' index='31' model='virtio-scsi'> - <address type='pci' domain='0x0000' bus='0x01' slot='0x02' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x01' function='0x0'/> </controller> <controller type='usb' index='0' model='none'/> - <controller type='pci' index='1' model='pci-bridge'> - <model name='pci-bridge'/> - <target chassisNr='1'/> - <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/> + <controller type='pci' index='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> </controller> <memballoon model='none'/> <panic model='pseries'/> diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c index b75807c..15ac744 100644 --- a/tests/qemuxml2xmltest.c +++ b/tests/qemuxml2xmltest.c @@ -680,12 +680,10 @@ mymain(void) DO_TEST("pseries-many-devices", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI); DO_TEST("pseries-many-buses-1", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, QEMU_CAPS_DEVICE_SPAPR_PCI_HOST_BRIDGE, - QEMU_CAPS_DEVICE_PCI_BRIDGE, QEMU_CAPS_VIRTIO_SCSI); DO_TEST("pseries-many-buses-2", QEMU_CAPS_CHARDEV, QEMU_CAPS_NODEFCONFIG, -- 2.7.5

Isolation groups will eventually allow us to make sure certain devices, eg. PCI hostdevs, are assigned to guest PCI buses in a way that guarantees improved isolation, error detection and recovery for machine types and hypervisors that support it, eg. pSeries guest on QEMU. --- src/bhyve/bhyve_device.c | 4 ++-- src/conf/device_conf.h | 4 ++++ src/conf/domain_addr.c | 33 +++++++++++++++++++++++++-------- src/conf/domain_addr.h | 7 ++++++- src/conf/domain_conf.h | 4 ++++ src/qemu/qemu_domain_address.c | 34 +++++++++++++++++----------------- 6 files changed, 58 insertions(+), 28 deletions(-) diff --git a/src/bhyve/bhyve_device.c b/src/bhyve/bhyve_device.c index fdfd512..03aa6c9 100644 --- a/src/bhyve/bhyve_device.c +++ b/src/bhyve/bhyve_device.c @@ -57,7 +57,7 @@ bhyveCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, } if (virDomainPCIAddressReserveAddr(addrs, addr, - VIR_PCI_CONNECT_TYPE_PCI_DEVICE) < 0) { + VIR_PCI_CONNECT_TYPE_PCI_DEVICE, 0) < 0) { goto cleanup; } @@ -100,7 +100,7 @@ bhyveAssignDevicePCISlots(virDomainDefPtr def, lpc_addr.slot = 0x1; if (virDomainPCIAddressReserveAddr(addrs, &lpc_addr, - VIR_PCI_CONNECT_TYPE_PCI_DEVICE) < 0) { + VIR_PCI_CONNECT_TYPE_PCI_DEVICE, 0) < 0) { goto error; } diff --git a/src/conf/device_conf.h b/src/conf/device_conf.h index 58b2c9c..4b1377c 100644 --- a/src/conf/device_conf.h +++ b/src/conf/device_conf.h @@ -163,6 +163,10 @@ struct _virDomainDeviceInfo { * assignment, never saved and never reported. */ int pciConnectFlags; /* enum virDomainPCIConnectFlags */ + + /* PCI devices will only be automatically placed on a PCI bus + * that shares the same isolation group */ + int isolationGroup; }; diff --git a/src/conf/domain_addr.c b/src/conf/domain_addr.c index e6a6399..cd26b21 100644 --- a/src/conf/domain_addr.c +++ b/src/conf/domain_addr.c @@ -365,7 +365,8 @@ virDomainPCIAddressBusSetModel(virDomainPCIAddressBusPtr bus, static int virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr, - virDomainPCIConnectFlags flags) + virDomainPCIConnectFlags flags, + int isolationGroup) { int add; size_t i; @@ -492,6 +493,9 @@ virDomainPCIAddressSetGrow(virDomainPCIAddressSetPtr addrs, for (; i < addrs->nbuses; i++) { if (virDomainPCIAddressBusSetModel(&addrs->buses[i], model) < 0) return -1; + + /* Set isolation group for the new bus */ + addrs->buses[i].isolationGroup = isolationGroup; } return add; @@ -534,6 +538,7 @@ static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr, virDomainPCIConnectFlags flags, + int isolationGroup, bool fromConfig) { int ret = -1; @@ -546,8 +551,10 @@ virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr addrs, goto cleanup; /* Add an extra bus if necessary */ - if (addrs->dryRun && virDomainPCIAddressSetGrow(addrs, addr, flags) < 0) + if (addrs->dryRun && + virDomainPCIAddressSetGrow(addrs, addr, flags, isolationGroup) < 0) { goto cleanup; + } /* Check that the requested bus exists, is the correct type, and we * are asking for a valid slot */ @@ -586,9 +593,11 @@ virDomainPCIAddressReserveAddrInternal(virDomainPCIAddressSetPtr addrs, int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr, - virDomainPCIConnectFlags flags) + virDomainPCIConnectFlags flags, + int isolationGroup) { - return virDomainPCIAddressReserveAddrInternal(addrs, addr, flags, true); + return virDomainPCIAddressReserveAddrInternal(addrs, addr, flags, + isolationGroup, true); } int @@ -624,7 +633,8 @@ virDomainPCIAddressEnsureAddr(virDomainPCIAddressSetPtr addrs, goto cleanup; ret = virDomainPCIAddressReserveAddrInternal(addrs, &dev->addr.pci, - flags, true); + flags, dev->isolationGroup, + true); } else { ret = virDomainPCIAddressReserveNextAddr(addrs, dev, flags, -1); } @@ -745,6 +755,7 @@ static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr next_addr, virDomainPCIConnectFlags flags, + int isolationGroup, int function) { virPCIDeviceAddress a = { 0 }; @@ -765,6 +776,10 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, for (a.bus = 0; a.bus < addrs->nbuses; a.bus++) { bool found = false; + /* Isolation groups for bus and device must match */ + if (addrs->buses[a.bus].isolationGroup != isolationGroup) + continue; + a.slot = addrs->buses[a.bus].minSlot; if (virDomainPCIAddressFindUnusedFunctionOnBus(&addrs->buses[a.bus], @@ -780,7 +795,7 @@ virDomainPCIAddressGetNextAddr(virDomainPCIAddressSetPtr addrs, /* There were no free slots after the last used one */ if (addrs->dryRun) { /* a is already set to the first new bus */ - if (virDomainPCIAddressSetGrow(addrs, &a, flags) < 0) + if (virDomainPCIAddressSetGrow(addrs, &a, flags, isolationGroup) < 0) goto error; /* this device will use the first slot of the new bus */ a.slot = addrs->buses[a.bus].minSlot; @@ -825,10 +840,12 @@ virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, { virPCIDeviceAddress addr; - if (virDomainPCIAddressGetNextAddr(addrs, &addr, flags, function) < 0) + if (virDomainPCIAddressGetNextAddr(addrs, &addr, flags, + dev->isolationGroup, function) < 0) return -1; - if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags, false) < 0) + if (virDomainPCIAddressReserveAddrInternal(addrs, &addr, flags, + dev->isolationGroup, false) < 0) return -1; if (!addrs->dryRun) { diff --git a/src/conf/domain_addr.h b/src/conf/domain_addr.h index 1849d2b..23c7900 100644 --- a/src/conf/domain_addr.h +++ b/src/conf/domain_addr.h @@ -100,6 +100,10 @@ typedef struct { * bit is set, that function is in use by a device. */ virDomainPCIAddressSlot slot[VIR_PCI_ADDRESS_SLOT_LAST + 1]; + + /* PCI devices will only be automatically placed on a PCI bus + * that shares the same isolation group */ + int isolationGroup; } virDomainPCIAddressBus; typedef virDomainPCIAddressBus *virDomainPCIAddressBusPtr; @@ -147,7 +151,8 @@ bool virDomainPCIAddressSlotInUse(virDomainPCIAddressSetPtr addrs, int virDomainPCIAddressReserveAddr(virDomainPCIAddressSetPtr addrs, virPCIDeviceAddressPtr addr, - virDomainPCIConnectFlags flags) + virDomainPCIConnectFlags flags, + int isolationGroup) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); int virDomainPCIAddressReserveNextAddr(virDomainPCIAddressSetPtr addrs, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 244977a..507891a 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -786,6 +786,10 @@ struct _virDomainPCIControllerOpts { * item in memory target config) -1 == unspecified */ int numaNode; + + /* PCI devices will only be automatically placed on a PCI bus + * that shares the same isolation group */ + int isolationGroup; }; typedef struct _virDomainUSBControllerOpts virDomainUSBControllerOpts; diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 08773c0..384d6fd 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -1032,7 +1032,8 @@ qemuDomainCollectPCIAddress(virDomainDefPtr def ATTRIBUTE_UNUSED, } if (virDomainPCIAddressReserveAddr(addrs, addr, - info->pciConnectFlags) < 0) { + info->pciConnectFlags, + info->isolationGroup) < 0) { goto cleanup; } @@ -1077,6 +1078,8 @@ qemuDomainPCIAddressSetCreate(virDomainDefPtr def, if (virDomainPCIAddressBusSetModel(&addrs->buses[idx], cont->model) < 0) goto error; + addrs->buses[idx].isolationGroup = cont->opts.pciopts.isolationGroup; + if (cont->model == VIR_DOMAIN_CONTROLLER_MODEL_PCIE_ROOT) hasPCIeRoot = true; } @@ -1193,7 +1196,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def, if (addrs->nbuses) { memset(&tmp_addr, 0, sizeof(tmp_addr)); tmp_addr.slot = 1; - if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; } @@ -1228,7 +1231,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def, goto cleanup; } } else { - if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; primaryVideo->info.addr.pci = tmp_addr; primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; @@ -1253,7 +1256,7 @@ qemuDomainValidateDevicePCISlotsPIIX3(virDomainDefPtr def, VIR_DEBUG("PCI address 0:0:2.0 in use, future addition of a video" " device will not be possible without manual" " intervention"); - } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) { + } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) { goto cleanup; } } @@ -1329,10 +1332,8 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, assign = true; } if (assign) { - if (virDomainPCIAddressReserveAddr(addrs, - &tmp_addr, flags) < 0) { + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; - } cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; cont->info.addr.pci.domain = 0; @@ -1354,10 +1355,8 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, memset(&tmp_addr, 0, sizeof(tmp_addr)); tmp_addr.slot = 0x1E; if (!virDomainPCIAddressSlotInUse(addrs, &tmp_addr)) { - if (virDomainPCIAddressReserveAddr(addrs, - &tmp_addr, flags) < 0) { + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; - } cont->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; cont->info.addr.pci.domain = 0; @@ -1380,12 +1379,12 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, tmp_addr.slot = 0x1F; tmp_addr.function = 0; tmp_addr.multi = VIR_TRISTATE_SWITCH_ON; - if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; tmp_addr.function = 3; tmp_addr.multi = VIR_TRISTATE_SWITCH_ABSENT; - if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; } @@ -1419,7 +1418,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, goto cleanup; } } else { - if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; primaryVideo->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; primaryVideo->info.addr.pci = tmp_addr; @@ -1445,8 +1444,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, " device will not be possible without manual" " intervention"); virResetLastError(); - } else if (virDomainPCIAddressReserveAddr(addrs, - &tmp_addr, flags) < 0) { + } else if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) { goto cleanup; } } @@ -1467,7 +1465,7 @@ qemuDomainValidateDevicePCISlotsQ35(virDomainDefPtr def, !virDeviceInfoPCIAddressWanted(&sound->info)) { continue; } - if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags) < 0) + if (virDomainPCIAddressReserveAddr(addrs, &tmp_addr, flags, 0) < 0) goto cleanup; sound->info.type = VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI; @@ -1684,7 +1682,8 @@ qemuDomainAssignDevicePCISlots(virDomainDefPtr def, if (foundAddr) { /* Reserve this function on the slot we found */ if (virDomainPCIAddressReserveAddr(addrs, &addr, - cont->info.pciConnectFlags) < 0) { + cont->info.pciConnectFlags, + cont->info.isolationGroup) < 0) { goto error; } @@ -2150,6 +2149,7 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, } dev.type = VIR_DOMAIN_DEVICE_CONTROLLER; dev.data.controller = def->controllers[contIndex]; + dev.data.controller->opts.pciopts.isolationGroup = bus->isolationGroup; /* set connect flags so it will be properly addressed */ qemuDomainFillDevicePCIConnectFlags(def, &dev, qemuCaps, driver); -- 2.7.5

--- docs/schemas/domaincommon.rng | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index d565a0b..7328fd3 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2009,6 +2009,11 @@ </optional> </element> </optional> + <optional> + <element name='isolationGroup'> + <ref name='uint8'/> + </element> + </optional> <!-- *-root controllers have an optional element "pcihole64"--> <choice> <group> -- 2.7.5

--- src/conf/domain_conf.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 10998ea..989ed88 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -9176,6 +9176,15 @@ virDomainControllerDefParseXML(xmlNodePtr node, goto error; } } + + rc = virXPathInt("string(./isolationGroup)", ctxt, + &def->opts.pciopts.isolationGroup); + if (rc == -2 || (rc == 0 && def->opts.pciopts.isolationGroup < 0)) { + virReportError(VIR_ERR_XML_ERROR, "%s", + _("invalid isolation group for PCI controller")); + goto error; + } + if (numaNode >= 0) def->opts.pciopts.numaNode = numaNode; break; @@ -21381,6 +21390,7 @@ virDomainControllerDefFormat(virBufferPtr buf, const char *model = NULL; const char *modelName = NULL; bool pcihole64 = false, pciModel = false, pciTarget = false; + bool pciIsolationGroup = false; virBuffer driverBuf = VIR_BUFFER_INITIALIZER; if (!type) { @@ -21437,13 +21447,15 @@ virDomainControllerDefFormat(virBufferPtr buf, def->opts.pciopts.idx != -1 || def->opts.pciopts.numaNode != -1) pciTarget = true; + if (def->opts.pciopts.isolationGroup) + pciIsolationGroup = true; break; default: break; } - if (pciModel || pciTarget || + if (pciModel || pciTarget || pciIsolationGroup || def->queues || def->cmd_per_lun || def->max_sectors || def->ioeventfd || def->iothread || virDomainDeviceInfoNeedsFormat(&def->info, flags) || pcihole64) { @@ -21522,6 +21534,11 @@ virDomainControllerDefFormat(virBufferPtr buf, "pcihole64>\n", def->opts.pciopts.pcihole64size); } + if (pciIsolationGroup) { + virBufferAsprintf(buf, "<isolationGroup>%d</isolationGroup>\n", + def->opts.pciopts.isolationGroup); + } + virBufferAdjustIndent(buf, -2); virBufferAddLit(buf, "</controller>\n"); } else { -- 2.7.5

All the pieces are now in place, so we can finally start using isolation groups to achieve our initial goal, which is separating hostdevs from emulated PCI devices while keeping hostdevs that belong to the same host IOMMU group together. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1280542 --- src/qemu/qemu_domain_address.c | 79 ++++++++++++++++++++++ .../qemuxml2argv-pseries-hostdev.args | 8 ++- .../qemuxml2xmlout-pseries-hostdev.xml | 16 ++++- 3 files changed, 97 insertions(+), 6 deletions(-) diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 384d6fd..877ff90 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -901,6 +901,82 @@ qemuDomainFillAllPCIConnectFlags(virDomainDefPtr def, /** + * qemuDomainFillDeviceIsolationGroupIter: + * @def: domain definition + * @dev: device definition + * @info: device information + * @opaque: user data + * + * Fill isolation group information for a single device. + * + * You're not meant to call this directly, use + * qemuDomainFillAllIsolationGroups() instead. + * + * Return: 0 on success, <0 on failure + * */ +static int +qemuDomainFillDeviceIsolationGroupIter(virDomainDefPtr def, + virDomainDeviceDefPtr dev, + virDomainDeviceInfoPtr info, + void *opaque ATTRIBUTE_UNUSED) +{ + virDomainHostdevDefPtr hostdev; + virPCIDeviceAddressPtr hostAddr; + + /* Only pSeries guests care about isolation groups at the moment */ + if (!qemuDomainIsPSeries(def)) + return 0; + + /* Only hostdev... */ + if (dev->type != VIR_DOMAIN_DEVICE_HOSTDEV) + return 0; + + hostdev = dev->data.hostdev; + + /* ... of the PCI kind need this extra information */ + if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS || + hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI) { + return 0; + } + + hostAddr = &hostdev->source.subsys.u.pci.addr; + + /* The isolation group is simply the IOMMU group assigned by the host */ + info->isolationGroup = virPCIDeviceAddressGetIOMMUGroupNum(hostAddr); + + if (info->isolationGroup < 0) { + VIR_WARN("Can't look up isolation group for device %04x:%02x:%02x.%x", + hostAddr->domain, hostAddr->bus, + hostAddr->slot, hostAddr->function); + } else { + VIR_DEBUG("Isolation group for device %04x:%02x:%02x.%x is %d", + hostAddr->domain, hostAddr->bus, + hostAddr->slot, hostAddr->function, + info->isolationGroup); + } + + return info->isolationGroup; +} + + +/** + * qemuDomainFillAllIsolationGroups: + * @def: domain definition + * + * Fill isolation group information for all devices in @def. + * + * Return: 0 on success, <0 on failure + */ +static int +qemuDomainFillAllIsolationGroups(virDomainDefPtr def) +{ + return virDomainDeviceInfoIterate(def, + qemuDomainFillDeviceIsolationGroupIter, + NULL); +} + + +/** * qemuDomainFillDevicePCIConnectFlags: * * @def: the entire DomainDef @@ -2036,6 +2112,9 @@ qemuDomainAssignPCIAddresses(virDomainDefPtr def, if (qemuDomainFillAllPCIConnectFlags(def, qemuCaps, driver) < 0) goto cleanup; + if (qemuDomainFillAllIsolationGroups(def) < 0) + goto cleanup; + if (nbuses > 0) { /* 1st pass to figure out how many PCI bridges we need */ if (!(addrs = qemuDomainPCIAddressSetCreate(def, nbuses, true))) diff --git a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.args b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.args index dbd2964..9630a83 100644 --- a/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.args +++ b/tests/qemuxml2argvdata/qemuxml2argv-pseries-hostdev.args @@ -18,6 +18,8 @@ QEMU_AUDIO_DRV=none \ server,nowait \ -mon chardev=charmonitor,id=monitor,mode=readline \ -boot c \ --device vfio-pci,host=0001:01:00.0,id=hostdev0,bus=pci.0,addr=0x1 \ --device vfio-pci,host=0005:90:01.2,id=hostdev1,bus=pci.0,addr=0x2 \ --device vfio-pci,host=0001:01:00.1,id=hostdev2,bus=pci.0,addr=0x3 +-device spapr-pci-host-bridge,index=1,id=pci.1 \ +-device spapr-pci-host-bridge,index=2,id=pci.2 \ +-device vfio-pci,host=0001:01:00.0,id=hostdev0,bus=pci.1.0,addr=0x1 \ +-device vfio-pci,host=0005:90:01.2,id=hostdev1,bus=pci.2.0,addr=0x1 \ +-device vfio-pci,host=0001:01:00.1,id=hostdev2,bus=pci.1.0,addr=0x2 diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdev.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdev.xml index a00c09c..7560661 100644 --- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdev.xml +++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-pseries-hostdev.xml @@ -19,26 +19,36 @@ <target index='0'/> </controller> <controller type='usb' index='0' model='none'/> + <controller type='pci' index='1' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='1'/> + <isolationGroup>2</isolationGroup> + </controller> + <controller type='pci' index='2' model='pci-root'> + <model name='spapr-pci-host-bridge'/> + <target index='2'/> + <isolationGroup>3</isolationGroup> + </controller> <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='0x01' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x01' 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='0x02' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x02' slot='0x01' 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='0x03' function='0x0'/> + <address type='pci' domain='0x0000' bus='0x01' slot='0x02' function='0x0'/> </hostdev> <memballoon model='none'/> <panic model='pseries'/> -- 2.7.5

Now for a slightly more serious overview; more details can be obtained by reading the bug report[1]. There are two main goals behind this series: 1) allow the use of multiple PHBs for pSeries guests; 2) isolate hostdevs from emulated devices. By implementing these changes, pSeries guests running on QEMU/KVM become more similar to those running on PowerVM, which is great for admins. It also makes it possible to have better error detection / recovery. The first part involves convincing libvirt that a guest can have more than a single pci-root controller, which is something that was explicitly forbidden until now. Only pSeries guests get to follow the new rules, of course. Once PHBs are usable, it makes sense to just use them for pretty much everything on pSeries guests. pci-bridge is no longer needed, which is good because it probably never really worked on such guests. To match PowerVM's behavior and provide better isolation, hostdevs should be assigned each their own PHB. Well, almost: the exact requirement is one PHB per host IOMMU group, with the default PHB being reserved for emulated devices. To achieve this, the concept of "isolation group"[2] is introduced: each PHB is assigned one, and only devices that match it will be automatically assigned to that PHB. For hostdevs, the isolation group is the same as the host IOMMU group; emulated devices are assigned the default isolation group, same as the default PHB. It all works out. The implementation is basically complete, minus the documentation. I'm debating whether the current handling of the default isolation group is good or not, but the ideas are all there and I expect I'll need a couple of respins to get all the details right, so feel free to start reviewing :) [1] https://bugzilla.redhat.com/show_bug.cgi?id=1280542 [2] Named like that because, at least for me, "IOMMU" is basically a tongue twister -- Andrea Bolognani / Red Hat / Virtualization

If anyone's looking at this, please be aware that I'm in the process of reworking Book 4 (eg. patches 23-26) quite heavily at the moment in order to address a couple of limitations: the lack of hotplug support, and the fact that isolation groups are assigned in a way that's very static and as such requires too much planning to be usable. The goal is for isolation groups to be more dynamic while still ensuring no conflicts can occur, so for example PHBs will be allowed to change their isolation group if there are no devices assigned to them. I'm also experimenting to see whether we can get away with not formatting <isolationGroup/> at all, and it looks like it might just work. Everything up until patch 22 should remain unchanged. -- Andrea Bolognani / Red Hat / Virtualization
participants (3)
-
Andrea Bolognani
-
Ján Tomko
-
Laine Stump