From 122fa379de44a2fd0a6d5fbcb634535d647ada17 Mon Sep 17 00:00:00 2001 From: Wido den Hollander Date: Wed, 25 Apr 2012 12:43:09 +0200 Subject: [PATCH] storage: Allow multiple hosts for a storage pool The current storage pools for NFS and iSCSI only require one host to connect to. Future storage pools like RBD and Sheepdog will require multiple hosts. This patch allows multiple source hosts and rewrites the current storage drivers. Signed-off-by: Wido den Hollander --- AUTHORS | 1 + src/conf/storage_conf.c | 72 ++++++++++++++++++++--------- src/conf/storage_conf.h | 5 +- src/esx/esx_storage_driver.c | 6 ++- src/storage/storage_backend_fs.c | 34 +++++++++++--- src/storage/storage_backend_iscsi.c | 36 ++++++++++++--- src/test/test_driver.c | 4 +- 7 files changed, 118 insertions(+), 40 deletions(-) diff --git a/AUTHORS b/AUTHORS index 20e1b4bd30..06b830a1c8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -233,6 +233,7 @@ Patches have also been contributed by: MATSUDA Daiki Jan Kiszka Ryan Woodsmall + Wido den Hollander [....send patches to get your name here....] diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c index 75793277da..6475181c55 100644 --- a/src/conf/storage_conf.c +++ b/src/conf/storage_conf.c @@ -276,7 +276,11 @@ virStoragePoolSourceClear(virStoragePoolSourcePtr source) if (!source) return; - VIR_FREE(source->host.name); + for (i = 0 ; i < source->nhost ; i++) { + VIR_FREE(source->hosts[i].name); + } + VIR_FREE(source->hosts); + for (i = 0 ; i < source->ndevice ; i++) { VIR_FREE(source->devices[i].freeExtents); VIR_FREE(source->devices[i].path); @@ -404,6 +408,7 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt, char *authType = NULL; int nsource, i; virStoragePoolOptionsPtr options; + char *name = NULL; char *port = NULL; relnode = ctxt->node; @@ -431,17 +436,34 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt, VIR_FREE(format); } - source->host.name = virXPathString("string(./host/@name)", ctxt); - port = virXPathString("string(./host/@port)", ctxt); - if (port) { - if (virStrToLong_i(port, NULL, 10, &source->host.port) < 0) { - virStorageReportError(VIR_ERR_XML_ERROR, - _("Invalid port number: %s"), - port); + source->nhost = virXPathNodeSet("./host", ctxt, &nodeset); + + if (source->nhost) { + if (VIR_ALLOC_N(source->hosts, source->nhost) < 0) { + virReportOOMError(); goto cleanup; } - } + for (i = 0 ; i < source->nhost ; i++) { + name = virXMLPropString(nodeset[i], "name"); + if (name == NULL) { + virStorageReportError(VIR_ERR_XML_ERROR, + "%s", _("missing storage pool host name")); + goto cleanup; + } + source->hosts[i].name = name; + + port = virXMLPropString(nodeset[i], "port"); + if (port) { + if (virStrToLong_i(port, NULL, 10, &source->hosts[i].port) < 0) { + virStorageReportError(VIR_ERR_XML_ERROR, + _("Invalid port number: %s"), + port); + goto cleanup; + } + } + } + } source->initiator.iqn = virXPathString("string(./initiator/iqn/@name)", ctxt); @@ -675,7 +697,7 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) { } if (options->flags & VIR_STORAGE_POOL_SOURCE_HOST) { - if (!ret->source.host.name) { + if (!ret->source.nhost) { virStorageReportError(VIR_ERR_XML_ERROR, "%s", _("missing storage pool source host name")); @@ -801,12 +823,13 @@ virStoragePoolSourceFormat(virBufferPtr buf, int i, j; virBufferAddLit(buf," \n"); - if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) && - src->host.name) { - virBufferAsprintf(buf, " host.name); - if (src->host.port) - virBufferAsprintf(buf, " port='%d'", src->host.port); - virBufferAddLit(buf, "/>\n"); + if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) && src->nhost) { + for (i = 0; i < src->nhost; i++) { + virBufferAsprintf(buf, " hosts[i].name); + if (src->hosts[i].port) + virBufferAsprintf(buf, " port='%d'", src->hosts[i].port); + virBufferAddLit(buf, "/>\n"); + } } if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) && @@ -1678,7 +1701,8 @@ int virStoragePoolSourceFindDuplicate(virStoragePoolObjListPtr pools, break; case VIR_STORAGE_POOL_NETFS: if ((STREQ(pool->def->source.dir, def->source.dir)) \ - && (STREQ(pool->def->source.host.name, def->source.host.name))) + && (pool->def->source.nhost == 1 && def->source.nhost == 1) \ + && (STREQ(pool->def->source.hosts[0].name, def->source.hosts[0].name))) matchpool = pool; break; case VIR_STORAGE_POOL_SCSI: @@ -1689,13 +1713,15 @@ int virStoragePoolSourceFindDuplicate(virStoragePoolObjListPtr pools, { matchpool = virStoragePoolSourceFindDuplicateDevices(pool, def); if (matchpool) { - if (STREQ(matchpool->def->source.host.name, def->source.host.name)) { - if ((matchpool->def->source.initiator.iqn) && (def->source.initiator.iqn)) { - if (STREQ(matchpool->def->source.initiator.iqn, def->source.initiator.iqn)) - break; - matchpool = NULL; + if (matchpool->def->source.nhost == 1 && def->source.nhost == 1) { + if (STREQ(matchpool->def->source.hosts[0].name, def->source.hosts[0].name)) { + if ((matchpool->def->source.initiator.iqn) && (def->source.initiator.iqn)) { + if (STREQ(matchpool->def->source.initiator.iqn, def->source.initiator.iqn)) + break; + matchpool = NULL; + } + break; } - break; } matchpool = NULL; } diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h index 1ef929510e..9222c4af36 100644 --- a/src/conf/storage_conf.h +++ b/src/conf/storage_conf.h @@ -212,8 +212,9 @@ struct _virStoragePoolSourceDevice { typedef struct _virStoragePoolSource virStoragePoolSource; typedef virStoragePoolSource *virStoragePoolSourcePtr; struct _virStoragePoolSource { - /* An optional host */ - virStoragePoolSourceHost host; + /* An optional (maybe multiple) host(s) */ + size_t nhost; + virStoragePoolSourceHostPtr hosts; /* And either one or more devices ... */ int ndevice; diff --git a/src/esx/esx_storage_driver.c b/src/esx/esx_storage_driver.c index adf1edbfaa..9b64891e0e 100644 --- a/src/esx/esx_storage_driver.c +++ b/src/esx/esx_storage_driver.c @@ -544,8 +544,12 @@ esxStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags) if (esxVI_LocalDatastoreInfo_DynamicCast(info) != NULL) { def.type = VIR_STORAGE_POOL_DIR; } else if ((nasInfo = esxVI_NasDatastoreInfo_DynamicCast(info)) != NULL) { + if (VIR_ALLOC_N(def.source.hosts, 1) < 0) { + virReportOOMError(); + goto cleanup; + } def.type = VIR_STORAGE_POOL_NETFS; - def.source.host.name = nasInfo->nas->remoteHost; + def.source.hosts[0].name = nasInfo->nas->remoteHost; def.source.dir = nasInfo->nas->remotePath; if (STRCASEEQ(nasInfo->nas->type, "NFS")) { diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 1af12e6746..169037b4b9 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -206,7 +206,13 @@ virStorageBackendFileSystemNetFindPoolSourcesFunc(virStoragePoolObjPtr pool ATTR if (!(src = virStoragePoolSourceListNewSource(&state->list))) goto cleanup; - if (!(src->host.name = strdup(state->host)) || + if (src->nhost != 1) { + virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Expected exactly 1 host for the storage pool")); + goto cleanup; + } + + if (!(src->hosts[0].name = strdup(state->host)) || !(src->dir = strdup(path))) { virReportOOMError(); goto cleanup; @@ -260,8 +266,14 @@ virStorageBackendFileSystemNetFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSE if (!source) goto cleanup; - state.host = source->host.name; - prog[3] = source->host.name; + if (source->nhost != 1) { + virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Expected exactly 1 host for the storage pool")); + goto cleanup; + } + + state.host = source->hosts[0].name; + prog[3] = source->hosts[0].name; if (virStorageBackendRunProgRegex(NULL, prog, 1, regexes, vars, virStorageBackendFileSystemNetFindPoolSourcesFunc, @@ -387,7 +399,12 @@ virStorageBackendFileSystemMount(virStoragePoolObjPtr pool) { int ret; if (pool->def->type == VIR_STORAGE_POOL_NETFS) { - if (pool->def->source.host.name == NULL) { + if (pool->def->source.nhost != 1) { + virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Expected exactly 1 host for the storage pool")); + return -1; + } + if (pool->def->source.hosts[0].name == NULL) { virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing source host")); return -1; @@ -415,7 +432,7 @@ virStorageBackendFileSystemMount(virStoragePoolObjPtr pool) { if (pool->def->type == VIR_STORAGE_POOL_NETFS) { if (virAsprintf(&src, "%s:%s", - pool->def->source.host.name, + pool->def->source.hosts[0].name, pool->def->source.dir) == -1) { virReportOOMError(); return -1; @@ -452,7 +469,12 @@ virStorageBackendFileSystemUnmount(virStoragePoolObjPtr pool) { int ret; if (pool->def->type == VIR_STORAGE_POOL_NETFS) { - if (pool->def->source.host.name == NULL) { + if (pool->def->source.nhost != 1) { + virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Expected exactly 1 host for the storage pool")); + return -1; + } + if (pool->def->source.hosts[0].name == NULL) { virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing source host")); return -1; diff --git a/src/storage/storage_backend_iscsi.c b/src/storage/storage_backend_iscsi.c index f04473d3c4..22a34afab0 100644 --- a/src/storage/storage_backend_iscsi.c +++ b/src/storage/storage_backend_iscsi.c @@ -96,13 +96,19 @@ virStorageBackendISCSIPortal(virStoragePoolSourcePtr source) char ipaddr[NI_MAXHOST]; char *portal; - if (virStorageBackendISCSITargetIP(source->host.name, + if (source->nhost != 1) { + virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Expected exactly 1 host for the storage pool")); + return NULL; + } + + if (virStorageBackendISCSITargetIP(source->hosts[0].name, ipaddr, sizeof(ipaddr)) < 0) return NULL; if (virAsprintf(&portal, "%s:%d,1", ipaddr, - source->host.port ? - source->host.port : 3260) < 0) { + source->hosts[0].port ? + source->hosts[0].port : 3260) < 0) { virReportOOMError(); return NULL; } @@ -563,6 +569,12 @@ virStorageBackendISCSIFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED, list.type))) return NULL; + if (source->nhost != 1) { + virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Expected exactly 1 host for the storage pool")); + goto cleanup; + } + if (!(portal = virStorageBackendISCSIPortal(source))) goto cleanup; @@ -581,7 +593,7 @@ virStorageBackendISCSIFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED, virReportOOMError(); goto cleanup; } - list.sources[i].host = source->host; + list.sources[i].host = source->hosts[0]; list.sources[i].initiator = source->initiator; list.sources[i].ndevice = 1; list.sources[i].devices[0].path = targets[i]; @@ -617,7 +629,13 @@ virStorageBackendISCSICheckPool(virConnectPtr conn ATTRIBUTE_UNUSED, *isActive = false; - if (pool->def->source.host.name == NULL) { + if (pool->def->source.nhost != 1) { + virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Expected exactly 1 host for the storage pool")); + return -1; + } + + if (pool->def->source.hosts[0].name == NULL) { virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing source host")); return -1; @@ -649,7 +667,13 @@ virStorageBackendISCSIStartPool(virConnectPtr conn ATTRIBUTE_UNUSED, int ret = -1; const char *loginargv[] = { "--login", NULL }; - if (pool->def->source.host.name == NULL) { + if (pool->def->source.nhost != 1) { + virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Expected exactly 1 host for the storage pool")); + return -1; + } + + if (pool->def->source.hosts[0].name == NULL) { virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("missing source host")); return -1; diff --git a/src/test/test_driver.c b/src/test/test_driver.c index 39ac503d90..73a7cb10af 100644 --- a/src/test/test_driver.c +++ b/src/test/test_driver.c @@ -4053,14 +4053,14 @@ testStorageFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED, break; case VIR_STORAGE_POOL_NETFS: - if (!source || !source->host.name) { + if (!source || !source->hosts[0].name) { testError(VIR_ERR_INVALID_ARG, "%s", "hostname must be specified for netfs sources"); goto cleanup; } if (virAsprintf(&ret, defaultPoolSourcesNetFSXML, - source->host.name) < 0) + source->hosts[0].name) < 0) virReportOOMError(); break; -- 2.47.2