From 42ee7111c3be6b042346fe587629ba0d29ef7c09 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 13 Apr 2007 00:43:57 +0000 Subject: [PATCH] Fixed up various functions for Xen 3.0.5 --- ChangeLog | 21 ++ src/xen_internal.c | 274 ++++++++++++++---- src/xen_unified.c | 11 +- src/xend_internal.c | 161 ++++++---- src/xml.c | 159 +++++----- src/xs_internal.c | 2 - .../sexpr2xml-no-source-cdrom.xml | 3 +- 7 files changed, 431 insertions(+), 200 deletions(-) diff --git a/ChangeLog b/ChangeLog index 04570090b2..20755417b4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +Thu Apr 12 19:51:00 EST 2007 Daniel Berrange + + * src/xen_internal.c: Updated structs to work with new Xen 3.0.5 + hypercall ABI. Mask out HVM bit when determining domain status. + Limit number of iterations when counting active IDs to 65000 + * src/xen_unified.c: Fix checking of return value for the + domainGetVCpus method. + * src/xend_internal.c: Added an impl of the DomainGetOSType + method which works with inactive domains too. Don't do a + redundant ping test against GetVersion, since we now already + fetch config file format number which serves as a ping test. + Allow the kernel SEXPR field to be missing for domain0, or if + using a bootloader. Mark interface as type=bridge, if there + is a bridge device listed, but no explicit script to fix inactive + domains. Allow multiple boot devices to be provided for HVM + * src/xml.c: Allow multiple boot devices to be provided for HVM. + Support new style graphics config for HVM in xen 3.0.5 + * src/xs_internal.c: Don't hardcode domain type of 'linux', + since we now have a fallback driver with xend that can make + the correct diagnosis for inactive domains. + Thu Apr 12 15:18:00 BST 2007 Richard Jones * src/libvirt.c: set VIR_CONNECT_RO on read-only connections. diff --git a/src/xen_internal.c b/src/xen_internal.c index 637a6a1f45..6a90f58956 100644 --- a/src/xen_internal.c +++ b/src/xen_internal.c @@ -93,6 +93,7 @@ static regex_t xen_cap_rec; */ #ifndef DOMFLAGS_DYING #define DOMFLAGS_DYING (1<<0) /* Domain is scheduled to die. */ +#define DOMFLAGS_HVM (1<<1) /* Domain is HVM */ #define DOMFLAGS_SHUTDOWN (1<<2) /* The guest OS has shut down. */ #define DOMFLAGS_PAUSED (1<<3) /* Currently paused by control software. */ #define DOMFLAGS_BLOCKED (1<<4) /* Currently blocked pending an event. */ @@ -146,87 +147,136 @@ struct xen_v2_getdomaininfo { }; typedef struct xen_v2_getdomaininfo xen_v2_getdomaininfo; + +/* As of Hypervisor Call v2, DomCtl v5 we are now 8-byte aligned + even on 32-bit archs when dealing with uint64_t */ +#define ALIGN_64 __attribute__((aligned(8))) + +struct xen_v2d5_getdomaininfo { + domid_t domain; /* the domain number */ + uint32_t flags; /* falgs, see before */ + uint64_t tot_pages ALIGN_64; /* total number of pages used */ + uint64_t max_pages ALIGN_64; /* maximum number of pages allowed */ + uint64_t shared_info_frame ALIGN_64; /* MFN of shared_info struct */ + uint64_t cpu_time ALIGN_64; /* CPU time used */ + uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */ + uint32_t max_vcpu_id; /* Maximum VCPUID in use by this domain. */ + uint32_t ssidref; + xen_domain_handle_t handle; +}; +typedef struct xen_v2d5_getdomaininfo xen_v2d5_getdomaininfo; + union xen_getdomaininfo { struct xen_v0_getdomaininfo v0; struct xen_v2_getdomaininfo v2; + struct xen_v2d5_getdomaininfo v2d5; }; typedef union xen_getdomaininfo xen_getdomaininfo; union xen_getdomaininfolist { struct xen_v0_getdomaininfo *v0; struct xen_v2_getdomaininfo *v2; + struct xen_v2d5_getdomaininfo *v2d5; }; typedef union xen_getdomaininfolist xen_getdomaininfolist; #define XEN_GETDOMAININFOLIST_ALLOC(domlist, size) \ (hypervisor_version < 2 ? \ ((domlist.v0 = malloc(sizeof(xen_v0_getdomaininfo)*(size))) != NULL) : \ - ((domlist.v2 = malloc(sizeof(xen_v2_getdomaininfo)*(size))) != NULL)) - -#define XEN_GETDOMAININFOLIST_FREE(domlist) \ - (hypervisor_version < 2 ? \ - free(domlist.v0) : \ - free(domlist.v2)) - -#define XEN_GETDOMAININFOLIST_CLEAR(domlist, size) \ - (hypervisor_version < 2 ? \ - memset(domlist.v0, 0, sizeof(xen_v0_getdomaininfo) * size) : \ - memset(domlist.v2, 0, sizeof(xen_v2_getdomaininfo) * size)) + (dom_interface_version < 5 ? \ + ((domlist.v2 = malloc(sizeof(xen_v2_getdomaininfo)*(size))) != NULL) : \ + ((domlist.v2d5 = malloc(sizeof(xen_v2d5_getdomaininfo)*(size))) != NULL))) + +#define XEN_GETDOMAININFOLIST_FREE(domlist) \ + (hypervisor_version < 2 ? \ + free(domlist.v0) : \ + (dom_interface_version < 5 ? \ + free(domlist.v2) : \ + free(domlist.v2d5))) + +#define XEN_GETDOMAININFOLIST_CLEAR(domlist, size) \ + (hypervisor_version < 2 ? \ + memset(domlist.v0, 0, sizeof(xen_v0_getdomaininfo) * size) : \ + (dom_interface_version < 5 ? \ + memset(domlist.v2, 0, sizeof(xen_v2_getdomaininfo) * size) : \ + memset(domlist.v2d5, 0, sizeof(xen_v2d5_getdomaininfo) * size))) #define XEN_GETDOMAININFOLIST_DOMAIN(domlist, n) \ (hypervisor_version < 2 ? \ domlist.v0[n].domain : \ - domlist.v2[n].domain) - -#define XEN_GETDOMAININFOLIST_DATA(domlist) \ - (hypervisor_version < 2 ? \ - (void*)(domlist->v0) : \ - (void*)(domlist->v2)) - -#define XEN_GETDOMAININFO_SIZE \ - (hypervisor_version < 2 ? \ - sizeof(xen_v0_getdomaininfo) : \ - sizeof(xen_v2_getdomaininfo)) - -#define XEN_GETDOMAININFO_CLEAR(dominfo) \ - (hypervisor_version < 2 ? \ - memset(&(dominfo.v0), 0, sizeof(xen_v0_getdomaininfo)) : \ - memset(&(dominfo.v2), 0, sizeof(xen_v2_getdomaininfo))) + (dom_interface_version < 5 ? \ + domlist.v2[n].domain : \ + domlist.v2d5[n].domain)) + +#define XEN_GETDOMAININFOLIST_DATA(domlist) \ + (hypervisor_version < 2 ? \ + (void*)(domlist->v0) : \ + (dom_interface_version < 5 ? \ + (void*)(domlist->v2) : \ + (void*)(domlist->v2d5))) + +#define XEN_GETDOMAININFO_SIZE \ + (hypervisor_version < 2 ? \ + sizeof(xen_v0_getdomaininfo) : \ + (dom_interface_version < 5 ? \ + sizeof(xen_v2_getdomaininfo) : \ + sizeof(xen_v2d5_getdomaininfo))) + +#define XEN_GETDOMAININFO_CLEAR(dominfo) \ + (hypervisor_version < 2 ? \ + memset(&(dominfo.v0), 0, sizeof(xen_v0_getdomaininfo)) : \ + (dom_interface_version < 5 ? \ + memset(&(dominfo.v2), 0, sizeof(xen_v2_getdomaininfo)) : \ + memset(&(dominfo.v2d5), 0, sizeof(xen_v2d5_getdomaininfo)))) #define XEN_GETDOMAININFO_DOMAIN(dominfo) \ (hypervisor_version < 2 ? \ dominfo.v0.domain : \ - dominfo.v2.domain) + (dom_interface_version < 5 ? \ + dominfo.v2.domain : \ + dominfo.v2d5.domain)) #define XEN_GETDOMAININFO_CPUTIME(dominfo) \ (hypervisor_version < 2 ? \ dominfo.v0.cpu_time : \ - dominfo.v2.cpu_time) + (dom_interface_version < 5 ? \ + dominfo.v2.cpu_time : \ + dominfo.v2d5.cpu_time)) #define XEN_GETDOMAININFO_CPUCOUNT(dominfo) \ (hypervisor_version < 2 ? \ dominfo.v0.nr_online_vcpus : \ - dominfo.v2.nr_online_vcpus) + (dom_interface_version < 5 ? \ + dominfo.v2.nr_online_vcpus : \ + dominfo.v2d5.nr_online_vcpus)) #define XEN_GETDOMAININFO_MAXCPUID(dominfo) \ (hypervisor_version < 2 ? \ dominfo.v0.max_vcpu_id : \ - dominfo.v2.max_vcpu_id) + (dom_interface_version < 5 ? \ + dominfo.v2.max_vcpu_id : \ + dominfo.v2d5.max_vcpu_id)) #define XEN_GETDOMAININFO_FLAGS(dominfo) \ (hypervisor_version < 2 ? \ dominfo.v0.flags : \ - dominfo.v2.flags) + (dom_interface_version < 5 ? \ + dominfo.v2.flags : \ + dominfo.v2d5.flags)) #define XEN_GETDOMAININFO_TOT_PAGES(dominfo) \ (hypervisor_version < 2 ? \ dominfo.v0.tot_pages : \ - dominfo.v2.tot_pages) + (dom_interface_version < 5 ? \ + dominfo.v2.tot_pages : \ + dominfo.v2d5.tot_pages)) #define XEN_GETDOMAININFO_MAX_PAGES(dominfo) \ (hypervisor_version < 2 ? \ dominfo.v0.max_pages : \ - dominfo.v2.max_pages) + (dom_interface_version < 5 ? \ + dominfo.v2.max_pages : \ + dominfo.v2d5.max_pages)) @@ -247,6 +297,18 @@ struct xen_v2_getdomaininfolistop { }; typedef struct xen_v2_getdomaininfolistop xen_v2_getdomaininfolistop; +/* As of HV version 2, sysctl version 3 the *buffer pointer is 64-bit aligned */ +struct xen_v2s3_getdomaininfolistop { + domid_t first_domain; + uint32_t max_domains; + union { + struct xen_v2d5_getdomaininfo *v; + uint64_t pad ALIGN_64; + } buffer; + uint32_t num_domains; +}; +typedef struct xen_v2s3_getdomaininfolistop xen_v2s3_getdomaininfolistop; + struct xen_v0_domainop { @@ -294,6 +356,11 @@ struct xen_v2_setmaxmem { }; typedef struct xen_v2_setmaxmem xen_v2_setmaxmem; +struct xen_v2d5_setmaxmem { + uint64_t maxmem ALIGN_64; +}; +typedef struct xen_v2d5_setmaxmem xen_v2d5_setmaxmem; + /* * The informations for an setmaxvcpu system hypercall */ @@ -340,6 +407,20 @@ struct xen_v2_setvcpumap { }; typedef struct xen_v2_setvcpumap xen_v2_setvcpumap; +/* HV version 2, Dom version 5 requires 64-bit alignment */ +struct xen_v2d5_cpumap { + union { + uint8_t *v; + uint64_t pad ALIGN_64; + } bitmap; + uint32_t nr_cpus; +}; +struct xen_v2d5_setvcpumap { + uint32_t vcpu; + struct xen_v2d5_cpumap cpumap; +}; +typedef struct xen_v2d5_setvcpumap xen_v2d5_setvcpumap; + /* * The informations for an vcpuinfo system hypercall */ @@ -370,11 +451,22 @@ struct xen_v2_vcpuinfo { }; typedef struct xen_v2_vcpuinfo xen_v2_vcpuinfo; +struct xen_v2d5_vcpuinfo { + uint32_t vcpu; /* the vcpu number */ + uint8_t online; /* seen as on line */ + uint8_t blocked; /* blocked on event */ + uint8_t running; /* scheduled on CPU */ + uint64_t cpu_time ALIGN_64; /* nanosecond of CPU used */ + uint32_t cpu; /* current mapping */ +}; +typedef struct xen_v2d5_vcpuinfo xen_v2d5_vcpuinfo; + /* * from V2 the pinning of a vcpu is read with a separate call */ #define XEN_V2_OP_GETVCPUMAP 25 typedef struct xen_v2_setvcpumap xen_v2_getvcpumap; +typedef struct xen_v2d5_setvcpumap xen_v2d5_getvcpumap; /* * The hypercall operation structures also have changed on @@ -402,7 +494,8 @@ struct xen_op_v2_sys { uint32_t cmd; uint32_t interface_version; union { - xen_v2_getdomaininfolistop getdomaininfolist; + xen_v2_getdomaininfolistop getdomaininfolist; + xen_v2s3_getdomaininfolistop getdomaininfolists3; uint8_t padding[128]; } u; }; @@ -415,10 +508,14 @@ struct xen_op_v2_dom { domid_t domain; union { xen_v2_setmaxmem setmaxmem; + xen_v2d5_setmaxmem setmaxmemd5; xen_v2_setmaxvcpu setmaxvcpu; xen_v2_setvcpumap setvcpumap; + xen_v2d5_setvcpumap setvcpumapd5; xen_v2_vcpuinfo getvcpuinfo; + xen_v2d5_vcpuinfo getvcpuinfod5; xen_v2_getvcpumap getvcpumap; + xen_v2d5_getvcpumap getvcpumapd5; uint8_t padding[128]; } u; }; @@ -726,13 +823,26 @@ virXen_getdomaininfolist(int handle, int first_domain, int maxids, memset(&op, 0, sizeof(op)); op.cmd = XEN_V2_OP_GETDOMAININFOLIST; - op.u.getdomaininfolist.first_domain = (domid_t) first_domain; - op.u.getdomaininfolist.max_domains = maxids; - op.u.getdomaininfolist.buffer = dominfos->v2; - op.u.getdomaininfolist.num_domains = maxids; + + if (sys_interface_version < 3) { + op.u.getdomaininfolist.first_domain = (domid_t) first_domain; + op.u.getdomaininfolist.max_domains = maxids; + op.u.getdomaininfolist.buffer = dominfos->v2; + op.u.getdomaininfolist.num_domains = maxids; + } else { + op.u.getdomaininfolists3.first_domain = (domid_t) first_domain; + op.u.getdomaininfolists3.max_domains = maxids; + op.u.getdomaininfolists3.buffer.v = dominfos->v2d5; + op.u.getdomaininfolists3.num_domains = maxids; + } ret = xenHypervisorDoV2Sys(handle, &op); - if (ret == 0) - ret = op.u.getdomaininfolist.num_domains; + + if (ret == 0) { + if (sys_interface_version < 3) + ret = op.u.getdomaininfolist.num_domains; + else + ret = op.u.getdomaininfolists3.num_domains; + } } else if (hypervisor_version == 1) { xen_op_v1 op; @@ -921,7 +1031,10 @@ virXen_setmaxmem(int handle, int id, unsigned long memory) memset(&op, 0, sizeof(op)); op.cmd = XEN_V2_OP_SETMAXMEM; op.domain = (domid_t) id; - op.u.setmaxmem.maxmem = memory; + if (dom_interface_version < 5) + op.u.setmaxmem.maxmem = memory; + else + op.u.setmaxmemd5.maxmem = memory; ret = xenHypervisorDoV2Dom(handle, &op); } else if (hypervisor_version == 1) { xen_op_v1 op; @@ -1014,10 +1127,17 @@ virXen_setvcpumap(int handle, int id, unsigned int vcpu, memset(&op, 0, sizeof(op)); op.cmd = XEN_V2_OP_SETVCPUMAP; op.domain = (domid_t) id; - op.u.setvcpumap.vcpu = vcpu; - op.u.setvcpumap.cpumap.bitmap = cpumap; - op.u.setvcpumap.cpumap.nr_cpus = maplen * 8; + if (dom_interface_version < 5) { + op.u.setvcpumap.vcpu = vcpu; + op.u.setvcpumap.cpumap.bitmap = cpumap; + op.u.setvcpumap.cpumap.nr_cpus = maplen * 8; + } else { + op.u.setvcpumapd5.vcpu = vcpu; + op.u.setvcpumapd5.cpumap.bitmap.v = cpumap; + op.u.setvcpumapd5.cpumap.nr_cpus = maplen * 8; + } ret = xenHypervisorDoV2Dom(handle, &op); + if (munlock(cpumap, maplen) < 0) { virXenError(VIR_ERR_XEN_CALL, " release", maplen); ret = -1; @@ -1082,29 +1202,56 @@ virXen_getvcpusinfo(int handle, int id, unsigned int vcpu, virVcpuInfoPtr ipt, memset(&op, 0, sizeof(op)); op.cmd = XEN_V2_OP_GETVCPUINFO; op.domain = (domid_t) id; - op.u.getvcpuinfo.vcpu = (uint16_t) vcpu; + if (dom_interface_version < 5) + op.u.getvcpuinfo.vcpu = (uint16_t) vcpu; + else + op.u.getvcpuinfod5.vcpu = (uint16_t) vcpu; ret = xenHypervisorDoV2Dom(handle, &op); + if (ret < 0) return(-1); ipt->number = vcpu; - if (op.u.getvcpuinfo.online) { - if (op.u.getvcpuinfo.running) ipt->state = VIR_VCPU_RUNNING; - if (op.u.getvcpuinfo.blocked) ipt->state = VIR_VCPU_BLOCKED; + if (dom_interface_version < 5) { + if (op.u.getvcpuinfo.online) { + if (op.u.getvcpuinfo.running) + ipt->state = VIR_VCPU_RUNNING; + if (op.u.getvcpuinfo.blocked) + ipt->state = VIR_VCPU_BLOCKED; + } else + ipt->state = VIR_VCPU_OFFLINE; + + ipt->cpuTime = op.u.getvcpuinfo.cpu_time; + ipt->cpu = op.u.getvcpuinfo.online ? (int)op.u.getvcpuinfo.cpu : -1; + } else { + if (op.u.getvcpuinfod5.online) { + if (op.u.getvcpuinfod5.running) + ipt->state = VIR_VCPU_RUNNING; + if (op.u.getvcpuinfod5.blocked) + ipt->state = VIR_VCPU_BLOCKED; + } else + ipt->state = VIR_VCPU_OFFLINE; + + ipt->cpuTime = op.u.getvcpuinfod5.cpu_time; + ipt->cpu = op.u.getvcpuinfod5.online ? (int)op.u.getvcpuinfod5.cpu : -1; } - else ipt->state = VIR_VCPU_OFFLINE; - ipt->cpuTime = op.u.getvcpuinfo.cpu_time; - ipt->cpu = op.u.getvcpuinfo.online ? (int)op.u.getvcpuinfo.cpu : -1; if ((cpumap != NULL) && (maplen > 0)) { if (mlock(cpumap, maplen) < 0) { virXenError(VIR_ERR_XEN_CALL, " locking", maplen); return (-1); } + memset(cpumap, 0, maplen); memset(&op, 0, sizeof(op)); op.cmd = XEN_V2_OP_GETVCPUMAP; op.domain = (domid_t) id; - op.u.setvcpumap.vcpu = vcpu; - op.u.setvcpumap.cpumap.bitmap = cpumap; - op.u.setvcpumap.cpumap.nr_cpus = maplen * 8; + if (dom_interface_version < 5) { + op.u.getvcpumap.vcpu = vcpu; + op.u.getvcpumap.cpumap.bitmap = cpumap; + op.u.getvcpumap.cpumap.nr_cpus = maplen * 8; + } else { + op.u.getvcpumapd5.vcpu = vcpu; + op.u.getvcpumapd5.cpumap.bitmap.v = cpumap; + op.u.getvcpumapd5.cpumap.nr_cpus = maplen * 8; + } ret = xenHypervisorDoV2Dom(handle, &op); if (munlock(cpumap, maplen) < 0) { virXenError(VIR_ERR_XEN_CALL, " release", maplen); @@ -1802,10 +1949,18 @@ xenHypervisorNumOfDomains(virConnectPtr conn) return (-1); nbids = ret; + /* Can't possibly have more than 65,000 concurrent guests + * so limit how many times we try, to avoid increasing + * without bound & thus allocating all of system memory ! + * XXX I'll regret this comment in a few years time ;-) + */ if (nbids == maxids) { - last_maxids *= 2; - maxids *= 2; - goto retry; + if (maxids < 65000) { + last_maxids *= 2; + maxids *= 2; + goto retry; + } + nbids = -1; } if ((nbids < 0) || (nbids > maxids)) return(-1); @@ -1994,7 +2149,8 @@ xenHypervisorGetDomInfo(virConnectPtr conn, int id, virDomainInfoPtr info) return (-1); domain_flags = XEN_GETDOMAININFO_FLAGS(dominfo); - domain_state = domain_flags & 0xFF; + domain_flags &= ~DOMFLAGS_HVM; /* Mask out HVM flags */ + domain_state = domain_flags & 0xFF; /* Mask out high bits */ switch (domain_state) { case DOMFLAGS_DYING: info->state = VIR_DOMAIN_SHUTDOWN; diff --git a/src/xen_unified.c b/src/xen_unified.c index a8a29c9bc8..fe8eb81b0d 100644 --- a/src/xen_unified.c +++ b/src/xen_unified.c @@ -546,13 +546,14 @@ xenUnifiedDomainGetVcpus (virDomainPtr dom, virVcpuInfoPtr info, int maxinfo, unsigned char *cpumaps, int maplen) { - int i; + int i, ret; for (i = 0; i < nb_drivers; ++i) - if (drivers[i]->domainGetVcpus && - drivers[i]->domainGetVcpus (dom, info, maxinfo, cpumaps, maplen) == 0) - return 0; - + if (drivers[i]->domainGetVcpus) { + ret = drivers[i]->domainGetVcpus (dom, info, maxinfo, cpumaps, maplen); + if (ret > 0) + return ret; + } return -1; } diff --git a/src/xend_internal.c b/src/xend_internal.c index c296ad615d..66a2e4a42f 100644 --- a/src/xend_internal.c +++ b/src/xend_internal.c @@ -54,6 +54,7 @@ static virDomainPtr xenDaemonLookupByUUID(virConnectPtr conn, static virDomainPtr xenDaemonCreateLinux(virConnectPtr conn, const char *xmlDesc, unsigned int flags); +static char *xenDaemonDomainGetOSType(virDomainPtr domain); static int xenDaemonAttachDevice(virDomainPtr domain, char *xml); static int xenDaemonDetachDevice(virDomainPtr domain, char *xml); static int xenDaemonDomainCoreDump(virDomainPtr domain, const char *filename, @@ -85,7 +86,7 @@ virDriver xenDaemonDriver = { xenDaemonDomainShutdown, /* domainShutdown */ xenDaemonDomainReboot, /* domainReboot */ xenDaemonDomainDestroy, /* domainDestroy */ - NULL, /* domainGetOSType */ + xenDaemonDomainGetOSType, /* domainGetOSType */ xenDaemonDomainGetMaxMemory, /* domainGetMaxMemory */ xenDaemonDomainSetMaxMemory, /* domainSetMaxMemory */ xenDaemonDomainSetMemory, /* domainMaxMemory */ @@ -1151,7 +1152,7 @@ xend_detect_config_version(virConnectPtr conn) { priv->xendConfigVersion = 1; } sexpr_free(root); - return priv->xendConfigVersion; + return (0); } /** @@ -1251,13 +1252,14 @@ xend_log(virConnectPtr xend, char *buffer, size_t n_buffer) * @node: the root of the parsed S-Expression * @buf: output buffer object * @hvm: true or 1 if no contains HVM S-Expression + * @bootloader: true or 1 if a bootloader is defined * * Parse the xend sexp for description of os and append it to buf. * * Returns 0 in case of success and -1 in case of error */ static int -xend_parse_sexp_desc_os(virConnectPtr xend, struct sexpr *node, virBufferPtr buf, int hvm) +xend_parse_sexp_desc_os(virConnectPtr xend, struct sexpr *node, virBufferPtr buf, int hvm, int bootloader) { const char *tmp; @@ -1269,37 +1271,44 @@ xend_parse_sexp_desc_os(virConnectPtr xend, struct sexpr *node, virBufferPtr buf if (hvm) { virBufferVSprintf(buf, " hvm\n"); tmp = sexpr_node(node, "domain/image/hvm/kernel"); - if (tmp == NULL) { + if (tmp == NULL && !bootloader) { virXendError(xend, VIR_ERR_INTERNAL_ERROR, - _("domain information incomplete, missing kernel")); + _("domain information incomplete, missing kernel & bootloader")); return(-1); - } - virBufferVSprintf(buf, " %s\n", tmp); + } + if (tmp) + virBufferVSprintf(buf, " %s\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, " \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, " \n", 21 ); - else if (strcmp(tmp, "d") == 0) - virBufferAdd(buf, " \n", 24 ); + while (*tmp) { + if (*tmp == 'a') + /* XXX no way to deal with boot from 2nd floppy */ + virBufferAdd(buf, " \n", 21 ); + else if (*tmp == '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, " \n", 21 ); + else if (*tmp == 'd') + virBufferAdd(buf, " \n", 24 ); + else if (*tmp == 'n') + virBufferAdd(buf, " \n", 26 ); + tmp++; + } } } else { virBufferVSprintf(buf, " linux\n"); tmp = sexpr_node(node, "domain/image/linux/kernel"); - if (tmp == NULL) { + if (tmp == NULL && !bootloader) { virXendError(xend, VIR_ERR_INTERNAL_ERROR, - _("domain information incomplete, missing kernel")); + _("domain information incomplete, missing kernel & bootloader")); return(-1); - } - virBufferVSprintf(buf, " %s\n", tmp); + } + if (tmp) + virBufferVSprintf(buf, " %s\n", tmp); tmp = sexpr_node(node, "domain/image/linux/ramdisk"); if ((tmp != NULL) && (tmp[0] != 0)) virBufferVSprintf(buf, " %s\n", tmp); @@ -1334,7 +1343,7 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root, int xendConfigVersi const char *tmp; char *tty; virBuffer buf; - int hvm = 0; + int hvm = 0, bootloader = 0; int domid = -1; int max_mem, cur_mem; @@ -1385,12 +1394,20 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root, int xendConfigVersi virBufferVSprintf(&buf, " %s\n", compact); } tmp = sexpr_node(root, "domain/bootloader"); - if (tmp != NULL) + if (tmp != NULL) { + bootloader = 1; virBufferVSprintf(&buf, " %s\n", tmp); + } - if (sexpr_lookup(root, "domain/image")) { - hvm = sexpr_lookup(root, "domain/image/hvm") ? 1 : 0; - xend_parse_sexp_desc_os(conn, root, &buf, hvm); + if (domid == 0) { + virBufferAdd(&buf, " \n", -1); + virBufferAdd(&buf, " linux\n", -1); + virBufferAdd(&buf, " \n", -1); + } else { + if (sexpr_lookup(root, "domain/image")) { + hvm = sexpr_lookup(root, "domain/image/hvm") ? 1 : 0; + xend_parse_sexp_desc_os(conn, root, &buf, hvm, bootloader); + } } max_mem = (int) (sexpr_u64(root, "domain/maxmem") << 10); @@ -1585,9 +1602,9 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root, int xendConfigVersi } else if (sexpr_lookup(node, "device/vif")) { const char *tmp2; tmp2 = sexpr_node(node, "device/vif/script"); - if (tmp2 && strstr(tmp2, "bridge")) { + tmp = sexpr_node(node, "device/vif/bridge"); + if ((tmp2 && strstr(tmp2, "bridge")) || tmp) { virBufferVSprintf(&buf, " \n"); - tmp = sexpr_node(node, "device/vif/bridge"); if (tmp != NULL) virBufferVSprintf(&buf, " \n", tmp); @@ -1612,9 +1629,9 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root, int xendConfigVersi tmp2); virBufferAdd(&buf, " \n", 17); - } else if (!hvm && - sexpr_lookup(node, "device/vfb")) { - /* New style graphics config for PV guests only in 3.0.4 */ + } else if (sexpr_lookup(node, "device/vfb")) { + /* New style graphics config for PV guests in >= 3.0.4, + * or for HVM guests in >= 3.0.5 */ tmp = sexpr_node(node, "device/vfb/type"); if (tmp && !strcmp(tmp, "sdl")) { @@ -1663,7 +1680,7 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root, int xendConfigVersi } } - /* Graphics device (HVM, or old (pre-3.0.4) style PV vnc config) */ + /* Graphics device (HVM <= 3.0.4, or PV <= 3.0.4) vnc config */ tmp = sexpr_fmt_node(root, "domain/image/%s/vnc", hvm ? "hvm" : "linux"); if (tmp != NULL) { if (tmp[0] == '1') { @@ -1901,7 +1918,6 @@ xenDaemonOpen(virConnectPtr conn, const char *name, int flags) { xmlURIPtr uri = NULL; int ret; - unsigned long version; /* If the name is just "xen" (it might originally have been NULL, see * xenUnifiedOpen) then try default paths and methods to get to the @@ -1914,8 +1930,8 @@ xenDaemonOpen(virConnectPtr conn, const char *name, int flags) ret = xenDaemonOpen_unix(conn, "/var/lib/xend/xend-socket"); if (ret < 0) goto try_http; - ret = xenDaemonGetVersion(conn, &version); - if (ret == 0) + ret = xend_detect_config_version(conn); + if (ret != -1) goto done; try_http: @@ -1925,8 +1941,8 @@ xenDaemonOpen(virConnectPtr conn, const char *name, int flags) ret = xenDaemonOpen_tcp(conn, "localhost", 8000); if (ret < 0) goto failed; - ret = xenDaemonGetVersion(conn, &version); - if (ret < 0) + ret = xend_detect_config_version(conn); + if (ret == -1) goto failed; } else { /* @@ -1950,15 +1966,15 @@ xenDaemonOpen(virConnectPtr conn, const char *name, int flags) if (ret < 0) goto failed; - ret = xenDaemonGetVersion(conn, &version); - if (ret < 0) + ret = xend_detect_config_version(conn); + if (ret == -1) goto failed; } else if (!strcasecmp(uri->scheme, "http")) { ret = xenDaemonOpen_tcp(conn, uri->server, uri->port); if (ret < 0) goto failed; - ret = xenDaemonGetVersion(conn, &version); - if (ret < 0) + ret = xend_detect_config_version(conn); + if (ret == -1) goto failed; } else { if (!(flags & VIR_DRV_OPEN_QUIET)) @@ -1967,17 +1983,7 @@ xenDaemonOpen(virConnectPtr conn, const char *name, int flags) } } - done: - /* The XenD config version is used to determine - * which APIs / features to activate. Lookup & cache - * it now to avoid repeated HTTP calls - */ - if (xend_detect_config_version(conn) < 0) { - virXendError(conn, VIR_ERR_INTERNAL_ERROR, - "cannot determine xend config version"); - goto failed; - } - + done: if (uri != NULL) xmlFreeURI(uri); return(ret); @@ -2122,6 +2128,49 @@ xenDaemonDomainDestroy(virDomainPtr domain) return xend_op(domain->conn, domain->name, "op", "destroy", NULL); } +/** + * xenDaemonDomainGetOSType: + * @domain: a domain object + * + * Get the type of domain operation system. + * + * Returns the new string or NULL in case of error, the string must be + * freed by the caller. + */ +static char * +xenDaemonDomainGetOSType(virDomainPtr domain) +{ + char *type; + struct sexpr *root; + xenUnifiedPrivatePtr priv; + + if ((domain == NULL) || (domain->conn == NULL) || (domain->name == NULL)) { + virXendError((domain ? domain->conn : NULL), VIR_ERR_INVALID_ARG, + __FUNCTION__); + return(NULL); + } + + priv = (xenUnifiedPrivatePtr) domain->conn->privateData; + + if (domain->id < 0 && priv->xendConfigVersion < 3) + return(NULL); + + /* can we ask for a subset ? worth it ? */ + root = sexpr_get(domain->conn, "/xend/domain/%s?detail=1", domain->name); + if (root == NULL) + return(NULL); + + if (sexpr_lookup(root, "domain/image/hvm")) { + type = strdup("hvm"); + } else { + type = strdup("linux"); + } + + sexpr_free(root); + + return(type); +} + /** * xenDaemonDomainSave: * @domain: pointer to the Domain block @@ -2892,7 +2941,7 @@ xenDaemonLookupByUUID(virConnectPtr conn, const unsigned char *uuid) uuid[4], uuid[5], uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], uuid[12], uuid[13], uuid[14], uuid[15]); - printf("Dpooing %s\n", uuidstr); + root = sexpr_get(conn, "/xend/domain/%s?detail=1", uuidstr); if (root == NULL) return (NULL); diff --git a/src/xml.c b/src/xml.c index 89913cf6b2..6796d53ece 100644 --- a/src/xml.c +++ b/src/xml.c @@ -591,7 +591,8 @@ virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node, virBufferPtr buf xmlNodePtr cur, txt; xmlChar *type = NULL; xmlChar *loader = NULL; - xmlChar *boot_dev = NULL; + char bootorder[5]; + int nbootorder = 0; int res; char *str; @@ -610,13 +611,32 @@ virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node, virBufferPtr buf if ((txt != NULL) && (txt->type == XML_TEXT_NODE) && (txt->next == NULL)) loader = txt->content; - } else if ((boot_dev == NULL) && - (xmlStrEqual(cur->name, BAD_CAST "boot"))) { - boot_dev = xmlGetProp(cur, BAD_CAST "dev"); + } else if ((xmlStrEqual(cur->name, BAD_CAST "boot"))) { + xmlChar *boot_dev = xmlGetProp(cur, BAD_CAST "dev"); + if (nbootorder == ((sizeof(bootorder)/sizeof(bootorder[0]))-1)) { + virXMLError(conn, VIR_ERR_XML_ERROR, "too many boot devices", 0); + return (-1); + } + if (xmlStrEqual(boot_dev, BAD_CAST "fd")) { + bootorder[nbootorder++] = 'a'; + } else if (xmlStrEqual(boot_dev, BAD_CAST "cdrom")) { + bootorder[nbootorder++] = 'd'; + } else if (xmlStrEqual(boot_dev, BAD_CAST "network")) { + bootorder[nbootorder++] = 'n'; + } else if (xmlStrEqual(boot_dev, BAD_CAST "hd")) { + bootorder[nbootorder++] = 'c'; + } else { + xmlFree(boot_dev); + /* Any other type of boot dev is unsupported right now */ + virXMLError(conn, VIR_ERR_XML_ERROR, NULL, 0); + return (-1); + } + xmlFree(boot_dev); } } cur = cur->next; } + bootorder[nbootorder] = '\0'; if ((type == NULL) || (!xmlStrEqual(type, BAD_CAST "hvm"))) { /* VIR_ERR_OS_TYPE */ virXMLError(conn, VIR_ERR_OS_TYPE, (const char *) type, 0); @@ -641,73 +661,58 @@ virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node, virBufferPtr buf virBufferVSprintf(buf, "(vcpus %d)", vcpus); - 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(conn, VIR_ERR_XML_ERROR, NULL, 0); - } + if (nbootorder) + virBufferVSprintf(buf, "(boot %s)", bootorder); - /* get the 1st floppy device file */ - cur = virXPathNode( - "/domain/devices/disk[@device='floppy' and target/@dev='fda']/source", - ctxt); + /* get the 1st floppy device file */ + cur = virXPathNode("/domain/devices/disk[@device='floppy' and target/@dev='fda']/source", + ctxt); if (cur != NULL) { - xmlChar *fdfile; - - fdfile = xmlGetProp(cur, BAD_CAST "file"); + xmlChar *fdfile; + fdfile = xmlGetProp(cur, BAD_CAST "file"); if (fdfile != NULL) { - virBufferVSprintf(buf, "(fda '%s')", fdfile); - free(fdfile); + virBufferVSprintf(buf, "(fda '%s')", fdfile); + free(fdfile); } - } + } - /* get the 2nd floppy device file */ - cur = virXPathNode( - "/domain/devices/disk[@device='floppy' and target/@dev='fdb']/source", - ctxt); + /* get the 2nd floppy device file */ + cur = virXPathNode("/domain/devices/disk[@device='floppy' and target/@dev='fdb']/source", + ctxt); if (cur != NULL) { - xmlChar *fdfile; - - fdfile = xmlGetProp(cur, BAD_CAST "file"); + xmlChar *fdfile; + fdfile = xmlGetProp(cur, BAD_CAST "file"); if (fdfile != NULL) { - virBufferVSprintf(buf, "(fdb '%s')", fdfile); - free(fdfile); + virBufferVSprintf(buf, "(fdb '%s')", fdfile); + free(fdfile); } - } + } - /* get the cdrom device file */ - /* Only XenD <= 3.0.2 wants cdrom config here */ - if (xendConfigVersion == 1) { - cur = virXPathNode( - "/domain/devices/disk[@device='cdrom' and target/@dev='hdc']/source", + /* get the cdrom device file */ + /* Only XenD <= 3.0.2 wants cdrom config here */ + if (xendConfigVersion == 1) { + cur = virXPathNode("/domain/devices/disk[@device='cdrom' and target/@dev='hdc']/source", ctxt); if (cur != NULL) { - xmlChar *cdfile; - - cdfile = xmlGetProp(cur, BAD_CAST "file"); - if (cdfile != NULL) { - virBufferVSprintf(buf, "(cdrom '%s')", - (const char *)cdfile); - xmlFree(cdfile); - } + xmlChar *cdfile; + + cdfile = xmlGetProp(cur, BAD_CAST "file"); + if (cdfile != NULL) { + virBufferVSprintf(buf, "(cdrom '%s')", + (const char *)cdfile); + xmlFree(cdfile); } } - - if (virXPathNode("/domain/features/acpi", ctxt) != NULL) - virBufferAdd(buf, "(acpi 1)", 8); - if (virXPathNode("/domain/features/apic", ctxt) != NULL) - virBufferAdd(buf, "(apic 1)", 8); - if (virXPathNode("/domain/features/pae", ctxt) != NULL) - virBufferAdd(buf, "(pae 1)", 7); } + if (virXPathNode("/domain/features/acpi", ctxt) != NULL) + virBufferAdd(buf, "(acpi 1)", 8); + if (virXPathNode("/domain/features/apic", ctxt) != NULL) + virBufferAdd(buf, "(apic 1)", 8); + if (virXPathNode("/domain/features/pae", ctxt) != NULL) + virBufferAdd(buf, "(pae 1)", 7); + res = virXPathBoolean("count(domain/devices/console) > 0", ctxt); if (res < 0) { virXMLError(conn, VIR_ERR_XML_ERROR, NULL, 0); @@ -717,25 +722,24 @@ virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node, virBufferPtr buf virBufferAdd(buf, "(serial pty)", 12); } - /* Is a graphics device specified? */ - cur = virXPathNode("/domain/devices/graphics[1]", ctxt); - if (cur != NULL) { - res = virDomainParseXMLGraphicsDescImage(conn, cur, buf, - xendConfigVersion); - if (res != 0) { - goto error; + /* HVM graphics for xen <= 3.0.5 */ + if (xendConfigVersion < 4) { + /* Is a graphics device specified? */ + cur = virXPathNode("/domain/devices/graphics[1]", ctxt); + if (cur != NULL) { + res = virDomainParseXMLGraphicsDescImage(conn, cur, buf, + xendConfigVersion); + if (res != 0) { + goto error; + } } } virBufferAdd(buf, "))", 2); - if (boot_dev) - xmlFree(boot_dev); - return (0); + error: - if (boot_dev) - xmlFree(boot_dev); return(-1); } @@ -821,13 +825,12 @@ virDomainParseXMLOSDescPV(virConnectPtr conn, xmlNodePtr node, virBufferPtr buf, if (cmdline != NULL) virBufferVSprintf(buf, "(args '%s')", (const char *) cmdline); - /* Is a graphics device specified? */ - /* Old style config before merge of PVFB */ + /* PV graphics for xen <= 3.0.4 */ if (xendConfigVersion < 3) { cur = virXPathNode("/domain/devices/graphics[1]", ctxt); if (cur != NULL) { res = virDomainParseXMLGraphicsDescImage(conn, cur, buf, - xendConfigVersion); + xendConfigVersion); if (res != 0) { goto error; } @@ -1326,7 +1329,7 @@ virDomainParseXMLDesc(virConnectPtr conn, const char *xmldesc, char **name, int goto error; } } - free(nodes); + free(nodes); } nb_nodes = virXPathNodeSet("/domain/devices/interface", ctxt, &nodes); @@ -1340,21 +1343,23 @@ virDomainParseXMLDesc(virConnectPtr conn, const char *xmldesc, char **name, int } virBufferAdd(&buf, ")", 1); } - free(nodes); + free(nodes); } - /* New style PVFB config - 3.0.4 merge */ - if (xendConfigVersion >= 3 && !hvm) { + /* New style PV graphics config xen >= 3.0.4, + * or HVM graphics config xen >= 3.0.5 */ + if ((xendConfigVersion >= 3 && !hvm) || + (xendConfigVersion >= 4 && hvm)) { nb_nodes = virXPathNodeSet("/domain/devices/graphics", ctxt, &nodes); - if (nb_nodes > 0) { + if (nb_nodes > 0) { for (i = 0; i < nb_nodes; i++) { res = virDomainParseXMLGraphicsDescVFB(conn, nodes[i], &buf); if (res != 0) { - free(nodes); + free(nodes); goto error; } } - free(nodes); + free(nodes); } } diff --git a/src/xs_internal.c b/src/xs_internal.c index 78dda410f3..35189eee05 100644 --- a/src/xs_internal.c +++ b/src/xs_internal.c @@ -741,8 +741,6 @@ xenStoreDomainGetOSType(virDomainPtr domain) { str = virDomainGetVMInfo(domain, vm, "image/ostype"); free(vm); } - if (str == NULL) - str = strdup("linux"); return (str); } diff --git a/tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml b/tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml index 5b9c7f61f2..c11ee9183c 100644 --- a/tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml +++ b/tests/sexpr2xmldata/sexpr2xml-no-source-cdrom.xml @@ -19,7 +19,8 @@ /usr/lib/xen/bin/qemu-dm - + + -- GitLab