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 -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list