[libvirt] [PATCH 06/34] Add new domain device: "controller"

Daniel P. Berrange berrange at redhat.com
Fri Jan 8 17:23:02 UTC 2010


From: Wolfgang Mauerer <wolfgang.mauerer at siemens.com>

This augments virDomainDevice with a <controller> element
that is used to represent disk controllers (e.g., scsi
controllers). The XML format is given by

  <controller type="scsi" index="<num>">
     <address type="pci" domain="0xNUM" bus="0xNUM" slot="0xNUM"/>
  </controller>

where type denotes the disk interface (scsi, ide,...), index
is an integer that identifies the controller for association
with disks, and the <address> element specifies the controller
address on the PCI bus as described in previous commits
The address element can be omitted; in this case, an address
will be assigned automatically.

Most of the code in this patch is from Wolfgang Mauerer's
previous disk controller series

 * docs/schemas/domain.rng: Define syntax for <controller>
   XML element
 * src/conf/domain_conf.c, src/conf/domain_conf.h: Define
   virDomainControllerDef struct, and routines for parsing
   and formatting XML
* src/libvirt_private.syms: Add virDomainControllerInsert
   and virDomainControllerDefFree
---
 docs/schemas/domain.rng  |   20 +++++
 src/conf/domain_conf.c   |  192 +++++++++++++++++++++++++++++++++++++++++++++-
 src/conf/domain_conf.h   |   31 ++++++++
 src/libvirt_private.syms |    2 +
 4 files changed, 244 insertions(+), 1 deletions(-)

diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index dd729c0..a32ce45 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -521,6 +521,25 @@
       </choice>
     </attribute>
   </define>
+  <define name="controller">
+    <element name="controller">
+      <optional>
+        <attribute name="type">
+          <choice>
+            <value>fdc</value>
+            <value>ide</value>
+            <value>scsi</value>
+          </choice>
+        </attribute>
+      </optional>
+      <attribute name="index">
+        <ref name="unsignedInt"/>
+      </attribute>
+      <optional>
+	<ref name="address"/>
+      </optional>
+    </element>
+  </define>
   <define name="filesystem">
     <element name="filesystem">
       <choice>
@@ -1225,6 +1244,7 @@
         <zeroOrMore>
           <choice>
             <ref name="disk"/>
+            <ref name="controller"/>
             <ref name="filesystem"/>
             <ref name="interface"/>
             <ref name="input"/>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 662ff81..dd10f36 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -86,7 +86,8 @@ VIR_ENUM_IMPL(virDomainDevice, VIR_DOMAIN_DEVICE_LAST,
               "sound",
               "video",
               "hostdev",
-              "watchdog")
+              "watchdog",
+              "controller")
 
 VIR_ENUM_IMPL(virDomainDeviceAddress, VIR_DOMAIN_DEVICE_ADDRESS_TYPE_LAST,
               "none",
@@ -119,6 +120,12 @@ VIR_ENUM_IMPL(virDomainDiskCache, VIR_DOMAIN_DISK_CACHE_LAST,
               "writethrough",
               "writeback")
 
+VIR_ENUM_IMPL(virDomainController, VIR_DOMAIN_CONTROLLER_TYPE_LAST,
+              "ide",
+              "fdc",
+              "scsi",
+              "sata")
+
 VIR_ENUM_IMPL(virDomainFS, VIR_DOMAIN_FS_TYPE_LAST,
               "mount",
               "block",
@@ -367,6 +374,16 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def)
     VIR_FREE(def);
 }
 
+void virDomainControllerDefFree(virDomainControllerDefPtr def)
+{
+    if (!def)
+        return;
+
+    virDomainDeviceInfoClear(&def->info);
+
+    VIR_FREE(def);
+}
+
 void virDomainFSDefFree(virDomainFSDefPtr def)
 {
     if (!def)
@@ -528,6 +545,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
     case VIR_DOMAIN_DEVICE_WATCHDOG:
         virDomainWatchdogDefFree(def->data.watchdog);
         break;
+    case VIR_DOMAIN_DEVICE_CONTROLLER:
+        virDomainControllerDefFree(def->data.controller);
+        break;
     }
 
     VIR_FREE(def);
