[libvirt] [PATCH RFC 3/8] qemu: add qemu emulator cache framework

Lee Schermerhorn lee.schermerhorn at hp.com
Sun Mar 11 18:45:04 UTC 2012


Define a qemu emulator cache structure and function to lookup,
create, refresh emulator cache objects.  The cache "tags" are
the paths to the emulator binaries.  E.g., "/usr/bin/qemu"

Subsequent patches will "hook up" the various extract/probe info
functions to consult the cache.

Notes/questions:
 1) "qemuCapsProbes" converted to bitmap along with capabilities flags
    as part of rebase.  Overkill?
 2) Is it OK for the root of the cache and the nEmulators to be statically
    defined in qemu_capabilities.c as opposed to a field in the driver struct?
    It is private to that source file and I don't see an easy wait to get
    a handle on the driver struct therein.

---
 src/qemu/qemu_capabilities.c |  166 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 166 insertions(+)

Index: libvirt-0.9.10/src/qemu/qemu_capabilities.c
===================================================================
--- libvirt-0.9.10.orig/src/qemu/qemu_capabilities.c
+++ libvirt-0.9.10/src/qemu/qemu_capabilities.c
@@ -170,6 +170,46 @@ struct qemu_arch_info {
     int nflags;
 };
 
+/*
+ *  * Flags to record which "probes" have been cached
+ *   */
+enum qemuCapsProbes {
+    QEMU_PROBE_VERSION_INFO   = 0,
+    QEMU_PROBE_MACHINE_TYPES  = 1,
+    QEMU_PROBE_CPU_MODELS     = 2,
+    QEMU_PROBE_SIZE
+};
+
+typedef struct _qemuEmulatorCache qemuEmulatorCache;
+typedef qemuEmulatorCache* qemuEmulatorCachePtr;
+struct _qemuEmulatorCache {
+    char                    *path;
+    char                    *arch;
+    time_t                  mtime;
+    virBitmapPtr            cachedProbes;
+
+    unsigned int            version;
+    virBitmapPtr            caps;
+
+    virCapsGuestMachinePtr  *machines;
+    int                     nmachines;
+
+    char                    **cpus;
+    unsigned int            ncpus;
+};
+
+static qemuEmulatorCachePtr *emulatorCache = NULL;
+static int nEmulators;
+
+static qemuEmulatorCachePtr
+qemuEmulatorCachedInfoGet(enum qemuCapsProbes,
+                          const char *binary,
+                          const char *arch);
+
+static void
+qemuEmulatorCachedInfoRelease(qemuEmulatorCachePtr emulator ATTRIBUTE_UNUSED)
+{ }
+
 /* Feature flags for the architecture info */
 static const struct qemu_feature_flags const arch_info_i686_flags [] = {
     { "pae",  1, 0 },
@@ -319,6 +359,12 @@ cleanup:
 }
 
 static int
+qemuCapsCacheMachineTypes(qemuEmulatorCachePtr emulator)
+{
+	return emulator ? 0 : 1;
+}
+
+static int
 qemuCapsGetOldMachinesFromInfo(virCapsGuestDomainInfoPtr info,
                                const char *emulator,
                                time_t emulator_mtime,
@@ -612,6 +658,11 @@ cleanup:
     return ret;
 }
 
+static int
+qemuCapsCacheCPUModels(qemuEmulatorCachePtr emulator)
+{
+	return emulator ? 0 : 1;
+}
 
 static int
 qemuCapsInitGuest(virCapsPtr caps,
@@ -1510,6 +1561,12 @@ cleanup:
     return ret;
 }
 
