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;
+}