[Libvir] PATCH: support Xen 3.0.5

Daniel P. Berrange berrange at redhat.com
Thu Apr 12 01:46:46 UTC 2007


I've been doing some testing with current xen-unstable (ie what will very
shortly be 3.0.5) and came across a whole bunch of things which needed
fixing - some expected, others not expected. The attached patch addresses
the following issues:

  - Many of the hypercalls have their structs changed so that int64_t
    or 'foo *' members are always 64-bit aligned even on 32-bit platforms.
    This is part of the work to allow 32-bit Dom0/DomU to work on 64-bit
    hypervisor. 

    For the int64_t types I had to annotate with __attribute__((aligned(8))).
    This did not work for pointer data types, so I for those I had to do
    a more complex hack with

        union {
           foo *v;
           int64_t pad __attribute__((aligned(8)))
        }

    This matches what is done in the public (BSD licensed) Xen HV header
    files.

    We already had ways to deal with v0  vs v2  hypercalls structs. This
    change is still techincally v2, but just a minor revision of the
    domctl or sysctl interfaces. Thus I have named the extra structs
    v2d5 or v2s3  to indicated hypercall version 2, domctl version 5
    or hypercall version 2, sysctl version 3 respectively.

  - The 'flags' field in the getdomaininfo hypercall now has an extra flag
    defined '(1<<1)' which was previously not used, is now used to indicate
    that the guest is HVM. Thus when fetching domain state, we have to mask
    out that flag, otherwise we'll never match the correct paused/running/
    blocked/etc states.

  - In the xenHypervisorNumOfDomains method, under certain scenarios we
    will re-try the hypercall, allocating a bigger memory buffer. Well
    due to the ABI alignment changes we hit that scenario everytime, and
    ended up allocating a multi-GB buffer :-) The fixed structs sort this
    out, but as a preventative measure for any future HV changes the patch
    will break out of the loop at the 10,000 guest mark to avoid allocating
    GB of memory.

  - The unified Xen driver broke the GetVCPUs method - it was mistakenly
    checking for return value == 0, instead of > 0. Trivial fix.
  
  - The method to open the XenD connection was calling xenDaemonGetVersion
    to test if the connection succeeded. But then also calling the
    xend_detect_config_version which does pretty much same thing. So I
    removed the former, and now we only do the latter as a 'ping' test 
    when opening. This removes 1 HTTP GET which is worthwhile performance
    boost given how horrifically slow XenD is.

  - The HVM SEXPR for configuring the VNC / SDL graphics is no longere
    part of the (image) block. it now matches the PVFB graphics config
    and is an explicit  (vfb)  block within the (devices) block.
    So if xend_config_format >= 4 we use the new style config - this
    is assuming upstream XenD is patched to increment xend_config_format
    from 3 to 4 - I send a patch & am confident it will be applied
    very shortly.

  - The QEMU device model allows a user to specify multiple devices
    for the boot order, eg  'andc' to indicated 'floppy', 'network'
    'cdrom', 'disk'. We assumed it was a single letter only. I now
    serialize this into multiple <boot dev='XXX'/> elements, ordered
    according to priority. The XML -> SEXPR conversion allows the
    same.


I've tested all this on a 32-bit Dom0 running on 32-bit HV, and 64-bit HV,
but not tested a 64-bit Dom0 on 64-bit HV. I'm pretty sure it'll work,but
if anyone is runnning 64-on-64 please test this patch.

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  -=| 
-------------- next part --------------
Index: xen_internal.c
===================================================================
RCS file: /data/cvs/libvirt/src/xen_internal.c,v
retrieving revision 1.70
diff -u -p -r1.70 xen_internal.c
--- xen_internal.c	4 Apr 2007 14:19:49 -0000	1.70
+++ xen_internal.c	12 Apr 2007 00:52:26 -0000
@@ -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
 
         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, uns
         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, un
         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, 
         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;
-        }
-        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 (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;
+        }
         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 
         return (-1);
 
     nbids = ret;
