From 74ec5e65ceba7b0665d8c377694ca412c29c46f4 Mon Sep 17 00:00:00 2001 From: Wolfgang Mauerer Date: Wed, 2 Dec 2009 19:15:38 +0000 Subject: [PATCH] Add new domain device: "controller" This augments virDomainDevice with a element that is used to represent disk controllers (e.g., scsi controllers). The XML format is given by
where type denotes the disk interface (scsi, ide,...), index is an integer that identifies the controller for association with disks, and the
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 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 deletion(-) diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng index dd729c0dff..a32ce45508 100644 --- a/docs/schemas/domain.rng +++ b/docs/schemas/domain.rng @@ -521,6 +521,25 @@ + + + + + + fdc + ide + scsi + + + + + + + + + + + @@ -1225,6 +1244,7 @@ + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 662ff810eb..dd10f369fe 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, @@ -4298,6 +4455,35 @@ virDomainDiskDefFormat(virConnectPtr conn, return 0; } +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, + " idx); + + if (virDomainDeviceInfoIsSet(&def->info)) { + virBufferAddLit(buf, ">\n"); + if (virDomainDeviceInfoFormat(buf, &def->info) < 0) + return -1; + virBufferAddLit(buf, " \n"); + } else { + virBufferAddLit(buf, "/>\n"); + } + + return 0; +} + static int virDomainFSDefFormat(virConnectPtr conn, virBufferPtr buf, @@ -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 a05835adf4..9f2271ca3f 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 4969296fee..1cf310965d 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -130,6 +130,8 @@ virDomainDiskDeviceTypeToString; virDomainDiskInsert; virDomainDiskInsertPreAlloced; virDomainDiskDefAssignAddress; +virDomainControllerInsert; +virDomainControllerInsertPreAlloced; virDomainFindByID; virDomainFindByName; virDomainFindByUUID;