On 03/01/2013 02:10 PM, Laine Stump wrote:
On 02/20/2013 12:06 PM, Peter Krempa wrote:
> This patch adds instrumentation that will ultimately allow to split out
> filling of defaults and input validation from the XML parser to separate
> functions.
>
> With this patch, after the XML is parsed, a callback to the driver is
> issued requesing to fill and validate driver specific details of the
> configuration. This allows to use sensible defaults and checks on a per
> driver basis at the time the XML is parsed.
>
> Two callback pointers are exposed in the virCaps object:
> * virDriverDeviceDefCallback - called for a single device parsed and for
> every single device in a domain config.
> A virDomainDeviceDefPtr is passed.
> * virDriverDomainDefCallback - called if a domain definition is parsed
> device specific callbacks were called.
> A virDomainDefPtr is passed.
>
> Errors may be reported in those callbacks resulting in a XML parsing
> failure.
>
> Additionally two internal filler functions are added:
> virDomainDeviceDefUpdateDefaultsInternal and
> virDomainDefUpdateDefaultsInternal that are meant to be used for
> separating the validation and defaults assignment code from the parser
> function.
> ---
> src/conf/capabilities.h | 6 +++++
> src/conf/domain_conf.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 78 insertions(+)
>
> diff --git a/src/conf/capabilities.h b/src/conf/capabilities.h
> index cc01765..56cd09f 100644
> --- a/src/conf/capabilities.h
> +++ b/src/conf/capabilities.h
> @@ -171,6 +171,12 @@ struct _virCaps {
> bool hasWideScsiBus;
> const char *defaultInitPath;
>
> +
> + /* these callbacks are called after a XML definition of a device or domain
> + * is parsed. They are meant to validate and fill driver-specific values. */
> + int (*virDriverDeviceDefCallback)(void *); /* virDomainDeviceDefPtr is passed
*/
> + int (*virDriverDomainDefCallback)(void *); /* virDomainDefPtr is passed */
If you know that virDriverDeviceDefCallback is always given a
virDomainDeviceDefPtr, why prototype it as void*? Same question for
virDriverDomainDefCallback.
Additionally, in the callback for a device, we will need to have the
virDomainDefPtr (e.g. so that we can see what machinetype was selected
for the domain). And in both of these callbacks we will need to get the
virCapsPtr so that (for example), we can have access to information
about which devices are available for which machine types, the default
pci addresses of integrated devices, etc.
So, I think the callbacks should be like this:
int (*virDriverDeviceDefCallback) (virCapsPtr caps, virDomainDefPtr
*domdef, virDomainDeviceDefPtr *devdef);
int (*virDriverDomainDefCallback) (virCapsPtr caps, virDomainDefPtr
*domdef);
> +
> virDomainXMLNamespace ns;
> };
>
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 421492f..d881983 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -2353,6 +2353,70 @@ int virDomainDeviceInfoIterate(virDomainDefPtr def,
> }
>
>
> +static int
> +virDomainDeviceDefUpdateDefaultsInternal(virDomainDeviceDefPtr dev
ATTRIBUTE_UNUSED)
I don't think I agree with calling these functions "UpdateDefaults",
because they could be used for any number of things, e.g. adding extra
devices, creating bridges for extra buses, validating addresses, etc.
Maybe they could be called virDomain*AdjustConfig*() or
virDomain*PostProcess*().
> +{
> + /* not in use yet */
> + return 0;
> +}
> +
> +
> +static int
> +virDomainDefUpdateDefaultsInternal(virDomainDefPtr def ATTRIBUTE_UNUSED,
> + virCapsPtr caps ATTRIBUTE_UNUSED)
> +{
> + /* not in use yet */
> + return 0;
> +}
> +
> +
> +static int
> +virDomainDeviceDefUpdateDefaults(virDomainDeviceDefPtr dev,
> + virCapsPtr caps)
> +{
> + int ret;
> + /* at first call the driver callback to update the device */
> + if (caps->virDriverDeviceDefCallback &&
> + (ret = (caps->virDriverDeviceDefCallback)(dev)) < 0)
> + return ret;
> +
> + /* then fill the parse defaults and do the checks */
> + return virDomainDeviceDefUpdateDefaultsInternal(dev);
> +}
> +
> +
> +static int
> +virDomainDefUpdateDefaultsDeviceIterator(virDomainDefPtr def ATTRIBUTE_UNUSED,
> + virDomainDeviceDefPtr dev,
> + virDomainDeviceInfoPtr info
ATTRIBUTE_UNUSED,
> + void *opaque)
> +{
> + virCapsPtr caps = opaque;
> + return virDomainDeviceDefUpdateDefaults(dev, caps);
> +}
> +
> +
> +static int
> +virDomainDefUpdateDefaults(virDomainDefPtr def,
> + virCapsPtr caps)
> +{
> + int ret;
> +
> + /* at first update all the devices , unfortunately they are separate */
> + if ((ret = virDomainDeviceInfoIterate(def,
> + virDomainDefUpdateDefaultsDeviceIterator,
> + caps)) < 0)
> + return ret;
> +
> + /* call the driver callback to update the rest of the definition */
> + if (caps->virDriverDomainDefCallback &&
> + (ret = (caps->virDriverDomainDefCallback)(def)) < 0)
> + return ret;
I find myself wondering if we're going to want to adjust the domain as a
whole first, then the devices, or the individual devices, then the
domain. I'm not sure which would be more useful. However, it does seem
like the device callback is more likely to look at info for the domain
(which we would probably want to be already adjusted at that time) than
for the domain callback to want to look at individual devices. I could
be wrong though...
And I've already found a counter-example. We will want the PCI addresses
of the devices (the ones which don't have an explicitly confugured
address anyway) to be assigned by the device callback, and it's true
that that will need the domain info to be properly setup (at least
machinetype). However, we'll want to go through and auto-create all the
required extra bridges during the domain callback, but knowing which
bridges we need to create requires that we have already assigned PCI
addresses to all of the devices. :-/
> +
> + return virDomainDefUpdateDefaultsInternal(def, caps);
> +}
> +
> +
> void virDomainDefClearPCIAddresses(virDomainDefPtr def)
> {
> virDomainDeviceInfoIterate(def, virDomainDeviceInfoClearPCIAddress, NULL);
> @@ -8224,6 +8288,10 @@ virDomainDeviceDefParse(virCapsPtr caps,
> goto error;
> }
>
> + /* callback to fill driver specific device aspects */
> + if (virDomainDeviceDefUpdateDefaults(dev, caps) < 0)
> + goto error;
> +
> cleanup:
> xmlFreeDoc(xml);
> xmlXPathFreeContext(ctxt);
> @@ -10714,6 +10782,10 @@ virDomainDefParseXML(virCapsPtr caps,
> if (virDomainDefAddImplicitControllers(def) < 0)
> goto error;
>
> + /* callback to fill driver specific domain aspects */
> + if (virDomainDefUpdateDefaults(def, caps) < 0)
> + goto error;
> +
> virBitmapFree(bootMap);
>
> return def;
--
libvir-list mailing list
libvir-list(a)redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list