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

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



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                |  150 ++++
 src/hash.c                  |  317 +++++++++
 src/internal.h              |   68 ++
 src/libvirt.c               | 1403 ++++++++++++++++++++++++++++++++++++++++++++
 src/virterror.c             |   21 
 6 files changed, 1961 insertions(+), 5 deletions(-)

diff -r 42e6f49e4e69 include/libvirt/virterror.h
--- a/include/libvirt/virterror.h	Thu Feb 07 12:33:13 2008 -0500
+++ b/include/libvirt/virterror.h	Thu Feb 07 16:52:34 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 42e6f49e4e69 src/driver.h
--- a/src/driver.h	Thu Feb 07 12:33:13 2008 -0500
+++ b/src/driver.h	Thu Feb 07 16:52:34 2008 -0500
@@ -473,6 +473,155 @@ 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 int
+    (*virDrvConnectDiscoverStoragePools)     (virConnectPtr conn,
+                                              const char *hostname,
+                                              const char *type,
+                                              unsigned int flags,
+                                              char ***xmlDesc);
+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);
+typedef virStoragePoolPtr
+    (*virDrvStoragePoolDefineXML)            (virConnectPtr conn,
+                                              const char *xmlDesc);
+typedef int
+    (*virDrvStoragePoolUndefine)             (virStoragePoolPtr pool);
+typedef int
+    (*virDrvStoragePoolBuild)                (virStoragePoolPtr pool,
+                                              unsigned int flags);
+typedef int
+    (*virDrvStoragePoolCreate)               (virStoragePoolPtr pool);
+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;
+    virDrvConnectDiscoverStoragePools discoverPools;
+    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);
@@ -495,6 +644,7 @@ struct _virStateDriver {
  */
 int virRegisterDriver(virDriverPtr);
 int virRegisterNetworkDriver(virNetworkDriverPtr);
+int virRegisterStorageDriver(virStorageDriverPtr);
 int virRegisterStateDriver(virStateDriverPtr);
 
 #ifdef __cplusplus
diff -r 42e6f49e4e69 src/hash.c
--- a/src/hash.c	Thu Feb 07 12:33:13 2008 -0500
+++ b/src/hash.c	Thu Feb 07 16:52:34 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 42e6f49e4e69 src/internal.h
--- a/src/internal.h	Thu Feb 07 12:33:13 2008 -0500
+++ b/src/internal.h	Thu Feb 07 16:52:34 2008 -0500
@@ -130,7 +130,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)
@@ -140,11 +140,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
@@ -165,6 +185,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.
@@ -172,6 +193,7 @@ struct _virConnect {
      */
     void *            privateData;
     void *            networkPrivateData;
+    void *            storagePrivateData;
 
     /* Per-connection error. */
     virError err;           /* the last error */
@@ -187,6 +209,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 */
     virJobPtr jobs;           /* list of active background jobs */
     int refs;                 /* reference count */
 };
@@ -216,6 +240,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 */
+};
+
+/**
+* _virNetwork:
+*
+* 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 */
+};
+
+/**
+* _virNetwork:
+*
+* 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 */
 };
 
 
@@ -265,8 +317,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 42e6f49e4e69 src/libvirt.c
--- a/src/libvirt.c	Thu Feb 07 12:33:13 2008 -0500
+++ b/src/libvirt.c	Thu Feb 07 16:52:34 2008 -0500
@@ -52,6 +52,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;
@@ -318,6 +320,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
  *
@@ -343,6 +397,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++;
 }
 
 /**
@@ -613,6 +695,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;
 
@@ -708,6 +813,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)
@@ -4052,6 +4159,1302 @@ virNetworkSetAutostart(virNetworkPtr net
     return -1;
 }
 
+
+/**
+ * virStoragePoolGetConnect:
+ * @pool: pointer to a poool
+ *
+ * Provides the connection pointer associated with a storage poolk.  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;
+}
+
+
+/**
+ * virConnectDiscoverStoragePools:
+ * @conn: pointer to hypervisor connection
+ * @hostname: host to discover pools on
+ * @type: type of storge pool to discover
+ * @flags: flags for discovery (unused, pass 0)
+ * @xmlDesc: return array of of XML documents, one per pool
+ *
+ * Talks to a host and attempt to auto-discover a set
+ * of exported storage pools available. eg For iSCSI this
+ * would be a set of iSCSI targets. For NFS this would be
+ * a list of exported paths.
+ *
+ * Each discovered pool is returned as an XML document
+ * suitable for feeding into virStoragePoolCreateXML
+ *
+ * returns number of discovered pools, or -1 on error
+ */
+int
+virConnectDiscoverStoragePools(virConnectPtr conn,
+                               const char *hostname,
+						       const char *type,
+                               unsigned int flags,
+						       char ***xmlDesc)
+{
+    DEBUG("conn=%p, host=%s, type=%s, flags=%d, xml=%p", conn, hostname, type, flags, xmlDesc);
+
+    if (!VIR_IS_CONNECT(conn)) {
+        virLibConnError(NULL, VIR_ERR_INVALID_CONN, __FUNCTION__);
+        return (-1);
+    }
+    if (hostname == NULL || type == NULL || xmlDesc == NULL) {
+        virLibConnError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
+        return (-1);
+    }
+
+    if (conn->storageDriver && conn->storageDriver->discoverPools)
+        return conn->storageDriver->discoverPools (conn, hostname, type, flags, xmlDesc);
+
+    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)
+{
+    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);
+
+    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)
+{
+    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);
+
+    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)
+{
+    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);
+
+    virLibConnError (conn, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return -1;
+
+}
+
+
+/**
+ * virStoragePoolDestroy:
+ * @pool: pointer to storage pool
+ *
+ * Destroy an active storage pool. The virStoragePoolPtr
+ * object should not be used after this method returns
+ * successfully as it has been free'd
+ *
+ * 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.
+ *
+ * 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
+ *
+ * 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 poolk.  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
+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 42e6f49e4e69 src/virterror.c
--- a/src/virterror.c	Thu Feb 07 12:33:13 2008 -0500
+++ b/src/virterror.c	Thu Feb 07 16:52:34 2008 -0500
@@ -258,6 +258,9 @@ virDefaultErrorFunc(virErrorPtr err)
             break;
         case VIR_FROM_STATS_LINUX:
             dom = "Linux Stats ";
+            break;
+        case VIR_FROM_STORAGE:
+            dom = "Storage ";
             break;
 
     }
@@ -665,6 +668,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]