Storage driver implementation for CreateXMLFrom

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.
This commit is contained in:
Cole Robinson 2009-05-19 13:37:51 +00:00
parent 5f99a7fd23
commit 4aa0959d60
3 changed files with 162 additions and 4 deletions

View File

@ -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

View 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;

View 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,