]> xenbits.xensource.com Git - libvirt.git/commitdiff
storage: Refresh storage pool after upload
authorJohn Ferlan <jferlan@redhat.com>
Mon, 28 Jul 2014 12:39:09 +0000 (08:39 -0400)
committerJohn Ferlan <jferlan@redhat.com>
Mon, 4 Aug 2014 14:35:52 +0000 (10:35 -0400)
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 in a separate thread once the stream closes. The
separate thread should avoid potential deadlocks if the refresh needed
to wait on some event from the event loop which is used to perform
the stream callback.

src/libvirt.c
src/libvirt_private.syms
src/storage/storage_driver.c
tools/virsh.pod

index 143d319a44b24a49b9c0dac4193bc2692e3fa31b..992e4f2ae0fea938c123bc66b40abd120e249f87 100644 (file)
@@ -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
index e792a44acb60aca527ba1a774b9bf68e6823472a..08111d4bfbec3b4c1cd2f1b24bbfe659c7707cd2 100644 (file)
@@ -825,6 +825,7 @@ virFDStreamCreateFile;
 virFDStreamOpen;
 virFDStreamOpenFile;
 virFDStreamOpenPTY;
+virFDStreamSetInternalCloseCb;
 
 
 # libvirt_internal.h
index efbe5ffab5053efe510fb1b0a5ffdf6ac3668cd1..b023281890e8bad60d8667f1ac1e7ad887b943a4 100644 (file)
@@ -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,78 @@ storageVolDownload(virStorageVolPtr obj,
 }
 
 
+/**
+ * Frees opaque data.
+ *
+ * @opaque Data to be freed.
+ */
+static void
+virStorageVolPoolRefreshDataFree(void *opaque)
+{
+    virStorageVolStreamInfoPtr cbdata = opaque;
+
+    VIR_FREE(cbdata->pool_name);
+    VIR_FREE(cbdata);
+}
+
+/**
+ * Thread to handle the pool refresh
+ *
+ * @st Pointer to stream being closed.
+ * @opaque Domain's device information structure.
+ */
+static void
+virStorageVolPoolRefreshThread(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);
+    virStorageVolPoolRefreshDataFree(cbdata);
+}
+
+/**
+ * Callback being called if a FDstream is closed. Will spin off a thread
+ * to perform a pool refresh.
+ *
+ * @st Pointer to stream being closed.
+ * @opaque Buffer to hold the pool name to be rereshed
+ */
+static void
+virStorageVolFDStreamCloseCb(virStreamPtr st ATTRIBUTE_UNUSED,
+                             void *opaque)
+{
+    virThread thread;
+
+    if (virThreadCreate(&thread, false, virStorageVolPoolRefreshThread,
+                        opaque) < 0) {
+        /* Not much else can be done */
+        VIR_ERROR(_("Failed to create thread to handle pool refresh"));
+        goto error;
+    }
+    return; /* Thread will free opaque data */
+
+ error:
+    virStorageVolPoolRefreshDataFree(opaque);
+}
+
 static int
 storageVolUpload(virStorageVolPtr obj,
                  virStreamPtr stream,
@@ -1966,6 +2044,7 @@ storageVolUpload(virStorageVolPtr obj,
     virStorageBackendPtr backend;
     virStoragePoolObjPtr pool = NULL;
     virStorageVolDefPtr vol = NULL;
+    virStorageVolStreamInfoPtr cbdata = NULL;
     int ret = -1;
 
     virCheckFlags(0, -1);
@@ -1996,11 +2075,35 @@ 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, NULL);
+        cbdata = NULL;
+    }
+
  cleanup:
     virStoragePoolObjUnlock(pool);
+    if (cbdata)
+        virStorageVolPoolRefreshDataFree(cbdata);
 
     return ret;
 }
index 849ae319ae44e2657f32ed8c1c787fa573763494..e377df91561743c8a8115f6346d756996a7de599 100644 (file)
@@ -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>