From d13009007c1bb807252c3c3a3774f22b919046a4 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Fri, 17 Aug 2018 14:50:59 +0200 Subject: [PATCH] virstorageobj: Move virStoragePoolObjSourceFindDuplicate and friends up This function is going to be made static in used in virStoragePoolObjAssignDef(). Therefore move it and all the static functions it calls a few lines up. Signed-off-by: Michal Privoznik Reviewed-by: John Ferlan --- src/conf/virstorageobj.c | 1230 +++++++++++++++++++------------------- 1 file changed, 615 insertions(+), 615 deletions(-) diff --git a/src/conf/virstorageobj.c b/src/conf/virstorageobj.c index dbc3e3f57b..f17f6cec6b 100644 --- a/src/conf/virstorageobj.c +++ b/src/conf/virstorageobj.c @@ -1118,284 +1118,392 @@ virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools, } -/** - * virStoragePoolObjAssignDef: - * @pools: Storage Pool object list pointer - * @def: Storage pool definition to add or update - * @check_active: If true, ensure that pool is not active - * - * Lookup the @def to see if it already exists in the @pools in order - * to either update or add if it does not exist. - * - * Returns locked and reffed object pointer or NULL on error - */ -virStoragePoolObjPtr -virStoragePoolObjAssignDef(virStoragePoolObjListPtr pools, - virStoragePoolDefPtr def, - bool check_active) +static int +getSCSIHostNumber(virStorageAdapterSCSIHostPtr scsi_host, + unsigned int *hostnum) { - virStoragePoolObjPtr obj = NULL; - char uuidstr[VIR_UUID_STRING_BUFLEN]; - int rc; - - virObjectRWLockWrite(pools); + int ret = -1; + unsigned int num; + char *name = NULL; - rc = virStoragePoolObjIsDuplicate(pools, def, check_active, &obj); + if (scsi_host->has_parent) { + virPCIDeviceAddressPtr addr = &scsi_host->parentaddr; + unsigned int unique_id = scsi_host->unique_id; - if (rc < 0) - goto error; - if (rc > 0) { - if (!virStoragePoolObjIsActive(obj)) { - virStoragePoolDefFree(obj->def); - obj->def = def; - } else { - virStoragePoolDefFree(obj->newDef); - obj->newDef = def; - } - virObjectRWUnlock(pools); - return obj; + if (!(name = virSCSIHostGetNameByParentaddr(addr->domain, + addr->bus, + addr->slot, + addr->function, + unique_id))) + goto cleanup; + if (virSCSIHostGetNumber(name, &num) < 0) + goto cleanup; + } else { + if (virSCSIHostGetNumber(scsi_host->name, &num) < 0) + goto cleanup; } - if (!(obj = virStoragePoolObjNew())) - goto error; + *hostnum = num; + ret = 0; - virUUIDFormat(def->uuid, uuidstr); - if (virHashAddEntry(pools->objs, uuidstr, obj) < 0) - goto error; - virObjectRef(obj); + cleanup: + VIR_FREE(name); + return ret; +} - if (virHashAddEntry(pools->objsName, def->name, obj) < 0) { - virHashRemoveEntry(pools->objs, uuidstr); - goto error; - } - virObjectRef(obj); - obj->def = def; - virObjectRWUnlock(pools); - return obj; - error: - virStoragePoolObjEndAPI(&obj); - virObjectRWUnlock(pools); - return NULL; +static bool +virStorageIsSameHostnum(const char *name, + unsigned int scsi_hostnum) +{ + unsigned int fc_hostnum; + + if (virSCSIHostGetNumber(name, &fc_hostnum) == 0 && + scsi_hostnum == fc_hostnum) + return true; + + return false; } -static virStoragePoolObjPtr -virStoragePoolObjLoad(virStoragePoolObjListPtr pools, - const char *file, - const char *path, - const char *autostartLink) +/* + * matchFCHostToSCSIHost: + * + * @conn: Connection pointer + * @fchost: fc_host adapter ptr (either def or pool->def) + * @scsi_hostnum: Already determined "scsi_pool" hostnum + * + * Returns true/false whether there is a match between the incoming + * fc_adapter host# and the scsi_host host# + */ +static bool +matchFCHostToSCSIHost(virConnectPtr conn, + virStorageAdapterFCHostPtr fchost, + unsigned int scsi_hostnum) { - virStoragePoolDefPtr def; - virStoragePoolObjPtr obj; + bool ret = false; + char *name = NULL; + char *scsi_host_name = NULL; + char *parent_name = NULL; - if (!(def = virStoragePoolDefParseFile(path))) - return NULL; + /* If we have a parent defined, get its hostnum, and compare to the + * scsi_hostnum. If they are the same, then we have a match + */ + if (fchost->parent && + virStorageIsSameHostnum(fchost->parent, scsi_hostnum)) + return true; - if (!virFileMatchesNameSuffix(file, def->name, ".xml")) { - virReportError(VIR_ERR_XML_ERROR, - _("Storage pool config filename '%s' does " - "not match pool name '%s'"), - path, def->name); - virStoragePoolDefFree(def); - return NULL; - } + /* If we find an fc adapter name, then either libvirt created a vHBA + * for this fc_host or a 'virsh nodedev-create' generated a vHBA. + */ + if ((name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) { - if (!(obj = virStoragePoolObjAssignDef(pools, def, false))) { - virStoragePoolDefFree(def); - return NULL; - } + /* Get the scsi_hostN for the vHBA in order to see if it + * matches our scsi_hostnum + */ + if (virStorageIsSameHostnum(name, scsi_hostnum)) { + ret = true; + goto cleanup; + } - VIR_FREE(obj->configFile); /* for driver reload */ - if (VIR_STRDUP(obj->configFile, path) < 0) { - virStoragePoolObjRemove(pools, obj); - virObjectUnref(obj); - return NULL; - } - VIR_FREE(obj->autostartLink); /* for driver reload */ - if (VIR_STRDUP(obj->autostartLink, autostartLink) < 0) { - virStoragePoolObjRemove(pools, obj); - virObjectUnref(obj); - return NULL; + /* We weren't provided a parent, so we have to query the node + * device driver in order to ascertain the parent of the vHBA. + * If the parent fc_hostnum is the same as the scsi_hostnum, we + * have a match. + */ + if (conn && !fchost->parent) { + if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0) + goto cleanup; + if ((parent_name = virNodeDeviceGetParentName(conn, + scsi_host_name))) { + if (virStorageIsSameHostnum(parent_name, scsi_hostnum)) { + ret = true; + goto cleanup; + } + } else { + /* Throw away the error and fall through */ + virResetLastError(); + VIR_DEBUG("Could not determine parent vHBA"); + } + } } - obj->autostart = virFileLinkPointsTo(obj->autostartLink, - obj->configFile); + /* NB: Lack of a name means that this vHBA hasn't yet been created, + * which means our scsi_host cannot be using the vHBA. Furthermore, + * lack of a provided parent means libvirt is going to choose the + * "best" fc_host capable adapter based on availabilty. That could + * conflict with an existing scsi_host definition, but there's no + * way to know that now. + */ - return obj; + cleanup: + VIR_FREE(name); + VIR_FREE(parent_name); + VIR_FREE(scsi_host_name); + return ret; } -static virStoragePoolObjPtr -virStoragePoolObjLoadState(virStoragePoolObjListPtr pools, - const char *stateDir, - const char *name) +static bool +matchSCSIAdapterParent(virStorageAdapterSCSIHostPtr pool_scsi_host, + virStorageAdapterSCSIHostPtr def_scsi_host) { - char *stateFile = NULL; - virStoragePoolDefPtr def = NULL; - virStoragePoolObjPtr obj = NULL; - xmlDocPtr xml = NULL; - xmlXPathContextPtr ctxt = NULL; - xmlNodePtr node = NULL; + virPCIDeviceAddressPtr pooladdr = &pool_scsi_host->parentaddr; + virPCIDeviceAddressPtr defaddr = &def_scsi_host->parentaddr; - if (!(stateFile = virFileBuildPath(stateDir, name, ".xml"))) - goto error; + if (pooladdr->domain == defaddr->domain && + pooladdr->bus == defaddr->bus && + pooladdr->slot == defaddr->slot && + pooladdr->function == defaddr->function && + pool_scsi_host->unique_id == def_scsi_host->unique_id) + return true; - if (!(xml = virXMLParseCtxt(stateFile, NULL, _("(pool state)"), &ctxt))) - goto error; + return false; +} - if (!(node = virXPathNode("//pool", ctxt))) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Could not find any 'pool' element in state file")); - goto error; - } - ctxt->node = node; - if (!(def = virStoragePoolDefParseXML(ctxt))) - goto error; +static bool +virStoragePoolSourceMatchSingleHost(virStoragePoolSourcePtr poolsrc, + virStoragePoolSourcePtr defsrc) +{ + if (poolsrc->nhost != 1 && defsrc->nhost != 1) + return false; - if (STRNEQ(name, def->name)) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("Storage pool state file '%s' does not match " - "pool name '%s'"), - stateFile, def->name); - goto error; - } + if (defsrc->hosts[0].port && + poolsrc->hosts[0].port != defsrc->hosts[0].port) + return false; - /* create the object */ - if (!(obj = virStoragePoolObjAssignDef(pools, def, true))) - goto error; + return STREQ(poolsrc->hosts[0].name, defsrc->hosts[0].name); +} - /* XXX: future handling of some additional useful status data, - * for now, if a status file for a pool exists, the pool will be marked - * as active - */ - obj->active = true; +static bool +virStoragePoolSourceISCSIMatch(virStoragePoolObjPtr obj, + virStoragePoolDefPtr def) +{ + virStoragePoolSourcePtr poolsrc = &obj->def->source; + virStoragePoolSourcePtr defsrc = &def->source; - cleanup: - VIR_FREE(stateFile); - xmlFreeDoc(xml); - xmlXPathFreeContext(ctxt); - return obj; + /* NB: Do not check the source host name */ + if (STRNEQ_NULLABLE(poolsrc->initiator.iqn, defsrc->initiator.iqn)) + return false; - error: - virStoragePoolDefFree(def); - goto cleanup; + return true; } -int -virStoragePoolObjLoadAllState(virStoragePoolObjListPtr pools, - const char *stateDir) +static virStoragePoolObjPtr +virStoragePoolObjSourceMatchTypeDIR(virStoragePoolObjPtr obj, + virStoragePoolDefPtr def) { - DIR *dir; - struct dirent *entry; - int ret = -1; - int rc; + if (obj->def->type == VIR_STORAGE_POOL_DIR) { + if (STREQ(obj->def->target.path, def->target.path)) + return obj; + } else if (obj->def->type == VIR_STORAGE_POOL_GLUSTER) { + if (STREQ(obj->def->source.name, def->source.name) && + STREQ_NULLABLE(obj->def->source.dir, def->source.dir) && + virStoragePoolSourceMatchSingleHost(&obj->def->source, + &def->source)) + return obj; + } else if (obj->def->type == VIR_STORAGE_POOL_NETFS) { + if (STREQ(obj->def->source.dir, def->source.dir) && + virStoragePoolSourceMatchSingleHost(&obj->def->source, + &def->source)) + return obj; + } - if ((rc = virDirOpenIfExists(&dir, stateDir)) <= 0) - return rc; + return NULL; +} - while ((ret = virDirRead(dir, &entry, stateDir)) > 0) { - virStoragePoolObjPtr obj; - if (!virFileStripSuffix(entry->d_name, ".xml")) - continue; +static virStoragePoolObjPtr +virStoragePoolObjSourceMatchTypeISCSI(virStoragePoolObjPtr obj, + virStoragePoolDefPtr def, + virConnectPtr conn) +{ + virStorageAdapterPtr pool_adapter = &obj->def->source.adapter; + virStorageAdapterPtr def_adapter = &def->source.adapter; + virStorageAdapterSCSIHostPtr pool_scsi_host; + virStorageAdapterSCSIHostPtr def_scsi_host; + virStorageAdapterFCHostPtr pool_fchost; + virStorageAdapterFCHostPtr def_fchost; + unsigned int pool_hostnum; + unsigned int def_hostnum; + unsigned int scsi_hostnum; - if (!(obj = virStoragePoolObjLoadState(pools, stateDir, entry->d_name))) - continue; - virStoragePoolObjEndAPI(&obj); + if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST && + def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST) { + pool_fchost = &pool_adapter->data.fchost; + def_fchost = &def_adapter->data.fchost; + + if (STREQ(pool_fchost->wwnn, def_fchost->wwnn) && + STREQ(pool_fchost->wwpn, def_fchost->wwpn)) + return obj; + } else if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST && + def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST) { + pool_scsi_host = &pool_adapter->data.scsi_host; + def_scsi_host = &def_adapter->data.scsi_host; + + if (pool_scsi_host->has_parent && + def_scsi_host->has_parent && + matchSCSIAdapterParent(pool_scsi_host, def_scsi_host)) + return obj; + + if (getSCSIHostNumber(pool_scsi_host, &pool_hostnum) < 0 || + getSCSIHostNumber(def_scsi_host, &def_hostnum) < 0) + return NULL; + if (pool_hostnum == def_hostnum) + return obj; + } else if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST && + def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST) { + pool_fchost = &pool_adapter->data.fchost; + def_scsi_host = &def_adapter->data.scsi_host; + + /* Get the scsi_hostN for the scsi_host source adapter def */ + if (getSCSIHostNumber(def_scsi_host, &scsi_hostnum) < 0) + return NULL; + + if (matchFCHostToSCSIHost(conn, pool_fchost, scsi_hostnum)) + return obj; + + } else if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST && + def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST) { + pool_scsi_host = &pool_adapter->data.scsi_host; + def_fchost = &def_adapter->data.fchost; + + if (getSCSIHostNumber(pool_scsi_host, &scsi_hostnum) < 0) + return NULL; + + if (matchFCHostToSCSIHost(conn, def_fchost, scsi_hostnum)) + return obj; } - VIR_DIR_CLOSE(dir); - return ret; + return NULL; } -int -virStoragePoolObjLoadAllConfigs(virStoragePoolObjListPtr pools, - const char *configDir, - const char *autostartDir) +static virStoragePoolObjPtr +virStoragePoolObjSourceMatchTypeDEVICE(virStoragePoolObjPtr obj, + virStoragePoolDefPtr def) { - DIR *dir; - struct dirent *entry; - int ret; - int rc; + virStoragePoolObjPtr matchobj = NULL; - if ((rc = virDirOpenIfExists(&dir, configDir)) <= 0) - return rc; + if (obj->def->type == VIR_STORAGE_POOL_ISCSI) { + if (def->type != VIR_STORAGE_POOL_ISCSI) + return NULL; - while ((ret = virDirRead(dir, &entry, configDir)) > 0) { - char *path; - char *autostartLink; - virStoragePoolObjPtr obj; + if ((matchobj = virStoragePoolSourceFindDuplicateDevices(obj, def))) { + if (!virStoragePoolSourceISCSIMatch(matchobj, def)) + return NULL; + } + return matchobj; + } - if (!virFileHasSuffix(entry->d_name, ".xml")) - continue; + if (def->type == VIR_STORAGE_POOL_ISCSI) + return NULL; - if (!(path = virFileBuildPath(configDir, entry->d_name, NULL))) - continue; + /* VIR_STORAGE_POOL_FS + * VIR_STORAGE_POOL_LOGICAL + * VIR_STORAGE_POOL_DISK + * VIR_STORAGE_POOL_ZFS */ + return virStoragePoolSourceFindDuplicateDevices(obj, def); +} - if (!(autostartLink = virFileBuildPath(autostartDir, entry->d_name, - NULL))) { - VIR_FREE(path); - continue; - } - obj = virStoragePoolObjLoad(pools, entry->d_name, path, autostartLink); - virStoragePoolObjEndAPI(&obj); +struct _virStoragePoolObjFindDuplicateData { + virConnectPtr conn; + virStoragePoolDefPtr def; +}; - VIR_FREE(path); - VIR_FREE(autostartLink); - } +static int +virStoragePoolObjSourceFindDuplicateCb(const void *payload, + const void *name ATTRIBUTE_UNUSED, + const void *opaque) +{ + virStoragePoolObjPtr obj = (virStoragePoolObjPtr) payload; + struct _virStoragePoolObjFindDuplicateData *data = + (struct _virStoragePoolObjFindDuplicateData *) opaque; - VIR_DIR_CLOSE(dir); - return ret; -} + /* Don't match against ourself if re-defining existing pool ! */ + if (STREQ(obj->def->name, data->def->name)) + return 0; + + switch ((virStoragePoolType)obj->def->type) { + case VIR_STORAGE_POOL_DIR: + case VIR_STORAGE_POOL_GLUSTER: + case VIR_STORAGE_POOL_NETFS: + if (data->def->type == obj->def->type && + virStoragePoolObjSourceMatchTypeDIR(obj, data->def)) + return 1; + break; + + case VIR_STORAGE_POOL_SCSI: + if (data->def->type == obj->def->type && + virStoragePoolObjSourceMatchTypeISCSI(obj, data->def, data->conn)) + return 1; + break; + + case VIR_STORAGE_POOL_ISCSI: + case VIR_STORAGE_POOL_ISCSI_DIRECT: + case VIR_STORAGE_POOL_FS: + case VIR_STORAGE_POOL_LOGICAL: + case VIR_STORAGE_POOL_DISK: + case VIR_STORAGE_POOL_ZFS: + if ((data->def->type == VIR_STORAGE_POOL_ISCSI || + data->def->type == VIR_STORAGE_POOL_ISCSI_DIRECT || + data->def->type == VIR_STORAGE_POOL_FS || + data->def->type == VIR_STORAGE_POOL_LOGICAL || + data->def->type == VIR_STORAGE_POOL_DISK || + data->def->type == VIR_STORAGE_POOL_ZFS) && + virStoragePoolObjSourceMatchTypeDEVICE(obj, data->def)) + return 1; + break; + case VIR_STORAGE_POOL_SHEEPDOG: + if (data->def->type == obj->def->type && + virStoragePoolSourceMatchSingleHost(&obj->def->source, + &data->def->source)) + return 1; + break; -int -virStoragePoolObjSaveDef(virStorageDriverStatePtr driver, - virStoragePoolObjPtr obj, - virStoragePoolDefPtr def) -{ - if (!obj->configFile) { - if (virFileMakePath(driver->configDir) < 0) { - virReportSystemError(errno, - _("cannot create config directory %s"), - driver->configDir); - return -1; - } + case VIR_STORAGE_POOL_MPATH: + /* Only one mpath pool is valid per host */ + if (data->def->type == obj->def->type) + return 1; + break; - if (!(obj->configFile = virFileBuildPath(driver->configDir, - def->name, ".xml"))) { - return -1; - } + case VIR_STORAGE_POOL_VSTORAGE: + if (data->def->type == obj->def->type && + STREQ(obj->def->source.name, data->def->source.name)) + return 1; + break; - if (!(obj->autostartLink = virFileBuildPath(driver->autostartDir, - def->name, ".xml"))) { - VIR_FREE(obj->configFile); - return -1; - } + case VIR_STORAGE_POOL_RBD: + case VIR_STORAGE_POOL_LAST: + break; } - return virStoragePoolSaveConfig(obj->configFile, def); + return 0; } int -virStoragePoolObjDeleteDef(virStoragePoolObjPtr obj) +virStoragePoolObjSourceFindDuplicate(virConnectPtr conn, + virStoragePoolObjListPtr pools, + virStoragePoolDefPtr def) { - if (!obj->configFile) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("no config file for %s"), obj->def->name); - return -1; - } + struct _virStoragePoolObjFindDuplicateData data = { .conn = conn, + .def = def }; + virStoragePoolObjPtr obj = NULL; - if (unlink(obj->configFile) < 0) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("cannot remove config for %s"), + virObjectRWLockRead(pools); + obj = virHashSearch(pools->objs, virStoragePoolObjSourceFindDuplicateCb, + &data, NULL); + virObjectRWUnlock(pools); + + if (obj) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("Storage source conflict with pool: '%s'"), obj->def->name); return -1; } @@ -1404,522 +1512,414 @@ virStoragePoolObjDeleteDef(virStoragePoolObjPtr obj) } -struct _virStoragePoolCountData { - virConnectPtr conn; - virStoragePoolObjListACLFilter filter; - bool wantActive; - int count; -}; - - -static int -virStoragePoolObjNumOfStoragePoolsCb(void *payload, - const void *name ATTRIBUTE_UNUSED, - void *opaque) +/** + * virStoragePoolObjAssignDef: + * @pools: Storage Pool object list pointer + * @def: Storage pool definition to add or update + * @check_active: If true, ensure that pool is not active + * + * Lookup the @def to see if it already exists in the @pools in order + * to either update or add if it does not exist. + * + * Returns locked and reffed object pointer or NULL on error + */ +virStoragePoolObjPtr +virStoragePoolObjAssignDef(virStoragePoolObjListPtr pools, + virStoragePoolDefPtr def, + bool check_active) { - virStoragePoolObjPtr obj = payload; - struct _virStoragePoolCountData *data = opaque; - - virObjectLock(obj); - - if (data->filter && !data->filter(data->conn, obj->def)) - goto cleanup; + virStoragePoolObjPtr obj = NULL; + char uuidstr[VIR_UUID_STRING_BUFLEN]; + int rc; - if (data->wantActive != virStoragePoolObjIsActive(obj)) - goto cleanup; + virObjectRWLockWrite(pools); - data->count++; + rc = virStoragePoolObjIsDuplicate(pools, def, check_active, &obj); - cleanup: - virObjectUnlock(obj); - return 0; -} + if (rc < 0) + goto error; + if (rc > 0) { + if (!virStoragePoolObjIsActive(obj)) { + virStoragePoolDefFree(obj->def); + obj->def = def; + } else { + virStoragePoolDefFree(obj->newDef); + obj->newDef = def; + } + virObjectRWUnlock(pools); + return obj; + } + if (!(obj = virStoragePoolObjNew())) + goto error; -int -virStoragePoolObjNumOfStoragePools(virStoragePoolObjListPtr pools, - virConnectPtr conn, - bool wantActive, - virStoragePoolObjListACLFilter filter) -{ - struct _virStoragePoolCountData data = { - .conn = conn, .filter = filter, .wantActive = wantActive, .count = 0 }; + virUUIDFormat(def->uuid, uuidstr); + if (virHashAddEntry(pools->objs, uuidstr, obj) < 0) + goto error; + virObjectRef(obj); - virObjectRWLockRead(pools); - virHashForEach(pools->objs, virStoragePoolObjNumOfStoragePoolsCb, &data); + if (virHashAddEntry(pools->objsName, def->name, obj) < 0) { + virHashRemoveEntry(pools->objs, uuidstr); + goto error; + } + virObjectRef(obj); + obj->def = def; virObjectRWUnlock(pools); + return obj; - return data.count; + error: + virStoragePoolObjEndAPI(&obj); + virObjectRWUnlock(pools); + return NULL; } -struct _virStoragePoolNameData { - virConnectPtr conn; - virStoragePoolObjListACLFilter filter; - bool wantActive; - bool error; - int nnames; - int maxnames; - char **const names; -}; - - -static int -virStoragePoolObjGetNamesCb(void *payload, - const void *name ATTRIBUTE_UNUSED, - void *opaque) +static virStoragePoolObjPtr +virStoragePoolObjLoad(virStoragePoolObjListPtr pools, + const char *file, + const char *path, + const char *autostartLink) { - virStoragePoolObjPtr obj = payload; - struct _virStoragePoolNameData *data = opaque; - - if (data->error) - return 0; - - if (data->maxnames >= 0 && data->nnames == data->maxnames) - return 0; + virStoragePoolDefPtr def; + virStoragePoolObjPtr obj; - virObjectLock(obj); + if (!(def = virStoragePoolDefParseFile(path))) + return NULL; - if (data->filter && !data->filter(data->conn, obj->def)) - goto cleanup; + if (!virFileMatchesNameSuffix(file, def->name, ".xml")) { + virReportError(VIR_ERR_XML_ERROR, + _("Storage pool config filename '%s' does " + "not match pool name '%s'"), + path, def->name); + virStoragePoolDefFree(def); + return NULL; + } - if (data->wantActive != virStoragePoolObjIsActive(obj)) - goto cleanup; + if (!(obj = virStoragePoolObjAssignDef(pools, def, false))) { + virStoragePoolDefFree(def); + return NULL; + } - if (data->names) { - if (VIR_STRDUP(data->names[data->nnames], obj->def->name) < 0) { - data->error = true; - goto cleanup; - } + VIR_FREE(obj->configFile); /* for driver reload */ + if (VIR_STRDUP(obj->configFile, path) < 0) { + virStoragePoolObjRemove(pools, obj); + virObjectUnref(obj); + return NULL; + } + VIR_FREE(obj->autostartLink); /* for driver reload */ + if (VIR_STRDUP(obj->autostartLink, autostartLink) < 0) { + virStoragePoolObjRemove(pools, obj); + virObjectUnref(obj); + return NULL; } - data->nnames++; + obj->autostart = virFileLinkPointsTo(obj->autostartLink, + obj->configFile); - cleanup: - virObjectUnlock(obj); - return 0; + return obj; } -int -virStoragePoolObjGetNames(virStoragePoolObjListPtr pools, - virConnectPtr conn, - bool wantActive, - virStoragePoolObjListACLFilter filter, - char **const names, - int maxnames) +static virStoragePoolObjPtr +virStoragePoolObjLoadState(virStoragePoolObjListPtr pools, + const char *stateDir, + const char *name) { - struct _virStoragePoolNameData data = { - .conn = conn, .filter = filter, .wantActive = wantActive, - .error = false, .nnames = 0, .maxnames = maxnames, .names = names }; - - virObjectRWLockRead(pools); - virHashForEach(pools->objs, virStoragePoolObjGetNamesCb, &data); - virObjectRWUnlock(pools); - - if (data.error) - goto error; - - return data.nnames; + char *stateFile = NULL; + virStoragePoolDefPtr def = NULL; + virStoragePoolObjPtr obj = NULL; + xmlDocPtr xml = NULL; + xmlXPathContextPtr ctxt = NULL; + xmlNodePtr node = NULL; - error: - while (data.nnames) - VIR_FREE(data.names[--data.nnames]); - return -1; -} + if (!(stateFile = virFileBuildPath(stateDir, name, ".xml"))) + goto error; + if (!(xml = virXMLParseCtxt(stateFile, NULL, _("(pool state)"), &ctxt))) + goto error; -static int -getSCSIHostNumber(virStorageAdapterSCSIHostPtr scsi_host, - unsigned int *hostnum) -{ - int ret = -1; - unsigned int num; - char *name = NULL; + if (!(node = virXPathNode("//pool", ctxt))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Could not find any 'pool' element in state file")); + goto error; + } - if (scsi_host->has_parent) { - virPCIDeviceAddressPtr addr = &scsi_host->parentaddr; - unsigned int unique_id = scsi_host->unique_id; + ctxt->node = node; + if (!(def = virStoragePoolDefParseXML(ctxt))) + goto error; - if (!(name = virSCSIHostGetNameByParentaddr(addr->domain, - addr->bus, - addr->slot, - addr->function, - unique_id))) - goto cleanup; - if (virSCSIHostGetNumber(name, &num) < 0) - goto cleanup; - } else { - if (virSCSIHostGetNumber(scsi_host->name, &num) < 0) - goto cleanup; + if (STRNEQ(name, def->name)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Storage pool state file '%s' does not match " + "pool name '%s'"), + stateFile, def->name); + goto error; } - *hostnum = num; - ret = 0; - - cleanup: - VIR_FREE(name); - return ret; -} + /* create the object */ + if (!(obj = virStoragePoolObjAssignDef(pools, def, true))) + goto error; + /* XXX: future handling of some additional useful status data, + * for now, if a status file for a pool exists, the pool will be marked + * as active + */ -static bool -virStorageIsSameHostnum(const char *name, - unsigned int scsi_hostnum) -{ - unsigned int fc_hostnum; + obj->active = true; - if (virSCSIHostGetNumber(name, &fc_hostnum) == 0 && - scsi_hostnum == fc_hostnum) - return true; + cleanup: + VIR_FREE(stateFile); + xmlFreeDoc(xml); + xmlXPathFreeContext(ctxt); + return obj; - return false; + error: + virStoragePoolDefFree(def); + goto cleanup; } -/* - * matchFCHostToSCSIHost: - * - * @conn: Connection pointer - * @fchost: fc_host adapter ptr (either def or pool->def) - * @scsi_hostnum: Already determined "scsi_pool" hostnum - * - * Returns true/false whether there is a match between the incoming - * fc_adapter host# and the scsi_host host# - */ -static bool -matchFCHostToSCSIHost(virConnectPtr conn, - virStorageAdapterFCHostPtr fchost, - unsigned int scsi_hostnum) +int +virStoragePoolObjLoadAllState(virStoragePoolObjListPtr pools, + const char *stateDir) { - bool ret = false; - char *name = NULL; - char *scsi_host_name = NULL; - char *parent_name = NULL; + DIR *dir; + struct dirent *entry; + int ret = -1; + int rc; - /* If we have a parent defined, get its hostnum, and compare to the - * scsi_hostnum. If they are the same, then we have a match - */ - if (fchost->parent && - virStorageIsSameHostnum(fchost->parent, scsi_hostnum)) - return true; + if ((rc = virDirOpenIfExists(&dir, stateDir)) <= 0) + return rc; - /* If we find an fc adapter name, then either libvirt created a vHBA - * for this fc_host or a 'virsh nodedev-create' generated a vHBA. - */ - if ((name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) { + while ((ret = virDirRead(dir, &entry, stateDir)) > 0) { + virStoragePoolObjPtr obj; - /* Get the scsi_hostN for the vHBA in order to see if it - * matches our scsi_hostnum - */ - if (virStorageIsSameHostnum(name, scsi_hostnum)) { - ret = true; - goto cleanup; - } + if (!virFileStripSuffix(entry->d_name, ".xml")) + continue; - /* We weren't provided a parent, so we have to query the node - * device driver in order to ascertain the parent of the vHBA. - * If the parent fc_hostnum is the same as the scsi_hostnum, we - * have a match. - */ - if (conn && !fchost->parent) { - if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0) - goto cleanup; - if ((parent_name = virNodeDeviceGetParentName(conn, - scsi_host_name))) { - if (virStorageIsSameHostnum(parent_name, scsi_hostnum)) { - ret = true; - goto cleanup; - } - } else { - /* Throw away the error and fall through */ - virResetLastError(); - VIR_DEBUG("Could not determine parent vHBA"); - } - } + if (!(obj = virStoragePoolObjLoadState(pools, stateDir, entry->d_name))) + continue; + virStoragePoolObjEndAPI(&obj); } - /* NB: Lack of a name means that this vHBA hasn't yet been created, - * which means our scsi_host cannot be using the vHBA. Furthermore, - * lack of a provided parent means libvirt is going to choose the - * "best" fc_host capable adapter based on availabilty. That could - * conflict with an existing scsi_host definition, but there's no - * way to know that now. - */ - - cleanup: - VIR_FREE(name); - VIR_FREE(parent_name); - VIR_FREE(scsi_host_name); + VIR_DIR_CLOSE(dir); return ret; } -static bool -matchSCSIAdapterParent(virStorageAdapterSCSIHostPtr pool_scsi_host, - virStorageAdapterSCSIHostPtr def_scsi_host) +int +virStoragePoolObjLoadAllConfigs(virStoragePoolObjListPtr pools, + const char *configDir, + const char *autostartDir) { - virPCIDeviceAddressPtr pooladdr = &pool_scsi_host->parentaddr; - virPCIDeviceAddressPtr defaddr = &def_scsi_host->parentaddr; - - if (pooladdr->domain == defaddr->domain && - pooladdr->bus == defaddr->bus && - pooladdr->slot == defaddr->slot && - pooladdr->function == defaddr->function && - pool_scsi_host->unique_id == def_scsi_host->unique_id) - return true; - - return false; -} + DIR *dir; + struct dirent *entry; + int ret; + int rc; + if ((rc = virDirOpenIfExists(&dir, configDir)) <= 0) + return rc; -static bool -virStoragePoolSourceMatchSingleHost(virStoragePoolSourcePtr poolsrc, - virStoragePoolSourcePtr defsrc) -{ - if (poolsrc->nhost != 1 && defsrc->nhost != 1) - return false; + while ((ret = virDirRead(dir, &entry, configDir)) > 0) { + char *path; + char *autostartLink; + virStoragePoolObjPtr obj; - if (defsrc->hosts[0].port && - poolsrc->hosts[0].port != defsrc->hosts[0].port) - return false; + if (!virFileHasSuffix(entry->d_name, ".xml")) + continue; - return STREQ(poolsrc->hosts[0].name, defsrc->hosts[0].name); -} + if (!(path = virFileBuildPath(configDir, entry->d_name, NULL))) + continue; + if (!(autostartLink = virFileBuildPath(autostartDir, entry->d_name, + NULL))) { + VIR_FREE(path); + continue; + } -static bool -virStoragePoolSourceISCSIMatch(virStoragePoolObjPtr obj, - virStoragePoolDefPtr def) -{ - virStoragePoolSourcePtr poolsrc = &obj->def->source; - virStoragePoolSourcePtr defsrc = &def->source; + obj = virStoragePoolObjLoad(pools, entry->d_name, path, autostartLink); + virStoragePoolObjEndAPI(&obj); - /* NB: Do not check the source host name */ - if (STRNEQ_NULLABLE(poolsrc->initiator.iqn, defsrc->initiator.iqn)) - return false; + VIR_FREE(path); + VIR_FREE(autostartLink); + } - return true; + VIR_DIR_CLOSE(dir); + return ret; } -static virStoragePoolObjPtr -virStoragePoolObjSourceMatchTypeDIR(virStoragePoolObjPtr obj, - virStoragePoolDefPtr def) +int +virStoragePoolObjSaveDef(virStorageDriverStatePtr driver, + virStoragePoolObjPtr obj, + virStoragePoolDefPtr def) { - if (obj->def->type == VIR_STORAGE_POOL_DIR) { - if (STREQ(obj->def->target.path, def->target.path)) - return obj; - } else if (obj->def->type == VIR_STORAGE_POOL_GLUSTER) { - if (STREQ(obj->def->source.name, def->source.name) && - STREQ_NULLABLE(obj->def->source.dir, def->source.dir) && - virStoragePoolSourceMatchSingleHost(&obj->def->source, - &def->source)) - return obj; - } else if (obj->def->type == VIR_STORAGE_POOL_NETFS) { - if (STREQ(obj->def->source.dir, def->source.dir) && - virStoragePoolSourceMatchSingleHost(&obj->def->source, - &def->source)) - return obj; + if (!obj->configFile) { + if (virFileMakePath(driver->configDir) < 0) { + virReportSystemError(errno, + _("cannot create config directory %s"), + driver->configDir); + return -1; + } + + if (!(obj->configFile = virFileBuildPath(driver->configDir, + def->name, ".xml"))) { + return -1; + } + + if (!(obj->autostartLink = virFileBuildPath(driver->autostartDir, + def->name, ".xml"))) { + VIR_FREE(obj->configFile); + return -1; + } } - return NULL; + return virStoragePoolSaveConfig(obj->configFile, def); } -static virStoragePoolObjPtr -virStoragePoolObjSourceMatchTypeISCSI(virStoragePoolObjPtr obj, - virStoragePoolDefPtr def, - virConnectPtr conn) +int +virStoragePoolObjDeleteDef(virStoragePoolObjPtr obj) { - virStorageAdapterPtr pool_adapter = &obj->def->source.adapter; - virStorageAdapterPtr def_adapter = &def->source.adapter; - virStorageAdapterSCSIHostPtr pool_scsi_host; - virStorageAdapterSCSIHostPtr def_scsi_host; - virStorageAdapterFCHostPtr pool_fchost; - virStorageAdapterFCHostPtr def_fchost; - unsigned int pool_hostnum; - unsigned int def_hostnum; - unsigned int scsi_hostnum; + if (!obj->configFile) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("no config file for %s"), obj->def->name); + return -1; + } - if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST && - def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST) { - pool_fchost = &pool_adapter->data.fchost; - def_fchost = &def_adapter->data.fchost; + if (unlink(obj->configFile) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("cannot remove config for %s"), + obj->def->name); + return -1; + } - if (STREQ(pool_fchost->wwnn, def_fchost->wwnn) && - STREQ(pool_fchost->wwpn, def_fchost->wwpn)) - return obj; - } else if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST && - def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST) { - pool_scsi_host = &pool_adapter->data.scsi_host; - def_scsi_host = &def_adapter->data.scsi_host; + return 0; +} - if (pool_scsi_host->has_parent && - def_scsi_host->has_parent && - matchSCSIAdapterParent(pool_scsi_host, def_scsi_host)) - return obj; - if (getSCSIHostNumber(pool_scsi_host, &pool_hostnum) < 0 || - getSCSIHostNumber(def_scsi_host, &def_hostnum) < 0) - return NULL; - if (pool_hostnum == def_hostnum) - return obj; - } else if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST && - def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST) { - pool_fchost = &pool_adapter->data.fchost; - def_scsi_host = &def_adapter->data.scsi_host; +struct _virStoragePoolCountData { + virConnectPtr conn; + virStoragePoolObjListACLFilter filter; + bool wantActive; + int count; +}; - /* Get the scsi_hostN for the scsi_host source adapter def */ - if (getSCSIHostNumber(def_scsi_host, &scsi_hostnum) < 0) - return NULL; - if (matchFCHostToSCSIHost(conn, pool_fchost, scsi_hostnum)) - return obj; +static int +virStoragePoolObjNumOfStoragePoolsCb(void *payload, + const void *name ATTRIBUTE_UNUSED, + void *opaque) +{ + virStoragePoolObjPtr obj = payload; + struct _virStoragePoolCountData *data = opaque; - } else if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_SCSI_HOST && - def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST) { - pool_scsi_host = &pool_adapter->data.scsi_host; - def_fchost = &def_adapter->data.fchost; + virObjectLock(obj); - if (getSCSIHostNumber(pool_scsi_host, &scsi_hostnum) < 0) - return NULL; + if (data->filter && !data->filter(data->conn, obj->def)) + goto cleanup; - if (matchFCHostToSCSIHost(conn, def_fchost, scsi_hostnum)) - return obj; - } + if (data->wantActive != virStoragePoolObjIsActive(obj)) + goto cleanup; - return NULL; + data->count++; + + cleanup: + virObjectUnlock(obj); + return 0; } -static virStoragePoolObjPtr -virStoragePoolObjSourceMatchTypeDEVICE(virStoragePoolObjPtr obj, - virStoragePoolDefPtr def) +int +virStoragePoolObjNumOfStoragePools(virStoragePoolObjListPtr pools, + virConnectPtr conn, + bool wantActive, + virStoragePoolObjListACLFilter filter) { - virStoragePoolObjPtr matchobj = NULL; - - if (obj->def->type == VIR_STORAGE_POOL_ISCSI) { - if (def->type != VIR_STORAGE_POOL_ISCSI) - return NULL; - - if ((matchobj = virStoragePoolSourceFindDuplicateDevices(obj, def))) { - if (!virStoragePoolSourceISCSIMatch(matchobj, def)) - return NULL; - } - return matchobj; - } + struct _virStoragePoolCountData data = { + .conn = conn, .filter = filter, .wantActive = wantActive, .count = 0 }; - if (def->type == VIR_STORAGE_POOL_ISCSI) - return NULL; + virObjectRWLockRead(pools); + virHashForEach(pools->objs, virStoragePoolObjNumOfStoragePoolsCb, &data); + virObjectRWUnlock(pools); - /* VIR_STORAGE_POOL_FS - * VIR_STORAGE_POOL_LOGICAL - * VIR_STORAGE_POOL_DISK - * VIR_STORAGE_POOL_ZFS */ - return virStoragePoolSourceFindDuplicateDevices(obj, def); + return data.count; } -struct _virStoragePoolObjFindDuplicateData { +struct _virStoragePoolNameData { virConnectPtr conn; - virStoragePoolDefPtr def; + virStoragePoolObjListACLFilter filter; + bool wantActive; + bool error; + int nnames; + int maxnames; + char **const names; }; + static int -virStoragePoolObjSourceFindDuplicateCb(const void *payload, - const void *name ATTRIBUTE_UNUSED, - const void *opaque) +virStoragePoolObjGetNamesCb(void *payload, + const void *name ATTRIBUTE_UNUSED, + void *opaque) { - virStoragePoolObjPtr obj = (virStoragePoolObjPtr) payload; - struct _virStoragePoolObjFindDuplicateData *data = - (struct _virStoragePoolObjFindDuplicateData *) opaque; + virStoragePoolObjPtr obj = payload; + struct _virStoragePoolNameData *data = opaque; - /* Don't match against ourself if re-defining existing pool ! */ - if (STREQ(obj->def->name, data->def->name)) + if (data->error) return 0; - switch ((virStoragePoolType)obj->def->type) { - case VIR_STORAGE_POOL_DIR: - case VIR_STORAGE_POOL_GLUSTER: - case VIR_STORAGE_POOL_NETFS: - if (data->def->type == obj->def->type && - virStoragePoolObjSourceMatchTypeDIR(obj, data->def)) - return 1; - break; - - case VIR_STORAGE_POOL_SCSI: - if (data->def->type == obj->def->type && - virStoragePoolObjSourceMatchTypeISCSI(obj, data->def, data->conn)) - return 1; - break; - - case VIR_STORAGE_POOL_ISCSI: - case VIR_STORAGE_POOL_ISCSI_DIRECT: - case VIR_STORAGE_POOL_FS: - case VIR_STORAGE_POOL_LOGICAL: - case VIR_STORAGE_POOL_DISK: - case VIR_STORAGE_POOL_ZFS: - if ((data->def->type == VIR_STORAGE_POOL_ISCSI || - data->def->type == VIR_STORAGE_POOL_ISCSI_DIRECT || - data->def->type == VIR_STORAGE_POOL_FS || - data->def->type == VIR_STORAGE_POOL_LOGICAL || - data->def->type == VIR_STORAGE_POOL_DISK || - data->def->type == VIR_STORAGE_POOL_ZFS) && - virStoragePoolObjSourceMatchTypeDEVICE(obj, data->def)) - return 1; - break; + if (data->maxnames >= 0 && data->nnames == data->maxnames) + return 0; - case VIR_STORAGE_POOL_SHEEPDOG: - if (data->def->type == obj->def->type && - virStoragePoolSourceMatchSingleHost(&obj->def->source, - &data->def->source)) - return 1; - break; + virObjectLock(obj); - case VIR_STORAGE_POOL_MPATH: - /* Only one mpath pool is valid per host */ - if (data->def->type == obj->def->type) - return 1; - break; + if (data->filter && !data->filter(data->conn, obj->def)) + goto cleanup; - case VIR_STORAGE_POOL_VSTORAGE: - if (data->def->type == obj->def->type && - STREQ(obj->def->source.name, data->def->source.name)) - return 1; - break; + if (data->wantActive != virStoragePoolObjIsActive(obj)) + goto cleanup; - case VIR_STORAGE_POOL_RBD: - case VIR_STORAGE_POOL_LAST: - break; + if (data->names) { + if (VIR_STRDUP(data->names[data->nnames], obj->def->name) < 0) { + data->error = true; + goto cleanup; + } } + data->nnames++; + + cleanup: + virObjectUnlock(obj); return 0; } int -virStoragePoolObjSourceFindDuplicate(virConnectPtr conn, - virStoragePoolObjListPtr pools, - virStoragePoolDefPtr def) +virStoragePoolObjGetNames(virStoragePoolObjListPtr pools, + virConnectPtr conn, + bool wantActive, + virStoragePoolObjListACLFilter filter, + char **const names, + int maxnames) { - struct _virStoragePoolObjFindDuplicateData data = { .conn = conn, - .def = def }; - virStoragePoolObjPtr obj = NULL; + struct _virStoragePoolNameData data = { + .conn = conn, .filter = filter, .wantActive = wantActive, + .error = false, .nnames = 0, .maxnames = maxnames, .names = names }; virObjectRWLockRead(pools); - obj = virHashSearch(pools->objs, virStoragePoolObjSourceFindDuplicateCb, - &data, NULL); + virHashForEach(pools->objs, virStoragePoolObjGetNamesCb, &data); virObjectRWUnlock(pools); - if (obj) { - virReportError(VIR_ERR_OPERATION_FAILED, - _("Storage source conflict with pool: '%s'"), - obj->def->name); - return -1; - } + if (data.error) + goto error; - return 0; + return data.nnames; + + error: + while (data.nnames) + VIR_FREE(data.names[--data.nnames]); + return -1; } -- GitLab