From cb228a0e24266f43dbab208bd38965e511f714ee Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 20 Feb 2008 15:06:53 +0000 Subject: [PATCH] Internal driver API for storage management --- ChangeLog | 8 + include/libvirt/virterror.h | 4 + src/driver.h | 146 ++++ src/hash.c | 317 ++++++++ src/internal.h | 68 +- src/libvirt.c | 1367 +++++++++++++++++++++++++++++++++++ src/virterror.c | 21 + 7 files changed, 1929 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4c029f2bf8..5d67f4623e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Wed Feb 20 10:01:27 EST 2008 Daniel P. Berrange + + * include/libvirt/virterror.h, src/virterror.c: Add error codes + for storage API drivers + * src/internal.h, src/hash.c: Add internal storage object structs + * src/driver.h: internal driver API for storage management + * src/libvirt.c: hook up storage API to internal driver API + Wed Feb 20 09:51:27 EST 2008 Daniel P. Berrange * include/libvirt/libvirt.h, include/libvirt/libvirt.h.in, diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index 7ade727159..fa9457796d 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -54,6 +54,7 @@ typedef enum { VIR_FROM_OPENVZ, /* Error from OpenVZ driver */ VIR_FROM_XENXM, /* Error at Xen XM layer */ VIR_FROM_STATS_LINUX, /* Error in the Linux Stats code */ + VIR_FROM_STORAGE, /* Error from storage driver */ } virErrorDomain; @@ -132,6 +133,9 @@ typedef enum { VIR_ERR_NO_NETWORK, /* network not found */ VIR_ERR_INVALID_MAC, /* invalid MAC adress */ VIR_ERR_AUTH_FAILED, /* authentication failed */ + VIR_ERR_INVALID_STORAGE_POOL, /* invalid storage pool object */ + VIR_ERR_INVALID_STORAGE_VOL, /* invalid storage vol object */ + VIR_WAR_NO_STORAGE, /* failed to start storage */ } virErrorNumber; /** diff --git a/src/driver.h b/src/driver.h index ede12f30ea..4db972b455 100644 --- a/src/driver.h +++ b/src/driver.h @@ -412,6 +412,151 @@ struct _virNetworkDriver { virDrvNetworkSetAutostart networkSetAutostart; }; + +typedef int + (*virDrvConnectNumOfStoragePools) (virConnectPtr conn); +typedef int + (*virDrvConnectListStoragePools) (virConnectPtr conn, + char **const names, + int maxnames); +typedef int + (*virDrvConnectNumOfDefinedStoragePools) (virConnectPtr conn); +typedef int + (*virDrvConnectListDefinedStoragePools) (virConnectPtr conn, + char **const names, + int maxnames); +typedef virStoragePoolPtr + (*virDrvStoragePoolLookupByName) (virConnectPtr conn, + const char *name); +typedef virStoragePoolPtr + (*virDrvStoragePoolLookupByUUID) (virConnectPtr conn, + const unsigned char *uuid); +typedef virStoragePoolPtr + (*virDrvStoragePoolLookupByVolume) (virStorageVolPtr vol); +typedef virStoragePoolPtr + (*virDrvStoragePoolCreateXML) (virConnectPtr conn, + const char *xmlDesc, + unsigned int flags); +typedef virStoragePoolPtr + (*virDrvStoragePoolDefineXML) (virConnectPtr conn, + const char *xmlDesc, + unsigned int flags); +typedef int + (*virDrvStoragePoolUndefine) (virStoragePoolPtr pool); +typedef int + (*virDrvStoragePoolBuild) (virStoragePoolPtr pool, + unsigned int flags); +typedef int + (*virDrvStoragePoolCreate) (virStoragePoolPtr pool, + unsigned int flags); +typedef int + (*virDrvStoragePoolDestroy) (virStoragePoolPtr pool); +typedef int + (*virDrvStoragePoolDelete) (virStoragePoolPtr pool, + unsigned int flags); +typedef int + (*virDrvStoragePoolRefresh) (virStoragePoolPtr pool, + unsigned int flags); +typedef int + (*virDrvStoragePoolGetInfo) (virStoragePoolPtr vol, + virStoragePoolInfoPtr info); +typedef char * + (*virDrvStoragePoolGetXMLDesc) (virStoragePoolPtr pool, + unsigned int flags); +typedef int + (*virDrvStoragePoolGetAutostart) (virStoragePoolPtr pool, + int *autostart); +typedef int + (*virDrvStoragePoolSetAutostart) (virStoragePoolPtr pool, + int autostart); +typedef int + (*virDrvStoragePoolNumOfVolumes) (virStoragePoolPtr pool); +typedef int + (*virDrvStoragePoolListVolumes) (virStoragePoolPtr pool, + char **const names, + int maxnames); + + +typedef virStorageVolPtr + (*virDrvStorageVolLookupByName) (virStoragePoolPtr pool, + const char *name); +typedef virStorageVolPtr + (*virDrvStorageVolLookupByKey) (virConnectPtr pool, + const char *key); +typedef virStorageVolPtr + (*virDrvStorageVolLookupByPath) (virConnectPtr pool, + const char *path); + + +typedef virStorageVolPtr + (*virDrvStorageVolCreateXML) (virStoragePoolPtr pool, + const char *xmldesc, + unsigned int flags); +typedef int + (*virDrvStorageVolDelete) (virStorageVolPtr vol, + unsigned int flags); + +typedef int + (*virDrvStorageVolGetInfo) (virStorageVolPtr vol, + virStorageVolInfoPtr info); +typedef char * + (*virDrvStorageVolGetXMLDesc) (virStorageVolPtr pool, + unsigned int flags); +typedef char * + (*virDrvStorageVolGetPath) (virStorageVolPtr vol); + + + +typedef struct _virStorageDriver virStorageDriver; +typedef virStorageDriver *virStorageDriverPtr; + +/** + * _virStorageDriver: + * + * Structure associated to a network virtualization driver, defining the various + * entry points for it. + * + * All drivers must support the following fields/methods: + * - open + * - close + */ +struct _virStorageDriver { + const char * name; /* the name of the driver */ + virDrvOpen open; + virDrvClose close; + + virDrvConnectNumOfStoragePools numOfPools; + virDrvConnectListStoragePools listPools; + virDrvConnectNumOfDefinedStoragePools numOfDefinedPools; + virDrvConnectListDefinedStoragePools listDefinedPools; + virDrvStoragePoolLookupByName poolLookupByName; + virDrvStoragePoolLookupByUUID poolLookupByUUID; + virDrvStoragePoolLookupByVolume poolLookupByVolume; + virDrvStoragePoolCreateXML poolCreateXML; + virDrvStoragePoolDefineXML poolDefineXML; + virDrvStoragePoolBuild poolBuild; + virDrvStoragePoolUndefine poolUndefine; + virDrvStoragePoolCreate poolCreate; + virDrvStoragePoolDestroy poolDestroy; + virDrvStoragePoolDelete poolDelete; + virDrvStoragePoolRefresh poolRefresh; + virDrvStoragePoolGetInfo poolGetInfo; + virDrvStoragePoolGetXMLDesc poolGetXMLDesc; + virDrvStoragePoolGetAutostart poolGetAutostart; + virDrvStoragePoolSetAutostart poolSetAutostart; + virDrvStoragePoolNumOfVolumes poolNumOfVolumes; + virDrvStoragePoolListVolumes poolListVolumes; + + virDrvStorageVolLookupByName volLookupByName; + virDrvStorageVolLookupByKey volLookupByKey; + virDrvStorageVolLookupByPath volLookupByPath; + virDrvStorageVolCreateXML volCreateXML; + virDrvStorageVolDelete volDelete; + virDrvStorageVolGetInfo volGetInfo; + virDrvStorageVolGetXMLDesc volGetXMLDesc; + virDrvStorageVolGetPath volGetPath; +}; + typedef int (*virDrvStateInitialize) (void); typedef int (*virDrvStateCleanup) (void); typedef int (*virDrvStateReload) (void); @@ -434,6 +579,7 @@ struct _virStateDriver { */ int virRegisterDriver(virDriverPtr); int virRegisterNetworkDriver(virNetworkDriverPtr); +int virRegisterStorageDriver(virStorageDriverPtr); int virRegisterStateDriver(virStateDriverPtr); #ifdef __cplusplus diff --git a/src/hash.c b/src/hash.c index 84b41b0bb5..45d743370d 100644 --- a/src/hash.c +++ b/src/hash.c @@ -651,6 +651,34 @@ virNetworkFreeName(virNetworkPtr network, const char *name ATTRIBUTE_UNUSED) return (virNetworkFree(network)); } +/** + * virStoragePoolFreeName: + * @pool: a pool object + * + * Destroy the pool object, this is just used by the pool hash callback. + * + * Returns 0 in case of success and -1 in case of failure. + */ +static int +virStoragePoolFreeName(virStoragePoolPtr pool, const char *name ATTRIBUTE_UNUSED) +{ + return (virStoragePoolFree(pool)); +} + +/** + * virStorageVolFreeName: + * @vol: a vol object + * + * Destroy the vol object, this is just used by the vol hash callback. + * + * Returns 0 in case of success and -1 in case of failure. + */ +static int +virStorageVolFreeName(virStorageVolPtr vol, const char *name ATTRIBUTE_UNUSED) +{ + return (virStorageVolFree(vol)); +} + /** * virGetConnect: * @@ -678,6 +706,12 @@ virGetConnect(void) { ret->networks = virHashCreate(20); if (ret->networks == NULL) goto failed; + ret->storagePools = virHashCreate(20); + if (ret->storagePools == NULL) + goto failed; + ret->storageVols = virHashCreate(20); + if (ret->storageVols == NULL) + goto failed; pthread_mutex_init(&ret->lock, NULL); @@ -690,6 +724,10 @@ failed: virHashFree(ret->domains, (virHashDeallocator) virDomainFreeName); if (ret->networks != NULL) virHashFree(ret->networks, (virHashDeallocator) virNetworkFreeName); + if (ret->storagePools != NULL) + virHashFree(ret->storagePools, (virHashDeallocator) virStoragePoolFreeName); + if (ret->storageVols != NULL) + virHashFree(ret->storageVols, (virHashDeallocator) virStorageVolFreeName); pthread_mutex_destroy(&ret->lock); free(ret); @@ -713,6 +751,11 @@ virReleaseConnect(virConnectPtr conn) { virHashFree(conn->domains, (virHashDeallocator) virDomainFreeName); if (conn->networks != NULL) virHashFree(conn->networks, (virHashDeallocator) virNetworkFreeName); + if (conn->storagePools != NULL) + virHashFree(conn->storagePools, (virHashDeallocator) virStoragePoolFreeName); + if (conn->storageVols != NULL) + virHashFree(conn->storageVols, (virHashDeallocator) virStorageVolFreeName); + virResetError(&conn->err); free(conn->name); @@ -1017,6 +1060,280 @@ virUnrefNetwork(virNetworkPtr network) { return (refs); } + +/** + * virGetStoragePool: + * @conn: the hypervisor connection + * @name: pointer to the storage pool name + * @uuid: pointer to the uuid + * + * Lookup if the storage pool is already registered for that connection, + * if yes return a new pointer to it, if no allocate a new structure, + * and register it in the table. In any case a corresponding call to + * virFreeStoragePool() is needed to not leak data. + * + * Returns a pointer to the network, or NULL in case of failure + */ +virStoragePoolPtr +__virGetStoragePool(virConnectPtr conn, const char *name, const unsigned char *uuid) { + virStoragePoolPtr ret = NULL; + + if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (uuid == NULL)) { + virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(NULL); + } + pthread_mutex_lock(&conn->lock); + + /* TODO search by UUID first as they are better differenciators */ + + ret = (virStoragePoolPtr) virHashLookup(conn->storagePools, name); + /* TODO check the UUID */ + if (ret == NULL) { + ret = (virStoragePoolPtr) calloc(1, sizeof(*ret)); + if (ret == NULL) { + virHashError(conn, VIR_ERR_NO_MEMORY, _("allocating storage pool")); + goto error; + } + ret->name = strdup(name); + if (ret->name == NULL) { + virHashError(conn, VIR_ERR_NO_MEMORY, _("allocating storage pool")); + goto error; + } + ret->magic = VIR_STORAGE_POOL_MAGIC; + ret->conn = conn; + if (uuid != NULL) + memcpy(&(ret->uuid[0]), uuid, VIR_UUID_BUFLEN); + + if (virHashAddEntry(conn->storagePools, name, ret) < 0) { + virHashError(conn, VIR_ERR_INTERNAL_ERROR, + _("failed to add storage pool to connection hash table")); + goto error; + } + conn->refs++; + } + ret->refs++; + pthread_mutex_unlock(&conn->lock); + return(ret); + +error: + pthread_mutex_unlock(&conn->lock); + if (ret != NULL) { + free(ret->name); + free(ret); + } + return(NULL); +} + + +/** + * virReleaseStoragePool: + * @pool: the pool to release + * + * Unconditionally release all memory associated with a pool. + * The conn.lock mutex must be held prior to calling this, and will + * be released prior to this returning. The pool obj must not + * be used once this method returns. + * + * It will also unreference the associated connection object, + * which may also be released if its ref count hits zero. + */ +static void +virReleaseStoragePool(virStoragePoolPtr pool) { + virConnectPtr conn = pool->conn; + DEBUG("release pool %p %s", pool, pool->name); + + /* TODO search by UUID first as they are better differenciators */ + if (virHashRemoveEntry(conn->storagePools, pool->name, NULL) < 0) + virHashError(conn, VIR_ERR_INTERNAL_ERROR, + _("pool missing from connection hash table")); + + pool->magic = -1; + free(pool->name); + free(pool); + + DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); + conn->refs--; + if (conn->refs == 0) { + virReleaseConnect(conn); + /* Already unlocked mutex */ + return; + } + + pthread_mutex_unlock(&conn->lock); +} + + +/** + * virUnrefStoragePool: + * @pool: the pool to unreference + * + * Unreference the pool. If the use count drops to zero, the structure is + * actually freed. + * + * Returns the reference count or -1 in case of failure. + */ +int +virUnrefStoragePool(virStoragePoolPtr pool) { + int refs; + + if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) { + virHashError(pool->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + pthread_mutex_lock(&pool->conn->lock); + DEBUG("unref pool %p %s %d", pool, pool->name, pool->refs); + pool->refs--; + refs = pool->refs; + if (refs == 0) { + virReleaseStoragePool(pool); + /* Already unlocked mutex */ + return (0); + } + + pthread_mutex_unlock(&pool->conn->lock); + return (refs); +} + + +/** + * virGetStorageVol: + * @conn: the hypervisor connection + * @pool: pool owning the volume + * @name: pointer to the storage vol name + * @uuid: pointer to the uuid + * + * Lookup if the storage vol is already registered for that connection, + * if yes return a new pointer to it, if no allocate a new structure, + * and register it in the table. In any case a corresponding call to + * virFreeStorageVol() is needed to not leak data. + * + * Returns a pointer to the storage vol, or NULL in case of failure + */ +virStorageVolPtr +__virGetStorageVol(virConnectPtr conn, const char *pool, const char *name, const char *key) { + virStorageVolPtr ret = NULL; + + if ((!VIR_IS_CONNECT(conn)) || (name == NULL) || (key == NULL)) { + virHashError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(NULL); + } + pthread_mutex_lock(&conn->lock); + + ret = (virStorageVolPtr) virHashLookup(conn->storageVols, key); + if (ret == NULL) { + ret = (virStorageVolPtr) calloc(1, sizeof(*ret)); + if (ret == NULL) { + virHashError(conn, VIR_ERR_NO_MEMORY, _("allocating storage vol")); + goto error; + } + ret->pool = strdup(pool); + if (ret->pool == NULL) { + virHashError(conn, VIR_ERR_NO_MEMORY, _("allocating storage vol")); + goto error; + } + ret->name = strdup(name); + if (ret->name == NULL) { + virHashError(conn, VIR_ERR_NO_MEMORY, _("allocating storage vol")); + goto error; + } + strncpy(ret->key, key, sizeof(ret->key)-1); + ret->key[sizeof(ret->key)-1] = '\0'; + ret->magic = VIR_STORAGE_VOL_MAGIC; + ret->conn = conn; + + if (virHashAddEntry(conn->storageVols, key, ret) < 0) { + virHashError(conn, VIR_ERR_INTERNAL_ERROR, + _("failed to add storage vol to connection hash table")); + goto error; + } + conn->refs++; + } + ret->refs++; + pthread_mutex_unlock(&conn->lock); + return(ret); + +error: + pthread_mutex_unlock(&conn->lock); + if (ret != NULL) { + free(ret->name); + free(ret->pool); + free(ret); + } + return(NULL); +} + + +/** + * virReleaseStorageVol: + * @vol: the vol to release + * + * Unconditionally release all memory associated with a vol. + * The conn.lock mutex must be held prior to calling this, and will + * be released prior to this returning. The vol obj must not + * be used once this method returns. + * + * It will also unreference the associated connection object, + * which may also be released if its ref count hits zero. + */ +static void +virReleaseStorageVol(virStorageVolPtr vol) { + virConnectPtr conn = vol->conn; + DEBUG("release vol %p %s", vol, vol->name); + + /* TODO search by UUID first as they are better differenciators */ + if (virHashRemoveEntry(conn->storageVols, vol->key, NULL) < 0) + virHashError(conn, VIR_ERR_INTERNAL_ERROR, + _("vol missing from connection hash table")); + + vol->magic = -1; + free(vol->name); + free(vol->pool); + free(vol); + + DEBUG("unref connection %p %s %d", conn, conn->name, conn->refs); + conn->refs--; + if (conn->refs == 0) { + virReleaseConnect(conn); + /* Already unlocked mutex */ + return; + } + + pthread_mutex_unlock(&conn->lock); +} + + +/** + * virUnrefStorageVol: + * @vol: the vol to unreference + * + * Unreference the vol. If the use count drops to zero, the structure is + * actually freed. + * + * Returns the reference count or -1 in case of failure. + */ +int +virUnrefStorageVol(virStorageVolPtr vol) { + int refs; + + if (!VIR_IS_CONNECTED_STORAGE_VOL(vol)) { + virHashError(vol->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + pthread_mutex_lock(&vol->conn->lock); + DEBUG("unref vol %p %s %d", vol, vol->name, vol->refs); + vol->refs--; + refs = vol->refs; + if (refs == 0) { + virReleaseStorageVol(vol); + /* Already unlocked mutex */ + return (0); + } + + pthread_mutex_unlock(&vol->conn->lock); + return (refs); +} + + /* * vim: set tabstop=4: * vim: set shiftwidth=4: diff --git a/src/internal.h b/src/internal.h index 033a25dcdf..7c6e13e455 100644 --- a/src/internal.h +++ b/src/internal.h @@ -120,7 +120,7 @@ extern int debugFlag; * VIR_DOMAIN_MAGIC: * * magic value used to protect the API when pointers to domain structures - * are passed down by the uers. + * are passed down by the users. */ #define VIR_DOMAIN_MAGIC 0xDEAD4321 #define VIR_IS_DOMAIN(obj) ((obj) && (obj)->magic==VIR_DOMAIN_MAGIC) @@ -130,12 +130,32 @@ extern int debugFlag; * VIR_NETWORK_MAGIC: * * magic value used to protect the API when pointers to network structures - * are passed down by the uers. + * are passed down by the users. */ #define VIR_NETWORK_MAGIC 0xDEAD1234 #define VIR_IS_NETWORK(obj) ((obj) && (obj)->magic==VIR_NETWORK_MAGIC) #define VIR_IS_CONNECTED_NETWORK(obj) (VIR_IS_NETWORK(obj) && VIR_IS_CONNECT((obj)->conn)) +/** + * VIR_STORAGE_POOL_MAGIC: + * + * magic value used to protect the API when pointers to storage pool structures + * are passed down by the users. + */ +#define VIR_STORAGE_POOL_MAGIC 0xDEAD5678 +#define VIR_IS_STORAGE_POOL(obj) ((obj) && (obj)->magic==VIR_STORAGE_POOL_MAGIC) +#define VIR_IS_CONNECTED_STORAGE_POOL(obj) (VIR_IS_STORAGE_POOL(obj) && VIR_IS_CONNECT((obj)->conn)) + +/** + * VIR_STORAGE_VOL_MAGIC: + * + * magic value used to protect the API when pointers to storage vol structures + * are passed down by the users. + */ +#define VIR_STORAGE_VOL_MAGIC 0xDEAD8765 +#define VIR_IS_STORAGE_VOL(obj) ((obj) && (obj)->magic==VIR_STORAGE_VOL_MAGIC) +#define VIR_IS_CONNECTED_STORAGE_VOL(obj) (VIR_IS_STORAGE_VOL(obj) && VIR_IS_CONNECT((obj)->conn)) + /* * arbitrary limitations */ @@ -155,6 +175,7 @@ struct _virConnect { /* The underlying hypervisor driver and network driver. */ virDriverPtr driver; virNetworkDriverPtr networkDriver; + virStorageDriverPtr storageDriver; /* Private data pointer which can be used by driver and * network driver as they wish. @@ -162,6 +183,7 @@ struct _virConnect { */ void * privateData; void * networkPrivateData; + void * storagePrivateData; /* Per-connection error. */ virError err; /* the last error */ @@ -177,6 +199,8 @@ struct _virConnect { pthread_mutex_t lock; virHashTablePtr domains; /* hash table for known domains */ virHashTablePtr networks; /* hash table for known domains */ + virHashTablePtr storagePools;/* hash table for known storage pools */ + virHashTablePtr storageVols;/* hash table for known storage vols */ int refs; /* reference count */ }; @@ -207,6 +231,34 @@ struct _virNetwork { unsigned char uuid[VIR_UUID_BUFLEN]; /* the network unique identifier */ }; +/** +* _virStoragePool: +* +* Internal structure associated to a storage pool +*/ +struct _virStoragePool { + unsigned int magic; /* specific value to check */ + int refs; /* reference count */ + virConnectPtr conn; /* pointer back to the connection */ + char *name; /* the storage pool external name */ + unsigned char uuid[VIR_UUID_BUFLEN]; /* the storage pool unique identifier */ +}; + +/** +* _virStorageVol: +* +* Internal structure associated to a storage volume +*/ +struct _virStorageVol { + unsigned int magic; /* specific value to check */ + int refs; /* reference count */ + virConnectPtr conn; /* pointer back to the connection */ + char *pool; /* Pool name of owner */ + char *name; /* the storage vol external name */ + /* XXX currently abusing path for this. Ought not to be so evil */ + char key[PATH_MAX]; /* unique key for storage vol */ +}; + /************************************************************************ * * @@ -243,8 +295,20 @@ virNetworkPtr __virGetNetwork (virConnectPtr conn, const unsigned char *uuid); int virUnrefNetwork (virNetworkPtr network); +virStoragePoolPtr __virGetStoragePool (virConnectPtr conn, + const char *name, + const unsigned char *uuid); +int virUnrefStoragePool (virStoragePoolPtr pool); +virStorageVolPtr __virGetStorageVol (virConnectPtr conn, + const char *pool, + const char *name, + const char *key); +int virUnrefStorageVol (virStorageVolPtr vol); + #define virGetDomain(c,n,u) __virGetDomain((c),(n),(u)) #define virGetNetwork(c,n,u) __virGetNetwork((c),(n),(u)) +#define virGetStoragePool(c,n,u) __virGetStoragePool((c),(n),(u)) +#define virGetStorageVol(c,p,n,u) __virGetStorageVol((c),(p),(n),(u)) int __virStateInitialize(void); int __virStateCleanup(void); diff --git a/src/libvirt.c b/src/libvirt.c index 85a6875670..7c9c297c13 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -51,6 +51,8 @@ static virDriverPtr virDriverTab[MAX_DRIVERS]; static int virDriverTabCount = 0; static virNetworkDriverPtr virNetworkDriverTab[MAX_DRIVERS]; static int virNetworkDriverTabCount = 0; +static virStorageDriverPtr virStorageDriverTab[MAX_DRIVERS]; +static int virStorageDriverTabCount = 0; static virStateDriverPtr virStateDriverTab[MAX_DRIVERS]; static int virStateDriverTabCount = 0; static int initialized = 0; @@ -316,6 +318,58 @@ virLibNetworkError(virNetworkPtr network, virErrorNumber error, errmsg, info, NULL, 0, 0, errmsg, info); } +/** + * virLibStoragePoolError: + * @conn: the connection if available + * @error: the error noumber + * @info: extra information string + * + * Handle an error at the connection level + */ +static void +virLibStoragePoolError(virStoragePoolPtr pool, virErrorNumber error, + const char *info) +{ + virConnectPtr conn = NULL; + const char *errmsg; + + if (error == VIR_ERR_OK) + return; + + errmsg = __virErrorMsg(error, info); + if (error != VIR_ERR_INVALID_STORAGE_POOL) + conn = pool->conn; + + __virRaiseError(conn, NULL, NULL, VIR_FROM_STORAGE, error, VIR_ERR_ERROR, + errmsg, info, NULL, 0, 0, errmsg, info); +} + +/** + * virLibStorageVolError: + * @conn: the connection if available + * @error: the error noumber + * @info: extra information string + * + * Handle an error at the connection level + */ +static void +virLibStorageVolError(virStorageVolPtr vol, virErrorNumber error, + const char *info) +{ + virConnectPtr conn = NULL; + const char *errmsg; + + if (error == VIR_ERR_OK) + return; + + errmsg = __virErrorMsg(error, info); + if (error != VIR_ERR_INVALID_STORAGE_VOL) + conn = vol->conn; + + __virRaiseError(conn, NULL, NULL, VIR_FROM_STORAGE, error, VIR_ERR_ERROR, + errmsg, info, NULL, 0, 0, errmsg, info); +} + /** * virRegisterNetworkDriver: * @driver: pointer to a network driver block @@ -344,6 +398,34 @@ virRegisterNetworkDriver(virNetworkDriverPtr driver) return virNetworkDriverTabCount++; } +/** + * virRegisterStorageDriver: + * @driver: pointer to a storage driver block + * + * Register a storage virtualization driver + * + * Returns the driver priority or -1 in case of error. + */ +int +virRegisterStorageDriver(virStorageDriverPtr driver) +{ + if (virInitialize() < 0) + return -1; + + if (driver == NULL) { + virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + + if (virStorageDriverTabCount >= MAX_DRIVERS) { + virLibConnError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); + return(-1); + } + + virStorageDriverTab[virStorageDriverTabCount] = driver; + return virStorageDriverTabCount++; +} + /** * virRegisterDriver: * @driver: pointer to a driver block @@ -607,6 +689,29 @@ do_open (const char *name, } } + + /* Secondary driver for storage. Optional */ + for (i = 0; i < virStorageDriverTabCount; i++) { + res = virStorageDriverTab[i]->open (ret, uri, auth, flags); +#ifdef ENABLE_DEBUG + DEBUG("storage driver %d %s returned %s", + i, virStorageDriverTab[i]->name, + res == VIR_DRV_OPEN_SUCCESS ? "SUCCESS" : + (res == VIR_DRV_OPEN_DECLINED ? "DECLINED" : + (res == VIR_DRV_OPEN_ERROR ? "ERROR" : "unknown status"))); +#endif + if (res == VIR_DRV_OPEN_ERROR) { + if (0 && STREQ(virStorageDriverTab[i]->name, "remote")) { + virLibConnWarning (NULL, VIR_WAR_NO_STORAGE, + "Is the daemon running ?"); + } + break; + } else if (res == VIR_DRV_OPEN_SUCCESS) { + ret->storageDriver = virStorageDriverTab[i]; + break; + } + } + /* Cleansing flags */ ret->flags = flags & VIR_CONNECT_RO; @@ -702,6 +807,8 @@ virConnectClose(virConnectPtr conn) if (conn->networkDriver) conn->networkDriver->close (conn); + if (conn->storageDriver) + conn->storageDriver->close (conn); conn->driver->close (conn); if (virUnrefConnect(conn) < 0) @@ -3535,6 +3642,1266 @@ virNetworkSetAutostart(virNetworkPtr network, return -1; } + +/** + * virStoragePoolGetConnect: + * @pool: pointer to a poool + * + * Provides the connection pointer associated with a storage pool. The + * reference counter on the connection is not increased by this + * call. + * + * WARNING: When writing libvirt bindings in other languages, do + * not use this function. Instead, store the connection and + * the pool object together. + * + * Returns the virConnectPtr or NULL in case of failure. + */ +virConnectPtr +virStoragePoolGetConnect (virStoragePoolPtr pool) +{ + DEBUG("pool=%p", pool); + + if (!VIR_IS_STORAGE_POOL (pool)) { + virLibStoragePoolError (NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return NULL; + } + return pool->conn; +} + +/** + * virConnectNumOfStoragePools: + * @conn: pointer to hypervisor connection + * + * Provides the number of active storage pools + * + * Returns the number of pools found, or -1 on error + */ +int +virConnectNumOfStoragePools (virConnectPtr conn) +{ + DEBUG("conn=%p", conn); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->numOfPools) + return conn->storageDriver->numOfPools (conn); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +/** + * virConnectListStoragePools: + * @conn: pointer to hypervisor connection + * @names: array of char * to fill with pool names (allocated by caller) + * @maxnames: size of the names array + * + * Provides the list of names of active storage pools + * upto maxnames. If there are more than maxnames, the + * remaining names will be silently ignored. + * + * Returns 0 on success, -1 on error + */ +int +virConnectListStoragePools (virConnectPtr conn, + char **const names, + int maxnames) +{ + DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + + if ((names == NULL) || (maxnames < 0)) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->listPools) + return conn->storageDriver->listPools (conn, names, maxnames); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; + +} + + +/** + * virConnectNumOfDefinedStoragePools: + * @conn: pointer to hypervisor connection + * + * Provides the number of inactive storage pools + * + * Returns the number of pools found, or -1 on error + */ +int +virConnectNumOfDefinedStoragePools(virConnectPtr conn) +{ + DEBUG("conn=%p", conn); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->numOfDefinedPools) + return conn->storageDriver->numOfDefinedPools (conn); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virConnectListDefinedStoragePools: + * @conn: pointer to hypervisor connection + * @names: array of char * to fill with pool names (allocated by caller) + * @maxnames: size of the names array + * + * Provides the list of names of inactive storage pools + * upto maxnames. If there are more than maxnames, the + * remaining names will be silently ignored. + * + * Returns 0 on success, -1 on error + */ +int +virConnectListDefinedStoragePools(virConnectPtr conn, + char **const names, + int maxnames) +{ + DEBUG("conn=%p, names=%p, maxnames=%d", conn, names, maxnames); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (-1); + } + + if ((names == NULL) || (maxnames < 0)) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->listDefinedPools) + return conn->storageDriver->listDefinedPools (conn, names, maxnames); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virStoragePoolLookupByName: + * @conn: pointer to hypervisor connection + * @name: name of pool to fetch + * + * Fetch a storage pool based on its unique name + * + * Returns a virStoragePoolPtr object, or NULL if no matching pool is found + */ +virStoragePoolPtr +virStoragePoolLookupByName(virConnectPtr conn, + const char *name) +{ + DEBUG("conn=%p, name=%s", conn, name); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (name == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + if (conn->storageDriver && conn->storageDriver->poolLookupByName) + return conn->storageDriver->poolLookupByName (conn, name); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + + +/** + * virStoragePoolLookupByUUID: + * @conn: pointer to hypervisor connection + * @uuid: globally unique id of pool to fetch + * + * Fetch a storage pool based on its globally unique id + * + * Returns a virStoragePoolPtr object, or NULL if no matching pool is found + */ +virStoragePoolPtr +virStoragePoolLookupByUUID(virConnectPtr conn, + const unsigned char *uuid) +{ + DEBUG("conn=%p, uuid=%s", conn, uuid); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (uuid == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + if (conn->storageDriver && conn->storageDriver->poolLookupByUUID) + return conn->storageDriver->poolLookupByUUID (conn, uuid); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; + +} + + +/** + * virStoragePoolLookupByUUIDString: + * @conn: pointer to hypervisor connection + * @uuidstr: globally unique id of pool to fetch + * + * Fetch a storage pool based on its globally unique id + * + * Returns a virStoragePoolPtr object, or NULL if no matching pool is found + */ +virStoragePoolPtr +virStoragePoolLookupByUUIDString(virConnectPtr conn, + const char *uuidstr) +{ + unsigned char uuid[VIR_UUID_BUFLEN]; + DEBUG("conn=%p, uuidstr=%s", conn, uuidstr); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (uuidstr == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + if (virUUIDParse(uuidstr, uuid) < 0) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + return virStoragePoolLookupByUUID(conn, uuid); +} + + +/** + * virStoragePoolLookupByVolume: + * @vol: pointer to storage volume + * + * Fetch a storage pool which contains a particular volume + * + * Returns a virStoragePoolPtr object, or NULL if no matching pool is found + */ +virStoragePoolPtr +virStoragePoolLookupByVolume(virStorageVolPtr vol) +{ + DEBUG("vol=%p", vol); + + if (!VIR_IS_STORAGE_VOL(vol)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + + if (vol->conn->storageDriver && vol->conn->storageDriver->poolLookupByVolume) + return vol->conn->storageDriver->poolLookupByVolume (vol); + + virLibConnError (vol->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; + +} + +/** + * virStoragePoolCreateXML: + * @conn: pointer to hypervisor connection + * @xmlDesc: XML description for new pool + * + * Create a new storage based on its XML description. The + * pool is not persitent, so its definition will disappear + * when it is destroyed, or if the host is restarted + * + * Returns a virStoragePoolPtr object, or NULL if creation failed + */ +virStoragePoolPtr +virStoragePoolCreateXML(virConnectPtr conn, + const char *xmlDesc, + unsigned int flags) +{ + DEBUG("conn=%p, xmlDesc=%s", conn, xmlDesc); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (xmlDesc == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + if (conn->flags & VIR_CONNECT_RO) { + virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (NULL); + } + + if (conn->storageDriver && conn->storageDriver->poolCreateXML) + return conn->storageDriver->poolCreateXML (conn, xmlDesc, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + +/** + * virStoragePoolDefineXML: + * @conn: pointer to hypervisor connection + * @xml: XML description for new pool + * + * Define a new inactive storage pool based on its XML description. The + * pool is persitent, until explicitly undefined. + * + * Returns a virStoragePoolPtr object, or NULL if creation failed + */ +virStoragePoolPtr +virStoragePoolDefineXML(virConnectPtr conn, + const char *xml, + unsigned int flags) +{ + DEBUG("conn=%p, xml=%s", conn, xml); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (conn->flags & VIR_CONNECT_RO) { + virLibConnError(conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (NULL); + } + if (xml == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + if (conn->storageDriver && conn->storageDriver->poolDefineXML) + return conn->storageDriver->poolDefineXML (conn, xml, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; + +} + +/** + * virStoragePoolBuild: + * @pool: pointer to storage pool + * + * Build the underlying storage pool + * + * Returns 0 on success, or -1 upon failure + */ +int +virStoragePoolBuild(virStoragePoolPtr pool, + unsigned int flags) +{ + virConnectPtr conn; + DEBUG("pool=%p, flags=%u", pool, flags); + + if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__); + return (-1); + } + conn = pool->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->poolBuild) + return conn->storageDriver->poolBuild (pool, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; + +} + + +/** + * virStoragePoolUndefine: + * @pool: pointer to storage pool + * + * Undefine an inactive storage pool + * + * Returns a virStoragePoolPtr object, or NULL if creation failed + */ +int +virStoragePoolUndefine(virStoragePoolPtr pool) +{ + virConnectPtr conn; + DEBUG("pool=%p", pool); + + if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_NETWORK, __FUNCTION__); + return (-1); + } + conn = pool->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->poolUndefine) + return conn->storageDriver->poolUndefine (pool); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; + +} + + +/** + * virStoragePoolCreate: + * @pool: pointer to storage pool + * + * Starts an inactive storage pool + * + * Returns 0 on success, or -1 if it could not be started + */ +int +virStoragePoolCreate(virStoragePoolPtr pool, + unsigned int flags) +{ + virConnectPtr conn; + DEBUG("pool=%p", pool); + + if (pool == NULL) { + TODO; + return (-1); + } + if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + conn = pool->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->poolCreate) + return conn->storageDriver->poolCreate (pool, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; + +} + + +/** + * virStoragePoolDestroy: + * @pool: pointer to storage pool + * + * Destroy an active storage pool. This will deactivate the + * pool on the host, but keep any persistent config associated + * with it. If it has a persistent config it can later be + * restarted with virStoragePoolCreate(). This does not free + * the associated virStoragePoolPtr object. + * + * Returns 0 on success, or -1 if it could not be destroyed + */ +int +virStoragePoolDestroy(virStoragePoolPtr pool) +{ + virConnectPtr conn; + DEBUG("pool=%p", pool); + + if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + + conn = pool->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->poolDestroy) + return conn->storageDriver->poolDestroy (pool); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + +/** + * virStoragePoolDelete: + * @pool: pointer to storage pool + * @flags: flags for obliteration process + * + * Delete the underlying pool resources. This is + * a non-recoverable operation. The virStoragePoolPtr object + * itself is not free'd. + * + * Returns 0 on success, or -1 if it could not be obliterate + */ +int +virStoragePoolDelete(virStoragePoolPtr pool, + unsigned int flags) +{ + virConnectPtr conn; + DEBUG("pool=%p, flags=%u", pool, flags); + + if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + + conn = pool->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->poolDelete) + return conn->storageDriver->poolDelete (pool, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virStoragePoolFree: + * @pool: pointer to storage pool + * + * Free a storage pool object, releasing all memory associated with + * it. Does not change the state of the pool on the host. + * + * Returns 0 on success, or -1 if it could not be free'd. + */ +int +virStoragePoolFree(virStoragePoolPtr pool) +{ + DEBUG("pool=%p", pool); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + if (virUnrefStoragePool(pool) < 0) + return (-1); + return(0); + +} + + +/** + * virStoragePoolRefresh: + * @pool: pointer to storage pool + * @flags: flags to control refresh behaviour (currently unused, use 0) + * + * Request that the pool refresh its list of volumes. This may + * involve communicating with a remote server, and/or initializing + * new devices at the OS layer + * + * Return 0 if the volume list was refreshed, -1 on failure + */ +int +virStoragePoolRefresh(virStoragePoolPtr pool, + unsigned int flags) +{ + virConnectPtr conn; + DEBUG("pool=%p flags=%u", pool, flags); + + if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + + conn = pool->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibStoragePoolError(pool, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->poolRefresh) + return conn->storageDriver->poolRefresh (pool, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virStoragePoolGetName: + * @pool: pointer to storage pool + * + * Fetch the locally unique name of the storage pool + * + * Return the name of the pool, or NULL on error + */ +const char* +virStoragePoolGetName(virStoragePoolPtr pool) +{ + DEBUG("pool=%p", pool); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (NULL); + } + return (pool->name); + +} + + +/** + * virStoragePoolGetUUID: + * @pool: pointer to storage pool + * @uuid: buffer of VIR_UUID_BUFLEN bytes in size + * + * Fetch the globally unique ID of the storage pool + * + * Return 0 on success, or -1 on error; + */ +int +virStoragePoolGetUUID(virStoragePoolPtr pool, + unsigned char *uuid) +{ + DEBUG("pool=%p, uuid=%p", pool, uuid); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + if (uuid == NULL) { + virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + memcpy(uuid, &pool->uuid[0], VIR_UUID_BUFLEN); + + return (0); + +} + +/** + * virStoragePoolGetUUIDString: + * @pool: pointer to storage pool + * @buf: buffer of VIR_UUID_STRING_BUFLEN bytes in size + * + * Fetch the globally unique ID of the storage pool as a string + * + * Return 0 on success, or -1 on error; + */ +int +virStoragePoolGetUUIDString(virStoragePoolPtr pool, + char *buf) +{ + unsigned char uuid[VIR_UUID_BUFLEN]; + DEBUG("pool=%p, buf=%p", pool, buf); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + if (buf == NULL) { + virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if (virStoragePoolGetUUID(pool, &uuid[0])) + return (-1); + + virUUIDFormat(uuid, buf); + return (0); + +} + + +/** + * virStoragePoolGetInfo: + * @pool: pointer to storage pool + * @info: pointer at which to store info + * + * Get volatile information about the storage pool + * such as free space / usage summary + * + * returns 0 on success, or -1 on failure. + */ +int +virStoragePoolGetInfo(virStoragePoolPtr pool, + virStoragePoolInfoPtr info) +{ + virConnectPtr conn; + DEBUG("pool=%p, info=%p", pool, info); + + if (!VIR_IS_CONNECTED_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + if (info == NULL) { + virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + memset(info, 0, sizeof(virStoragePoolInfo)); + + conn = pool->conn; + + if (conn->storageDriver->poolGetInfo) + return conn->storageDriver->poolGetInfo (pool, info); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; + +} + + +/** + * virStoragePoolGetXMLDesc: + * @pool: pointer to storage pool + * @flags: flags for XML format options (unused, pass 0) + * + * Fetch an XML document describing all aspects of the + * storage pool. This is suitable for later feeding back + * into the virStoragePoolCreateXML method. + * + * returns a XML document, or NULL on error + */ +char * +virStoragePoolGetXMLDesc(virStoragePoolPtr pool, + unsigned int flags) +{ + virConnectPtr conn; + DEBUG("pool=%p, flags=%u", pool, flags); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (NULL); + } + if (flags != 0) { + virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + conn = pool->conn; + + if (conn->storageDriver && conn->storageDriver->poolGetXMLDesc) + return conn->storageDriver->poolGetXMLDesc (pool, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; + +} + + +/** + * virStoragePoolGetAutostart: + * @pool: pointer to storage pool + * @autostart: location in which to store autostart flag + * + * Fetches the value of the autostart flag, which determines + * whether the pool is automatically started at boot time + * + * return 0 on success, -1 on failure + */ +int +virStoragePoolGetAutostart(virStoragePoolPtr pool, + int *autostart) +{ + virConnectPtr conn; + DEBUG("pool=%p, autostart=%p", pool, autostart); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + if (!autostart) { + virLibStoragePoolError(pool, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + conn = pool->conn; + + if (conn->storageDriver && conn->storageDriver->poolGetAutostart) + return conn->storageDriver->poolGetAutostart (pool, autostart); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virStoragePoolSetAutostart: + * @pool: pointer to storage pool + * @autostart: new flag setting + * + * Sets the autostart flag + * + * returns 0 on success, -1 on failure + */ +int +virStoragePoolSetAutostart(virStoragePoolPtr pool, + int autostart) +{ + virConnectPtr conn; + DEBUG("pool=%p, autostart=%d", pool, autostart); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibStoragePoolError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + + conn = pool->conn; + + if (conn->storageDriver && conn->storageDriver->poolSetAutostart) + return conn->storageDriver->poolSetAutostart (pool, autostart); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virStoragePoolNumOfVolumes: + * @pool: pointer to storage pool + * + * Fetch the number of storage volumes within a pool + * + * Returns the number of storage pools, or -1 on failure + */ +int +virStoragePoolNumOfVolumes(virStoragePoolPtr pool) +{ + DEBUG("pool=%p", pool); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibConnError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + + if (pool->conn->storageDriver && pool->conn->storageDriver->poolNumOfVolumes) + return pool->conn->storageDriver->poolNumOfVolumes (pool); + + virLibConnError (pool->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virStoragePoolListVolumes: + * @pool: pointer to storage pool + * @names: array in which to storage volume names + * @maxnames: size of names array + * + * Fetch list of storage volume names, limiting to + * at most maxnames. + * + * Returns the number of names fetched, or -1 on error + */ +int +virStoragePoolListVolumes(virStoragePoolPtr pool, + char **const names, + int maxnames) +{ + DEBUG("pool=%p, names=%p, maxnames=%d", pool, names, maxnames); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibConnError(NULL, VIR_ERR_INVALID_STORAGE_POOL, __FUNCTION__); + return (-1); + } + + if ((names == NULL) || (maxnames < 0)) { + virLibConnError(pool->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + if (pool->conn->storageDriver && pool->conn->storageDriver->poolListVolumes) + return pool->conn->storageDriver->poolListVolumes (pool, names, maxnames); + + virLibConnError (pool->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virStorageVolGetConnect: + * @vol: pointer to a poool + * + * Provides the connection pointer associated with a storage volume. The + * reference counter on the connection is not increased by this + * call. + * + * WARNING: When writing libvirt bindings in other languages, do + * not use this function. Instead, store the connection and + * the volume object together. + * + * Returns the virConnectPtr or NULL in case of failure. + */ +virConnectPtr +virStorageVolGetConnect (virStorageVolPtr vol) +{ + DEBUG("vol=%p", vol); + + if (!VIR_IS_STORAGE_VOL (vol)) { + virLibStoragePoolError (NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return NULL; + } + return vol->conn; +} + + +/** + * virStorageVolLookupByName: + * @pool: pointer to storage pool + * @name: name of storage volume + * + * Fetch a pointer to a storage volume based on its name + * within a pool + * + * return a storage volume, or NULL if not found / error + */ +virStorageVolPtr +virStorageVolLookupByName(virStoragePoolPtr pool, + const char *name) +{ + DEBUG("pool=%p, name=%s", pool, name); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (name == NULL) { + virLibConnError(pool->conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + if (pool->conn->storageDriver && pool->conn->storageDriver->volLookupByName) + return pool->conn->storageDriver->volLookupByName (pool, name); + + virLibConnError (pool->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + + + +/** + * virStorageVolLookupByKey: + * @conn: pointer to hypervisor connection + * @key: globally unique key + * + * Fetch a pointer to a storage volume based on its + * globally unique key + * + * return a storage volume, or NULL if not found / error + */ +virStorageVolPtr +virStorageVolLookupByKey(virConnectPtr conn, + const char *key) +{ + DEBUG("conn=%p, key=%s", conn, key); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (key == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + if (conn->storageDriver && conn->storageDriver->volLookupByKey) + return conn->storageDriver->volLookupByKey (conn, key); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + +/** + * virStorageVolLookupByPath: + * @conn: pointer to hypervisor connection + * @path: locally unique path + * + * Fetch a pointer to a storage volume based on its + * locally (host) unique path + * + * return a storage volume, or NULL if not found / error + */ +virStorageVolPtr +virStorageVolLookupByPath(virConnectPtr conn, + const char *path) +{ + DEBUG("conn=%p, path=%s", conn, path); + + if (!VIR_IS_CONNECT(conn)) { + virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__); + return (NULL); + } + if (path == NULL) { + virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + if (conn->storageDriver && conn->storageDriver->volLookupByPath) + return conn->storageDriver->volLookupByPath (conn, path); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + + +/** + * virStorageVolGetName: + * @vol: pointer to storage volume + * + * Fetch the storage volume name. This is unique + * within the scope of a pool + * + * return the volume name, or NULL on error + */ +const char* +virStorageVolGetName(virStorageVolPtr vol) +{ + DEBUG("vol=%p", vol); + + if (!VIR_IS_STORAGE_VOL(vol)) { + virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (NULL); + } + return (vol->name); +} + + +/** + * virStorageVolGetKey: + * @vol: pointer to storage volume + * + * Fetch the storage volume key. This is globally + * unique, so the same volume will hve the same + * key no matter what host it is accessed from + * + * return the volume key, or NULL on error + */ +const char* +virStorageVolGetKey(virStorageVolPtr vol) +{ + DEBUG("vol=%p", vol); + + if (!VIR_IS_STORAGE_VOL(vol)) { + virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (NULL); + } + return (vol->key); +} + + +/** + * virStorageVolCreateXML: + * @pool: pointer to storage pool + * @xmldesc: description of volume to create + * @flags: flags for creation (unused, pass 0) + * + * Create a storage volume within a pool based + * on an XML description. Not all pools support + * creation of volumes + * + * return the storage volume, or NULL on error + */ +virStorageVolPtr +virStorageVolCreateXML(virStoragePoolPtr pool, + const char *xmldesc, + unsigned int flags) +{ + DEBUG("pool=%p, flags=%u", pool, flags); + + if (!VIR_IS_STORAGE_POOL(pool)) { + virLibConnError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (NULL); + } + + if (pool->conn->flags & VIR_CONNECT_RO) { + virLibConnError(pool->conn, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (NULL); + } + + if (pool->conn->storageDriver && pool->conn->storageDriver->volCreateXML) + return pool->conn->storageDriver->volCreateXML (pool, xmldesc, flags); + + virLibConnError (pool->conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + + +/** + * virStorageVolDelete: + * @vol: pointer to storage volume + * + * Delete the storage volume from the pool + * + * Return 0 on success, or -1 on error + */ +int +virStorageVolDelete(virStorageVolPtr vol, + unsigned int flags) +{ + virConnectPtr conn; + DEBUG("vol=%p, flags=%u", vol, flags); + + if (!VIR_IS_CONNECTED_STORAGE_VOL(vol)) { + virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (-1); + } + + conn = vol->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibStorageVolError(vol, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + return (-1); + } + + if (conn->storageDriver && conn->storageDriver->volDelete) + return conn->storageDriver->volDelete (vol, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virStorageVolFree: + * @vol: pointer to storage volume + * + * Release the storage volume handle. The underlying + * storage volume contains to exist + * + * Return 0 on success, or -1 on error + */ +int +virStorageVolFree(virStorageVolPtr vol) +{ + DEBUG("vol=%p", vol); + + if (!VIR_IS_STORAGE_VOL(vol)) { + virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (-1); + } + if (virUnrefStorageVol(vol) < 0) + return (-1); + return(0); +} + + +/** + * virStorageVolGetInfo: + * @vol: pointer to storage volume + * @info: pointer at which to store info + * + * Fetches volatile information about the storage + * volume such as its current allocation + * + * Return 0 on success, or -1 on failure + */ +int +virStorageVolGetInfo(virStorageVolPtr vol, + virStorageVolInfoPtr info) +{ + virConnectPtr conn; + DEBUG("vol=%p, info=%p", vol, info); + + if (!VIR_IS_CONNECTED_STORAGE_VOL(vol)) { + virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (-1); + } + if (info == NULL) { + virLibStorageVolError(vol, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (-1); + } + + memset(info, 0, sizeof(virStorageVolInfo)); + + conn = vol->conn; + + if (conn->storageDriver->volGetInfo) + return conn->storageDriver->volGetInfo (vol, info); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return -1; +} + + +/** + * virStorageVolGetXMLDesc: + * @vol: pointer to storage volume + * @flags: flags for XML generation (unused, pass 0) + * + * Fetch an XML document describing all aspects of + * the storage volume + * + * Return the XML document, or NULL on error + */ +char * +virStorageVolGetXMLDesc(virStorageVolPtr vol, + unsigned int flags) +{ + virConnectPtr conn; + DEBUG("vol=%p, flags=%u", vol, flags); + + if (!VIR_IS_STORAGE_VOL(vol)) { + virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (NULL); + } + if (flags != 0) { + virLibStorageVolError(vol, VIR_ERR_INVALID_ARG, __FUNCTION__); + return (NULL); + } + + conn = vol->conn; + + if (conn->storageDriver && conn->storageDriver->volGetXMLDesc) + return conn->storageDriver->volGetXMLDesc (vol, flags); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; + +} + + +/** + * virStorageVolGetPath: + * @vol: pointer to storage volume + * + * Fetch the storage volume path. Depending on the pool + * configuration this is either persistent across hosts, + * or dynamically assigned at pool startup. Consult + * pool documentation for information on getting the + * persistent naming + * + * Returns the storage volume path, or NULL on error + */ +char * +virStorageVolGetPath(virStorageVolPtr vol) +{ + virConnectPtr conn; + DEBUG("vol=%p", vol); + + if (!VIR_IS_STORAGE_VOL(vol)) { + virLibStorageVolError(NULL, VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__); + return (NULL); + } + + conn = vol->conn; + + if (conn->storageDriver && conn->storageDriver->volGetPath) + return conn->storageDriver->volGetPath (vol); + + virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + return NULL; +} + + /* * vim: set tabstop=4: * vim: set shiftwidth=4: diff --git a/src/virterror.c b/src/virterror.c index 84399e212b..2629c37fc9 100644 --- a/src/virterror.c +++ b/src/virterror.c @@ -296,6 +296,9 @@ virDefaultErrorFunc(virErrorPtr err) case VIR_FROM_STATS_LINUX: dom = "Linux Stats "; break; + case VIR_FROM_STORAGE: + dom = "Storage "; + break; } if ((err->dom != NULL) && (err->code != VIR_ERR_INVALID_DOMAIN)) { @@ -675,6 +678,24 @@ __virErrorMsg(virErrorNumber error, const char *info) else errmsg = _("authentication failed: %s"); break; + case VIR_ERR_INVALID_STORAGE_POOL: + if (info == NULL) + errmsg = _("invalid storage pool pointer in"); + else + errmsg = _("invalid storage pool pointer in %s"); + break; + case VIR_ERR_INVALID_STORAGE_VOL: + if (info == NULL) + errmsg = _("invalid storage volume pointer in"); + else + errmsg = _("invalid storage volume pointer in %s"); + break; + case VIR_WAR_NO_STORAGE: + if (info == NULL) + errmsg = _("Failed to find a storage driver"); + else + errmsg = _("Failed to find a storage driver: %s"); + break; } return (errmsg); }