}
-/**
- * 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;
}
}
-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;
}