提交 d1300900 编写于 作者: M Michal Privoznik

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: NMichal Privoznik <mprivozn@redhat.com>
Reviewed-by: NJohn Ferlan <jferlan@redhat.com>
上级 4391b522
...@@ -1118,284 +1118,392 @@ virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools, ...@@ -1118,284 +1118,392 @@ virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools,
} }
/** static int
* virStoragePoolObjAssignDef: getSCSIHostNumber(virStorageAdapterSCSIHostPtr scsi_host,
* @pools: Storage Pool object list pointer unsigned int *hostnum)
* @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 = NULL; int ret = -1;
char uuidstr[VIR_UUID_STRING_BUFLEN]; unsigned int num;
int rc; char *name = NULL;
virObjectRWLockWrite(pools);
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) if (!(name = virSCSIHostGetNameByParentaddr(addr->domain,
goto error; addr->bus,
if (rc > 0) { addr->slot,
if (!virStoragePoolObjIsActive(obj)) { addr->function,
virStoragePoolDefFree(obj->def); unique_id)))
obj->def = def; goto cleanup;
} else { if (virSCSIHostGetNumber(name, &num) < 0)
virStoragePoolDefFree(obj->newDef); goto cleanup;
obj->newDef = def; } else {
} if (virSCSIHostGetNumber(scsi_host->name, &num) < 0)
virObjectRWUnlock(pools); goto cleanup;
return obj;
} }
if (!(obj = virStoragePoolObjNew())) *hostnum = num;
goto error; ret = 0;
virUUIDFormat(def->uuid, uuidstr); cleanup:
if (virHashAddEntry(pools->objs, uuidstr, obj) < 0) VIR_FREE(name);
goto error; return ret;
virObjectRef(obj); }
if (virHashAddEntry(pools->objsName, def->name, obj) < 0) {
virHashRemoveEntry(pools->objs, uuidstr);
goto error;
}
virObjectRef(obj);
obj->def = def;
virObjectRWUnlock(pools);
return obj;
error: static bool
virStoragePoolObjEndAPI(&obj); virStorageIsSameHostnum(const char *name,
virObjectRWUnlock(pools); unsigned int scsi_hostnum)
return NULL; {
unsigned int fc_hostnum;
if (virSCSIHostGetNumber(name, &fc_hostnum) == 0 &&
scsi_hostnum == fc_hostnum)
return true;
return false;
} }
static virStoragePoolObjPtr /*
virStoragePoolObjLoad(virStoragePoolObjListPtr pools, * matchFCHostToSCSIHost:
const char *file, *
const char *path, * @conn: Connection pointer
const char *autostartLink) * @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; bool ret = false;
virStoragePoolObjPtr obj; char *name = NULL;
char *scsi_host_name = NULL;
char *parent_name = NULL;
if (!(def = virStoragePoolDefParseFile(path))) /* If we have a parent defined, get its hostnum, and compare to the
return NULL; * 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")) { /* If we find an fc adapter name, then either libvirt created a vHBA
virReportError(VIR_ERR_XML_ERROR, * for this fc_host or a 'virsh nodedev-create' generated a vHBA.
_("Storage pool config filename '%s' does " */
"not match pool name '%s'"), if ((name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) {
path, def->name);
virStoragePoolDefFree(def);
return NULL;
}
if (!(obj = virStoragePoolObjAssignDef(pools, def, false))) { /* Get the scsi_hostN for the vHBA in order to see if it
virStoragePoolDefFree(def); * matches our scsi_hostnum
return NULL; */
} if (virStorageIsSameHostnum(name, scsi_hostnum)) {
ret = true;
goto cleanup;
}
VIR_FREE(obj->configFile); /* for driver reload */ /* We weren't provided a parent, so we have to query the node
if (VIR_STRDUP(obj->configFile, path) < 0) { * device driver in order to ascertain the parent of the vHBA.
virStoragePoolObjRemove(pools, obj); * If the parent fc_hostnum is the same as the scsi_hostnum, we
virObjectUnref(obj); * have a match.
return NULL; */
} if (conn && !fchost->parent) {
VIR_FREE(obj->autostartLink); /* for driver reload */ if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0)
if (VIR_STRDUP(obj->autostartLink, autostartLink) < 0) { goto cleanup;
virStoragePoolObjRemove(pools, obj); if ((parent_name = virNodeDeviceGetParentName(conn,
virObjectUnref(obj); scsi_host_name))) {
return NULL; 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, /* NB: Lack of a name means that this vHBA hasn't yet been created,
obj->configFile); * 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 static bool
virStoragePoolObjLoadState(virStoragePoolObjListPtr pools, matchSCSIAdapterParent(virStorageAdapterSCSIHostPtr pool_scsi_host,
const char *stateDir, virStorageAdapterSCSIHostPtr def_scsi_host)
const char *name)
{ {
char *stateFile = NULL; virPCIDeviceAddressPtr pooladdr = &pool_scsi_host->parentaddr;
virStoragePoolDefPtr def = NULL; virPCIDeviceAddressPtr defaddr = &def_scsi_host->parentaddr;
virStoragePoolObjPtr obj = NULL;
xmlDocPtr xml = NULL;
xmlXPathContextPtr ctxt = NULL;
xmlNodePtr node = NULL;
if (!(stateFile = virFileBuildPath(stateDir, name, ".xml"))) if (pooladdr->domain == defaddr->domain &&
goto error; 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))) return false;
goto error; }
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; static bool
if (!(def = virStoragePoolDefParseXML(ctxt))) virStoragePoolSourceMatchSingleHost(virStoragePoolSourcePtr poolsrc,
goto error; virStoragePoolSourcePtr defsrc)
{
if (poolsrc->nhost != 1 && defsrc->nhost != 1)
return false;
if (STRNEQ(name, def->name)) { if (defsrc->hosts[0].port &&
virReportError(VIR_ERR_INTERNAL_ERROR, poolsrc->hosts[0].port != defsrc->hosts[0].port)
_("Storage pool state file '%s' does not match " return false;
"pool name '%s'"),
stateFile, def->name);
goto error;
}
/* create the object */ return STREQ(poolsrc->hosts[0].name, defsrc->hosts[0].name);
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
*/
obj->active = true; static bool
virStoragePoolSourceISCSIMatch(virStoragePoolObjPtr obj,
virStoragePoolDefPtr def)
{
virStoragePoolSourcePtr poolsrc = &obj->def->source;
virStoragePoolSourcePtr defsrc = &def->source;
cleanup: /* NB: Do not check the source host name */
VIR_FREE(stateFile); if (STRNEQ_NULLABLE(poolsrc->initiator.iqn, defsrc->initiator.iqn))
xmlFreeDoc(xml); return false;
xmlXPathFreeContext(ctxt);
return obj;
error: return true;
virStoragePoolDefFree(def);
goto cleanup;
} }
int static virStoragePoolObjPtr
virStoragePoolObjLoadAllState(virStoragePoolObjListPtr pools, virStoragePoolObjSourceMatchTypeDIR(virStoragePoolObjPtr obj,
const char *stateDir) virStoragePoolDefPtr def)
{ {
DIR *dir; if (obj->def->type == VIR_STORAGE_POOL_DIR) {
struct dirent *entry; if (STREQ(obj->def->target.path, def->target.path))
int ret = -1; return obj;
int rc; } 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 NULL;
return rc; }
while ((ret = virDirRead(dir, &entry, stateDir)) > 0) {
virStoragePoolObjPtr obj;
if (!virFileStripSuffix(entry->d_name, ".xml")) static virStoragePoolObjPtr
continue; 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))) if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST &&
continue; def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST) {
virStoragePoolObjEndAPI(&obj); 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 NULL;
return ret;
} }
int static virStoragePoolObjPtr
virStoragePoolObjLoadAllConfigs(virStoragePoolObjListPtr pools, virStoragePoolObjSourceMatchTypeDEVICE(virStoragePoolObjPtr obj,
const char *configDir, virStoragePoolDefPtr def)
const char *autostartDir)
{ {
DIR *dir; virStoragePoolObjPtr matchobj = NULL;
struct dirent *entry;
int ret;
int rc;
if ((rc = virDirOpenIfExists(&dir, configDir)) <= 0) if (obj->def->type == VIR_STORAGE_POOL_ISCSI) {
return rc; if (def->type != VIR_STORAGE_POOL_ISCSI)
return NULL;
while ((ret = virDirRead(dir, &entry, configDir)) > 0) { if ((matchobj = virStoragePoolSourceFindDuplicateDevices(obj, def))) {
char *path; if (!virStoragePoolSourceISCSIMatch(matchobj, def))
char *autostartLink; return NULL;
virStoragePoolObjPtr obj; }
return matchobj;
}
if (!virFileHasSuffix(entry->d_name, ".xml")) if (def->type == VIR_STORAGE_POOL_ISCSI)
continue; return NULL;
if (!(path = virFileBuildPath(configDir, entry->d_name, NULL))) /* VIR_STORAGE_POOL_FS
continue; * 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); struct _virStoragePoolObjFindDuplicateData {
virStoragePoolObjEndAPI(&obj); virConnectPtr conn;
virStoragePoolDefPtr def;
};
VIR_FREE(path); static int
VIR_FREE(autostartLink); 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); /* Don't match against ourself if re-defining existing pool ! */
return ret; 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 case VIR_STORAGE_POOL_MPATH:
virStoragePoolObjSaveDef(virStorageDriverStatePtr driver, /* Only one mpath pool is valid per host */
virStoragePoolObjPtr obj, if (data->def->type == obj->def->type)
virStoragePoolDefPtr def) return 1;
{ break;
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, case VIR_STORAGE_POOL_VSTORAGE:
def->name, ".xml"))) { if (data->def->type == obj->def->type &&
return -1; STREQ(obj->def->source.name, data->def->source.name))
} return 1;
break;
if (!(obj->autostartLink = virFileBuildPath(driver->autostartDir, case VIR_STORAGE_POOL_RBD:
def->name, ".xml"))) { case VIR_STORAGE_POOL_LAST:
VIR_FREE(obj->configFile); break;
return -1;
}
} }
return virStoragePoolSaveConfig(obj->configFile, def); return 0;
} }
int int
virStoragePoolObjDeleteDef(virStoragePoolObjPtr obj) virStoragePoolObjSourceFindDuplicate(virConnectPtr conn,
virStoragePoolObjListPtr pools,
virStoragePoolDefPtr def)
{ {
if (!obj->configFile) { struct _virStoragePoolObjFindDuplicateData data = { .conn = conn,
virReportError(VIR_ERR_INTERNAL_ERROR, .def = def };
_("no config file for %s"), obj->def->name); virStoragePoolObjPtr obj = NULL;
return -1;
}
if (unlink(obj->configFile) < 0) { virObjectRWLockRead(pools);
virReportError(VIR_ERR_INTERNAL_ERROR, obj = virHashSearch(pools->objs, virStoragePoolObjSourceFindDuplicateCb,
_("cannot remove config for %s"), &data, NULL);
virObjectRWUnlock(pools);
if (obj) {
virReportError(VIR_ERR_OPERATION_FAILED,
_("Storage source conflict with pool: '%s'"),
obj->def->name); obj->def->name);
return -1; return -1;
} }
...@@ -1404,522 +1512,414 @@ virStoragePoolObjDeleteDef(virStoragePoolObjPtr obj) ...@@ -1404,522 +1512,414 @@ virStoragePoolObjDeleteDef(virStoragePoolObjPtr obj)
} }
struct _virStoragePoolCountData { /**
virConnectPtr conn; * virStoragePoolObjAssignDef:
virStoragePoolObjListACLFilter filter; * @pools: Storage Pool object list pointer
bool wantActive; * @def: Storage pool definition to add or update
int count; * @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.
static int *
virStoragePoolObjNumOfStoragePoolsCb(void *payload, * Returns locked and reffed object pointer or NULL on error
const void *name ATTRIBUTE_UNUSED, */
void *opaque) virStoragePoolObjPtr
virStoragePoolObjAssignDef(virStoragePoolObjListPtr pools,
virStoragePoolDefPtr def,
bool check_active)
{ {
virStoragePoolObjPtr obj = payload; virStoragePoolObjPtr obj = NULL;
struct _virStoragePoolCountData *data = opaque; char uuidstr[VIR_UUID_STRING_BUFLEN];
int rc;
virObjectLock(obj);
if (data->filter && !data->filter(data->conn, obj->def))
goto cleanup;
if (data->wantActive != virStoragePoolObjIsActive(obj)) virObjectRWLockWrite(pools);
goto cleanup;
data->count++; rc = virStoragePoolObjIsDuplicate(pools, def, check_active, &obj);
cleanup: if (rc < 0)
virObjectUnlock(obj); goto error;
return 0; 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 virUUIDFormat(def->uuid, uuidstr);
virStoragePoolObjNumOfStoragePools(virStoragePoolObjListPtr pools, if (virHashAddEntry(pools->objs, uuidstr, obj) < 0)
virConnectPtr conn, goto error;
bool wantActive, virObjectRef(obj);
virStoragePoolObjListACLFilter filter)
{
struct _virStoragePoolCountData data = {
.conn = conn, .filter = filter, .wantActive = wantActive, .count = 0 };
virObjectRWLockRead(pools); if (virHashAddEntry(pools->objsName, def->name, obj) < 0) {
virHashForEach(pools->objs, virStoragePoolObjNumOfStoragePoolsCb, &data); virHashRemoveEntry(pools->objs, uuidstr);
goto error;
}
virObjectRef(obj);
obj->def = def;
virObjectRWUnlock(pools); virObjectRWUnlock(pools);
return obj;
return data.count; error:
virStoragePoolObjEndAPI(&obj);
virObjectRWUnlock(pools);
return NULL;
} }
struct _virStoragePoolNameData { static virStoragePoolObjPtr
virConnectPtr conn; virStoragePoolObjLoad(virStoragePoolObjListPtr pools,
virStoragePoolObjListACLFilter filter; const char *file,
bool wantActive; const char *path,
bool error; const char *autostartLink)
int nnames;
int maxnames;
char **const names;
};
static int
virStoragePoolObjGetNamesCb(void *payload,
const void *name ATTRIBUTE_UNUSED,
void *opaque)
{ {
virStoragePoolObjPtr obj = payload; virStoragePoolDefPtr def;
struct _virStoragePoolNameData *data = opaque; virStoragePoolObjPtr obj;
if (data->error)
return 0;
if (data->maxnames >= 0 && data->nnames == data->maxnames)
return 0;
virObjectLock(obj); if (!(def = virStoragePoolDefParseFile(path)))
return NULL;
if (data->filter && !data->filter(data->conn, obj->def)) if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
goto cleanup; 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)) if (!(obj = virStoragePoolObjAssignDef(pools, def, false))) {
goto cleanup; virStoragePoolDefFree(def);
return NULL;
}
if (data->names) { VIR_FREE(obj->configFile); /* for driver reload */
if (VIR_STRDUP(data->names[data->nnames], obj->def->name) < 0) { if (VIR_STRDUP(obj->configFile, path) < 0) {
data->error = true; virStoragePoolObjRemove(pools, obj);
goto cleanup; 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: return obj;
virObjectUnlock(obj);
return 0;
} }
int static virStoragePoolObjPtr
virStoragePoolObjGetNames(virStoragePoolObjListPtr pools, virStoragePoolObjLoadState(virStoragePoolObjListPtr pools,
virConnectPtr conn, const char *stateDir,
bool wantActive, const char *name)
virStoragePoolObjListACLFilter filter,
char **const names,
int maxnames)
{ {
struct _virStoragePoolNameData data = { char *stateFile = NULL;
.conn = conn, .filter = filter, .wantActive = wantActive, virStoragePoolDefPtr def = NULL;
.error = false, .nnames = 0, .maxnames = maxnames, .names = names }; virStoragePoolObjPtr obj = NULL;
xmlDocPtr xml = NULL;
virObjectRWLockRead(pools); xmlXPathContextPtr ctxt = NULL;
virHashForEach(pools->objs, virStoragePoolObjGetNamesCb, &data); xmlNodePtr node = NULL;
virObjectRWUnlock(pools);
if (data.error)
goto error;
return data.nnames;
error: if (!(stateFile = virFileBuildPath(stateDir, name, ".xml")))
while (data.nnames) goto error;
VIR_FREE(data.names[--data.nnames]);
return -1;
}
if (!(xml = virXMLParseCtxt(stateFile, NULL, _("(pool state)"), &ctxt)))
goto error;
static int if (!(node = virXPathNode("//pool", ctxt))) {
getSCSIHostNumber(virStorageAdapterSCSIHostPtr scsi_host, virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
unsigned int *hostnum) _("Could not find any 'pool' element in state file"));
{ goto error;
int ret = -1; }
unsigned int num;
char *name = NULL;
if (scsi_host->has_parent) { ctxt->node = node;
virPCIDeviceAddressPtr addr = &scsi_host->parentaddr; if (!(def = virStoragePoolDefParseXML(ctxt)))
unsigned int unique_id = scsi_host->unique_id; goto error;
if (!(name = virSCSIHostGetNameByParentaddr(addr->domain, if (STRNEQ(name, def->name)) {
addr->bus, virReportError(VIR_ERR_INTERNAL_ERROR,
addr->slot, _("Storage pool state file '%s' does not match "
addr->function, "pool name '%s'"),
unique_id))) stateFile, def->name);
goto cleanup; goto error;
if (virSCSIHostGetNumber(name, &num) < 0)
goto cleanup;
} else {
if (virSCSIHostGetNumber(scsi_host->name, &num) < 0)
goto cleanup;
} }
*hostnum = num; /* create the object */
ret = 0; if (!(obj = virStoragePoolObjAssignDef(pools, def, true)))
goto error;
cleanup:
VIR_FREE(name);
return ret;
}
/* 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 obj->active = true;
virStorageIsSameHostnum(const char *name,
unsigned int scsi_hostnum)
{
unsigned int fc_hostnum;
if (virSCSIHostGetNumber(name, &fc_hostnum) == 0 && cleanup:
scsi_hostnum == fc_hostnum) VIR_FREE(stateFile);
return true; xmlFreeDoc(xml);
xmlXPathFreeContext(ctxt);
return obj;
return false; error:
virStoragePoolDefFree(def);
goto cleanup;
} }
/* int
* matchFCHostToSCSIHost: virStoragePoolObjLoadAllState(virStoragePoolObjListPtr pools,
* const char *stateDir)
* @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)
{ {
bool ret = false; DIR *dir;
char *name = NULL; struct dirent *entry;
char *scsi_host_name = NULL; int ret = -1;
char *parent_name = NULL; int rc;
/* If we have a parent defined, get its hostnum, and compare to the if ((rc = virDirOpenIfExists(&dir, stateDir)) <= 0)
* scsi_hostnum. If they are the same, then we have a match return rc;
*/
if (fchost->parent &&
virStorageIsSameHostnum(fchost->parent, scsi_hostnum))
return true;
/* If we find an fc adapter name, then either libvirt created a vHBA while ((ret = virDirRead(dir, &entry, stateDir)) > 0) {
* for this fc_host or a 'virsh nodedev-create' generated a vHBA. virStoragePoolObjPtr obj;
*/
if ((name = virVHBAGetHostByWWN(NULL, fchost->wwnn, fchost->wwpn))) {
/* Get the scsi_hostN for the vHBA in order to see if it if (!virFileStripSuffix(entry->d_name, ".xml"))
* matches our scsi_hostnum continue;
*/
if (virStorageIsSameHostnum(name, scsi_hostnum)) {
ret = true;
goto cleanup;
}
/* We weren't provided a parent, so we have to query the node if (!(obj = virStoragePoolObjLoadState(pools, stateDir, entry->d_name)))
* device driver in order to ascertain the parent of the vHBA. continue;
* If the parent fc_hostnum is the same as the scsi_hostnum, we virStoragePoolObjEndAPI(&obj);
* 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");
}
}
} }
/* NB: Lack of a name means that this vHBA hasn't yet been created, VIR_DIR_CLOSE(dir);
* 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);
return ret; return ret;
} }
static bool int
matchSCSIAdapterParent(virStorageAdapterSCSIHostPtr pool_scsi_host, virStoragePoolObjLoadAllConfigs(virStoragePoolObjListPtr pools,
virStorageAdapterSCSIHostPtr def_scsi_host) const char *configDir,
const char *autostartDir)
{ {
virPCIDeviceAddressPtr pooladdr = &pool_scsi_host->parentaddr; DIR *dir;
virPCIDeviceAddressPtr defaddr = &def_scsi_host->parentaddr; struct dirent *entry;
int ret;
if (pooladdr->domain == defaddr->domain && int rc;
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;
}
if ((rc = virDirOpenIfExists(&dir, configDir)) <= 0)
return rc;
static bool while ((ret = virDirRead(dir, &entry, configDir)) > 0) {
virStoragePoolSourceMatchSingleHost(virStoragePoolSourcePtr poolsrc, char *path;
virStoragePoolSourcePtr defsrc) char *autostartLink;
{ virStoragePoolObjPtr obj;
if (poolsrc->nhost != 1 && defsrc->nhost != 1)
return false;
if (defsrc->hosts[0].port && if (!virFileHasSuffix(entry->d_name, ".xml"))
poolsrc->hosts[0].port != defsrc->hosts[0].port) continue;
return false;
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 obj = virStoragePoolObjLoad(pools, entry->d_name, path, autostartLink);
virStoragePoolSourceISCSIMatch(virStoragePoolObjPtr obj, virStoragePoolObjEndAPI(&obj);
virStoragePoolDefPtr def)
{
virStoragePoolSourcePtr poolsrc = &obj->def->source;
virStoragePoolSourcePtr defsrc = &def->source;
/* NB: Do not check the source host name */ VIR_FREE(path);
if (STRNEQ_NULLABLE(poolsrc->initiator.iqn, defsrc->initiator.iqn)) VIR_FREE(autostartLink);
return false; }
return true; VIR_DIR_CLOSE(dir);
return ret;
} }
static virStoragePoolObjPtr int
virStoragePoolObjSourceMatchTypeDIR(virStoragePoolObjPtr obj, virStoragePoolObjSaveDef(virStorageDriverStatePtr driver,
virStoragePoolDefPtr def) virStoragePoolObjPtr obj,
virStoragePoolDefPtr def)
{ {
if (obj->def->type == VIR_STORAGE_POOL_DIR) { if (!obj->configFile) {
if (STREQ(obj->def->target.path, def->target.path)) if (virFileMakePath(driver->configDir) < 0) {
return obj; virReportSystemError(errno,
} else if (obj->def->type == VIR_STORAGE_POOL_GLUSTER) { _("cannot create config directory %s"),
if (STREQ(obj->def->source.name, def->source.name) && driver->configDir);
STREQ_NULLABLE(obj->def->source.dir, def->source.dir) && return -1;
virStoragePoolSourceMatchSingleHost(&obj->def->source, }
&def->source))
return obj; if (!(obj->configFile = virFileBuildPath(driver->configDir,
} else if (obj->def->type == VIR_STORAGE_POOL_NETFS) { def->name, ".xml"))) {
if (STREQ(obj->def->source.dir, def->source.dir) && return -1;
virStoragePoolSourceMatchSingleHost(&obj->def->source, }
&def->source))
return obj; if (!(obj->autostartLink = virFileBuildPath(driver->autostartDir,
def->name, ".xml"))) {
VIR_FREE(obj->configFile);
return -1;
}
} }
return NULL; return virStoragePoolSaveConfig(obj->configFile, def);
} }
static virStoragePoolObjPtr int
virStoragePoolObjSourceMatchTypeISCSI(virStoragePoolObjPtr obj, virStoragePoolObjDeleteDef(virStoragePoolObjPtr obj)
virStoragePoolDefPtr def,
virConnectPtr conn)
{ {
virStorageAdapterPtr pool_adapter = &obj->def->source.adapter; if (!obj->configFile) {
virStorageAdapterPtr def_adapter = &def->source.adapter; virReportError(VIR_ERR_INTERNAL_ERROR,
virStorageAdapterSCSIHostPtr pool_scsi_host; _("no config file for %s"), obj->def->name);
virStorageAdapterSCSIHostPtr def_scsi_host; return -1;
virStorageAdapterFCHostPtr pool_fchost; }
virStorageAdapterFCHostPtr def_fchost;
unsigned int pool_hostnum;
unsigned int def_hostnum;
unsigned int scsi_hostnum;
if (pool_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST && if (unlink(obj->configFile) < 0) {
def_adapter->type == VIR_STORAGE_ADAPTER_TYPE_FC_HOST) { virReportError(VIR_ERR_INTERNAL_ERROR,
pool_fchost = &pool_adapter->data.fchost; _("cannot remove config for %s"),
def_fchost = &def_adapter->data.fchost; obj->def->name);
return -1;
}
if (STREQ(pool_fchost->wwnn, def_fchost->wwnn) && return 0;
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 || struct _virStoragePoolCountData {
getSCSIHostNumber(def_scsi_host, &def_hostnum) < 0) virConnectPtr conn;
return NULL; virStoragePoolObjListACLFilter filter;
if (pool_hostnum == def_hostnum) bool wantActive;
return obj; int count;
} 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)) static int
return obj; 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 && virObjectLock(obj);
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) if (data->filter && !data->filter(data->conn, obj->def))
return NULL; goto cleanup;
if (matchFCHostToSCSIHost(conn, def_fchost, scsi_hostnum)) if (data->wantActive != virStoragePoolObjIsActive(obj))
return obj; goto cleanup;
}
return NULL; data->count++;
cleanup:
virObjectUnlock(obj);
return 0;
} }
static virStoragePoolObjPtr int
virStoragePoolObjSourceMatchTypeDEVICE(virStoragePoolObjPtr obj, virStoragePoolObjNumOfStoragePools(virStoragePoolObjListPtr pools,
virStoragePoolDefPtr def) virConnectPtr conn,
bool wantActive,
virStoragePoolObjListACLFilter filter)
{ {
virStoragePoolObjPtr matchobj = NULL; struct _virStoragePoolCountData data = {
.conn = conn, .filter = filter, .wantActive = wantActive, .count = 0 };
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;
}
if (def->type == VIR_STORAGE_POOL_ISCSI) virObjectRWLockRead(pools);
return NULL; virHashForEach(pools->objs, virStoragePoolObjNumOfStoragePoolsCb, &data);
virObjectRWUnlock(pools);
/* VIR_STORAGE_POOL_FS return data.count;
* VIR_STORAGE_POOL_LOGICAL
* VIR_STORAGE_POOL_DISK
* VIR_STORAGE_POOL_ZFS */
return virStoragePoolSourceFindDuplicateDevices(obj, def);
} }
struct _virStoragePoolObjFindDuplicateData { struct _virStoragePoolNameData {
virConnectPtr conn; virConnectPtr conn;
virStoragePoolDefPtr def; virStoragePoolObjListACLFilter filter;
bool wantActive;
bool error;
int nnames;
int maxnames;
char **const names;
}; };
static int static int
virStoragePoolObjSourceFindDuplicateCb(const void *payload, virStoragePoolObjGetNamesCb(void *payload,
const void *name ATTRIBUTE_UNUSED, const void *name ATTRIBUTE_UNUSED,
const void *opaque) void *opaque)
{ {
virStoragePoolObjPtr obj = (virStoragePoolObjPtr) payload; virStoragePoolObjPtr obj = payload;
struct _virStoragePoolObjFindDuplicateData *data = struct _virStoragePoolNameData *data = opaque;
(struct _virStoragePoolObjFindDuplicateData *) opaque;
/* Don't match against ourself if re-defining existing pool ! */ if (data->error)
if (STREQ(obj->def->name, data->def->name))
return 0; return 0;
switch ((virStoragePoolType)obj->def->type) { if (data->maxnames >= 0 && data->nnames == data->maxnames)
case VIR_STORAGE_POOL_DIR: return 0;
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: virObjectLock(obj);
if (data->def->type == obj->def->type &&
virStoragePoolSourceMatchSingleHost(&obj->def->source,
&data->def->source))
return 1;
break;
case VIR_STORAGE_POOL_MPATH: if (data->filter && !data->filter(data->conn, obj->def))
/* Only one mpath pool is valid per host */ goto cleanup;
if (data->def->type == obj->def->type)
return 1;
break;
case VIR_STORAGE_POOL_VSTORAGE: if (data->wantActive != virStoragePoolObjIsActive(obj))
if (data->def->type == obj->def->type && goto cleanup;
STREQ(obj->def->source.name, data->def->source.name))
return 1;
break;
case VIR_STORAGE_POOL_RBD: if (data->names) {
case VIR_STORAGE_POOL_LAST: if (VIR_STRDUP(data->names[data->nnames], obj->def->name) < 0) {
break; data->error = true;
goto cleanup;
}
} }
data->nnames++;
cleanup:
virObjectUnlock(obj);
return 0; return 0;
} }
int int
virStoragePoolObjSourceFindDuplicate(virConnectPtr conn, virStoragePoolObjGetNames(virStoragePoolObjListPtr pools,
virStoragePoolObjListPtr pools, virConnectPtr conn,
virStoragePoolDefPtr def) bool wantActive,
virStoragePoolObjListACLFilter filter,
char **const names,
int maxnames)
{ {
struct _virStoragePoolObjFindDuplicateData data = { .conn = conn, struct _virStoragePoolNameData data = {
.def = def }; .conn = conn, .filter = filter, .wantActive = wantActive,
virStoragePoolObjPtr obj = NULL; .error = false, .nnames = 0, .maxnames = maxnames, .names = names };
virObjectRWLockRead(pools); virObjectRWLockRead(pools);
obj = virHashSearch(pools->objs, virStoragePoolObjSourceFindDuplicateCb, virHashForEach(pools->objs, virStoragePoolObjGetNamesCb, &data);
&data, NULL);
virObjectRWUnlock(pools); virObjectRWUnlock(pools);
if (obj) { if (data.error)
virReportError(VIR_ERR_OPERATION_FAILED, goto error;
_("Storage source conflict with pool: '%s'"),
obj->def->name);
return -1;
}
return 0; return data.nnames;
error:
while (data.nnames)
VIR_FREE(data.names[--data.nnames]);
return -1;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册