mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-10-30 09:53:10 +00:00
be1bb6c95b
Alter the volume logic to use the hash tables instead of forward linked lists. There are three hash tables to allow for fast lookup by name, target.path, and key. Modify the virStoragePoolObjAddVol to place the object in all 3 tables if possible using self locking RWLock on the volumes object. Conversely when removing the volume, it's a removal of the object from the various hash tables. Implement functions to handle remote ForEach and Search Volume type helpers. These are used by the disk backend in order to facilitate adding a primary, extended, or logical partition. Implement the various VolDefFindBy* helpers as simple (and fast) hash lookups. The NumOfVolumes, GetNames, and ListExport helpers are all implemented using standard for each hash table calls.
2064 lines
55 KiB
C
2064 lines
55 KiB
C
/*
|
|
* virstorageobj.c: internal storage pool and volume objects handling
|
|
* (derived from storage_conf.c)
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <config.h>
|
|
#include <dirent.h>
|
|
|
|
#include "datatypes.h"
|
|
#include "node_device_conf.h"
|
|
#include "virstorageobj.h"
|
|
|
|
#include "viralloc.h"
|
|
#include "virerror.h"
|
|
#include "virfile.h"
|
|
#include "virhash.h"
|
|
#include "virlog.h"
|
|
#include "virscsihost.h"
|
|
#include "virstring.h"
|
|
#include "virvhba.h"
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_STORAGE
|
|
|
|
VIR_LOG_INIT("conf.virstorageobj");
|
|
|
|
static virClassPtr virStoragePoolObjClass;
|
|
static virClassPtr virStoragePoolObjListClass;
|
|
static virClassPtr virStorageVolObjClass;
|
|
static virClassPtr virStorageVolObjListClass;
|
|
|
|
static void
|
|
virStoragePoolObjDispose(void *opaque);
|
|
static void
|
|
virStoragePoolObjListDispose(void *opaque);
|
|
static void
|
|
virStorageVolObjDispose(void *opaque);
|
|
static void
|
|
virStorageVolObjListDispose(void *opaque);
|
|
|
|
|
|
|
|
typedef struct _virStorageVolObj virStorageVolObj;
|
|
typedef virStorageVolObj *virStorageVolObjPtr;
|
|
struct _virStorageVolObj {
|
|
virObjectLockable parent;
|
|
|
|
virStorageVolDefPtr voldef;
|
|
};
|
|
|
|
typedef struct _virStorageVolObjList virStorageVolObjList;
|
|
typedef virStorageVolObjList *virStorageVolObjListPtr;
|
|
struct _virStorageVolObjList {
|
|
virObjectRWLockable parent;
|
|
|
|
/* key string -> virStorageVolObj mapping
|
|
* for (1), lockless lookup-by-key */
|
|
virHashTable *objsKey;
|
|
|
|
/* name string -> virStorageVolObj mapping
|
|
* for (1), lockless lookup-by-name */
|
|
virHashTable *objsName;
|
|
|
|
/* path string -> virStorageVolObj mapping
|
|
* for (1), lockless lookup-by-path */
|
|
virHashTable *objsPath;
|
|
};
|
|
|
|
struct _virStoragePoolObj {
|
|
virObjectLockable parent;
|
|
|
|
char *configFile;
|
|
char *autostartLink;
|
|
bool active;
|
|
bool autostart;
|
|
unsigned int asyncjobs;
|
|
|
|
virStoragePoolDefPtr def;
|
|
virStoragePoolDefPtr newDef;
|
|
|
|
virStorageVolObjListPtr volumes;
|
|
};
|
|
|
|
struct _virStoragePoolObjList {
|
|
virObjectRWLockable parent;
|
|
|
|
/* uuid string -> virStoragePoolObj mapping
|
|
* for (1), lockless lookup-by-uuid */
|
|
virHashTable *objs;
|
|
|
|
/* name string -> virStoragePoolObj mapping
|
|
* for (1), lockless lookup-by-name */
|
|
virHashTable *objsName;
|
|
};
|
|
|
|
|
|
static int
|
|
virStorageVolObjOnceInit(void)
|
|
{
|
|
if (!(virStorageVolObjClass = virClassNew(virClassForObjectLockable(),
|
|
"virStorageVolObj",
|
|
sizeof(virStorageVolObj),
|
|
virStorageVolObjDispose)))
|
|
return -1;
|
|
|
|
if (!(virStorageVolObjListClass = virClassNew(virClassForObjectRWLockable(),
|
|
"virStorageVolObjList",
|
|
sizeof(virStorageVolObjList),
|
|
virStorageVolObjListDispose)))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
VIR_ONCE_GLOBAL_INIT(virStorageVolObj)
|
|
|
|
|
|
static virStorageVolObjPtr
|
|
virStorageVolObjNew(void)
|
|
{
|
|
virStorageVolObjPtr obj;
|
|
|
|
if (virStorageVolObjInitialize() < 0)
|
|
return NULL;
|
|
|
|
if (!(obj = virObjectLockableNew(virStorageVolObjClass)))
|
|
return NULL;
|
|
|
|
virObjectLock(obj);
|
|
return obj;
|
|
}
|
|
|
|
|
|
static void
|
|
virStorageVolObjEndAPI(virStorageVolObjPtr *obj)
|
|
{
|
|
if (!*obj)
|
|
return;
|
|
|
|
virObjectUnlock(*obj);
|
|
virObjectUnref(*obj);
|
|
*obj = NULL;
|
|
}
|
|
|
|
|
|
static void
|
|
virStorageVolObjDispose(void *opaque)
|
|
{
|
|
virStorageVolObjPtr obj = opaque;
|
|
|
|
if (!obj)
|
|
return;
|
|
|
|
virStorageVolDefFree(obj->voldef);
|
|
}
|
|
|
|
|
|
static virStorageVolObjListPtr
|
|
virStorageVolObjListNew(void)
|
|
{
|
|
virStorageVolObjListPtr vols;
|
|
|
|
if (virStorageVolObjInitialize() < 0)
|
|
return NULL;
|
|
|
|
if (!(vols = virObjectRWLockableNew(virStorageVolObjListClass)))
|
|
return NULL;
|
|
|
|
if (!(vols->objsKey = virHashCreate(10, virObjectFreeHashData)) ||
|
|
!(vols->objsName = virHashCreate(10, virObjectFreeHashData)) ||
|
|
!(vols->objsPath = virHashCreate(10, virObjectFreeHashData))) {
|
|
virObjectUnref(vols);
|
|
return NULL;
|
|
}
|
|
|
|
return vols;
|
|
}
|
|
|
|
|
|
static void
|
|
virStorageVolObjListDispose(void *opaque)
|
|
{
|
|
virStorageVolObjListPtr vols = opaque;
|
|
|
|
if (!vols)
|
|
return;
|
|
|
|
virHashFree(vols->objsKey);
|
|
virHashFree(vols->objsName);
|
|
virHashFree(vols->objsPath);
|
|
}
|
|
|
|
|
|
static int
|
|
virStoragePoolObjOnceInit(void)
|
|
{
|
|
if (!(virStoragePoolObjClass = virClassNew(virClassForObjectLockable(),
|
|
"virStoragePoolObj",
|
|
sizeof(virStoragePoolObj),
|
|
virStoragePoolObjDispose)))
|
|
return -1;
|
|
|
|
if (!(virStoragePoolObjListClass = virClassNew(virClassForObjectRWLockable(),
|
|
"virStoragePoolObjList",
|
|
sizeof(virStoragePoolObjList),
|
|
virStoragePoolObjListDispose)))
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
VIR_ONCE_GLOBAL_INIT(virStoragePoolObj)
|
|
|
|
|
|
virStoragePoolObjPtr
|
|
virStoragePoolObjNew(void)
|
|
{
|
|
virStoragePoolObjPtr obj;
|
|
|
|
if (virStoragePoolObjInitialize() < 0)
|
|
return NULL;
|
|
|
|
if (!(obj = virObjectLockableNew(virStoragePoolObjClass)))
|
|
return NULL;
|
|
|
|
if (!(obj->volumes = virStorageVolObjListNew())) {
|
|
virObjectUnref(obj);
|
|
return NULL;
|
|
}
|
|
|
|
virObjectLock(obj);
|
|
obj->active = false;
|
|
return obj;
|
|
}
|
|
|
|
|
|
void
|
|
virStoragePoolObjEndAPI(virStoragePoolObjPtr *obj)
|
|
{
|
|
if (!*obj)
|
|
return;
|
|
|
|
virObjectUnlock(*obj);
|
|
virObjectUnref(*obj);
|
|
*obj = NULL;
|
|
}
|
|
|
|
|
|
virStoragePoolDefPtr
|
|
virStoragePoolObjGetDef(virStoragePoolObjPtr obj)
|
|
{
|
|
return obj->def;
|
|
}
|
|
|
|
|
|
void
|
|
virStoragePoolObjSetDef(virStoragePoolObjPtr obj,
|
|
virStoragePoolDefPtr def)
|
|
{
|
|
virStoragePoolDefFree(obj->def);
|
|
obj->def = def;
|
|
}
|
|
|
|
|
|
virStoragePoolDefPtr
|
|
virStoragePoolObjGetNewDef(virStoragePoolObjPtr obj)
|
|
{
|
|
return obj->newDef;
|
|
}
|
|
|
|
|
|
void
|
|
virStoragePoolObjDefUseNewDef(virStoragePoolObjPtr obj)
|
|
{
|
|
virStoragePoolDefFree(obj->def);
|
|
obj->def = obj->newDef;
|
|
obj->newDef = NULL;
|
|
}
|
|
|
|
|
|
const char *
|
|
virStoragePoolObjGetConfigFile(virStoragePoolObjPtr obj)
|
|
{
|
|
return obj->configFile;
|
|
}
|
|
|
|
|
|
void
|
|
virStoragePoolObjSetConfigFile(virStoragePoolObjPtr obj,
|
|
char *configFile)
|
|
{
|
|
VIR_FREE(obj->configFile);
|
|
obj->configFile = configFile;
|
|
}
|
|
|
|
|
|
const char *
|
|
virStoragePoolObjGetAutostartLink(virStoragePoolObjPtr obj)
|
|
{
|
|
return obj->autostartLink;
|
|
}
|
|
|
|
|
|
bool
|
|
virStoragePoolObjIsActive(virStoragePoolObjPtr obj)
|
|
{
|
|
return obj->active;
|
|
}
|
|
|
|
|
|
void
|
|
virStoragePoolObjSetActive(virStoragePoolObjPtr obj,
|
|
bool active)
|
|
{
|
|
obj->active = active;
|
|
}
|
|
|
|
|
|
bool
|
|
virStoragePoolObjIsAutostart(virStoragePoolObjPtr obj)
|
|
{
|
|
if (!obj->configFile)
|
|
return 0;
|
|
|
|
return obj->autostart;
|
|
}
|
|
|
|
|
|
void
|
|
virStoragePoolObjSetAutostart(virStoragePoolObjPtr obj,
|
|
bool autostart)
|
|
{
|
|
obj->autostart = autostart;
|
|
}
|
|
|
|
|
|
unsigned int
|
|
virStoragePoolObjGetAsyncjobs(virStoragePoolObjPtr obj)
|
|
{
|
|
return obj->asyncjobs;
|
|
}
|
|
|
|
|
|
void
|
|
virStoragePoolObjIncrAsyncjobs(virStoragePoolObjPtr obj)
|
|
{
|
|
obj->asyncjobs++;
|
|
}
|
|
|
|
|
|
void
|
|
virStoragePoolObjDecrAsyncjobs(virStoragePoolObjPtr obj)
|
|
{
|
|
obj->asyncjobs--;
|
|
}
|
|
|
|
|
|
void
|
|
virStoragePoolObjDispose(void *opaque)
|
|
{
|
|
virStoragePoolObjPtr obj = opaque;
|
|
|
|
if (!obj)
|
|
return;
|
|
|
|
virStoragePoolObjClearVols(obj);
|
|
virObjectUnref(obj->volumes);
|
|
|
|
virStoragePoolDefFree(obj->def);
|
|
virStoragePoolDefFree(obj->newDef);
|
|
|
|
VIR_FREE(obj->configFile);
|
|
VIR_FREE(obj->autostartLink);
|
|
}
|
|
|
|
|
|
void
|
|
virStoragePoolObjListDispose(void *opaque)
|
|
{
|
|
virStoragePoolObjListPtr pools = opaque;
|
|
|
|
virHashFree(pools->objs);
|
|
virHashFree(pools->objsName);
|
|
}
|
|
|
|
|
|
virStoragePoolObjListPtr
|
|
virStoragePoolObjListNew(void)
|
|
{
|
|
virStoragePoolObjListPtr pools;
|
|
|
|
if (virStoragePoolObjInitialize() < 0)
|
|
return NULL;
|
|
|
|
if (!(pools = virObjectRWLockableNew(virStoragePoolObjListClass)))
|
|
return NULL;
|
|
|
|
if (!(pools->objs = virHashCreate(20, virObjectFreeHashData)) ||
|
|
!(pools->objsName = virHashCreate(20, virObjectFreeHashData))) {
|
|
virObjectUnref(pools);
|
|
return NULL;
|
|
}
|
|
|
|
return pools;
|
|
}
|
|
|
|
|
|
struct _virStoragePoolObjListForEachData {
|
|
virStoragePoolObjListIterator iter;
|
|
const void *opaque;
|
|
};
|
|
|
|
static int
|
|
virStoragePoolObjListForEachCb(void *payload,
|
|
const void *name ATTRIBUTE_UNUSED,
|
|
void *opaque)
|
|
{
|
|
virStoragePoolObjPtr obj = payload;
|
|
struct _virStoragePoolObjListForEachData *data = opaque;
|
|
|
|
virObjectLock(obj);
|
|
data->iter(obj, data->opaque);
|
|
virObjectUnlock(obj);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* virStoragePoolObjListForEach
|
|
* @pools: Pointer to pools object
|
|
* @iter: Callback iteration helper
|
|
* @opaque: Opaque data to use as argument to helper
|
|
*
|
|
* For each object in @pools, call the @iter helper using @opaque as
|
|
* an argument. This function doesn't care whether the @iter fails or
|
|
* not as it's being used for Autostart and UpdateAllState callers
|
|
* that want to iterate over all the @pools objects not stopping if
|
|
* one happens to fail.
|
|
*/
|
|
void
|
|
virStoragePoolObjListForEach(virStoragePoolObjListPtr pools,
|
|
virStoragePoolObjListIterator iter,
|
|
const void *opaque)
|
|
{
|
|
struct _virStoragePoolObjListForEachData data = { .iter = iter,
|
|
.opaque = opaque };
|
|
|
|
virObjectRWLockRead(pools);
|
|
virHashForEach(pools->objs, virStoragePoolObjListForEachCb, &data);
|
|
virObjectRWUnlock(pools);
|
|
}
|
|
|
|
|
|
struct _virStoragePoolObjListSearchData {
|
|
virStoragePoolObjListSearcher searcher;
|
|
const void *opaque;
|
|
};
|
|
|
|
|
|
static int
|
|
virStoragePoolObjListSearchCb(const void *payload,
|
|
const void *name ATTRIBUTE_UNUSED,
|
|
const void *opaque)
|
|
{
|
|
virStoragePoolObjPtr obj = (virStoragePoolObjPtr) payload;
|
|
struct _virStoragePoolObjListSearchData *data =
|
|
(struct _virStoragePoolObjListSearchData *)opaque;
|
|
|
|
virObjectLock(obj);
|
|
if (data->searcher(obj, data->opaque))
|
|
return 1;
|
|
virObjectUnlock(obj);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* virStoragePoolObjListSearch
|
|
* @pools: Pointer to pools object
|
|
* @search: Callback searcher helper
|
|
* @opaque: Opaque data to use as argument to helper
|
|
*
|
|
* Search through the @pools objects calling the @search helper using
|
|
* the @opaque data in order to find an object that matches some criteria
|
|
* and return that object locked.
|
|
*
|
|
* Returns a locked and reffed object when found and NULL when not found
|
|
*/
|
|
virStoragePoolObjPtr
|
|
virStoragePoolObjListSearch(virStoragePoolObjListPtr pools,
|
|
virStoragePoolObjListSearcher searcher,
|
|
const void *opaque)
|
|
{
|
|
virStoragePoolObjPtr obj = NULL;
|
|
struct _virStoragePoolObjListSearchData data = { .searcher = searcher,
|
|
.opaque = opaque };
|
|
|
|
virObjectRWLockRead(pools);
|
|
obj = virHashSearch(pools->objs, virStoragePoolObjListSearchCb, &data, NULL);
|
|
virObjectRWUnlock(pools);
|
|
|
|
return virObjectRef(obj);
|
|
}
|
|
|
|
|
|
void
|
|
virStoragePoolObjRemove(virStoragePoolObjListPtr pools,
|
|
virStoragePoolObjPtr obj)
|
|
{
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virUUIDFormat(obj->def->uuid, uuidstr);
|
|
virObjectRef(obj);
|
|
virObjectUnlock(obj);
|
|
virObjectRWLockWrite(pools);
|
|
virObjectLock(obj);
|
|
virHashRemoveEntry(pools->objs, uuidstr);
|
|
virHashRemoveEntry(pools->objsName, obj->def->name);
|
|
virObjectUnlock(obj);
|
|
virObjectUnref(obj);
|
|
virObjectRWUnlock(pools);
|
|
}
|
|
|
|
|
|
static virStoragePoolObjPtr
|
|
virStoragePoolObjFindByUUIDLocked(virStoragePoolObjListPtr pools,
|
|
const unsigned char *uuid)
|
|
{
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virUUIDFormat(uuid, uuidstr);
|
|
|
|
return virObjectRef(virHashLookup(pools->objs, uuidstr));
|
|
}
|
|
|
|
|
|
/**
|
|
* virStoragePoolObjFindByUUID
|
|
* @pools: Storage pool object list pointer
|
|
* @uuid: Storage object uuid to find
|
|
*
|
|
* Lock the @pools and lookup the object by @uuid
|
|
*
|
|
* Returns: Locked and reffed storage pool object or NULL if not found
|
|
*/
|
|
virStoragePoolObjPtr
|
|
virStoragePoolObjFindByUUID(virStoragePoolObjListPtr pools,
|
|
const unsigned char *uuid)
|
|
{
|
|
virStoragePoolObjPtr obj;
|
|
|
|
virObjectRWLockRead(pools);
|
|
obj = virStoragePoolObjFindByUUIDLocked(pools, uuid);
|
|
virObjectRWUnlock(pools);
|
|
if (obj)
|
|
virObjectLock(obj);
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
static virStoragePoolObjPtr
|
|
virStoragePoolObjFindByNameLocked(virStoragePoolObjListPtr pools,
|
|
const char *name)
|
|
{
|
|
return virObjectRef(virHashLookup(pools->objsName, name));
|
|
}
|
|
|
|
|
|
/**
|
|
* virStoragePoolObjFindByName
|
|
* @pools: Storage pool object list pointer
|
|
* @name: Storage object name to find
|
|
*
|
|
* Lock the @pools and lookup the object by @name
|
|
*
|
|
* Returns: Locked and reffed storage pool object or NULL if not found
|
|
*/
|
|
virStoragePoolObjPtr
|
|
virStoragePoolObjFindByName(virStoragePoolObjListPtr pools,
|
|
const char *name)
|
|
{
|
|
virStoragePoolObjPtr obj;
|
|
|
|
virObjectRWLockRead(pools);
|
|
obj = virStoragePoolObjFindByNameLocked(pools, name);
|
|
virObjectRWUnlock(pools);
|
|
if (obj)
|
|
virObjectLock(obj);
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
static virStoragePoolObjPtr
|
|
virStoragePoolSourceFindDuplicateDevices(virStoragePoolObjPtr obj,
|
|
virStoragePoolDefPtr def)
|
|
{
|
|
size_t i, j;
|
|
|
|
for (i = 0; i < obj->def->source.ndevice; i++) {
|
|
for (j = 0; j < def->source.ndevice; j++) {
|
|
if (STREQ(obj->def->source.devices[i].path, def->source.devices[j].path))
|
|
return obj;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void
|
|
virStoragePoolObjClearVols(virStoragePoolObjPtr obj)
|
|
{
|
|
virHashRemoveAll(obj->volumes->objsKey);
|
|
virHashRemoveAll(obj->volumes->objsName);
|
|
virHashRemoveAll(obj->volumes->objsPath);
|
|
}
|
|
|
|
|
|
int
|
|
virStoragePoolObjAddVol(virStoragePoolObjPtr obj,
|
|
virStorageVolDefPtr voldef)
|
|
{
|
|
virStorageVolObjPtr volobj = NULL;
|
|
virStorageVolObjListPtr volumes = obj->volumes;
|
|
|
|
virObjectRWLockWrite(volumes);
|
|
|
|
if (!(volobj = virStorageVolObjNew()))
|
|
goto error;
|
|
|
|
if (virHashAddEntry(volumes->objsKey, voldef->key, volobj) < 0)
|
|
goto error;
|
|
virObjectRef(volobj);
|
|
|
|
if (virHashAddEntry(volumes->objsName, voldef->name, volobj) < 0) {
|
|
virHashRemoveEntry(volumes->objsKey, voldef->key);
|
|
goto error;
|
|
}
|
|
virObjectRef(volobj);
|
|
|
|
if (virHashAddEntry(volumes->objsPath, voldef->target.path, volobj) < 0) {
|
|
virHashRemoveEntry(volumes->objsKey, voldef->key);
|
|
virHashRemoveEntry(volumes->objsName, voldef->name);
|
|
goto error;
|
|
}
|
|
virObjectRef(volobj);
|
|
|
|
volobj->voldef = voldef;
|
|
virObjectRWUnlock(volumes);
|
|
virStorageVolObjEndAPI(&volobj);
|
|
return 0;
|
|
|
|
error:
|
|
virStorageVolObjEndAPI(&volobj);
|
|
virObjectRWUnlock(volumes);
|
|
return -1;
|
|
}
|
|
|
|
|
|
void
|
|
virStoragePoolObjRemoveVol(virStoragePoolObjPtr obj,
|
|
virStorageVolDefPtr voldef)
|
|
{
|
|
virStorageVolObjListPtr volumes = obj->volumes;
|
|
virStorageVolObjPtr volobj;
|
|
|
|
virObjectRWLockWrite(volumes);
|
|
volobj = virHashLookup(volumes->objsName, voldef->name);
|
|
if (!volobj) {
|
|
VIR_INFO("Cannot find volume '%s' from storage pool '%s'",
|
|
voldef->name, obj->def->name);
|
|
virObjectRWUnlock(volumes);
|
|
return;
|
|
}
|
|
VIR_INFO("Deleting volume '%s' from storage pool '%s'",
|
|
voldef->name, obj->def->name);
|
|
|
|
virObjectRef(volobj);
|
|
virObjectLock(volobj);
|
|
virHashRemoveEntry(volumes->objsKey, voldef->key);
|
|
virHashRemoveEntry(volumes->objsName, voldef->name);
|
|
virHashRemoveEntry(volumes->objsPath, voldef->target.path);
|
|
virStorageVolObjEndAPI(&volobj);
|
|
|
|
virObjectRWUnlock(volumes);
|
|
}
|
|
|
|
|
|
size_t
|
|
virStoragePoolObjGetVolumesCount(virStoragePoolObjPtr obj)
|
|
{
|
|
size_t nbElems;
|
|
|
|
virObjectRWLockRead(obj->volumes);
|
|
nbElems = virHashSize(obj->volumes->objsKey);
|
|
virObjectRWUnlock(obj->volumes);
|
|
|
|
return nbElems;
|
|
}
|
|
|
|
|
|
struct _virStoragePoolObjForEachVolData {
|
|
virStorageVolObjListIterator iter;
|
|
const void *opaque;
|
|
};
|
|
|
|
static int
|
|
virStoragePoolObjForEachVolumeCb(void *payload,
|
|
const void *name ATTRIBUTE_UNUSED,
|
|
void *opaque)
|
|
{
|
|
int ret = 0;
|
|
virStorageVolObjPtr volobj = payload;
|
|
struct _virStoragePoolObjForEachVolData *data = opaque;
|
|
|
|
virObjectLock(volobj);
|
|
if (data->iter(volobj->voldef, data->opaque) < 0)
|
|
ret = -1;
|
|
virObjectUnlock(volobj);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int
|
|
virStoragePoolObjForEachVolume(virStoragePoolObjPtr obj,
|
|
virStorageVolObjListIterator iter,
|
|
const void *opaque)
|
|
{
|
|
struct _virStoragePoolObjForEachVolData data = {
|
|
.iter = iter, .opaque = opaque };
|
|
|
|
virObjectRWLockRead(obj->volumes);
|
|
virHashForEach(obj->volumes->objsKey, virStoragePoolObjForEachVolumeCb,
|
|
&data);
|
|
virObjectRWUnlock(obj->volumes);
|
|
return 0;
|
|
}
|
|
|
|
|
|
struct _virStoragePoolObjSearchVolData {
|
|
virStorageVolObjListSearcher iter;
|
|
const void *opaque;
|
|
};
|
|
|
|
static int
|
|
virStoragePoolObjSearchVolumeCb(const void *payload,
|
|
const void *name ATTRIBUTE_UNUSED,
|
|
const void *opaque)
|
|
{
|
|
virStorageVolObjPtr volobj = (virStorageVolObjPtr) payload;
|
|
struct _virStoragePoolObjSearchVolData *data =
|
|
(struct _virStoragePoolObjSearchVolData *) opaque;
|
|
int found = 0;
|
|
|
|
virObjectLock(volobj);
|
|
if (data->iter(volobj->voldef, data->opaque))
|
|
found = 1;
|
|
virObjectUnlock(volobj);
|
|
|
|
return found;
|
|
}
|
|
|
|
|
|
virStorageVolDefPtr
|
|
virStoragePoolObjSearchVolume(virStoragePoolObjPtr obj,
|
|
virStorageVolObjListSearcher iter,
|
|
const void *opaque)
|
|
{
|
|
virStorageVolObjPtr volobj;
|
|
struct _virStoragePoolObjSearchVolData data = {
|
|
.iter = iter, .opaque = opaque };
|
|
|
|
virObjectRWLockRead(obj->volumes);
|
|
volobj = virHashSearch(obj->volumes->objsKey,
|
|
virStoragePoolObjSearchVolumeCb,
|
|
&data, NULL);
|
|
virObjectRWUnlock(obj->volumes);
|
|
|
|
if (volobj)
|
|
return volobj->voldef;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
virStorageVolDefPtr
|
|
virStorageVolDefFindByKey(virStoragePoolObjPtr obj,
|
|
const char *key)
|
|
{
|
|
virStorageVolObjPtr volobj;
|
|
|
|
virObjectRWLockRead(obj->volumes);
|
|
volobj = virHashLookup(obj->volumes->objsKey, key);
|
|
virObjectRWUnlock(obj->volumes);
|
|
|
|
if (volobj)
|
|
return volobj->voldef;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
virStorageVolDefPtr
|
|
virStorageVolDefFindByPath(virStoragePoolObjPtr obj,
|
|
const char *path)
|
|
{
|
|
virStorageVolObjPtr volobj;
|
|
|
|
virObjectRWLockRead(obj->volumes);
|
|
volobj = virHashLookup(obj->volumes->objsPath, path);
|
|
virObjectRWUnlock(obj->volumes);
|
|
|
|
if (volobj)
|
|
return volobj->voldef;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
virStorageVolDefPtr
|
|
virStorageVolDefFindByName(virStoragePoolObjPtr obj,
|
|
const char *name)
|
|
{
|
|
virStorageVolObjPtr volobj;
|
|
|
|
virObjectRWLockRead(obj->volumes);
|
|
volobj = virHashLookup(obj->volumes->objsName, name);
|
|
virObjectRWUnlock(obj->volumes);
|
|
|
|
if (volobj)
|
|
return volobj->voldef;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
struct _virStorageVolObjCountData {
|
|
virConnectPtr conn;
|
|
virStoragePoolVolumeACLFilter filter;
|
|
virStoragePoolDefPtr pooldef;
|
|
int count;
|
|
};
|
|
|
|
|
|
static int
|
|
virStoragePoolObjNumOfVolumesCb(void *payload,
|
|
const void *name ATTRIBUTE_UNUSED,
|
|
void *opaque)
|
|
{
|
|
virStorageVolObjPtr volobj = payload;
|
|
struct _virStorageVolObjCountData *data = opaque;
|
|
|
|
virObjectLock(volobj);
|
|
|
|
if (data->filter &&
|
|
!data->filter(data->conn, data->pooldef, volobj->voldef))
|
|
goto cleanup;
|
|
|
|
data->count++;
|
|
|
|
cleanup:
|
|
virObjectUnlock(volobj);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
virStoragePoolObjNumOfVolumes(virStoragePoolObjPtr obj,
|
|
virConnectPtr conn,
|
|
virStoragePoolVolumeACLFilter filter)
|
|
{
|
|
virStorageVolObjListPtr volumes = obj->volumes;
|
|
struct _virStorageVolObjCountData data = {
|
|
.conn = conn, .filter = filter, .pooldef = obj->def, .count = 0 };
|
|
|
|
virObjectRWLockRead(volumes);
|
|
virHashForEach(volumes->objsName, virStoragePoolObjNumOfVolumesCb, &data);
|
|
virObjectRWUnlock(volumes);
|
|
|
|
return data.count;
|
|
}
|
|
|
|
|
|
struct _virStorageVolObjNameData {
|
|
virConnectPtr conn;
|
|
virStoragePoolVolumeACLFilter filter;
|
|
virStoragePoolDefPtr pooldef;
|
|
bool error;
|
|
int nnames;
|
|
int maxnames;
|
|
char **const names;
|
|
};
|
|
|
|
static int
|
|
virStoragePoolObjVolumeGetNamesCb(void *payload,
|
|
const void *name ATTRIBUTE_UNUSED,
|
|
void *opaque)
|
|
{
|
|
virStorageVolObjPtr volobj = payload;
|
|
struct _virStorageVolObjNameData *data = opaque;
|
|
|
|
if (data->error)
|
|
return 0;
|
|
|
|
if (data->maxnames >= 0 && data->nnames == data->maxnames)
|
|
return 0;
|
|
|
|
virObjectLock(volobj);
|
|
|
|
if (data->filter &&
|
|
!data->filter(data->conn, data->pooldef, volobj->voldef))
|
|
goto cleanup;
|
|
|
|
if (data->names) {
|
|
if (VIR_STRDUP(data->names[data->nnames], volobj->voldef->name) < 0) {
|
|
data->error = true;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
data->nnames++;
|
|
|
|
cleanup:
|
|
virObjectUnlock(volobj);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
virStoragePoolObjVolumeGetNames(virStoragePoolObjPtr obj,
|
|
virConnectPtr conn,
|
|
virStoragePoolVolumeACLFilter filter,
|
|
char **const names,
|
|
int maxnames)
|
|
{
|
|
virStorageVolObjListPtr volumes = obj->volumes;
|
|
struct _virStorageVolObjNameData data = {
|
|
.conn = conn, .filter = filter, .pooldef = obj->def, .error = false,
|
|
.nnames = 0, .maxnames = maxnames, .names = names };
|
|
|
|
virObjectRWLockRead(volumes);
|
|
virHashForEach(volumes->objsName, virStoragePoolObjVolumeGetNamesCb, &data);
|
|
virObjectRWUnlock(volumes);
|
|
|
|
if (data.error)
|
|
goto error;
|
|
|
|
return data.nnames;
|
|
|
|
error:
|
|
while (--data.nnames)
|
|
VIR_FREE(data.names[data.nnames]);
|
|
return -1;
|
|
}
|
|
|
|
|
|
struct _virStorageVolObjExportData {
|
|
virConnectPtr conn;
|
|
virStoragePoolVolumeACLFilter filter;
|
|
virStoragePoolDefPtr pooldef;
|
|
bool error;
|
|
int nvols;
|
|
virStorageVolPtr *vols;
|
|
};
|
|
|
|
static int
|
|
virStoragePoolObjVolumeListExportCb(void *payload,
|
|
const void *name ATTRIBUTE_UNUSED,
|
|
void *opaque)
|
|
{
|
|
virStorageVolObjPtr volobj = payload;
|
|
struct _virStorageVolObjExportData *data = opaque;
|
|
virStorageVolPtr vol = NULL;
|
|
|
|
if (data->error)
|
|
return 0;
|
|
|
|
virObjectLock(volobj);
|
|
|
|
if (data->filter &&
|
|
!data->filter(data->conn, data->pooldef, volobj->voldef))
|
|
goto cleanup;
|
|
|
|
if (data->vols) {
|
|
if (!(vol = virGetStorageVol(data->conn, data->pooldef->name,
|
|
volobj->voldef->name, volobj->voldef->key,
|
|
NULL, NULL))) {
|
|
data->error = true;
|
|
goto cleanup;
|
|
}
|
|
data->vols[data->nvols] = vol;
|
|
}
|
|
|
|
data->nvols++;
|
|
|
|
cleanup:
|
|
virObjectUnlock(volobj);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
virStoragePoolObjVolumeListExport(virConnectPtr conn,
|
|
virStoragePoolObjPtr obj,
|
|
virStorageVolPtr **vols,
|
|
virStoragePoolVolumeACLFilter filter)
|
|
{
|
|
virStorageVolObjListPtr volumes = obj->volumes;
|
|
struct _virStorageVolObjExportData data = {
|
|
.conn = conn, .filter = filter, .pooldef = obj->def, .error = false,
|
|
.nvols = 0, .vols = NULL };
|
|
|
|
virObjectRWLockRead(volumes);
|
|
|
|
if (!vols) {
|
|
int ret = virHashSize(volumes->objsName);
|
|
virObjectRWUnlock(volumes);
|
|
return ret;
|
|
}
|
|
|
|
if (VIR_ALLOC_N(data.vols, virHashSize(volumes->objsName) + 1) < 0) {
|
|
virObjectRWUnlock(volumes);
|
|
return -1;
|
|
}
|
|
|
|
virHashForEach(volumes->objsName, virStoragePoolObjVolumeListExportCb, &data);
|
|
virObjectRWUnlock(volumes);
|
|
|
|
if (data.error)
|
|
goto error;
|
|
|
|
*vols = data.vols;
|
|
|
|
return data.nvols;
|
|
|
|
error:
|
|
virObjectListFree(data.vols);
|
|
return -1;
|
|
}
|
|
|
|
|
|
/**
|
|
* virStoragePoolObjAssignDef:
|
|
* @pools: Storage Pool object list pointer
|
|
* @def: Storage pool definition to add or update
|
|
*
|
|
* 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)
|
|
{
|
|
virStoragePoolObjPtr obj;
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virObjectRWLockWrite(pools);
|
|
|
|
if ((obj = virStoragePoolObjFindByNameLocked(pools, def->name))) {
|
|
virObjectLock(obj);
|
|
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;
|
|
|
|
virUUIDFormat(def->uuid, uuidstr);
|
|
if (virHashAddEntry(pools->objs, uuidstr, obj) < 0)
|
|
goto error;
|
|
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:
|
|
virStoragePoolObjEndAPI(&obj);
|
|
virObjectRWUnlock(pools);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static virStoragePoolObjPtr
|
|
virStoragePoolObjLoad(virStoragePoolObjListPtr pools,
|
|
const char *file,
|
|
const char *path,
|
|
const char *autostartLink)
|
|
{
|
|
virStoragePoolDefPtr def;
|
|
virStoragePoolObjPtr obj;
|
|
|
|
if (!(def = virStoragePoolDefParseFile(path)))
|
|
return NULL;
|
|
|
|
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 (!(obj = virStoragePoolObjAssignDef(pools, def))) {
|
|
virStoragePoolDefFree(def);
|
|
return NULL;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
obj->autostart = virFileLinkPointsTo(obj->autostartLink,
|
|
obj->configFile);
|
|
|
|
return obj;
|
|
}
|
|
|
|
|
|
static virStoragePoolObjPtr
|
|
virStoragePoolObjLoadState(virStoragePoolObjListPtr pools,
|
|
const char *stateDir,
|
|
const char *name)
|
|
{
|
|
char *stateFile = NULL;
|
|
virStoragePoolDefPtr def = NULL;
|
|
virStoragePoolObjPtr obj = NULL;
|
|
xmlDocPtr xml = NULL;
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
xmlNodePtr node = NULL;
|
|
|
|
if (!(stateFile = virFileBuildPath(stateDir, name, ".xml")))
|
|
goto error;
|
|
|
|
if (!(xml = virXMLParseCtxt(stateFile, NULL, _("(pool state)"), &ctxt)))
|
|
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;
|
|
if (!(def = virStoragePoolDefParseXML(ctxt)))
|
|
goto error;
|
|
|
|
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;
|
|
}
|
|
|
|
/* create the object */
|
|
if (!(obj = virStoragePoolObjAssignDef(pools, def)))
|
|
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;
|
|
|
|
cleanup:
|
|
VIR_FREE(stateFile);
|
|
xmlFreeDoc(xml);
|
|
xmlXPathFreeContext(ctxt);
|
|
return obj;
|
|
|
|
error:
|
|
virStoragePoolDefFree(def);
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
int
|
|
virStoragePoolObjLoadAllState(virStoragePoolObjListPtr pools,
|
|
const char *stateDir)
|
|
{
|
|
DIR *dir;
|
|
struct dirent *entry;
|
|
int ret = -1;
|
|
int rc;
|
|
|
|
if ((rc = virDirOpenIfExists(&dir, stateDir)) <= 0)
|
|
return rc;
|
|
|
|
while ((ret = virDirRead(dir, &entry, stateDir)) > 0) {
|
|
virStoragePoolObjPtr obj;
|
|
|
|
if (!virFileStripSuffix(entry->d_name, ".xml"))
|
|
continue;
|
|
|
|
if (!(obj = virStoragePoolObjLoadState(pools, stateDir, entry->d_name)))
|
|
continue;
|
|
virStoragePoolObjEndAPI(&obj);
|
|
}
|
|
|
|
VIR_DIR_CLOSE(dir);
|
|
return ret;
|
|
}
|
|
|
|
|
|
int
|
|
virStoragePoolObjLoadAllConfigs(virStoragePoolObjListPtr pools,
|
|
const char *configDir,
|
|
const char *autostartDir)
|
|
{
|
|
DIR *dir;
|
|
struct dirent *entry;
|
|
int ret;
|
|
int rc;
|
|
|
|
if ((rc = virDirOpenIfExists(&dir, configDir)) <= 0)
|
|
return rc;
|
|
|
|
while ((ret = virDirRead(dir, &entry, configDir)) > 0) {
|
|
char *path;
|
|
char *autostartLink;
|
|
virStoragePoolObjPtr obj;
|
|
|
|
if (!virFileHasSuffix(entry->d_name, ".xml"))
|
|
continue;
|
|
|
|
if (!(path = virFileBuildPath(configDir, entry->d_name, NULL)))
|
|
continue;
|
|
|
|
if (!(autostartLink = virFileBuildPath(autostartDir, entry->d_name,
|
|
NULL))) {
|
|
VIR_FREE(path);
|
|
continue;
|
|
}
|
|
|
|
obj = virStoragePoolObjLoad(pools, entry->d_name, path, autostartLink);
|
|
virStoragePoolObjEndAPI(&obj);
|
|
|
|
VIR_FREE(path);
|
|
VIR_FREE(autostartLink);
|
|
}
|
|
|
|
VIR_DIR_CLOSE(dir);
|
|
return ret;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
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 virStoragePoolSaveConfig(obj->configFile, def);
|
|
}
|
|
|
|
|
|
int
|
|
virStoragePoolObjDeleteDef(virStoragePoolObjPtr obj)
|
|
{
|
|
if (!obj->configFile) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
_("no config file for %s"), obj->def->name);
|
|
return -1;
|
|
}
|
|
|
|
if (unlink(obj->configFile) < 0) {
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
_("cannot remove config for %s"),
|
|
obj->def->name);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
struct _virStoragePoolCountData {
|
|
virConnectPtr conn;
|
|
virStoragePoolObjListACLFilter filter;
|
|
bool wantActive;
|
|
int count;
|
|
};
|
|
|
|
|
|
static int
|
|
virStoragePoolObjNumOfStoragePoolsCb(void *payload,
|
|
const void *name ATTRIBUTE_UNUSED,
|
|
void *opaque)
|
|
{
|
|
virStoragePoolObjPtr obj = payload;
|
|
struct _virStoragePoolCountData *data = opaque;
|
|
|
|
virObjectLock(obj);
|
|
|
|
if (data->filter && !data->filter(data->conn, obj->def))
|
|
goto cleanup;
|
|
|
|
if (data->wantActive != virStoragePoolObjIsActive(obj))
|
|
goto cleanup;
|
|
|
|
data->count++;
|
|
|
|
cleanup:
|
|
virObjectUnlock(obj);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
virStoragePoolObjNumOfStoragePools(virStoragePoolObjListPtr pools,
|
|
virConnectPtr conn,
|
|
bool wantActive,
|
|
virStoragePoolObjListACLFilter filter)
|
|
{
|
|
struct _virStoragePoolCountData data = {
|
|
.conn = conn, .filter = filter, .wantActive = wantActive, .count = 0 };
|
|
|
|
virObjectRWLockRead(pools);
|
|
virHashForEach(pools->objs, virStoragePoolObjNumOfStoragePoolsCb, &data);
|
|
virObjectRWUnlock(pools);
|
|
|
|
return data.count;
|
|
}
|
|
|
|
|
|
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)
|
|
{
|
|
virStoragePoolObjPtr obj = payload;
|
|
struct _virStoragePoolNameData *data = opaque;
|
|
|
|
if (data->error)
|
|
return 0;
|
|
|
|
if (data->maxnames >= 0 && data->nnames == data->maxnames)
|
|
return 0;
|
|
|
|
virObjectLock(obj);
|
|
|
|
if (data->filter && !data->filter(data->conn, obj->def))
|
|
goto cleanup;
|
|
|
|
if (data->wantActive != virStoragePoolObjIsActive(obj))
|
|
goto cleanup;
|
|
|
|
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
|
|
virStoragePoolObjGetNames(virStoragePoolObjListPtr pools,
|
|
virConnectPtr conn,
|
|
bool wantActive,
|
|
virStoragePoolObjListACLFilter filter,
|
|
char **const names,
|
|
int maxnames)
|
|
{
|
|
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;
|
|
|
|
error:
|
|
while (data.nnames)
|
|
VIR_FREE(data.names[--data.nnames]);
|
|
return -1;
|
|
}
|
|
|
|
|
|
/*
|
|
* virStoragePoolObjIsDuplicate:
|
|
* @doms : virStoragePoolObjListPtr to search
|
|
* @def : virStoragePoolDefPtr definition of pool to lookup
|
|
* @check_active: If true, ensure that pool is not active
|
|
*
|
|
* Returns: -1 on error
|
|
* 0 if pool is new
|
|
* 1 if pool is a duplicate
|
|
*/
|
|
int
|
|
virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools,
|
|
virStoragePoolDefPtr def,
|
|
bool check_active)
|
|
{
|
|
int ret = -1;
|
|
virStoragePoolObjPtr obj = NULL;
|
|
|
|
/* See if a Pool with matching UUID already exists */
|
|
obj = virStoragePoolObjFindByUUID(pools, def->uuid);
|
|
if (obj) {
|
|
/* UUID matches, but if names don't match, refuse it */
|
|
if (STRNEQ(obj->def->name, def->name)) {
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
virUUIDFormat(obj->def->uuid, uuidstr);
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
_("pool '%s' is already defined with uuid %s"),
|
|
obj->def->name, uuidstr);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (check_active) {
|
|
/* UUID & name match, but if Pool is already active, refuse it */
|
|
if (virStoragePoolObjIsActive(obj)) {
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
_("pool is already active as '%s'"),
|
|
obj->def->name);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
ret = 1;
|
|
} else {
|
|
/* UUID does not match, but if a name matches, refuse it */
|
|
obj = virStoragePoolObjFindByName(pools, def->name);
|
|
if (obj) {
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
virUUIDFormat(obj->def->uuid, uuidstr);
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
_("pool '%s' already exists with uuid %s"),
|
|
def->name, uuidstr);
|
|
goto cleanup;
|
|
}
|
|
ret = 0;
|
|
}
|
|
|
|
cleanup:
|
|
virStoragePoolObjEndAPI(&obj);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int
|
|
getSCSIHostNumber(virStorageAdapterSCSIHostPtr scsi_host,
|
|
unsigned int *hostnum)
|
|
{
|
|
int ret = -1;
|
|
unsigned int num;
|
|
char *name = NULL;
|
|
|
|
if (scsi_host->has_parent) {
|
|
virPCIDeviceAddressPtr addr = &scsi_host->parentaddr;
|
|
unsigned int unique_id = scsi_host->unique_id;
|
|
|
|
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;
|
|
}
|
|
|
|
*hostnum = num;
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
VIR_FREE(name);
|
|
return ret;
|
|
}
|
|
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
/*
|
|
* 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)
|
|
{
|
|
bool ret = false;
|
|
char *name = NULL;
|
|
char *scsi_host_name = NULL;
|
|
char *parent_name = 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 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))) {
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* 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");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* 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);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static bool
|
|
matchSCSIAdapterParent(virStorageAdapterSCSIHostPtr pool_scsi_host,
|
|
virStorageAdapterSCSIHostPtr def_scsi_host)
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
static bool
|
|
virStoragePoolSourceMatchSingleHost(virStoragePoolSourcePtr poolsrc,
|
|
virStoragePoolSourcePtr defsrc)
|
|
{
|
|
if (poolsrc->nhost != 1 && defsrc->nhost != 1)
|
|
return false;
|
|
|
|
if (defsrc->hosts[0].port &&
|
|
poolsrc->hosts[0].port != defsrc->hosts[0].port)
|
|
return false;
|
|
|
|
return STREQ(poolsrc->hosts[0].name, defsrc->hosts[0].name);
|
|
}
|
|
|
|
|
|
static bool
|
|
virStoragePoolSourceISCSIMatch(virStoragePoolObjPtr obj,
|
|
virStoragePoolDefPtr def)
|
|
{
|
|
virStoragePoolSourcePtr poolsrc = &obj->def->source;
|
|
virStoragePoolSourcePtr defsrc = &def->source;
|
|
|
|
/* NB: Do not check the source host name */
|
|
if (STRNEQ_NULLABLE(poolsrc->initiator.iqn, defsrc->initiator.iqn))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
static virStoragePoolObjPtr
|
|
virStoragePoolObjSourceMatchTypeDIR(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;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
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 (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;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static virStoragePoolObjPtr
|
|
virStoragePoolObjSourceMatchTypeDEVICE(virStoragePoolObjPtr obj,
|
|
virStoragePoolDefPtr def)
|
|
{
|
|
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;
|
|
}
|
|
|
|
if (def->type == VIR_STORAGE_POOL_ISCSI)
|
|
return NULL;
|
|
|
|
/* VIR_STORAGE_POOL_FS
|
|
* VIR_STORAGE_POOL_LOGICAL
|
|
* VIR_STORAGE_POOL_DISK
|
|
* VIR_STORAGE_POOL_ZFS */
|
|
return virStoragePoolSourceFindDuplicateDevices(obj, def);
|
|
}
|
|
|
|
|
|
struct _virStoragePoolObjFindDuplicateData {
|
|
virConnectPtr conn;
|
|
virStoragePoolDefPtr def;
|
|
};
|
|
|
|
static int
|
|
virStoragePoolObjSourceFindDuplicateCb(const void *payload,
|
|
const void *name ATTRIBUTE_UNUSED,
|
|
const void *opaque)
|
|
{
|
|
virStoragePoolObjPtr obj = (virStoragePoolObjPtr) payload;
|
|
struct _virStoragePoolObjFindDuplicateData *data =
|
|
(struct _virStoragePoolObjFindDuplicateData *) opaque;
|
|
|
|
/* 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_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_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;
|
|
|
|
case VIR_STORAGE_POOL_MPATH:
|
|
/* Only one mpath pool is valid per host */
|
|
if (data->def->type == obj->def->type)
|
|
return 1;
|
|
break;
|
|
|
|
case VIR_STORAGE_POOL_VSTORAGE:
|
|
if (data->def->type == obj->def->type &&
|
|
STREQ(obj->def->source.name, data->def->source.name))
|
|
return 1;
|
|
break;
|
|
|
|
case VIR_STORAGE_POOL_RBD:
|
|
case VIR_STORAGE_POOL_LAST:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
virStoragePoolObjSourceFindDuplicate(virConnectPtr conn,
|
|
virStoragePoolObjListPtr pools,
|
|
virStoragePoolDefPtr def)
|
|
{
|
|
struct _virStoragePoolObjFindDuplicateData data = { .conn = conn,
|
|
.def = def };
|
|
virStoragePoolObjPtr obj = NULL;
|
|
|
|
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;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#define MATCH(FLAG) (flags & (FLAG))
|
|
static bool
|
|
virStoragePoolMatch(virStoragePoolObjPtr obj,
|
|
unsigned int flags)
|
|
{
|
|
/* filter by active state */
|
|
if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE) &&
|
|
!((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE) &&
|
|
virStoragePoolObjIsActive(obj)) ||
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE) &&
|
|
!virStoragePoolObjIsActive(obj))))
|
|
return false;
|
|
|
|
/* filter by persistence */
|
|
if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_PERSISTENT) &&
|
|
!((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_PERSISTENT) &&
|
|
obj->configFile) ||
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_TRANSIENT) &&
|
|
!obj->configFile)))
|
|
return false;
|
|
|
|
/* filter by autostart option */
|
|
if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_AUTOSTART) &&
|
|
!((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_AUTOSTART) &&
|
|
obj->autostart) ||
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_NO_AUTOSTART) &&
|
|
!obj->autostart)))
|
|
return false;
|
|
|
|
/* filter by pool type */
|
|
if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_POOL_TYPE)) {
|
|
if (!((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_DIR) &&
|
|
(obj->def->type == VIR_STORAGE_POOL_DIR)) ||
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FS) &&
|
|
(obj->def->type == VIR_STORAGE_POOL_FS)) ||
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_NETFS) &&
|
|
(obj->def->type == VIR_STORAGE_POOL_NETFS)) ||
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_LOGICAL) &&
|
|
(obj->def->type == VIR_STORAGE_POOL_LOGICAL)) ||
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_DISK) &&
|
|
(obj->def->type == VIR_STORAGE_POOL_DISK)) ||
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI) &&
|
|
(obj->def->type == VIR_STORAGE_POOL_ISCSI)) ||
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_SCSI) &&
|
|
(obj->def->type == VIR_STORAGE_POOL_SCSI)) ||
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_MPATH) &&
|
|
(obj->def->type == VIR_STORAGE_POOL_MPATH)) ||
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_RBD) &&
|
|
(obj->def->type == VIR_STORAGE_POOL_RBD)) ||
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG) &&
|
|
(obj->def->type == VIR_STORAGE_POOL_SHEEPDOG)) ||
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER) &&
|
|
(obj->def->type == VIR_STORAGE_POOL_GLUSTER)) ||
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ZFS) &&
|
|
(obj->def->type == VIR_STORAGE_POOL_ZFS)) ||
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE) &&
|
|
(obj->def->type == VIR_STORAGE_POOL_VSTORAGE))))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
#undef MATCH
|
|
|
|
|
|
struct _virStoragePoolExportData {
|
|
virConnectPtr conn;
|
|
virStoragePoolObjListACLFilter filter;
|
|
bool checkActive;
|
|
bool wantActive;
|
|
bool checkMatch;
|
|
unsigned int flags;
|
|
bool error;
|
|
int nPools;
|
|
virStoragePoolPtr *pools;
|
|
};
|
|
|
|
|
|
static int
|
|
virStoragePoolObjListExportCb(void *payload,
|
|
const void *name ATTRIBUTE_UNUSED,
|
|
void *opaque)
|
|
{
|
|
virStoragePoolObjPtr obj = payload;
|
|
struct _virStoragePoolExportData *data = opaque;
|
|
virStoragePoolPtr pool = NULL;
|
|
|
|
if (data->error)
|
|
return 0;
|
|
|
|
virObjectLock(obj);
|
|
|
|
if (data->filter && !data->filter(data->conn, obj->def))
|
|
goto cleanup;
|
|
|
|
if (!virStoragePoolMatch(obj, data->flags))
|
|
goto cleanup;
|
|
|
|
if (data->pools) {
|
|
if (!(pool = virGetStoragePool(data->conn, obj->def->name,
|
|
obj->def->uuid, NULL, NULL))) {
|
|
data->error = true;
|
|
goto cleanup;
|
|
}
|
|
data->pools[data->nPools] = pool;
|
|
}
|
|
|
|
data->nPools++;
|
|
|
|
cleanup:
|
|
virObjectUnlock(obj);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
virStoragePoolObjListExport(virConnectPtr conn,
|
|
virStoragePoolObjListPtr poolobjs,
|
|
virStoragePoolPtr **pools,
|
|
virStoragePoolObjListFilter filter,
|
|
unsigned int flags)
|
|
{
|
|
struct _virStoragePoolExportData data = {
|
|
.conn = conn, .filter = filter, .flags = flags, .error = false,
|
|
.nPools = 0, .pools = NULL };
|
|
|
|
virObjectRWLockRead(poolobjs);
|
|
|
|
if (pools && VIR_ALLOC_N(data.pools, virHashSize(poolobjs->objs) + 1) < 0)
|
|
goto error;
|
|
|
|
virHashForEach(poolobjs->objs, virStoragePoolObjListExportCb, &data);
|
|
virObjectRWUnlock(poolobjs);
|
|
|
|
if (data.error)
|
|
goto error;
|
|
|
|
if (data.pools) {
|
|
/* trim the array to the final size */
|
|
ignore_value(VIR_REALLOC_N(data.pools, data.nPools + 1));
|
|
*pools = data.pools;
|
|
}
|
|
|
|
return data.nPools;
|
|
|
|
error:
|
|
virObjectListFree(data.pools);
|
|
return -1;
|
|
}
|