https://bugzilla.redhat.com/show_bug.cgi?id=1072653 Upon successful upload of a volume, the target volume and storage pool were not updated to reflect any changes as a result of the upload. Make use of the existing stream close callback mechanism to force a backend pool refresh to occur once the stream closes. Signed-off-by: John Ferlan <jferlan@xxxxxxxxxx> --- src/libvirt.c | 8 +++++ src/libvirt_private.syms | 1 + src/storage/storage_driver.c | 78 ++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 3 ++ 4 files changed, 90 insertions(+) diff --git a/src/libvirt.c b/src/libvirt.c index 143d319..992e4f2 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -13960,6 +13960,14 @@ virStorageVolDownload(virStorageVolPtr vol, * detect any errors. The results will be unpredictable if * another active stream is writing to the storage volume. * + * When the data stream is closed whether the upload is successful + * or not the target storage pool will be refreshed to reflect pool + * and volume changes as a result of the upload. Depending on + * the target volume storage backend and the source stream type + * for a successful upload, the target volume may take on the + * characteristics from the source stream such as format type, + * capacity, and allocation. + * * Returns 0, or -1 upon error. */ int diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index b1fb7c9..7ef68a1 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -825,6 +825,7 @@ virFDStreamCreateFile; virFDStreamOpen; virFDStreamOpenFile; virFDStreamOpenPTY; +virFDStreamSetInternalCloseCb; # libvirt_internal.h diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c index efbe5ff..5fd5514 100644 --- a/src/storage/storage_driver.c +++ b/src/storage/storage_driver.c @@ -59,6 +59,12 @@ static virStorageDriverStatePtr driverState; static int storageStateCleanup(void); +typedef struct _virStorageVolStreamInfo virStorageVolStreamInfo; +typedef virStorageVolStreamInfo *virStorageVolStreamInfoPtr; +struct _virStorageVolStreamInfo { + char *pool_name; +}; + static void storageDriverLock(virStorageDriverStatePtr driver) { virMutexLock(&driver->lock); @@ -1956,6 +1962,52 @@ storageVolDownload(virStorageVolPtr obj, } +/** + * Frees opaque data provided for the stream closing callback + * + * @opaque Data to be freed. + */ +static void virStorageVolFDStreamCloseCbFree(void *opaque) +{ + virStorageVolStreamInfoPtr cbdata = opaque; + + VIR_FREE(cbdata->pool_name); + VIR_FREE(cbdata); +} + +/** + * Callback being called if a FDstream is closed. Frees device entries + * from data structures and removes lockfiles. + * + * @st Pointer to stream being closed. + * @opaque Domain's device information structure. + */ +static void virStorageVolFDStreamCloseCb(virStreamPtr st ATTRIBUTE_UNUSED, + void *opaque) +{ + + virStorageVolStreamInfoPtr cbdata = opaque; + virStoragePoolObjPtr pool = NULL; + virStorageBackendPtr backend; + + storageDriverLock(driverState); + if (!(pool = virStoragePoolObjFindByName(&driverState->pools, + cbdata->pool_name))) + goto cleanup; + + if (!(backend = virStorageBackendForType(pool->def->type))) + goto cleanup; + + virStoragePoolObjClearVols(pool); + if (backend->refreshPool(NULL, pool) < 0) + VIR_DEBUG("Failed to refresh storage pool"); + + cleanup: + if (pool) + virStoragePoolObjUnlock(pool); + storageDriverUnlock(driverState); +} + static int storageVolUpload(virStorageVolPtr obj, virStreamPtr stream, @@ -1966,6 +2018,7 @@ storageVolUpload(virStorageVolPtr obj, virStorageBackendPtr backend; virStoragePoolObjPtr pool = NULL; virStorageVolDefPtr vol = NULL; + virStorageVolStreamInfoPtr cbdata = NULL; int ret = -1; virCheckFlags(0, -1); @@ -1996,11 +2049,36 @@ storageVolUpload(virStorageVolPtr obj, goto cleanup; } + /* If we have a refreshPool, use the callback routine in order to + * refresh the pool after the volume upload stream closes. This way + * we make sure the volume and pool data are refreshed without user + * interaction and we can just lookup the backend in the callback + * routine in order to call the refresh API. + */ + if (backend->refreshPool) { + if (VIR_ALLOC(cbdata) < 0 || + VIR_STRDUP(cbdata->pool_name, pool->def->name) < 0) + goto cleanup; + } + ret = backend->uploadVol(obj->conn, pool, vol, stream, offset, length, flags); + /* Add cleanup callback - call after uploadVol since the stream + * is then fully set up + */ + if (cbdata) { + virFDStreamSetInternalCloseCb(stream, + virStorageVolFDStreamCloseCb, + cbdata, + virStorageVolFDStreamCloseCbFree); + cbdata = NULL; + } + cleanup: virStoragePoolObjUnlock(pool); + if (cbdata) + virStorageVolFDStreamCloseCbFree(cbdata); return ret; } diff --git a/tools/virsh.pod b/tools/virsh.pod index 849ae31..e377df9 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -2981,6 +2981,9 @@ of the amount of data to be uploaded. A negative value is interpreted as an unsigned long long value to essentially include everything from the offset to the end of the volume. An error will occur if the I<local-file> is greater than the specified length. +See the description for the libvirt virStorageVolUpload API for details +regarding possible target volume and pool changes as a result of the +pool refresh when the upload is attempted. =item B<vol-download> [I<--pool> I<pool-or-uuid>] [I<--offset> I<bytes>] [I<--length> I<bytes>] I<vol-name-or-key-or-path> I<local-file> -- 1.9.3 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list