mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-26 18:41:17 +00:00
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:
parent
5f99a7fd23
commit
4aa0959d60
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user