On Thu, Aug 10, 2006 at 08:31:28AM -0400, Daniel Veillard wrote: > On Wed, Aug 09, 2006 at 11:54:26PM +0100, Daniel P. Berrange wrote: > [ lot of details about problems ] > > The upshot of all this is that although the last release of libvirt > > included HVM support it was basically unusable for domain creation > > unless you were using HD to boot. The XML returned was also incorrect. > > > > Now the good news. Since it was sooo broken, we can fix without worrying > > about XML compatability since there is no way any application could be > > relying on it in its current state. > > Agreed. And the changes suggested should not affect the very simple > case which worked, except for the 'ioemu:' device prefix. We can just > discard it when reading the XML and add it when > just discard it except that before xen-3.0.3 this will need to be added > back, and post xen-3.0.3 this should be allowed by xend Ok attached an updated version of the patch which the various changes discussed in this thread - in particular the addition of a 'device' attribute to the <disk> element accepting 'disk', 'floppy', or 'cdrom' and defaulting to 'disk' if it is omitted. Best illustrated by example XML dump: <domain type='xen' id='53'> <name>too</name> <uuid>b5d70dd275cdaca517769660b059d8bc</uuid> <os> <type>hvm</type> <loader>/usr/lib/xen/boot/hvmloader</loader> <boot dev='cdrom'/> </os> <memory>409600</memory> <vcpu>1</vcpu> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>restart</on_crash> <devices> <emulator>/usr/lib64/xen/bin/qemu-dm</emulator> <interface type='bridge'> <source bridge='xenbr0'/> <mac address='00:16:3e:1b:b1:47'/> <script path='vif-bridge'/> </interface> <disk type='file' device='disk'> <source file='/root/foo.img'/> <target dev='hda'/> </disk> <disk type='file' device='cdrom'> <source file='/root/boot.iso'/> <target dev='hdc'/> <readonly/> </disk> <graphics type='vnc' port='5953'/> <console tty='/dev/pts/16'/> </devices> </domain> Note that the ioemu: prefix is now not exposed in the XML - we add it back on when creating the SEXPR, or strip it when parsing the SEXPR. Until Xen 3.0.3 when 'device=cdrom' the only valid target dev is 'hdc', after 3.0.3 this can be relaxed to allow hda->hdd Regards, Dan. -- |=- Red Hat, Engineering, Emerging Technologies, Boston. +1 978 392 2496 -=| |=- Perl modules: http://search.cpan.org/~danberr/ -=| |=- Projects: http://freshmeat.net/~danielpb/ -=| |=- GnuPG: 7D3B9505 F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 -=|
? COPYING ? build.log Index: src/libvirt.c =================================================================== RCS file: /data/cvs/libvirt/src/libvirt.c,v retrieving revision 1.41 diff -c -b -r1.41 libvirt.c *** src/libvirt.c 9 Aug 2006 15:21:16 -0000 1.41 --- src/libvirt.c 10 Aug 2006 22:38:56 -0000 *************** *** 720,726 **** int virDomainDestroy(virDomainPtr domain) { ! int ret = -1, i; virConnectPtr conn; if (!VIR_IS_CONNECTED_DOMAIN(domain)) { --- 720,726 ---- int virDomainDestroy(virDomainPtr domain) { ! int i; virConnectPtr conn; if (!VIR_IS_CONNECTED_DOMAIN(domain)) { *************** *** 743,749 **** (conn->drivers[i]->no != VIR_DRV_XEN_HYPERVISOR) && (conn->drivers[i]->domainDestroy != NULL)) { if (conn->drivers[i]->domainDestroy(domain) == 0) ! ret = 0; } } for (i = 0;i < conn->nb_drivers;i++) { --- 743,749 ---- (conn->drivers[i]->no != VIR_DRV_XEN_HYPERVISOR) && (conn->drivers[i]->domainDestroy != NULL)) { if (conn->drivers[i]->domainDestroy(domain) == 0) ! return (0); } } for (i = 0;i < conn->nb_drivers;i++) { *************** *** 751,766 **** (conn->drivers[i]->no == VIR_DRV_XEN_HYPERVISOR) && (conn->drivers[i]->domainDestroy != NULL)) { if (conn->drivers[i]->domainDestroy(domain) == 0) ! ret = 0; } } - if (ret != 0) { virLibConnError(conn, VIR_ERR_CALL_FAILED, __FUNCTION__); ! return (ret); ! } ! ! return (ret); } /** --- 751,762 ---- (conn->drivers[i]->no == VIR_DRV_XEN_HYPERVISOR) && (conn->drivers[i]->domainDestroy != NULL)) { if (conn->drivers[i]->domainDestroy(domain) == 0) ! return (0); } } virLibConnError(conn, VIR_ERR_CALL_FAILED, __FUNCTION__); ! return (-1); } /** *************** *** 799,805 **** int virDomainSuspend(virDomainPtr domain) { ! int ret = -1, i; virConnectPtr conn; if (!VIR_IS_CONNECTED_DOMAIN(domain)) { --- 795,801 ---- int virDomainSuspend(virDomainPtr domain) { ! int i; virConnectPtr conn; if (!VIR_IS_CONNECTED_DOMAIN(domain)) { *************** *** 822,828 **** (conn->drivers[i]->no != VIR_DRV_XEN_HYPERVISOR) && (conn->drivers[i]->domainSuspend != NULL)) { if (conn->drivers[i]->domainSuspend(domain) == 0) ! ret = 0; } } for (i = 0;i < conn->nb_drivers;i++) { --- 818,824 ---- (conn->drivers[i]->no != VIR_DRV_XEN_HYPERVISOR) && (conn->drivers[i]->domainSuspend != NULL)) { if (conn->drivers[i]->domainSuspend(domain) == 0) ! return (0); } } for (i = 0;i < conn->nb_drivers;i++) { *************** *** 830,845 **** (conn->drivers[i]->no == VIR_DRV_XEN_HYPERVISOR) && (conn->drivers[i]->domainSuspend != NULL)) { if (conn->drivers[i]->domainSuspend(domain) == 0) ! ret = 0; } } - if (ret != 0) { virLibConnError(conn, VIR_ERR_CALL_FAILED, __FUNCTION__); ! return (ret); ! } ! ! return (ret); } /** --- 826,837 ---- (conn->drivers[i]->no == VIR_DRV_XEN_HYPERVISOR) && (conn->drivers[i]->domainSuspend != NULL)) { if (conn->drivers[i]->domainSuspend(domain) == 0) ! return (0); } } virLibConnError(conn, VIR_ERR_CALL_FAILED, __FUNCTION__); ! return (-1); } /** Index: src/xend_internal.c =================================================================== RCS file: /data/cvs/libvirt/src/xend_internal.c,v retrieving revision 1.52 diff -c -b -r1.52 xend_internal.c *** src/xend_internal.c 9 Aug 2006 15:21:16 -0000 1.52 --- src/xend_internal.c 10 Aug 2006 22:38:57 -0000 *************** *** 791,796 **** --- 791,808 ---- goto error; ret = sscanf(r, + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x" + "%02x%02x%02x%02x", + uuid + 0, uuid + 1, uuid + 2, uuid + 3, + uuid + 4, uuid + 5, uuid + 6, uuid + 7, + uuid + 8, uuid + 9, uuid + 10, uuid + 11, + uuid + 12, uuid + 13, uuid + 14, uuid + 15); + if (ret == 16) + goto done; + + ret = sscanf(r, "%02x%02x%02x%02x-" "%02x%02x-" "%02x%02x-" *************** *** 1416,1436 **** virBufferVSprintf(buf, " <loader>%s</loader>\n", tmp); tmp = sexpr_node(node, "domain/image/hvm/boot"); if ((tmp != NULL) && (tmp[0] != 0)) { - /* - * FIXME: - * Figure out how to map the 'a', 'b', 'c' nonsense to a - * device. - */ if (tmp[0] == 'a') ! virBufferAdd(buf, " <boot dev='/dev/fd0'/>\n", 25 ); else if (tmp[0] == 'c') /* * Don't know what to put here. Say the vm has been given 3 * disks - hda, hdb, hdc. How does one identify the boot disk? */ ! virBufferAdd(buf, " <boot dev='hda'/>\n", 22 ); else if (strcmp(tmp, "d") == 0) ! virBufferAdd(buf, " <boot dev='/dev/cdrom'/>\n", 29 ); } } else { virBufferVSprintf(buf, " <type>linux</type>\n"); --- 1428,1446 ---- virBufferVSprintf(buf, " <loader>%s</loader>\n", tmp); tmp = sexpr_node(node, "domain/image/hvm/boot"); if ((tmp != NULL) && (tmp[0] != 0)) { if (tmp[0] == 'a') ! /* XXX no way to deal with boot from 2nd floppy */ ! virBufferAdd(buf, " <boot dev='fd'/>\n", 21 ); else if (tmp[0] == 'c') /* * Don't know what to put here. Say the vm has been given 3 * disks - hda, hdb, hdc. How does one identify the boot disk? + * We're going to assume that first disk is the boot disk since + * this is most common practice */ ! virBufferAdd(buf, " <boot dev='hd'/>\n", 21 ); else if (strcmp(tmp, "d") == 0) ! virBufferAdd(buf, " <boot dev='cdrom'/>\n", 24 ); } } else { virBufferVSprintf(buf, " <type>linux</type>\n"); *************** *** 1482,1492 **** /* ERROR */ return (NULL); } ! ret = malloc(1000); if (ret == NULL) return (NULL); buf.content = ret; ! buf.size = 1000; buf.use = 0; domid = sexpr_int(root, "domain/domid"); --- 1492,1502 ---- /* ERROR */ return (NULL); } ! ret = malloc(4000); if (ret == NULL) return (NULL); buf.content = ret; ! buf.size = 4000; buf.use = 0; domid = sexpr_int(root, "domain/domid"); *************** *** 1552,1558 **** continue; if (!memcmp(tmp, "file:", 5)) { tmp += 5; ! virBufferVSprintf(&buf, " <disk type='file'>\n"); virBufferVSprintf(&buf, " <source file='%s'/>\n", tmp); tmp = sexpr_node(node, "device/vbd/dev"); --- 1562,1568 ---- continue; if (!memcmp(tmp, "file:", 5)) { tmp += 5; ! virBufferVSprintf(&buf, " <disk type='file' device='disk'>\n"); virBufferVSprintf(&buf, " <source file='%s'/>\n", tmp); tmp = sexpr_node(node, "device/vbd/dev"); *************** *** 1561,1566 **** --- 1571,1578 ---- "domain information incomplete, vbd has no dev"); goto error; } + if (!strncmp(tmp, "ioemu:", 6)) + tmp += 6; virBufferVSprintf(&buf, " <target dev='%s'/>\n", tmp); tmp = sexpr_node(node, "device/vbd/mode"); if ((tmp != NULL) && (!strcmp(tmp, "r"))) *************** *** 1568,1574 **** virBufferAdd(&buf, " </disk>\n", 12); } else if (!memcmp(tmp, "phy:", 4)) { tmp += 4; ! virBufferVSprintf(&buf, " <disk type='block'>\n"); virBufferVSprintf(&buf, " <source dev='%s'/>\n", tmp); tmp = sexpr_node(node, "device/vbd/dev"); if (tmp == NULL) { --- 1580,1586 ---- virBufferAdd(&buf, " </disk>\n", 12); } else if (!memcmp(tmp, "phy:", 4)) { tmp += 4; ! virBufferVSprintf(&buf, " <disk type='block' device='disk'>\n"); virBufferVSprintf(&buf, " <source dev='%s'/>\n", tmp); tmp = sexpr_node(node, "device/vbd/dev"); if (tmp == NULL) { *************** *** 1576,1581 **** --- 1588,1595 ---- "domain information incomplete, vbd has no dev"); goto error; } + if (!strncmp(tmp, "ioemu:", 6)) + tmp += 6; virBufferVSprintf(&buf, " <target dev='%s'/>\n", tmp); tmp = sexpr_node(node, "device/vbd/mode"); if ((tmp != NULL) && (!strcmp(tmp, "r"))) *************** *** 1625,1630 **** --- 1639,1668 ---- } if (hvm) { + tmp = sexpr_node(root, "domain/image/hvm/fda"); + if ((tmp != NULL) && (tmp[0] != 0)) { + virBufferAdd(&buf, " <disk type='file' device='floppy'>\n", 39); + virBufferVSprintf(&buf, " <source file='%s'/>\n", tmp); + virBufferAdd(&buf, " <target dev='fda'/>\n", 26); + virBufferAdd(&buf, " </disk>\n", 12); + } + tmp = sexpr_node(root, "domain/image/hvm/fdb"); + if ((tmp != NULL) && (tmp[0] != 0)) { + virBufferAdd(&buf, " <disk type='file' device='floppy'>\n", 39); + virBufferVSprintf(&buf, " <source file='%s'/>\n", tmp); + virBufferAdd(&buf, " <target dev='fdb'/>\n", 26); + virBufferAdd(&buf, " </disk>\n", 12); + } + /* XXX new (3.0.3) Xend puts cdrom devs in usual (devices) block */ + tmp = sexpr_node(root, "domain/image/hvm/cdrom"); + if ((tmp != NULL) && (tmp[0] != 0)) { + virBufferAdd(&buf, " <disk type='file' device='cdrom'>\n", 38); + virBufferVSprintf(&buf, " <source file='%s'/>\n", tmp); + virBufferAdd(&buf, " <target dev='hdc'/>\n", 26); + virBufferAdd(&buf, " <readonly/>\n", 18); + virBufferAdd(&buf, " </disk>\n", 12); + } + /* Graphics device */ tmp = sexpr_node(root, "domain/image/hvm/vnc"); if (tmp != NULL) { *************** *** 1641,1651 **** if (tmp[0] == '1') virBufferAdd(&buf, " <graphics type='sdl'/>\n", 27 ); } - - /* - * TODO: - * Device for cdrom - */ } tty = xenStoreDomainGetConsolePath(conn, domid); --- 1679,1684 ---- Index: src/xml.c =================================================================== RCS file: /data/cvs/libvirt/src/xml.c,v retrieving revision 1.31 diff -c -b -r1.31 xml.c *** src/xml.c 10 Aug 2006 14:26:35 -0000 1.31 --- src/xml.c 10 Aug 2006 22:38:58 -0000 *************** *** 268,274 **** } val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "dev"); if (val != NULL) { ! virBufferVSprintf(buf, " <target dev='%s'/>\n", val); free(val); } val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "read-only"); --- 268,277 ---- } val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "dev"); if (val != NULL) { ! char *tmp = val; ! if (!strncmp(tmp, "ioemu:", 6)) ! tmp += 6; ! virBufferVSprintf(buf, " <target dev='%s'/>\n", tmp); free(val); } val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "read-only"); *************** *** 286,292 **** } val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "dev"); if (val != NULL) { ! virBufferVSprintf(buf, " <target dev='%s'/>\n", val); free(val); } val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "read-only"); --- 289,298 ---- } val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "dev"); if (val != NULL) { ! char *tmp = val; ! if (!strncmp(tmp, "ioemu:", 6)) ! tmp += 6; ! virBufferVSprintf(buf, " <target dev='%s'/>\n", tmp); free(val); } val = virDomainGetXMLDeviceInfo(domain, "vbd", dev, "read-only"); *************** *** 635,656 **** obj = NULL; if (boot_dev) { ! /* TODO: ! * Have to figure out the naming used here. ! */ ! if (xmlStrEqual(type, BAD_CAST "hda")) { virBufferVSprintf(buf, "(boot a)", (const char *) boot_dev); ! } else if (xmlStrEqual(type, BAD_CAST "hdd")) { virBufferVSprintf(buf, "(boot d)", (const char *) boot_dev); ! } else { ! /* Force hd[b|c] if boot_dev specified but not floppy or cdrom? */ virBufferVSprintf(buf, "(boot c)", (const char *) boot_dev); } } ! /* TODO: ! * Is a cdrom disk device specified? ! * Kind of ugly since it is buried in the devices/diskk node. ! */ /* Is a graphics device specified? */ obj = xmlXPathEval(BAD_CAST "/domain/devices/graphics[1]", ctxt); --- 641,712 ---- obj = NULL; if (boot_dev) { ! if (xmlStrEqual(boot_dev, BAD_CAST "fd")) { virBufferVSprintf(buf, "(boot a)", (const char *) boot_dev); ! } else if (xmlStrEqual(boot_dev, BAD_CAST "cdrom")) { virBufferVSprintf(buf, "(boot d)", (const char *) boot_dev); ! } else if (xmlStrEqual(boot_dev, BAD_CAST "hd")) { virBufferVSprintf(buf, "(boot c)", (const char *) boot_dev); + } else { + /* Any other type of boot dev is unsupported right now */ + virXMLError(VIR_ERR_XML_ERROR, NULL, 0); } + + /* get the 1st floppy device file */ + obj = xmlXPathEval(BAD_CAST "/domain/devices/disk[@device='floppy' and target/@dev='fda']/source", ctxt); + if ((obj != NULL) && (obj->type == XPATH_NODESET) && + (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) { + cur = obj->nodesetval->nodeTab[0]; + virBufferVSprintf(buf, "(fda '%s')", + (const char *) xmlGetProp(cur, BAD_CAST "file")); + cur = NULL; + } + if (obj) { + xmlXPathFreeObject(obj); + obj = NULL; } ! ! /* get the 2nd floppy device file */ ! obj = xmlXPathEval(BAD_CAST "/domain/devices/disk[@device='floppy' and target/@dev='fdb']/source", ctxt); ! if ((obj != NULL) && (obj->type == XPATH_NODESET) && ! (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) { ! cur = obj->nodesetval->nodeTab[0]; ! virBufferVSprintf(buf, "(fdb '%s')", ! (const char *) xmlGetProp(cur, BAD_CAST "file")); ! cur = NULL; ! } ! if (obj) { ! xmlXPathFreeObject(obj); ! obj = NULL; ! } ! ! ! /* get the cdrom device file */ ! /* XXX new (3.0.3) Xend puts cdrom devs in usual (devices) block */ ! obj = xmlXPathEval(BAD_CAST "/domain/devices/disk[@device='cdrom' and target/@dev='hdc']/source", ctxt); ! if ((obj != NULL) && (obj->type == XPATH_NODESET) && ! (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr == 1)) { ! cur = obj->nodesetval->nodeTab[0]; ! virBufferVSprintf(buf, "(cdrom '%s')", ! (const char *) xmlGetProp(cur, BAD_CAST "file")); ! cur = NULL; ! } ! if (obj) { ! xmlXPathFreeObject(obj); ! obj = NULL; ! } ! } ! ! obj = xmlXPathEval(BAD_CAST "count(domain/devices/console) > 0", ctxt); ! if ((obj == NULL) || (obj->type != XPATH_BOOLEAN)) { ! virXMLError(VIR_ERR_XML_ERROR, NULL, 0); ! goto error; ! } ! if (obj->boolval) { ! virBufferAdd(buf, "(serial pty)", 12); ! } ! xmlXPathFreeObject(obj); ! obj = NULL; /* Is a graphics device specified? */ obj = xmlXPathEval(BAD_CAST "/domain/devices/graphics[1]", ctxt); *************** *** 779,788 **** * Returns 0 in case of success, -1 in case of error. */ static int ! virDomainParseXMLDiskDesc(xmlNodePtr node, virBufferPtr buf) { xmlNodePtr cur; xmlChar *type = NULL; xmlChar *source = NULL; xmlChar *target = NULL; int ro = 0; --- 835,845 ---- * Returns 0 in case of success, -1 in case of error. */ static int ! virDomainParseXMLDiskDesc(xmlNodePtr node, virBufferPtr buf, int hvm) { xmlNodePtr cur; xmlChar *type = NULL; + xmlChar *device = NULL; xmlChar *source = NULL; xmlChar *target = NULL; int ro = 0; *************** *** 796,801 **** --- 853,860 ---- typ = 1; xmlFree(type); } + device = xmlGetProp(node, BAD_CAST "device"); + cur = node->children; while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) { *************** *** 829,835 **** --- 888,914 ---- xmlFree(source); return (-1); } + + /* Skip floppy/cdrom disk used as the boot device + since that's incorporated into the HVM kernel + (image (hvm..)) part of the sexpr, rather than + the (devices...) bit. Odd Xend HVM config :-( */ + if (hvm && device && + (!strcmp((const char *)device, "floppy") || + !strcmp((const char *)device, "cdrom"))) { + return 0; + } + + + virBufferAdd(buf, "(device ", 8); virBufferAdd(buf, "(vbd ", 5); + /* XXX ioemu prefix is going away in XenD 3.0.3 */ + if (hvm) { + char *tmp = (char *)target; + if (!strncmp((const char *) tmp, "ioemu:", 6)) + tmp += 6; + virBufferVSprintf(buf, "(dev 'ioemu:%s')", (const char *) tmp); + } else virBufferVSprintf(buf, "(dev '%s')", (const char *) target); if (typ == 0) virBufferVSprintf(buf, "(uname 'file:%s')", source); *************** *** 845,850 **** --- 924,930 ---- virBufferVSprintf(buf, "(mode 'r')"); virBufferAdd(buf, ")", 1); + virBufferAdd(buf, ")", 1); xmlFree(target); xmlFree(source); return (0); *************** *** 912,917 **** --- 992,998 ---- } if (script != NULL) virBufferVSprintf(buf, "(script '%s')", script); + virBufferAdd(buf, "(type ioemu)", 12); virBufferAdd(buf, ")", 1); if (mac != NULL) *************** *** 948,953 **** --- 1029,1035 ---- xmlXPathContextPtr ctxt = NULL; int i, res; int bootloader = 0; + int hvm = 0; if (name != NULL) *name = NULL; *************** *** 1072,1077 **** --- 1154,1160 ---- if ((tmpobj == NULL) || !xmlStrEqual(tmpobj->stringval, BAD_CAST "hvm")) { res = virDomainParseXMLOSDescPV(obj->nodesetval->nodeTab[0], &buf); } else { + hvm = 1; res = virDomainParseXMLOSDescHVM(obj->nodesetval->nodeTab[0], &buf, ctxt); } *************** *** 1090,1101 **** if ((obj != NULL) && (obj->type == XPATH_NODESET) && (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) { for (i = 0; i < obj->nodesetval->nodeNr; i++) { ! virBufferAdd(&buf, "(device ", 8); ! res = virDomainParseXMLDiskDesc(obj->nodesetval->nodeTab[i], &buf); if (res != 0) { goto error; } - virBufferAdd(&buf, ")", 1); } } xmlXPathFreeObject(obj); --- 1173,1182 ---- if ((obj != NULL) && (obj->type == XPATH_NODESET) && (obj->nodesetval != NULL) && (obj->nodesetval->nodeNr >= 0)) { for (i = 0; i < obj->nodesetval->nodeNr; i++) { ! res = virDomainParseXMLDiskDesc(obj->nodesetval->nodeTab[i], &buf, hvm); if (res != 0) { goto error; } } } xmlXPathFreeObject(obj);