+    /* Can't possibly have more than 10,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 < 10000) {
+            last_maxids *= 2;
+            maxids *= 2;
+            goto retry;
+        }
+        nbids = -1;
     }
     if ((nbids < 0) || (nbids > maxids))
         return(-1);
@@ -1994,7 +2149,8 @@ xenHypervisorGetDomInfo(virConnectPtr co
         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;
Index: xen_unified.c
===================================================================
RCS file: /data/cvs/libvirt/src/xen_unified.c,v
retrieving revision 1.3
diff -u -p -r1.3 xen_unified.c
--- xen_unified.c	10 Apr 2007 13:00:26 -0000	1.3
+++ xen_unified.c	12 Apr 2007 00:52:26 -0000
@@ -546,13 +546,14 @@ xenUnifiedDomainGetVcpus (virDomainPtr d
                           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;
 }
 
Index: xend_internal.c
===================================================================
RCS file: /data/cvs/libvirt/src/xend_internal.c,v
retrieving revision 1.107
diff -u -p -r1.107 xend_internal.c
--- xend_internal.c	11 Apr 2007 16:06:30 -0000	1.107
+++ xend_internal.c	12 Apr 2007 00:52:28 -0000
@@ -1151,7 +1151,7 @@ xend_detect_config_version(virConnectPtr
         priv->xendConfigVersion = 1;
     }
     sexpr_free(root);
-    return priv->xendConfigVersion;
+    return (0);
 }
 
 /**
@@ -1251,13 +1251,14 @@ xend_log(virConnectPtr xend, char *buffe
  * @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 +1270,44 @@ xend_parse_sexp_desc_os(virConnectPtr xe
     if (hvm) {
         virBufferVSprintf(buf, "    <type>hvm</type>\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, "    <loader>%s</loader>\n", tmp);
+        }
+        if (tmp)
+            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 );
+            while (*tmp) {
+                if (*tmp == 'a')
+                    /* XXX no way to deal with boot from 2nd floppy */
+                    virBufferAdd(buf, "    <boot dev='fd'/>\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, "    <boot dev='hd'/>\n", 21 );
+                else if (*tmp == 'd')
+                    virBufferAdd(buf, "    <boot dev='cdrom'/>\n", 24 );
+                else if (*tmp == 'n')
+                    virBufferAdd(buf, "    <boot dev='network'/>\n", 26 );
+                tmp++;
+            }
         }
     } else {
         virBufferVSprintf(buf, "    <type>linux</type>\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, "    <kernel>%s</kernel>\n", tmp);
+        }
+        if (tmp)
+            virBufferVSprintf(buf, "    <kernel>%s</kernel>\n", tmp);
         tmp = sexpr_node(node, "domain/image/linux/ramdisk");
         if ((tmp != NULL) && (tmp[0] != 0))
            virBufferVSprintf(buf, "    <initrd>%s</initrd>\n", tmp);
@@ -1334,7 +1342,7 @@ xend_parse_sexp_desc(virConnectPtr conn,
     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 +1393,14 @@ xend_parse_sexp_desc(virConnectPtr conn,
 	    virBufferVSprintf(&buf, "  <uuid>%s</uuid>\n", compact);
     }
     tmp = sexpr_node(root, "domain/bootloader");
-    if (tmp != NULL)
+    if (tmp != NULL) {
+        bootloader = 1;
         virBufferVSprintf(&buf, "  <bootloader>%s</bootloader>\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);
+        xend_parse_sexp_desc_os(conn, root, &buf, hvm, bootloader);
     }
 
     max_mem = (int) (sexpr_u64(root, "domain/maxmem") << 10);
@@ -1612,9 +1622,9 @@ xend_parse_sexp_desc(virConnectPtr conn,
                                   tmp2);
 
             virBufferAdd(&buf, "    </interface>\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 +1673,7 @@ xend_parse_sexp_desc(virConnectPtr conn,
         }
     }
 
-    /* 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 +1911,6 @@ xenDaemonOpen(virConnectPtr conn, const 
 {
     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 +1923,8 @@ xenDaemonOpen(virConnectPtr conn, const 
         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 +1934,8 @@ xenDaemonOpen(virConnectPtr conn, const 
         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 +1959,15 @@ xenDaemonOpen(virConnectPtr conn, const 
             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 +1976,7 @@ xenDaemonOpen(virConnectPtr conn, const 
         }
     }
 
- 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);
@@ -2962,7 +2961,7 @@ xenDaemonCreateLinux(virConnectPtr conn,
 
         return (NULL);
     }
-
+    printf("%s\n", sexpr);
     ret = xenDaemonDomainCreateLinux(conn, sexpr);
     free(sexpr);
     if (ret != 0) {
Index: xml.c
===================================================================
RCS file: /data/cvs/libvirt/src/xml.c,v
retrieving revision 1.71
diff -u -p -r1.71 xml.c
--- xml.c	11 Apr 2007 16:06:30 -0000	1.71
+++ xml.c	12 Apr 2007 00:52:29 -0000
@@ -591,7 +591,8 @@ virDomainParseXMLOSDescHVM(virConnectPtr
     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
                 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
 
     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;
+            xmlChar *cdfile;
 
-                cdfile = xmlGetProp(cur, BAD_CAST "file");
-		if (cdfile != NULL) {
-		    virBufferVSprintf(buf, "(cdrom '%s')",
-				      (const char *)cdfile);
-		    xmlFree(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
         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 
     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
                 goto error;
             }
         }
-	free(nodes);
+        free(nodes);
     }
 
     nb_nodes = virXPathNodeSet("/domain/devices/interface", ctxt, &nodes);
@@ -1340,21 +1343,23 @@ virDomainParseXMLDesc(virConnectPtr conn
             }
             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);
         }
     }
 


More information about the libvir-list mailing list