+static int
+qemuCapsCacheVersionInfo(qemuEmulatorCachePtr emulator)
+{
+	return emulator ? 0 : 1;
+}
+
 static void
 uname_normalize (struct utsname *ut)
 {
@@ -1610,3 +1667,112 @@ qemuCapsGet(virBitmapPtr caps,
     else
         return b;
 }
+
+static qemuEmulatorCachePtr
+qemuEmulatorCachedInfoGet(enum qemuCapsProbes probe,
+                          const char *binary,
+                          const char *arch)
+{
+    qemuEmulatorCachePtr emulator = NULL;
+    struct stat st;
+    bool alreadyCached;
+    int i;
+
+    if (stat(binary, &st) != 0) {
+        char ebuf[1024];
+        VIR_INFO("Failed to stat emulator %s : %s",
+                 binary, virStrerror(errno, ebuf, sizeof(ebuf)));
+        goto error;
+    }
+
+    for (i = 0; i < nEmulators; ++i) {
+        emulator = emulatorCache[i];
+
+        if (!STREQ(binary, emulator->path))
+            continue;
+
+        if (arch && !emulator->arch) {
+            if (!(emulator->arch = strdup(arch)))
+                goto no_memory;
+           /*
+            * We have an 'arch' now, where we didn't before.
+            * So, even if we've already cached this probe,
+            * refresh the cache with the specified arch.
+            */
+            break;
+        }
+
+        if (st.st_mtime != emulator->mtime)
+            break;  /* binary changed, refresh cache */
+
+        if (virBitmapGetBit(emulator->cachedProbes, probe, &alreadyCached) < 0) {
+            VIR_ERROR(_("Unrecognized probe id '%d'"), probe);
+            goto error;
+        }
+        if (!alreadyCached)
+            break;  /* do it now */
+
+        return emulator;
+    }
+
+    if (i == nEmulators) {
+         if (VIR_REALLOC_N(emulatorCache, nEmulators + 1) < 0)
+             goto no_memory;
+         if (VIR_ALLOC(emulator) < 0)
+             goto no_memory;
+         if (!(emulator->path = strdup(binary)))
+             goto no_memory_free_emulator;
+         if (arch && !(emulator->arch = strdup(arch)))
+	     goto no_memory_free_emulator;
+         if (!(emulator->cachedProbes = virBitmapAlloc(QEMU_PROBE_SIZE)))
+             goto no_memory_free_emulator;
+        VIR_DEBUG("Adding emulator cache for %s - %s",
+                    emulator->path, emulator->arch);
+         emulatorCache[nEmulators] = emulator;
+         nEmulators += 1;
+    } else {
+        VIR_DEBUG("Refreshing emulator cache for %s - %s",
+                    emulator->path, emulator->arch);
+    }
+
+    switch (probe) {
+
+    case QEMU_PROBE_VERSION_INFO:
+        if (qemuCapsCacheVersionInfo(emulator) != 0 ||
+            virBitmapSetBit(emulator->cachedProbes, QEMU_PROBE_VERSION_INFO) < 0)
+            goto error;
+        break;
+
+    case QEMU_PROBE_MACHINE_TYPES:
+        if (qemuCapsCacheMachineTypes(emulator) != 0 ||
+            virBitmapSetBit(emulator->cachedProbes, QEMU_PROBE_MACHINE_TYPES) < 0)
+            goto error;
+        break;
+
+    case QEMU_PROBE_CPU_MODELS:
+        if (qemuCapsCacheCPUModels(emulator) != 0 ||
+            virBitmapSetBit(emulator->cachedProbes, QEMU_PROBE_CPU_MODELS) < 0)
+            goto error;
+        break;
+
+    default:
+        /* We REALLY shouldn't get here... */
+        VIR_ERROR(_("Unrecognized probe id '%d'"), probe);
+        goto error;
+    }
+
+
+    emulator->mtime = st.st_mtime;
+    return emulator;
+
+no_memory_free_emulator:
+    VIR_FREE(emulator->path);
+    VIR_FREE(emulator->arch);
+    VIR_FREE(emulator);
+
+no_memory:
+    virReportOOMError();
+
+error:
+    return NULL;
+}




More information about the libvir-list mailing list