[libvirt] [PATCH v2 1/2] Storage driver implementation for CreateXMLFrom

Cole Robinson crobinso at redhat.com
Mon May 18 17:30:32 UTC 2009


There is some funkiness here, since we are either dealing with 2 different
pools (which means validation x 2) or the same pool, where we have to be
careful not to deadlock.
---
 src/storage_backend.h |    2 +
 src/storage_driver.c  |  159 +++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 157 insertions(+), 4 deletions(-)

diff --git a/src/storage_backend.h b/src/storage_backend.h
index c9c1e35..7bf8814 100644
--- a/src/storage_backend.h
+++ b/src/storage_backend.h
@@ -38,6 +38,7 @@ typedef int (*virStorageBackendBuildVol)(virConnectPtr conn, virStorageVolDefPtr
 typedef int (*virStorageBackendCreateVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol);
 typedef int (*virStorageBackendRefreshVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol);
 typedef int (*virStorageBackendDeleteVol)(virConnectPtr conn, virStoragePoolObjPtr pool, virStorageVolDefPtr vol, unsigned int flags);
+typedef int (*virStorageBackendBuildVolFrom)(virConnectPtr conn, virStorageVolDefPtr origvol, virStorageVolDefPtr newvol, unsigned int flags);
 
 
 typedef struct _virStorageBackend virStorageBackend;
@@ -54,6 +55,7 @@ struct _virStorageBackend {
     virStorageBackendDeletePool deletePool;
 
     virStorageBackendBuildVol buildVol;
+    virStorageBackendBuildVolFrom buildVolFrom;
     virStorageBackendCreateVol createVol;
     virStorageBackendRefreshVol refreshVol;
     virStorageBackendDeleteVol deleteVol;
diff --git a/src/storage_driver.c b/src/storage_driver.c
index b72f0a0..807fd1d 100644
--- a/src/storage_driver.c
+++ b/src/storage_driver.c
@@ -1303,6 +1303,160 @@ cleanup:
     return ret;
 }
 
+static virStorageVolPtr
+storageVolumeCreateXMLFrom(virStoragePoolPtr obj,
+                           const char *xmldesc,
+                           virStorageVolPtr vobj,
+                           unsigned int flags ATTRIBUTE_UNUSED) {
+    virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
+    virStoragePoolObjPtr pool, origpool = NULL;
+    virStorageBackendPtr backend;
+    virStorageVolDefPtr origvol = NULL, newvol = NULL;
+    virStorageVolPtr ret = NULL, volobj = NULL;
+    int buildret, diffpool;
+
+    diffpool = !STREQ(obj->name, vobj->pool);
+
+    storageDriverLock(driver);
+    pool = virStoragePoolObjFindByUUID(&driver->pools, obj->uuid);
+    if (diffpool)
+        origpool = virStoragePoolObjFindByName(&driver->pools, vobj->pool);
+    else
+        origpool = pool;
+    storageDriverUnlock(driver);
+
+    if (!pool) {
+        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "%s", _("no storage pool with matching uuid"));
+        goto cleanup;
+    }
+
+    if (diffpool && !origpool) {
+        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "%s", _("no storage pool with matching name"));
+        goto cleanup;
+    }
+
+    if (!virStoragePoolObjIsActive(pool)) {
+        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+                              "%s", _("storage pool is not active"));
+        goto cleanup;
+    }
+
+    if (diffpool && !virStoragePoolObjIsActive(origpool)) {
+        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+                              "%s", _("storage pool is not active"));
+        goto cleanup;
+    }
+
+    if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
+        goto cleanup;
+
+    origvol = virStorageVolDefFindByName(origpool, vobj->name);
+    if (!origvol) {
+        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              "%s", _("no storage vol with matching name"));
+        goto cleanup;
+    }
+
+    newvol = virStorageVolDefParse(obj->conn, pool->def, xmldesc, NULL);
+    if (newvol == NULL)
+        goto cleanup;
+
+    if (virStorageVolDefFindByName(pool, newvol->name)) {
+        virStorageReportError(obj->conn, VIR_ERR_INVALID_STORAGE_POOL,
+                              _("storage volume name '%s' already in use."),
+                              newvol->name);
+        goto cleanup;
+    }
+
+    /* Is there ever a valid case for this? */
+    if (newvol->capacity < origvol->capacity)
+        newvol->capacity = origvol->capacity;
+
+    if (!backend->buildVolFrom) {
+        virStorageReportError(obj->conn, VIR_ERR_NO_SUPPORT,
+                              "%s", _("storage pool does not support volume creation from an existing volume"));
+        goto cleanup;
+    }
+
+    if (origvol->building) {
+        virStorageReportError(obj->conn, VIR_ERR_INTERNAL_ERROR,
+                              _("volume '%s' is still being allocated."),
+                              origvol->name);
+        goto cleanup;
+    }
+
+    if (backend->refreshVol &&
+        backend->refreshVol(obj->conn, pool, origvol) < 0)
+        goto cleanup;
+
+    if (VIR_REALLOC_N(pool->volumes.objs,
+                      pool->volumes.count+1) < 0) {
+        virReportOOMError(obj->conn);
+        goto cleanup;
+    }
+
+    /* 'Define' the new volume so we get async progress reporting */
+    if (backend->createVol(obj->conn, pool, newvol) < 0) {
+        goto cleanup;
+    }
+
+    pool->volumes.objs[pool->volumes.count++] = newvol;
+    volobj = virGetStorageVol(obj->conn, pool->def->name, newvol->name,
+                              newvol->key);
+
+    /* Drop the pool lock during volume allocation */
+    pool->asyncjobs++;
+    origvol->building = 1;
+    newvol->building = 1;
+    virStoragePoolObjUnlock(pool);
+
+    if (diffpool) {
+        origpool->asyncjobs++;
+        virStoragePoolObjUnlock(origpool);
+    }
+
+    buildret = backend->buildVolFrom(obj->conn, newvol, origvol, flags);
+
+    storageDriverLock(driver);
+    virStoragePoolObjLock(pool);
+    if (diffpool)
+        virStoragePoolObjLock(origpool);
+    storageDriverUnlock(driver);
+
+    origvol->building = 0;
+    newvol->building = 0;
+    newvol = NULL;
+    pool->asyncjobs--;
+
+    if (diffpool) {
+        origpool->asyncjobs--;
+        virStoragePoolObjUnlock(origpool);
+        origpool = NULL;
+    }
+
+    if (buildret < 0) {
+        virStoragePoolObjUnlock(pool);
+        storageVolumeDelete(volobj, 0);
+        pool = NULL;
+        goto cleanup;
+    }
+
+    ret = volobj;
+    volobj = NULL;
+
+cleanup:
+    if (volobj)
+        virUnrefStorageVol(volobj);
+    virStorageVolDefFree(newvol);
+    if (pool)
+        virStoragePoolObjUnlock(pool);
+    if (diffpool && origpool)
+        virStoragePoolObjUnlock(origpool);
+    return ret;
+}
+
 static int
 storageVolumeDelete(virStorageVolPtr obj,
                     unsigned int flags) {
@@ -1523,10 +1677,6 @@ cleanup:
     return ret;
 }
 
-
-
-
-
 static virStorageDriver storageDriver = {
     .name = "storage",
     .open = storageOpen,
@@ -1558,6 +1708,7 @@ static virStorageDriver storageDriver = {
     .volLookupByKey = storageVolumeLookupByKey,
     .volLookupByPath = storageVolumeLookupByPath,
     .volCreateXML = storageVolumeCreateXML,
+    .volCreateXMLFrom = storageVolumeCreateXMLFrom,
     .volDelete = storageVolumeDelete,
     .volGetInfo = storageVolumeGetInfo,
     .volGetXMLDesc = storageVolumeGetXMLDesc,
-- 
1.6.2.2




More information about the libvir-list mailing list