On Tue, Jul 21, 2009 at 04:01:37PM +0100, Mark McLoughlin wrote:
In qemu-0.11 there is a 'pc-0.10' machine type which allows
you to run
guests with a machine which is compatible with the pc machine in
qemu-0.10 - e.g. using the original PCI class for virtio-blk and
virtio-console and disabling MSI support in virtio-net. The idea here
is that we don't want to surprise guests by changing the hardware when
qemu is updated.
I've just posted some patches for qemu-0.11 which allows libvirt to
canonicalize the 'pc' machine alias to the latest machine version.
This patches makes us use that so that when a guest is configured to
use the 'pc' machine type, we resolve that to 'pc-0.11' machine and
save that in the guest XML.
We currently also list "valid" machine types in the capabilities
XML for each driver. I use quotes, because this list is currently
dubiously hardcoded. I'm thinking it might be better to do the
parsing of -M ? output as part of the capaiblities intiialization
code. The canonicalize method would then just need to query the
existing capabilities data & could even be done in the domain XML
parser code instead of qemu driver.
---
src/qemu_conf.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/qemu_conf.h | 3 +
src/qemu_driver.c | 3 +
3 files changed, 120 insertions(+), 0 deletions(-)
diff --git a/src/qemu_conf.c b/src/qemu_conf.c
index 4043d70..3f4edfa 100644
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -470,6 +470,120 @@ virCapsPtr qemudCapsInit(void) {
return NULL;
}
+/* Format is:
+ * <machine> <desc> [(alias of <machine>)]
+ */
+static int
+qemudParseMachineTypesStr(const char *machines ATTRIBUTE_UNUSED,
+ const char *machine ATTRIBUTE_UNUSED,
+ char **canonical)
+{
+ const char *p = machines;
+
+ *canonical = NULL;
+
+ do {
+ const char *eol;
+ char *s;
+
+ if (!(eol = strchr(p, '\n')))
+ return -1; /* eof file without finding @machine */
+
+ if (!STRPREFIX(p, machine)) {
+ p = eol + 1;
+ continue; /* doesn't match @machine */
+ }
+
+ p += strlen(machine);
+
+ if (*p != ' ') {
+ p = eol + 1;
+ continue; /* not a complete match of @machine */
+ }
+
+ do {
+ p++;
+ } while (*p == ' ');
+
+ p = strstr(p, "(alias of ");
+ if (!p || p > eol)
+ return 0; /* not an alias, name is canonical */
+
+ *canonical = strndup(p + strlen("(alias of "), eol - p);
Need to check for NULL here.
+
+ s = strchr(*canonical, ')');
+ if (!s) {
+ VIR_FREE(*canonical);
+ *canonical = NULL;
+ return -1; /* output is screwed up */
+ }
+
+ *s = '\0';
+ break;
+ } while (1);
+
+ return 0;
+}
+
+int
+qemudCanonicalizeMachine(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virDomainDefPtr def)
+{
+ const char *const qemuarg[] = { def->emulator, "-M", "?",
NULL };
+ const char *const qemuenv[] = { "LC_ALL=C", NULL };
+ char *machines, *canonical;
+ enum { MAX_MACHINES_OUTPUT_SIZE = 1024*4 };
+ pid_t child;
+ int newstdout = -1, len;
+ int ret = -1, status;
+
+ if (virExec(NULL, qemuarg, qemuenv, NULL,
+ &child, -1, &newstdout, NULL, VIR_EXEC_CLEAR_CAPS) < 0)
+ return -1;
+
+ len = virFileReadLimFD(newstdout, MAX_MACHINES_OUTPUT_SIZE, &machines);
+ if (len < 0) {
+ virReportSystemError(NULL, errno, "%s",
+ _("Unable to read 'qemu -M ?' output"));
+ goto cleanup;
+ }
+
+ if (qemudParseMachineTypesStr(machines, def->os.machine, &canonical) < 0)
+ goto cleanup2;
+
+ if (canonical) {
+ VIR_FREE(def->os.machine);
+ def->os.machine = canonical;
+ }
+
+ ret = 0;
+
+cleanup2:
+ VIR_FREE(machines);
+cleanup:
+ if (close(newstdout) < 0)
+ ret = -1;
+
+rewait:
+ if (waitpid(child, &status, 0) != child) {
+ if (errno == EINTR)
+ goto rewait;
+
+ VIR_ERROR(_("Unexpected exit status from qemu %d pid %lu"),
+ WEXITSTATUS(status), (unsigned long)child);
+ ret = -1;
+ }
+ /* Check & log unexpected exit status, but don't fail,
+ * as there's really no need to throw an error if we did
+ * actually read a valid version number above */
+ if (WEXITSTATUS(status) != 0) {
+ VIR_WARN(_("Unexpected exit status '%d', qemu probably
failed"),
+ WEXITSTATUS(status));
+ }
+
+ return ret;
+}
+
static unsigned int qemudComputeCmdFlags(const char *help,
unsigned int version,
unsigned int is_kvm,
diff --git a/src/qemu_conf.h b/src/qemu_conf.h
index fbf2ab9..b668669 100644
--- a/src/qemu_conf.h
+++ b/src/qemu_conf.h
@@ -123,6 +123,9 @@ int qemudExtractVersionInfo (const char *qemu,
unsigned int *version,
unsigned int *flags);
+int qemudCanonicalizeMachine (virConnectPtr conn,
+ virDomainDefPtr def);
+
int qemudParseHelpStr (const char *str,
unsigned int *flags,
unsigned int *version,
diff --git a/src/qemu_driver.c b/src/qemu_driver.c
index d2db1a2..98f8e95 100644
--- a/src/qemu_driver.c
+++ b/src/qemu_driver.c
@@ -4102,6 +4102,9 @@ static virDomainPtr qemudDomainDefine(virConnectPtr conn, const
char *xml) {
}
}
+ if (qemudCanonicalizeMachine(conn, def) < 0)
+ goto cleanup;
+
if (!(vm = virDomainAssignDef(conn,
&driver->domains,
def))) {
--
1.6.2.5
Daniel
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|