]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Storage driver implementation for CreateXMLFrom
authorCole Robinson <crobinso@redhat.com>
Tue, 19 May 2009 13:37:51 +0000 (13:37 +0000)
committerCole Robinson <crobinso@redhat.com>
Tue, 19 May 2009 13:37:51 +0000 (13:37 +0000)
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.

ChangeLog
src/storage_backend.h
src/storage_driver.c

index 12d5d314fdea1a6b138f66baf03f101c1a6f3c9b..475ac00a3b5faf1efe7c8e0f8e9d07a2046666dd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Tue May 19 09:36:48 EDT 2009 Cole Robinson <crobinso@redhat.com>
+
+       * src/storage_backend.h src/storage_driver.c: Storage driver
+       implementation for CreateXMLFrom
+
 Tue May 19 09:26:53 EDT 2009 Cole Robinson <crobinso@redhat.com>
 
        * src/node_device_hal.c: Fix node device media insert/eject
index c9c1e35af2e82083bdf24861505659f776fb6cf5..7bf8814d3e2163b134d740f475c476e6f47a21c5 100644 (file)
@@ -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;
index c2de6fa8b317dd24c3bb1b9c1524d533cabd8e62..48c3bca15f80a9cf4d5e0ea1699d21133d3bcff6 100644 (file)
@@ -1306,6 +1306,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) {
@@ -1526,10 +1680,6 @@ cleanup:
     return ret;
 }
 
-
-
-
-
 static virStorageDriver storageDriver = {
     .name = "storage",
     .open = storageOpen,
@@ -1561,6 +1711,7 @@ static virStorageDriver storageDriver = {
     .volLookupByKey = storageVolumeLookupByKey,
     .volLookupByPath = storageVolumeLookupByPath,
     .volCreateXML = storageVolumeCreateXML,
+    .volCreateXMLFrom = storageVolumeCreateXMLFrom,
     .volDelete = storageVolumeDelete,
     .volGetInfo = storageVolumeGetInfo,
     .volGetXMLDesc = storageVolumeGetXMLDesc,