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(a)redhat.com>
---
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