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