[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: [Libvir] PATCH: 2/16: Internal driver API



On Tue, Feb 12, 2008 at 04:30:45AM +0000, Daniel P. Berrange wrote:
> This defines the internal driver API for the storage APIs. The
> pattern follows that used for the existing APIs. NB,  both the
> storage pool and storage volume objects are now top level objects.
> Previous iterations of this code have the volume as a child of
> the pool. This unneccessarily complicated the reference counting
> and forced you to always have a pool available first.

 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 
 6 files changed, 1921 insertions(+), 2 deletions(-)


diff -r ebc0562abcea include/libvirt/virterror.h
--- a/include/libvirt/virterror.h	Thu Feb 14 15:58:47 2008 -0500
+++ b/include/libvirt/virterror.h	Thu Feb 14 16:04:16 2008 -0500
@@ -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 -r ebc0562abcea src/driver.h
--- a/src/driver.h	Thu Feb 14 15:58:47 2008 -0500
+++ b/src/driver.h	Thu Feb 14 16:04:16 2008 -0500
@@ -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 -r ebc0562abcea src/hash.c
--- a/src/hash.c	Thu Feb 14 15:58:47 2008 -0500
+++ b/src/hash.c	Thu Feb 14 16:04:16 2008 -0500
@@ -652,6 +652,34 @@ virNetworkFreeName(virNetworkPtr 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:
  *
  * Allocates a new hypervisor connection structure
@@ -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 -r ebc0562abcea src/internal.h
--- a/src/internal.h	Thu Feb 14 15:58:47 2008 -0500
+++ b/src/internal.h	Thu Feb 14 16:04:16 2008 -0500
@@ -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,11 +130,31 @@ 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 */
 };
 
@@ -205,6 +229,34 @@ struct _virNetwork {
     virConnectPtr conn;                  /* pointer back to the connection */
     char *name;                          /* the network external name */
     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 (virConne
                                 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 -r ebc0562abcea src/libvirt.c
--- a/src/libvirt.c	Thu Feb 14 15:58:47 2008 -0500
+++ b/src/libvirt.c	Thu Feb 14 16:04:16 2008 -0500
@@ -51,6 +51,8 @@ static int virDriverTabCount = 0;
 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;
@@ -317,6 +319,58 @@ virLibNetworkError(virNetworkPtr network
 }
 
 /**
+ * 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
  *
@@ -342,6 +396,34 @@ virRegisterNetworkDriver(virNetworkDrive
 
     virNetworkDriverTab[virNetworkDriverTabCount] = 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++;
 }
 
 /**
@@ -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 net
     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 -r ebc0562abcea src/virterror.c
--- a/src/virterror.c	Thu Feb 14 15:58:47 2008 -0500
+++ b/src/virterror.c	Thu Feb 14 16:04:16 2008 -0500
@@ -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, cons
 	    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);
 }


-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]