@@ -561,6 +581,10 @@ void virDomainDefFree(virDomainDefPtr def)
         virDomainDiskDefFree(def->disks[i]);
     VIR_FREE(def->disks);
 
+    for (i = 0 ; i < def->ncontrollers ; i++)
+        virDomainControllerDefFree(def->controllers[i]);
+    VIR_FREE(def->controllers);
+
     for (i = 0 ; i < def->nfss ; i++)
         virDomainFSDefFree(def->fss[i]);
     VIR_FREE(def->fss);
@@ -1335,6 +1359,63 @@ cleanup:
 }
 
 
+/* Parse the XML definition for a controller
+ * @param node XML nodeset to parse for controller definition
+ */
+static virDomainControllerDefPtr
+virDomainControllerDefParseXML(virConnectPtr conn,
+                               xmlNodePtr node,
+                               int flags)
+{
+    virDomainControllerDefPtr def;
+    char *type = NULL;
+    char *idx = NULL;
+
+    if (VIR_ALLOC(def) < 0) {
+        virReportOOMError(conn);
+        return NULL;
+    }
+
+    type = virXMLPropString(node, "type");
+    if (type) {
+        if ((def->type = virDomainDiskBusTypeFromString(type)) < 0) {
+            virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                 _("unknown disk controller type '%s'"), type);
+            goto error;
+        }
+    }
+
+    idx = virXMLPropString(node, "index");
+    if (idx) {
+        if (virStrToLong_i(idx, NULL, 10, &def->idx) < 0) {
+            virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                                 _("cannot parse disk controller index %s"), idx);
+            goto error;
+        }
+    }
+
+    if (virDomainDeviceInfoParseXML(conn, node, &def->info, flags) < 0)
+        goto error;
+
+    if (def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
+        def->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+        virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR, "%s",
+                             _("Disk controllers must use the 'pci' address type"));
+        goto error;
+    }
+
+cleanup:
+    VIR_FREE(type);
+    VIR_FREE(idx);
+
+    return def;
+
+ error:
+    virDomainControllerDefFree(def);
+    def = NULL;
+    goto cleanup;
+}
+
 /* Parse the XML definition for a disk
  * @param node XML nodeset to parse for disk definition
  */
@@ -2995,6 +3076,10 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virConnectPtr conn,
         dev->type = VIR_DOMAIN_DEVICE_HOSTDEV;
         if (!(dev->data.hostdev = virDomainHostdevDefParseXML(conn, node, flags)))
             goto error;
