From: Shivaprasad G Bhat <sbhat(a)linux.vnet.ibm.com>
virDomainDeviceDefParseXMLMany will be used to parse '<devices>'
XML elements that will be used to supply multiple hostdevs
for hotplug/unplug. The idea is to parse each dev individually,
by calling the same code that already handles it today. The
result is returned in a new virDomainDeviceDefListPtr pointer
type, which is an array of device definitions.
This idea of calling existing functions to handles a single
device definition in a loop is the central idea of how PCI
multifunction hotplug and hotunplug is implemented in the
next patches. Roughly speaking, we'll use virDomainDeviceDefListPtr
lists to call (almost) the same hotplug/unplug mechanics we have
today for each hostdev in the list.
Signed-off-by: Shivaprasad G Bhat <sbhat(a)linux.vnet.ibm.com>
Signed-off-by: Daniel Henrique Barboza <danielhb413(a)gmail.com>
---
src/conf/domain_conf.c | 171 +++++++++++++++++++++++++++++++++++----
src/conf/domain_conf.h | 32 ++++++++
src/libvirt_private.syms | 5 ++
3 files changed, 194 insertions(+), 14 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 5b918cc737..887f7a2633 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -1287,6 +1287,90 @@ virDomainXMLOptionDispose(void *obj)
(xmlopt->config.privFree)(xmlopt->config.priv);
}
+/* virDomainDeviceDefListAddCopy - add a *copy* of the device to this list */
+static int
+virDomainDeviceDefListAddCopy(virDomainDeviceDefListPtr list,
+ virDomainDeviceDefPtr dev,
+ virDomainDeviceDefListDataPtr data,
+ void *parseOpaque)
+{
+ virDomainDeviceDefPtr copy = virDomainDeviceDefCopy(dev,
+ data->def,
+ data->xmlopt,
+ parseOpaque);
+
+ if (!copy)
+ return -1;
+
+ if (VIR_APPEND_ELEMENT(list->devs, list->count, copy) < 0) {
+ virDomainDeviceDefFree(copy);
+ return -1;
+ }
+
+ return 0;
+}
+
+void virDomainDeviceDefListFree(virDomainDeviceDefListPtr list)
+{
+ size_t i;
+
+ if (!list)
+ return;
+ for (i = 0; i < list->count; i++)
+ virDomainDeviceDefFree(list->devs[i]);
+ VIR_FREE(list->devs);
+}
+
+void virDomainDeviceDefListFreeShallow(virDomainDeviceDefListPtr list)
+{
+ size_t i;
+
+ if (!list)
+ return;
+ for (i = 0; i < list->count; i++)
+ VIR_FREE(list->devs[i]);
+}
+
+
+/* virDomainDeviceDefListIter - Iterate through the list with the callback*/
+int
+virDomainDeviceDefListIterate(virDomainDeviceDefListPtr list,
+ virDomainDeviceDefListIterCallback cb,
+ void *data)
+{
+ size_t i;
+
+ for (i = 0; i < list->count; i++)
+ if (cb(list->devs[i], data))
+ return -1;
+
+ return 0;
+}
+
+virDomainDeviceDefListPtr
+virDomainDeviceDefListCopy(virDomainDeviceDefListPtr list,
+ virDomainDeviceDefListDataPtr data,
+ void *parseOpaque)
+{
+ size_t i;
+ virDomainDeviceDefListPtr devlist = NULL;
+
+ if (list && (VIR_ALLOC(devlist) < 0))
+ goto cleanup;
+
+ for (i = 0; i < list->count; i++) {
+ if (virDomainDeviceDefListAddCopy(devlist, list->devs[i],
+ data, parseOpaque) < 0)
+ goto cleanup;
+ }
+
+ return devlist;
+ cleanup:
+ virDomainDeviceDefListFree(devlist);
+ return NULL;
+}
+
+
/**
* virDomainKeyWrapCipherDefParseXML:
*
@@ -16506,23 +16590,16 @@ virDomainVsockDefParseXML(virDomainXMLOptionPtr xmlopt,
return g_steal_pointer(&vsock);
}
-virDomainDeviceDefPtr
-virDomainDeviceDefParse(const char *xmlStr,
- const virDomainDef *def,
- virDomainXMLOptionPtr xmlopt,
- void *parseOpaque,
- unsigned int flags)
+static virDomainDeviceDefPtr
+virDomainDeviceDefParseXML(xmlNodePtr node,
+ const virDomainDef *def,
+ virDomainXMLOptionPtr xmlopt,
+ xmlXPathContextPtr ctxt,
+ void *parseOpaque,
+ unsigned int flags)
{
- g_autoptr(xmlDoc) xml = NULL;
- xmlNodePtr node;
- g_autoptr(xmlXPathContext) ctxt = NULL;
g_autofree virDomainDeviceDefPtr dev = NULL;
- if (!(xml = virXMLParseStringCtxt(xmlStr, _("(device_definition)"),
&ctxt)))
- return NULL;
-
- node = ctxt->node;
-
if (VIR_ALLOC(dev) < 0)
return NULL;
@@ -16678,6 +16755,32 @@ virDomainDeviceDefParse(const char *xmlStr,
}
+virDomainDeviceDefPtr
+virDomainDeviceDefParse(const char *xmlStr,
+ const virDomainDef *def,
+ virDomainXMLOptionPtr xmlopt,
+ void *parseOpaque,
+ unsigned int flags)
+{
+ xmlDocPtr xml;
+ xmlNodePtr node;
+ xmlXPathContextPtr ctxt = NULL;
+ virDomainDeviceDefPtr dev = NULL;
+
+ if (!(xml = virXMLParseStringCtxt(xmlStr, _("(device_definition)"),
&ctxt)))
+ return NULL;
+
+ node = ctxt->node;
+
+ dev = virDomainDeviceDefParseXML(node, def, xmlopt, ctxt, parseOpaque, flags);
+
+ xmlFreeDoc(xml);
+ xmlXPathFreeContext(ctxt);
+
+ return dev;
+ }
+
+
virDomainDiskDefPtr
virDomainDiskDefParse(const char *xmlStr,
virDomainXMLOptionPtr xmlopt,
@@ -31617,6 +31720,46 @@ virDomainDiskTranslateSourcePool(virDomainDiskDefPtr def)
return 0;
}
+virDomainDeviceDefListPtr
+virDomainDeviceDefParseXMLMany(const char *xml,
+ const virDomainDef *def,
+ virDomainXMLOptionPtr xmlopt,
+ void *parseOpaque,
+ unsigned int flags)
+{
+ xmlXPathContextPtr ctxt = NULL;
+ xmlDocPtr xmlPtr;
+ xmlNodePtr node, root;
+ virDomainDeviceDefPtr dev = NULL;
+ virDomainDeviceDefListPtr devlist;
+
+ if (!(xmlPtr = virXMLParseStringCtxt(xml, _("(device_definition)"),
&ctxt)))
+ return NULL;
+
+ if (VIR_ALLOC(devlist) < 0)
+ goto exit;
+
+ root = xmlDocGetRootElement(xmlPtr);
+ node = root->children;
+ while (node) {
+ if (node->type == XML_ELEMENT_NODE) {
+ dev = virDomainDeviceDefParseXML(node, def, xmlopt, ctxt,
+ parseOpaque, flags);
+ if (VIR_APPEND_ELEMENT(devlist->devs, devlist->count, dev) < 0) {
+ virDomainDeviceDefFree(dev);
+ virDomainDeviceDefListFree(devlist);
+ goto exit;
+ }
+ dev = NULL;
+ }
+ node = node->next;
+ }
+
+ exit:
+ xmlFreeDoc(xmlPtr);
+ xmlXPathFreeContext(ctxt);
+ return devlist;
+}
/**
* virDomainDiskGetDetectZeroesMode:
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 77a01fbec0..26d9ca6ba9 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -2648,6 +2648,33 @@ typedef enum {
typedef int (*virDomainDefPostParseBasicCallback)(virDomainDefPtr def,
void *opaque);
+typedef struct _virDomainDeviceDefListData virDomainDeviceDefListData;
+typedef virDomainDeviceDefListData *virDomainDeviceDefListDataPtr;
+struct _virDomainDeviceDefListData {
+ const virDomainDef *def;
+ virDomainXMLOptionPtr xmlopt;
+};
+
+struct virDomainDeviceDefList {
+ virDomainDeviceDefPtr *devs;
+ size_t count;
+};
+typedef struct virDomainDeviceDefList *virDomainDeviceDefListPtr;
+
+typedef int (*virDomainDeviceDefListIterCallback)(virDomainDeviceDefPtr dev,
+ void *opaque);
+int virDomainDeviceDefListIterate(virDomainDeviceDefListPtr devlist,
+ virDomainDeviceDefListIterCallback cb,
+ void *data);
+virDomainDeviceDefListPtr
+virDomainDeviceDefListCopy(virDomainDeviceDefListPtr list,
+ virDomainDeviceDefListDataPtr data,
+ void *parseOpaque);
+
+void virDomainDeviceDefListFree(virDomainDeviceDefListPtr list);
+void virDomainDeviceDefListFreeShallow(virDomainDeviceDefListPtr list);
+
+
/* Called once after everything else has been parsed, for adjusting
* overall domain defaults.
* @parseOpaque is opaque data passed by virDomainDefParse* caller,
@@ -3053,6 +3080,11 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(const char *xmlStr,
virDomainXMLOptionPtr xmlopt,
void *parseOpaque,
unsigned int flags);
+virDomainDeviceDefListPtr virDomainDeviceDefParseXMLMany(const char *xmlStr,
+ const virDomainDef *def,
+ virDomainXMLOptionPtr xmlopt,
+ void *parseOpaque,
+ unsigned int flags);
virDomainDiskDefPtr virDomainDiskDefParse(const char *xmlStr,
virDomainXMLOptionPtr xmlopt,
unsigned int flags);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 5b247ded4b..eda759c219 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -341,7 +341,12 @@ virDomainDeleteConfig;
virDomainDeviceAliasIsUserAlias;
virDomainDeviceDefCopy;
virDomainDeviceDefFree;
+virDomainDeviceDefListCopy;
+virDomainDeviceDefListFree;
+virDomainDeviceDefListFreeShallow;
+virDomainDeviceDefListIterate;
virDomainDeviceDefParse;
+virDomainDeviceDefParseXMLMany;
virDomainDeviceFindSCSIController;
virDomainDeviceGetInfo;
virDomainDeviceInfoIterate;
--
2.24.1