[libvirt] [Qemu-devel] [RFC] qmp: query-device-slots command
Eduardo Habkost
ehabkost at redhat.com
Tue Dec 13 20:59:11 UTC 2016
On Tue, Dec 13, 2016 at 08:51:34PM +0100, Markus Armbruster wrote:
> Eduardo Habkost <ehabkost at redhat.com> writes:
>
> > On Tue, Dec 13, 2016 at 12:04:17PM +0100, Markus Armbruster wrote:
> >> Quick interface review only:
> >>
> >> Eduardo Habkost <ehabkost at redhat.com> writes:
> >>
> >> > This adds a new command to QMP: query-device-slots. It will allow
> >> > management software to query possible slots where devices can be
> >> > plugged.
> >> >
> >> > This implementation of the command will return:
> >> >
> >> > * Multiple PCI slots per bus, in the case of PCI buses;
> >> > * One slot per bus in the case of the other buses;
> >>
> >> Umm, that doesn't seem right. For instance, a SCSI bus has multiple
> >> slots. The slot address is the SCSI ID. An IDE bus may have one (SATA)
> >> or two (PATA). For more examples, see qdev-device-use.txt section
> >> "Specifying Bus and Address on Bus".
> >
> > Yes, I should have clarified that: this version changes only PCI
> > to expose multiple slots, but other buses also need be changed to
> > implement BusClass::enumerate_slots() properly, too.
> >
> >>
> >> > * One slot for each entry from query-hotpluggable-cpus.
> >> > In the example below, I am not sure if the PCIe ports are all
> >> > supposed to report all slots, but I didn't find any existing
> >> > field in PCIBus that would help me figure out the actual number
> >> > of slots in a given PCI bus.
> >> >
> >> > Git tree
> >> > --------
> >> >
> >> > This patch needs the previous query-machines series I am working
> >> > on. The full tree can be found on the git tree at:
> >> >
> >> > git://github.com/ehabkost/qemu-hacks.git work/query-machines-bus-info
> >> >
> >> > Example output
> >> > --------------
> >> >
> >> > The following output was returned by QEMU when running it as:
> >> >
> >> > $ qemu-system-x86_64 -machine q35 \
> >> > -readconfig docs/q35-chipset.cfg \
> >> > -smp 4,maxcpus=8,sockets=2,cores=2,threads=2
> >> >
> >> > {
> >> > "return": [
> >>
> >> Are you sure >3000 lines of example output make sense here?
> >
> > I'm not. :)
> >
> > That's why I need feedback from the PCI experts. I believe most
> > of the PCI ports on q35 accept only one device, but I see no code
> > implementing that restriction, and no obvious PCIBus or
> > PCIBusClass field indicating that.
> >
> >>
> >> [...]
> >> > ]
> >> > }
> >> >
> >> > Signed-off-by: Eduardo Habkost <ehabkost at redhat.com>
> >> > ---
> >> > qapi-schema.json | 114 +++++++++++++++++++++++++++++++++++++++++++++++++
> >> > include/hw/qdev-core.h | 6 +++
> >> > hw/core/bus.c | 49 +++++++++++++++++++++
> >> > hw/pci/pci.c | 106 +++++++++++++++++++++++++++++++++------------
> >> > qdev-monitor.c | 86 ++++++++++++++++++++++++++++++++++---
> >> > 5 files changed, 328 insertions(+), 33 deletions(-)
> >> >
> >> > diff --git a/qapi-schema.json b/qapi-schema.json
> >> > index d48ff3f..484d91e 100644
> >> > --- a/qapi-schema.json
> >> > +++ b/qapi-schema.json
> >> > @@ -3166,6 +3166,120 @@
> >> > { 'command': 'closefd', 'data': {'fdname': 'str'} }
> >> >
> >> > ##
> >> > +# @DeviceSlotType:
> >> > +#
> >> > +# Type of device slot
> >> > +#
> >> > +# @generic: Generic device slot, with no bus-specific information
> >> > +# @pci: PCI device slot
> >> > +# @cpu: CPU device slot
> >> > +##
> >> > +{ 'enum': 'DeviceSlotType',
> >> > + 'data': ['generic', 'pci', 'cpu'] }
> >> > +
> >> > +##
> >> > +# @DeviceSlotInfo:
> >> > +#
> >> > +# Information on a slot where devices can be plugged. Some buses
> >> > +# are represented as a single slot that can support multiple devices,
> >> > +# and some buses have multiple slots that are identified by arguments
> >> > +# to @device_add.
> >>
> >> Okay, let me try to wrap my poor, ignorant mind around this.
> >>
> >> There are two kinds of buses: "single slot that can support multiple
> >> devices", and "multiple slots that are identified by arguments".
> >>
> >> How are the two kinds related to @type?
> >
> > They are related to @type indirectly because different bus types
> > will return different data. But I don't want to make this part of
> > the specification: clients should be prepared to handle both
> > cases.
>
> Well, color me confused :)
>
> > e.g. a QEMU version might return a single generic catch-all
> > sysbus-device slot that support any number of devices. Future
> > versions may return more detailed information, and return slots
> > only for the sysbus devices that really work with the machine.
>
> Hmm. See below.
>
> >>
> >> Examples for "multiple slots that are identified by arguments":
> >>
> >> -device edu,addr=06.0,bus=...
> >> -device scsi-hd,scsi-hd=5,bus=...
> >> -device ide-hd,unit=1,bus=...
> >> -device virtserialport,nr=7,bus=...
> >>
> >> Note that each of these buses has its own way to specify a slot address,
> >> namely a bus-specific option.
> >
> > Yes.
> >
> >>
> >> Can you give examples for "single slot that can support multiple
> >> devices"?
> >
> > I can't name any example except sysbus, right now.
>
> Sysbus is a bad example, because it's a hack, not a bus.
>
> Physical devices are wired up in some device-specific way. An important
> special wiring case is plugging into a standard socket provided by a
> bus. But not every device is connected only to a bus. Devices can also
> be wired to other devices in ad hoc ways.
>
> In the initial qdev design, devices could only plug into buses.
> Anything that didn't fit the mold was declared to plug into the "system
> bus", which isn't a bus at all.
>
> The hack used to be fairly harmless, because you couldn't do much with
> system bus devices anyway. Not true anymore: Alex created means to add
> certain system bus devices to certain machines with -device. Has been a
> thorn in my side ever since. I'm afraid we need to understand how
> exactly it works before we can finalize the design for this command.
I agree it is a hack, I just wanted to be able to cover it too
(and possibly other cases where there's no obvious "address"
parameter to devices).
The other options I had were:
a) Omitting the bus from the output;
b) Waiting until we fix sysbus before implementing the interface.
I avoided (a) because I would like to tell libvirt "always check
query-device-slots before plugging anything. if it's not there,
it means you can't plug it". To do that, I would need to ensure
all buses are present in the list (even sysbus).
(But as I say below: I don't love this solution and I am open to
suggestions).
>
> > There are two cases that I tried to cover by reporting
> > multiple-device no-argument slots:
> >
> > 1) Buses that were not converted (yet) to implement
> > enumerate_buses() (in the current version: everything except
> > PCI)
> > 2) Buses that really do not require any extra slot address
> > argument (sysbus? others?)
> >
> > I'm proposing this interface because I don't want (1) or (2) to
> > be missing from the returned data (otherwise management software
> > can't differentiate "this bus is not available" from "this bus
> > simply doesn't implement slot enumeration yet").
> >
> > We won't need the special multi-device-slot case if we eliminate
> > all instances of (1) and (2). Can we do that in 2.9? I'm not
> > sure.
>
> If we can't do a complete job, and we don't want to hide slots affected
> by that, the data we return for them should unequivocally state that
> it's incomplete because computing complete data hasn't been implemented,
> yet.
OK, so we agree we need a way to tell the client the data is
incomplete (or not as detailed as we would like).
I tried to solve that by providing a mechanism to tell the client
"look, I can tell you that there's a bus called <bus name>, and
it is valid to use it as the 'bus' argument for -device and
device_add, but I don't know the rest of the rules (sorry!)". We
can do that by simply including the bus on the list as if it was
a multi-device slot.
But I don't love this solution, so I am open to other suggestions
on how to tell the client that slot information is incomplete for
a bus.
Maybe the following?
1) Add a new DeviceSlotType value meaning "this entry represents
a bus/device-type that can't enumerate its slots" (let's call
it "bus-with-no-slot-info" by now).
2) Remove DeviceSlotType "generic".
3) Remove max-devices field, and simply document the device-limit
semantics for each DeviceSlotType (cpu: 1 device, pci: 1
device, bus-with-no-slot-info: undefined limit).
This looks like a trade-off between moving data to specific union
types (and representing type-specific limits/rules in the schema
documentation), or moving data to the base union type (and
representing type-specific limits as data in the base union
type).
>
> >> > +#
> >> > +# @bus: ID of the bus object where the device can be plugged. Optional,
> >> > +# as some devices don't need a bus to be plugged (e.g. CPUs).
> >> > +# Can be copied to the "bus" argument to @device_add.
> >>
> >> Suggest something like "Can be used as value for @device_add's bus
> >> option".
> >
> > Will do.
> >
> >>
> >> Should we give similar information on the slot address? The option name
> >> is obvious. What about acceptable values?
> >
> > Actually, this part of the documentation was a leftover from a
> > previous version where @bus was inside DeviceSlotInfo. Now I
> > moved @bus inside @props for all device types, and it should be
> > documented the same way as the other fields inside @props.
> >
> >>
> >> > +#
> >> > +# @type: type of device slot.
> >> > +#
> >> > +# @accepted-device-types: List of device types accepted by the slot.
> >> > +# Any device plugged to the slot should implement
> >> > +# one of the accepted device types.
> >> > +#
> >> > +# @max-devices: #optional maximum number of devices that can be plugged
> >> > +# to the slot.
> >>
> >> What does it mean when @max-devices isn't given?
> >
> > It means there is no hard limit on the number of pluggable
> > devices. sysbus is one of such cases.
>
> Sysbus certainly has limits, but they're more complicated than just "at
> most @max-devices devices".
>
> >> > +#
> >> > +# @devices: List of QOM paths for devices that are already plugged.
> >> > +#
> >> > +# @available: If false, the slot is not available for plugging any device.
> >> > +# This value can change at runtime if condition changes
> >> > +# (e.g. if the device becomes full, or if the machine
> >> > +# was already initialized and the slot doesn't support
> >> > +# hotplug).
> >> > +#
> >> > +# @hotpluggable: If true, the slot accepts hotplugged devices.
> >> > +#
> >> > +# DeviceSlotInfo structs always have a @props member, whose members
> >> > +# can be directly copied to the arguments to @device_add.
> >>
> >> Do you mean names of properties common to all @accepted-device-types?
> >
> > I mean that it should be safe to simply use the keys+values in
> > @props as arguments to device_add or -device, for any slot @type.
> > Some clients may want to extract some information from @props (if
> > they already manage PCI addresses, for example), but some of them
> > may simply choose any available slot and copy @props blindly.
> >
> > I didn't want to state anything about QOM properties, because I
> > only want @props to represent device_add/-device arguments. Some
> > of those arguments are consumed by the device_add code itself
> > (e.g. "bus") and others are translated to QOM properties. I don't
> > want the interface to impose any restrictions on how this is
> > implemented.
>
> Hmm, is this meant to work as follows? To plug a device into this slot,
> you use
>
> { "execute": "device_add",
> "arguments": { "driver": TYPE, ... PROPS ... }
>
> where TYPE is a (concrete subtype of a) member of
> @accepted-device-types, and PROPS is the value of @props spliced in.
> Example: the data for slot 06.0 of PCI bus pci.0 would be something like
>
> {
> "bus": "pci.0",
There's no "bus" field in DeviceSlotInfo. It was a documentation bug.
> "props": {
> "bus": "pci.0",
> "addr": "06.0"
> }
> }
>
> Doesn't match your example output; I guess I'm still misunderstanding
> something.
This is a busy PCI slot, from my example:
{
"available": false,
"devices": [
"/machine/q35/mch"
],
"accepted-device-types": [
"legacy-pci-device",
"pci-express-device"
],
"props": {
"bus": "/machine/q35/pcie.0",
"addr": 0
},
"hotpluggable": false,
"type": "pci",
"max-devices": 1
},
This is an empty PCI slot from my example. It has available=false because
hotplug is not supported on the root bus:
{
"available": false,
"devices": [],
"accepted-device-types": [
"legacy-pci-device",
"pci-express-device"
],
"props": {
"bus": "/machine/q35/pcie.0",
"addr": 32
},
"hotpluggable": false,
"type": "pci",
"max-devices": 1
},
This is an empty PCI slot on pc_piix (not on my example):
{
"available": true,
"devices": [],
"accepted-device-types": [
"legacy-pci-device"
],
"props": {
"bus": "/machine/i440fx/pci.0",
"addr": 32
},
"hotpluggable": true,
"type": "pci",
"max-devices": 1
},
This is a free PCIe slot, from my example:
{
"available": true,
"devices": [],
"accepted-device-types": [
"pci-express-device"
],
"props": {
"bus": "/machine/peripheral/ich9-pcie-port-3/ich9-pcie-port-3",
"addr": 0
},
"hotpluggable": true,
"type": "pci",
"max-devices": 1
},
Note that it returns the uint32 value of "addr" (there's some magic on the
devfn setter to make it accept both "<slot>[.<function>]" strings and <devfn>
integers. On the next version, I plan to fix this insanity and replace "addr"
with proper "slot" and "function" integer properties. (See FIXME below)
>
> >
> >>
> >> > +##
> >> > +{ 'union': 'DeviceSlotInfo',
> >> > + 'base': { 'type': 'DeviceSlotType',
> >> > + 'accepted-device-types': [ 'str' ],
> >> > + '*max-devices': 'int', 'devices': [ 'str' ],
> >> > + 'available': 'bool', 'hotpluggable': 'bool' },
> >> > + 'discriminator': 'type',
> >> > + 'data': { 'generic': 'GenericSlotInfo',
> >> > + 'pci': 'PCISlotInfo',
> >> > + 'cpu': 'CPUSlotInfo' } }
> >> > +
> >> > +##
> >> > +# @GenericSlotProperties:
> >> > +##
> >> > +{ 'struct': 'GenericSlotProperties',
> >> > + 'data': { 'bus': 'str' } }
> >> > +
> >> > +
> >> > +##
> >> > +# @GenericSlotInfo:
> >> > +#
> >> > +# Generic slot information, with no bus-specific information
> >> > +##
> >> > +{ 'struct': 'GenericSlotInfo',
> >> > + 'data': { 'props': 'GenericSlotProperties' } }
> >> > +
> >> > +##
> >> > +# @PCIDeviceSlotProperties:
> >> > +#
> >> > +# Properties that can be set when plugging a PCI device.
> >> > +#
> >> > +# @addr: "addr" argument to @device_add.
> >> > +#
> >> > +#FIXME: replace @addr with slot and function properties.
> >> > +##
> >> > +{ 'struct': 'PCIDeviceSlotProperties',
> >> > + 'data': { 'bus': 'str', 'addr': 'int' } }
> >> > +
> >> > +##
> >> > +# @PCISlotInfo:
> >> > +#
> >> > +# Information on a PCI device slot.
> >> > +#
> >> > +# @props: The @device_add arguments that can be used when plugging
> >> > +# the device.
> >> > +##
> >> > +{ 'struct': 'PCISlotInfo',
> >> > + 'data': { 'props': 'PCIDeviceSlotProperties' } }
> >> > +
> >> > +##
> >> > +# @CPUSlotInfo:
> >> > +#
> >> > +# Information on a CPU device slot.
> >> > +#
> >> > +# @props: The @device_add arguments that can be used when plugging
> >> > +# the device.
> >> > +##
> >> > +{ 'struct': 'CPUSlotInfo',
> >> > + 'data': { 'props': 'CpuInstanceProperties' } }
> >> > +
> >> > +##
> >> > +# @query-device-slots:
> >> > +#
> >> > +# Return the list of possible slots for plugging devices using
> >> > +# @device_add.
> >> > +##
> >> > +{ 'command': 'query-device-slots',
> >> > + 'returns': [ 'DeviceSlotInfo' ] }
> >> > +
> >> > +##
> >> > # @MachineBusInfo
> >> > #
> >> > # Information about a bus present on a machine.
> >> [...]
--
Eduardo
More information about the libvir-list
mailing list