+    } else if (xmlStrEqual(node->name, BAD_CAST "controller")) {
+        dev->type = VIR_DOMAIN_DEVICE_CONTROLLER;
+        if (!(dev->data.controller = virDomainControllerDefParseXML(conn, node, flags)))
+            goto error;
     } else {
         virDomainReportError(conn, VIR_ERR_XML_ERROR,
                              "%s", _("unknown device type"));
@@ -3067,6 +3152,59 @@ void virDomainDiskInsertPreAlloced(virDomainDefPtr def,
 }
 
 
+int virDomainControllerInsert(virDomainDefPtr def,
+                              virDomainControllerDefPtr controller)
+{
+
+    if (VIR_REALLOC_N(def->controllers, def->ncontrollers+1) < 0)
+        return -1;
+
+    virDomainControllerInsertPreAlloced(def, controller);
+
+    return 0;
+}
+
+void virDomainControllerInsertPreAlloced(virDomainDefPtr def,
+                                         virDomainControllerDefPtr controller)
+{
+    int i;
+    /* Tenatively plan to insert controller at the end. */
+    int insertAt = -1;
+
+    /* Then work backwards looking for controllers of
+     * the same type. If we find a controller with a
+     * index greater than the new one, insert at
+     * that position
+     */
+    for (i = (def->ncontrollers - 1) ; i >= 0 ; i--) {
+        /* If bus matches and current controller is after
+         * new controller, then new controller should go here */
+        if ((def->controllers[i]->type == controller->type) &&
+            (def->controllers[i]->idx > controller->idx)) {
+            insertAt = i;
+        } else if (def->controllers[i]->type == controller->type &&
+                   insertAt == -1) {
+            /* Last controller with match bus is before the
+             * new controller, then put new controller just after
+             */
+            insertAt = i + 1;
+        }
+    }
+
+    /* No controllers with this bus yet, so put at end of list */
+    if (insertAt == -1)
+        insertAt = def->ncontrollers;
+
+    if (insertAt < def->ncontrollers)
+        memmove(def->controllers + insertAt + 1,
+                def->controllers + insertAt,
+                (sizeof(def->controllers[0]) * (def->ncontrollers-insertAt)));
+
+    def->controllers[insertAt] = controller;
+    def->ncontrollers++;
+}
+
+
 #ifndef PROXY
 static char *virDomainDefDefaultEmulator(virConnectPtr conn,
                                          virDomainDefPtr def,
@@ -3382,6 +3520,25 @@ static virDomainDefPtr virDomainDefParseXML(virConnectPtr conn,
     }
     VIR_FREE(nodes);
 
+    /* analysis of the controller devices */
+    if ((n = virXPathNodeSet(conn, "./devices/controller", ctxt, &nodes)) < 0) {
+        virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                             "%s", _("cannot extract controller devices"));
+        goto error;
+    }
+    if (n && VIR_ALLOC_N(def->controllers, n) < 0)
+        goto no_memory;
+    for (i = 0 ; i < n ; i++) {
+        virDomainControllerDefPtr controller = virDomainControllerDefParseXML(conn,
+                                                                              nodes[i],
+                                                                              flags);
+        if (!controller)
+            goto error;
+
+        def->controllers[def->ncontrollers++] = controller;
+    }
+    VIR_FREE(nodes);
+
     /* analysis of the filesystems */
     if ((n = virXPathNodeSet(conn, "./devices/filesystem", ctxt, &nodes)) < 0) {
         virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
@@ -4299,6 +4456,35 @@ virDomainDiskDefFormat(virConnectPtr conn,
 }
 
 static int
+virDomainControllerDefFormat(virConnectPtr conn,
+                             virBufferPtr buf,
+                             virDomainControllerDefPtr def)
+{
+    const char *type = virDomainControllerTypeToString(def->type);
+
+    if (!type) {
+        virDomainReportError(conn, VIR_ERR_INTERNAL_ERROR,
+                             _("unexpected controller type %d"), def->type);
+        return -1;
+    }
+
+    virBufferVSprintf(buf,
+                      "    <controller type='%s' index='%d'",
+                      type, def->idx);
+
+    if (virDomainDeviceInfoIsSet(&def->info)) {
+        virBufferAddLit(buf, ">\n");
+        if (virDomainDeviceInfoFormat(buf, &def->info) < 0)
+            return -1;
+        virBufferAddLit(buf, "    </controller>\n");
+    } else {
+        virBufferAddLit(buf, "/>\n");
+    }
+
+    return 0;
+}
+
+static int
 virDomainFSDefFormat(virConnectPtr conn,
                      virBufferPtr buf,
                      virDomainFSDefPtr def)
@@ -5045,6 +5231,10 @@ char *virDomainDefFormat(virConnectPtr conn,
         if (virDomainDiskDefFormat(conn, &buf, def->disks[n]) < 0)
             goto cleanup;
 
+    for (n = 0 ; n < def->ncontrollers ; n++)
+        if (virDomainControllerDefFormat(conn, &buf, def->controllers[n]) < 0)
+            goto cleanup;
+
     for (n = 0 ; n < def->nfss ; n++)
         if (virDomainFSDefFormat(conn, &buf, def->fss[n]) < 0)
             goto cleanup;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index a05835a..9f2271c 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -160,6 +160,25 @@ struct _virDomainDiskDef {
 };
 
 
+enum virDomainControllerType {
+    VIR_DOMAIN_CONTROLLER_TYPE_IDE,
+    VIR_DOMAIN_CONTROLLER_TYPE_FDC,
+    VIR_DOMAIN_CONTROLLER_TYPE_SCSI,
+    VIR_DOMAIN_CONTROLLER_TYPE_SATA,
+
+    VIR_DOMAIN_CONTROLLER_TYPE_LAST
+};
+
+/* Stores the virtual disk controller configuration */
+typedef struct _virDomainControllerDef virDomainControllerDef;
+typedef virDomainControllerDef *virDomainControllerDefPtr;
+struct _virDomainControllerDef {
+    int type;
+    int idx;
+    virDomainDeviceInfo info;
+};
+
+
 /* Two types of disk backends */
 enum virDomainFSType {
     VIR_DOMAIN_FS_TYPE_MOUNT,   /* Better named 'bind' */
@@ -488,6 +507,7 @@ enum virDomainDeviceType {
     VIR_DOMAIN_DEVICE_VIDEO,
     VIR_DOMAIN_DEVICE_HOSTDEV,
     VIR_DOMAIN_DEVICE_WATCHDOG,
+    VIR_DOMAIN_DEVICE_CONTROLLER,
 
     VIR_DOMAIN_DEVICE_LAST,
 };
@@ -498,6 +518,7 @@ struct _virDomainDeviceDef {
     int type;
     union {
         virDomainDiskDefPtr disk;
+        virDomainControllerDefPtr controller;
         virDomainFSDefPtr fs;
         virDomainNetDefPtr net;
         virDomainInputDefPtr input;
@@ -610,6 +631,9 @@ struct _virDomainDef {
     int ndisks;
     virDomainDiskDefPtr *disks;
 
+    int ncontrollers;
+    virDomainControllerDefPtr *controllers;
+
     int nfss;
     virDomainFSDefPtr *fss;
 
@@ -693,6 +717,7 @@ virDomainObjPtr virDomainFindByName(const virDomainObjListPtr doms,
 void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def);
 void virDomainInputDefFree(virDomainInputDefPtr def);
 void virDomainDiskDefFree(virDomainDiskDefPtr def);
+void virDomainControllerDefFree(virDomainControllerDefPtr def);
 void virDomainFSDefFree(virDomainFSDefPtr def);
 void virDomainNetDefFree(virDomainNetDefPtr def);
 void virDomainChrDefFree(virDomainChrDefPtr def);
@@ -775,6 +800,11 @@ void virDomainDiskInsertPreAlloced(virDomainDefPtr def,
                                    virDomainDiskDefPtr disk);
 void virDomainDiskDefAssignAddress(virDomainDiskDefPtr def);
 
+int virDomainControllerInsert(virDomainDefPtr def,
+                              virDomainControllerDefPtr controller);
+void virDomainControllerInsertPreAlloced(virDomainDefPtr def,
+                                         virDomainControllerDefPtr controller);
+
 int virDomainSaveXML(virConnectPtr conn,
                      const char *configDir,
                      virDomainDefPtr def,
@@ -855,6 +885,7 @@ VIR_ENUM_DECL(virDomainDisk)
 VIR_ENUM_DECL(virDomainDiskDevice)
 VIR_ENUM_DECL(virDomainDiskBus)
 VIR_ENUM_DECL(virDomainDiskCache)
+VIR_ENUM_DECL(virDomainController)
 VIR_ENUM_DECL(virDomainFS)
 VIR_ENUM_DECL(virDomainNet)
 VIR_ENUM_DECL(virDomainChrTarget)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 9a4f444..a346aa5 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -130,6 +130,8 @@ virDomainDiskDeviceTypeToString;
 virDomainDiskInsert;
 virDomainDiskInsertPreAlloced;
 virDomainDiskDefAssignAddress;
+virDomainControllerInsert;
+virDomainControllerInsertPreAlloced;
 virDomainFindByID;
 virDomainFindByName;
 virDomainFindByUUID;
-- 
1.6.5.2




More information about the libvir-list mailing list