[libvirt] [PATCH 6/8] domain: Make <address type='pci'/> request address allocation
John Ferlan
jferlan at redhat.com
Mon Mar 21 18:44:53 UTC 2016
On 03/08/2016 11:36 AM, Cole Robinson wrote:
> If a bare device <address type='pci'/> is specified, set an internal
> flag address->auto_allocate. Individual hv drivers can then check for
> this and act on it if they want, nothing is allocated in generic code.
>
> If drivers allocate an address, they are expected to unset auto_allocate.
> Generic domain conf code then checks at XML format time to ensure no
> device addresses still have auto_allocate set; this ensures we aren't
> formatting any bogus address XML, and informing the user if their
> request didn't work. Add a genericxml2xml test case for this.
>
> The auto_allocate property is a part of the generic address structure
> and not the PCI specific bits, this will make it easier to reuse with
> other address types too.
>
> One note: we detect <address type='pci'/> by counting it's XML properties,
> rather than comparing specifically against parsed values, which seems
> easier to maintain.
> ---
> docs/schemas/domaincommon.rng | 5 +++-
> src/conf/domain_conf.c | 29 +++++++++++++++++++++-
> src/conf/domain_conf.h | 1 +
> .../generic-pci-autofill-addr.xml | 27 ++++++++++++++++++++
> tests/genericxml2xmltest.c | 17 +++++++++----
> 5 files changed, 72 insertions(+), 7 deletions(-)
> create mode 100644 tests/genericxml2xmlindata/generic-pci-autofill-addr.xml
>
Will also need to update 'formatdomain.html.in' to describe the new
allowance of just "<address type='pci'>...
Would this be useful if "multifunction='on'" without specifying an
address? e.g.:
<address type='pci' multifunction='on'>
Could other address types find the functionality useful? That is, I want
address type 'drive' or 'usb', but I have no idea how to fill in the
rest, I want the hv to do it for me.
Rather than focus on anything that could change if patch3 is adjusted...
I'll point only a couple of things here. I do think the less times to
iterate through devices the better - the whole address assignment
processing and post part device iteration is complex enough already!
John
> diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
> index 6ca937c..d083250 100644
> --- a/docs/schemas/domaincommon.rng
> +++ b/docs/schemas/domaincommon.rng
> @@ -4471,7 +4471,10 @@
> <attribute name="type">
> <value>pci</value>
> </attribute>
> - <ref name="pciaddress"/>
> + <choice>
> + <ref name="pciaddress"/>
> + <empty/>
> + </choice>
> </group>
> <group>
> <attribute name="type">
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index bc4e369..bbc42a4 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -3827,6 +3827,23 @@ virDomainDefPostParseTimer(virDomainDefPtr def)
> }
>
>
> + static int
^
Extraneous space
> +virDomainCheckUnallocatedDeviceAddrs(virDomainDefPtr def ATTRIBUTE_UNUSED,
> + virDomainDeviceDefPtr dev,
> + virDomainDeviceInfoPtr info,
> + void *data ATTRIBUTE_UNUSED)
> +{
> + if (!info->auto_allocate)
> + return 0;
> +
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("driver didn't allocate requested address type '%s' for device '%s'"),
> + virDomainDeviceAddressTypeToString(info->type),
> + virDomainDeviceTypeToString(dev->type));
> + return -1;
> +}
> +
> +
> static int
> virDomainDefPostParseInternal(virDomainDefPtr def,
> virCapsPtr caps ATTRIBUTE_UNUSED,
> @@ -3851,6 +3868,11 @@ virDomainDefPostParseInternal(virDomainDefPtr def,
> if (virDomainDefPostParseTimer(def) < 0)
> return -1;
>
> + /* ensure the driver filled in any auto_allocate addrs */
> + if (virDomainDeviceInfoIterate(def, virDomainCheckUnallocatedDeviceAddrs,
> + NULL) < 0)
> + return -1;
> +
Why couldn't this go in virDomainDefPostParseDeviceIterator?
That is, rather than have yet another iterator through the devices, call
virDomainCheckUnallocatedDeviceAddrs right after or at the end of
virDomainDeviceDefPostParse...
> if (virDomainDefAddImplicitDevices(def) < 0)
> return -1;
>
> @@ -4872,8 +4894,13 @@ virDomainDeviceInfoParseXML(xmlNodePtr node,
>
> switch ((virDomainDeviceAddressType) info->type) {
> case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI:
> - if (virDevicePCIAddressParseXML(address, &info->addr.pci) < 0)
> + if (virXMLPropertyCount(address) == 1) {
Wish there was some other way than counting attributes, but I guess
since "type" is an attribute we can hopefully guarantee that only
"type=<something>" has been supplied.
> + /* Bare <address type='pci'/> is a request to allocate
> + the address. */
> + info->auto_allocate = true;
> + } else if (virDevicePCIAddressParseXML(address, &info->addr.pci) < 0) {
> goto cleanup;
> + }
> break;
>
> case VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE:
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index aba53a2..dd9d0b1 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -346,6 +346,7 @@ struct _virDomainDeviceInfo {
> */
> char *alias;
> int type; /* virDomainDeviceAddressType */
> + bool auto_allocate;
The name is generic enough to make me think it could work for other
address types, but only PCI is supported.
> union {
> virDevicePCIAddress pci;
> virDomainDeviceDriveAddress drive;
> diff --git a/tests/genericxml2xmlindata/generic-pci-autofill-addr.xml b/tests/genericxml2xmlindata/generic-pci-autofill-addr.xml
> new file mode 100644
> index 0000000..06eadb6
> --- /dev/null
> +++ b/tests/genericxml2xmlindata/generic-pci-autofill-addr.xml
> @@ -0,0 +1,27 @@
> +<domain type='test'>
> + <name>QEMUGuest1</name>
> + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
> + <memory unit='KiB'>219136</memory>
> + <currentMemory unit='KiB'>219136</currentMemory>
> + <vcpu placement='static'>1</vcpu>
> + <os>
> + <type arch='i686' machine='pc'>hvm</type>
> + <boot dev='hd'/>
> + </os>
> + <clock offset='utc'/>
> + <on_poweroff>destroy</on_poweroff>
> + <on_reboot>restart</on_reboot>
> + <on_crash>destroy</on_crash>
> + <devices>
> + <emulator>/usr/bin/qemu</emulator>
> + <disk type='block' device='disk'>
> + <driver name='qemu' type='raw'/>
> + <source dev='/dev/HostVG/QEMUGuest1'/>
> + <target dev='vda' bus='virtio'/>
> + <address type='pci'/>
> + </disk>
> + <controller type='usb' index='0'>
> + <address type='pci'/>
> + </controller>
> + </devices>
> +</domain>
> diff --git a/tests/genericxml2xmltest.c b/tests/genericxml2xmltest.c
> index 666fc86..b329d10 100644
> --- a/tests/genericxml2xmltest.c
> +++ b/tests/genericxml2xmltest.c
> @@ -21,6 +21,7 @@ struct testInfo {
> const char *name;
> int different;
> bool inactive_only;
> + testCompareDomXML2XMLFlags compare_flags;
> };
>
> static int
> @@ -39,7 +40,7 @@ testCompareXMLToXMLHelper(const void *data)
>
> ret = testCompareDomXML2XMLFiles(caps, xmlopt, xml_in,
> info->different ? xml_out : xml_in,
> - !info->inactive_only, 0,
> + !info->inactive_only, info->compare_flags,
> NULL, NULL, 0);
> cleanup:
> VIR_FREE(xml_in);
> @@ -59,21 +60,27 @@ mymain(void)
> if (!(xmlopt = virTestGenericDomainXMLConfInit()))
> return EXIT_FAILURE;
>
> -#define DO_TEST_FULL(name, is_different, inactive) \
> +#define DO_TEST_FULL(name, is_different, inactive, compare_flags) \
> do { \
> - const struct testInfo info = {name, is_different, inactive}; \
> + const struct testInfo info = {name, is_different, \
> + inactive, compare_flags}; \
> if (virtTestRun("GENERIC XML-2-XML " name, \
> testCompareXMLToXMLHelper, &info) < 0) \
> ret = -1; \
> } while (0)
>
> #define DO_TEST(name) \
> - DO_TEST_FULL(name, 0, false)
> + DO_TEST_FULL(name, 0, false, 0)
> +
> +#define DO_TEST_PARSE_ERROR(name) \
> + DO_TEST_FULL(name, 0, false, \
> + TEST_COMPARE_DOM_XML2XML_FLAG_EXPECT_PARSE_ERROR)
>
> #define DO_TEST_DIFFERENT(name) \
> - DO_TEST_FULL(name, 1, false)
> + DO_TEST_FULL(name, 1, false, 0)
>
> DO_TEST_DIFFERENT("disk-virtio");
> + DO_TEST_PARSE_ERROR("pci-autofill-addr");
>
> virObjectUnref(caps);
> virObjectUnref(xmlopt);
>
More information about the libvir-list
mailing list