]> xenbits.xensource.com Git - libvirt.git/commitdiff
storage: cache backing chain while qemu domain is live
authorEric Blake <eblake@redhat.com>
Tue, 9 Oct 2012 22:08:14 +0000 (16:08 -0600)
committerEric Blake <eblake@redhat.com>
Fri, 19 Oct 2012 23:35:10 +0000 (17:35 -0600)
Technically, we should not be re-probing any file that qemu might
be currently writing to.  As such, we should cache the backing
file chain prior to starting qemu.  This patch adds the cache,
but does not use it until the next patch.

Ultimately, we want to also store the chain in domain XML, so that
it is remembered across libvirtd restarts, and so that the only
kosher way to modify the backing chain of an offline domain will be
through libvirt API calls, but we aren't there yet.  So for now, we
merely invalidate the cache any time we do a live operation that
alters the chain (block-pull, block-commit, external disk snapshot),
as well as tear down the cache when the domain is not running.

* src/conf/domain_conf.h (_virDomainDiskDef): New field.
* src/conf/domain_conf.c (virDomainDiskDefFree): Clean new field.
* src/qemu/qemu_domain.h (qemuDomainDetermineDiskChain): New
prototype.
* src/qemu/qemu_domain.c (qemuDomainDetermineDiskChain): New
function.
* src/qemu/qemu_driver.c (qemuDomainAttachDeviceDiskLive)
(qemuDomainChangeDiskMediaLive): Pre-populate chain.
(qemuDomainSnapshotCreateSingleDiskActive): Uncache chain before
snapshot.
* src/qemu/qemu_process.c (qemuProcessHandleBlockJob): Update
chain after block pull.

src/conf/domain_conf.c
src/conf/domain_conf.h
src/qemu/qemu_domain.c
src/qemu/qemu_domain.h
src/qemu/qemu_driver.c
src/qemu/qemu_process.c

index 7618468c210c16083dfd73e5c4e9c4e7f99ed890..71d1666c54a1568af4a41003472607210bcf6c67 100644 (file)
@@ -975,6 +975,7 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def)
     VIR_FREE(def->src);
     VIR_FREE(def->dst);
     VIR_FREE(def->driverName);
+    virStorageFileFreeMetadata(def->backingChain);
     VIR_FREE(def->mirror);
     VIR_FREE(def->auth.username);
     VIR_FREE(def->wwn);
index 039e34ddc1ddfada26e324bd9adea9bb2273776a..6e6b259d10e012d47f69510d8d4260c5bc6e2ddb 100644 (file)
@@ -47,6 +47,7 @@
 # include "virobject.h"
 # include "device_conf.h"
 # include "bitmap.h"
+# include "storage_file.h"
 
 /* forward declarations of all device types, required by
  * virDomainDeviceDef
@@ -568,6 +569,7 @@ struct _virDomainDiskDef {
     } auth;
     char *driverName;
     int format; /* enum virStorageFileFormat */
+    virStorageFileMetadataPtr backingChain;
 
     char *mirror;
     int mirrorFormat; /* enum virStorageFileFormat */
index fb775c13c7e3a10071490ff52441682eb23c7483..4e6a5e93a836ad0ef9960e17a9cf3b4397b5a0f1 100644 (file)
@@ -2012,3 +2012,29 @@ qemuDomainCleanupRun(struct qemud_driver *driver,
     priv->ncleanupCallbacks = 0;
     priv->ncleanupCallbacks_max = 0;
 }
+
+int
+qemuDomainDetermineDiskChain(struct qemud_driver *driver,
+                             virDomainDiskDefPtr disk,
+                             bool force)
+{
+    bool probe = driver->allowDiskFormatProbing;
+
+    if (!disk->src)
+        return 0;
+
+    if (disk->backingChain) {
+        if (force) {
+            virStorageFileFreeMetadata(disk->backingChain);
+            disk->backingChain = NULL;
+        } else {
+            return 0;
+        }
+    }
+    disk->backingChain = virStorageFileGetMetadata(disk->src, disk->format,
+                                                   driver->user, driver->group,
+                                                   probe);
+    if (!disk->backingChain)
+        return -1;
+    return 0;
+}
index 26b6c557c023ff202b30530b691e96fceed2dee1..8a66f14ec9143c8b3bce5ed1d6dcc948d453d62a 100644 (file)
@@ -343,6 +343,9 @@ bool qemuDomainJobAllowed(qemuDomainObjPrivatePtr priv,
 int qemuDomainCheckDiskPresence(struct qemud_driver *driver,
                                 virDomainObjPtr vm,
                                 bool start_with_state);
+int qemuDomainDetermineDiskChain(struct qemud_driver *driver,
+                                 virDomainDiskDefPtr disk,
+                                 bool force);
 
 int qemuDomainCleanupAdd(virDomainObjPtr vm,
                          qemuDomainCleanupCallback cb);
index 6de65ea8254084ae76e69a071f8741341093960c..c3e4fd4a71d3c09ca83cc3bd3d6cb5e820fa1b16 100644 (file)
@@ -5816,6 +5816,9 @@ qemuDomainAttachDeviceDiskLive(virConnectPtr conn,
         goto end;
     }
 
+    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
+        goto end;
+
     if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
         if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0)) {
             virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -6044,6 +6047,9 @@ qemuDomainChangeDiskMediaLive(virDomainObjPtr vm,
     virCgroupPtr cgroup = NULL;
     int ret = -1;
 
+    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
+        goto end;
+
     if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
         if (virCgroupForDomain(driver->cgroup,
                                vm->def->name, &cgroup, 0) != 0) {
@@ -10789,6 +10795,14 @@ qemuDomainSnapshotCreateSingleDiskActive(struct qemud_driver *driver,
     disk->src = source;
     origdriver = disk->format;
     disk->format = VIR_STORAGE_FILE_RAW; /* Don't want to probe backing files */
+    /* XXX Here, we know we are about to alter disk->backingChain if
+     * successful, so we nuke the existing chain so that future
+     * commands will recompute it.  Better would be storing the chain
+     * ourselves rather than reprobing, but this requires modifying
+     * domain_conf and our XML to fully track the chain across
+     * libvirtd restarts.  */
+    virStorageFileFreeMetadata(disk->backingChain);
+    disk->backingChain = NULL;
 
     if (virDomainLockDiskAttach(driver->lockManager, driver->uri,
                                 vm, disk) < 0)
index d3951d1326f2b187599aabcc9d28e954cf479ea0..0628621cb53944b1f5ea5f63e31da1dcf068a8ee 100644 (file)
@@ -909,6 +909,14 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     if (disk) {
         path = disk->src;
         event = virDomainEventBlockJobNewFromObj(vm, path, type, status);
+        /* XXX If we completed a block pull, then recompute the cached
+         * backing chain to match.  Better would be storing the chain
+         * ourselves rather than reprobing, but this requires
+         * modifying domain_conf and our XML to fully track the chain
+         * across libvirtd restarts.  */
+        if (type == VIR_DOMAIN_BLOCK_JOB_TYPE_PULL &&
+            status == VIR_DOMAIN_BLOCK_JOB_COMPLETED)
+            qemuDomainDetermineDiskChain(driver, disk, true);
     }
 
     virDomainObjUnlock(vm);