[Libvir] Problem with hypercall

Daniel P. Berrange berrange at redhat.com
Thu Sep 28 20:43:19 UTC 2006


On Thu, Sep 28, 2006 at 07:20:35PM +0100, Daniel P. Berrange wrote:
> On Tue, Sep 19, 2006 at 12:12:19PM -0400, Daniel Veillard wrote:
> > On Wed, Sep 13, 2006 at 09:13:35PM -0400, Daniel Veillard wrote:
> > > On Wed, Sep 13, 2006 at 12:55:01PM -0600, Jim Fehlig wrote:
> > > > I found that the buffer provided for XEN_V1_OP_GETDOMAININFOLIST 
> > > > hypercall differs slightly from the buffer in xen/dom0_ops.h.
> > > 
> > >   ohh, that's quite possible I made a mistake in rebuilding the code, yes
> > > 
> > > > Attached is a patch against current cvs that works for me, but I'm not 
> > > > familiar with this part of the code so not sure if this is the proper fix.
> > > 
> > >   I will try to double check today or tomorrow as I'm on the road,
> > > thanks a lot for the patch.
> > 
> >   Okay, I'm finally back, confirmed my error (sorry I should have tried a
> > 32bit box too but had none handy with the old code). So applied and commited,
> 
> Urm, but this has now broken things on 32-bit  3.0.3 based Xen HV.
> 
> # virsh dominfo Domain-0 | grep CPU
> CPU(s):         115
> 
> And also
> 
> #  virsh vcpuinfo Domain-0 
> libvir: Xen error : failed Xen syscall  ioctl  3166208
> 
> Looks like we need different versions of this struct depending on which
> Xen we're working against.

This is really quite a nasty problem, because the struct is passed into from
numerous locations in the xen_internal.h code & I didn't want to cover the
entire source with conditionals.

So what I've done is declared a new xen_v2_domaininfo struct which is
the same as xen_v0_domaininfo, but with Jim's patch reverted again.
Then provide two unions

  union xen_getdomaininfo {
    struct xen_v0_getdomaininfo v0;
    struct xen_v2_getdomaininfo v2;
  };
  typedef union xen_getdomaininfo xen_getdomaininfo;

  union xen_getdomaininfolist {
    struct xen_v0_getdomaininfo *v0;
    struct xen_v2_getdomaininfo *v2;
  };
  typedef union xen_getdomaininfolist xen_getdomaininfolist;

The caller must populate & read either v0, or v2 as apropriate - to avoid
ugly  if (hypervisor_version < 2) ...v0... else ...v2...  I define a bunhc
of macros for accessing fields in these two unions. eg

  #define XEN_GETDOMAININFOLIST_DOMAIN(domlist, n) \
    (hypervisor_version < 2 ? \
     domlist.v0[n].domain : \
     domlist.v2[n].domain)

Or

  #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))


Anyway, I'm attaching a patch which I've tested against 32-bit HV on both
Xen 3.0.2 and 3.0.3, and also a 64-bit HV on 3.0.2 and 3.0.3  and all the
operations now work correctly again...

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: src/xen_internal.c
===================================================================
RCS file: /data/cvs/libvirt/src/xen_internal.c,v
retrieving revision 1.41
diff -u -b -r1.41 xen_internal.c
--- src/xen_internal.c	21 Sep 2006 15:24:37 -0000	1.41
+++ src/xen_internal.c	28 Sep 2006 21:23:02 -0000
@@ -99,13 +99,109 @@
 };
 typedef struct xen_v0_getdomaininfo xen_v0_getdomaininfo;
 
-struct xen_v0_getdomaininfolist {
+struct xen_v2_getdomaininfo {
+    domid_t  domain;	/* the domain number */
+    uint32_t flags;	/* falgs, see before */
+    uint64_t tot_pages;	/* total number of pages used */
+    uint64_t max_pages;	/* maximum number of pages allowed */
+    uint64_t shared_info_frame; /* MFN of shared_info struct */
+    uint64_t cpu_time;  /* 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_v2_getdomaininfo xen_v2_getdomaininfo;
+
+union xen_getdomaininfo {
+    struct xen_v0_getdomaininfo v0;
+    struct xen_v2_getdomaininfo v2;
+};
+typedef union xen_getdomaininfo xen_getdomaininfo;
+
+union xen_getdomaininfolist {
+    struct xen_v0_getdomaininfo *v0;
+    struct xen_v2_getdomaininfo *v2;
+};
+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))
+
+#define XEN_GETDOMAININFOLIST_DOMAIN(domlist, n) \
+    (hypervisor_version < 2 ? \
+     domlist.v0[n].domain : \
+     domlist.v2[n].domain)
+
+
+
+#define XEN_GETDOMAININFO_CLEAR(dominfo) \
+    (hypervisor_version < 2 ? \
+     memset(&(dominfo.v0), 0, sizeof(xen_v0_getdomaininfo)) : \
+     memset(&(dominfo.v2), 0, sizeof(xen_v2_getdomaininfo)))
+
+#define XEN_GETDOMAININFO_DOMAIN(dominfo) \
+    (hypervisor_version < 2 ? \
+     dominfo.v0.domain : \
+     dominfo.v2.domain)
+
+#define XEN_GETDOMAININFO_CPUTIME(dominfo) \
+    (hypervisor_version < 2 ? \
+     dominfo.v0.cpu_time : \
+     dominfo.v2.cpu_time)
+
+#define XEN_GETDOMAININFO_CPUCOUNT(dominfo) \
+    (hypervisor_version < 2 ? \
+     dominfo.v0.nr_online_vcpus : \
+     dominfo.v2.nr_online_vcpus)
+
+#define XEN_GETDOMAININFO_FLAGS(dominfo) \
+    (hypervisor_version < 2 ? \
+     dominfo.v0.flags : \
+     dominfo.v2.flags)
+
+#define XEN_GETDOMAININFO_TOT_PAGES(dominfo) \
+    (hypervisor_version < 2 ? \
+     dominfo.v0.tot_pages : \
+     dominfo.v2.tot_pages)
+
+#define XEN_GETDOMAININFO_MAX_PAGES(dominfo) \
+    (hypervisor_version < 2 ? \
+     dominfo.v0.max_pages : \
+     dominfo.v2.max_pages)
+
+
+
+struct xen_v0_getdomaininfolistop {
     domid_t   first_domain;
     uint32_t  max_domains;
     struct xen_v0_getdomaininfo *buffer;
     uint32_t  num_domains;
 };
-typedef struct xen_v0_getdomaininfolist xen_v0_getdomaininfolist;
+typedef struct xen_v0_getdomaininfolistop xen_v0_getdomaininfolistop;
+
+
+struct xen_v2_getdomaininfolistop {
+    domid_t   first_domain;
+    uint32_t  max_domains;
+    struct xen_v2_getdomaininfo *buffer;
+    uint32_t  num_domains;
+};
+typedef struct xen_v2_getdomaininfolistop xen_v2_getdomaininfolistop;
+
+
 
 struct xen_v0_domainop {
     domid_t   domain;
@@ -244,7 +340,7 @@
     uint32_t cmd;
     uint32_t interface_version;
     union {
-        xen_v0_getdomaininfolist getdomaininfolist;
+        xen_v0_getdomaininfolistop getdomaininfolist;
 	xen_v0_domainop          domain;
 	xen_v0_setmaxmem         setmaxmem;
 	xen_v0_setmaxvcpu        setmaxvcpu;
@@ -261,7 +357,7 @@
     uint32_t cmd;
     uint32_t interface_version;
     union {
-        xen_v0_getdomaininfolist getdomaininfolist;
+        xen_v2_getdomaininfolistop getdomaininfolist;
 	uint8_t padding[128];
     } u;
 };
@@ -545,7 +641,7 @@
  */
 static int
 virXen_getdomaininfolist(int handle, int first_domain, int maxids,
-                         xen_v0_getdomaininfo *dominfos)
+                         xen_getdomaininfolist *dominfos)
 {
     int ret = -1;
 
@@ -561,7 +657,7 @@
 	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;
+        op.u.getdomaininfolist.buffer = dominfos->v2;
 	op.u.getdomaininfolist.num_domains = maxids;
 	ret = xenHypervisorDoV2Sys(handle, &op);
 	if (ret == 0)
@@ -573,7 +669,7 @@
 	op.cmd = XEN_V1_OP_GETDOMAININFOLIST;
 	op.u.getdomaininfolist.first_domain = (domid_t) first_domain;
 	op.u.getdomaininfolist.max_domains = maxids;
-	op.u.getdomaininfolist.buffer = dominfos;
+        op.u.getdomaininfolist.buffer = dominfos->v0;
 	op.u.getdomaininfolist.num_domains = maxids;
 	ret = xenHypervisorDoV1Op(handle, &op);
 	if (ret == 0)
@@ -585,7 +681,7 @@
 	op.cmd = XEN_V0_OP_GETDOMAININFOLIST;
 	op.u.getdomaininfolist.first_domain = (domid_t) first_domain;
 	op.u.getdomaininfolist.max_domains = maxids;
-	op.u.getdomaininfolist.buffer = dominfos;
+        op.u.getdomaininfolist.buffer = dominfos->v0;
 	op.u.getdomaininfolist.num_domains = maxids;
 	ret = xenHypervisorDoV0Op(handle, &op);
 	if (ret == 0)
@@ -599,6 +695,21 @@
     return(ret);
 }
 
+static int
+virXen_getdomaininfo(int handle, int first_domain,
+                     xen_getdomaininfo *dominfo) {
+    xen_getdomaininfolist dominfos;
+
+    if (hypervisor_version < 2) {
+        dominfos.v0 = &(dominfo->v0);
+    } else {
+        dominfos.v2 = &(dominfo->v2);
+    }
+
+    return virXen_getdomaininfolist(handle, first_domain, 1, &dominfos);
+}
+
+
 #ifndef PROXY
 /**
  * virXen_pausedomain:
@@ -998,7 +1109,7 @@
     int fd, ret, cmd;
     hypercall_t hc;
     v0_hypercall_t v0_hc;
-    xen_v0_getdomaininfo info;
+    xen_getdomaininfo info;
 
     if (initialized) {
         if (hypervisor_version == -1)
@@ -1073,7 +1184,7 @@
     /* TODO: one probably will need to autodetect thse subversions too */
     sys_interface_version = 2; /* XEN_SYSCTL_INTERFACE_VERSION */
     dom_interface_version = 3; /* XEN_DOMCTL_INTERFACE_VERSION */
-    if (virXen_getdomaininfolist(fd, 0, 1, &info) == 1) {
+    if (virXen_getdomaininfo(fd, 0, &info) == 1) {
 #ifdef DEBUG
         fprintf(stderr, "Using hypervisor call v2, sys version 2\n");
 #endif
@@ -1081,7 +1192,7 @@
     }
     hypervisor_version = 1;
     sys_interface_version = -1;
-    if (virXen_getdomaininfolist(fd, 0, 1, &info) == 1) {
+    if (virXen_getdomaininfo(fd, 0, &info) == 1) {
 #ifdef DEBUG
         fprintf(stderr, "Using hypervisor call v1\n");
 #endif
@@ -1227,7 +1338,7 @@
 int
 xenHypervisorNumOfDomains(virConnectPtr conn)
 {
-    xen_v0_getdomaininfo *dominfos;
+    xen_getdomaininfolist dominfos;
     int ret, nbids;
     static int last_maxids = 2;
     int maxids = last_maxids;
@@ -1236,18 +1347,17 @@
         return (-1);
 
 retry:
-    dominfos = malloc(maxids * sizeof(xen_v0_getdomaininfo));
-    if (dominfos == NULL) {
+    if (!(XEN_GETDOMAININFOLIST_ALLOC(dominfos, maxids))) {
         virXenError(VIR_ERR_NO_MEMORY, _("allocating %d domain info"),
 	            maxids);
 	return(-1);
     }
     
-    memset(dominfos, 0, sizeof(xen_v0_getdomaininfo) * maxids);
+    XEN_GETDOMAININFOLIST_CLEAR(dominfos, maxids);
 
-    ret = virXen_getdomaininfolist(conn->handle, 0, maxids, dominfos);
+    ret = virXen_getdomaininfolist(conn->handle, 0, maxids, &dominfos);
 
-    free(dominfos);
+    XEN_GETDOMAININFOLIST_FREE(dominfos);
 
     if (ret < 0)
         return (-1);
@@ -1276,41 +1386,40 @@
 int
 xenHypervisorListDomains(virConnectPtr conn, int *ids, int maxids)
 {
-    xen_v0_getdomaininfo *dominfos;
+    xen_getdomaininfolist dominfos;
     int ret, nbids, i;
 
     if ((conn == NULL) || (conn->handle < 0) ||
         (ids == NULL) || (maxids < 1))
         return (-1);
 
-    dominfos = malloc(maxids * sizeof(xen_v0_getdomaininfo));
-    if (dominfos == NULL) {
+    if (!(XEN_GETDOMAININFOLIST_ALLOC(dominfos, maxids))) {
         virXenError(VIR_ERR_NO_MEMORY, "allocating %d domain info",
 	            maxids);
 	return(-1);
     }
     
-    memset(dominfos, 0, sizeof(xen_v0_getdomaininfo) * maxids);
+    XEN_GETDOMAININFOLIST_CLEAR(dominfos, maxids);
     memset(ids, 0, maxids * sizeof(int));
 
-    ret = virXen_getdomaininfolist(conn->handle, 0, maxids, dominfos);
+    ret = virXen_getdomaininfolist(conn->handle, 0, maxids, &dominfos);
 
     if (ret < 0) {
-	free(dominfos);
+        XEN_GETDOMAININFOLIST_FREE(dominfos);
         return (-1);
     }
 
     nbids = ret;
     if ((nbids < 0) || (nbids > maxids)) {
-	free(dominfos);
+        XEN_GETDOMAININFOLIST_FREE(dominfos);
         return(-1);
     }
 
     for (i = 0;i < nbids;i++) {
-        ids[i] = dominfos[i].domain;
+        ids[i] = XEN_GETDOMAININFOLIST_DOMAIN(dominfos, i);
     }
 
-    free(dominfos);
+    XEN_GETDOMAININFOLIST_FREE(dominfos);
     return (nbids);
 }
 
@@ -1327,21 +1436,20 @@
 unsigned long
 xenHypervisorGetDomMaxMemory(virConnectPtr conn, int id)
 {
-    xen_v0_getdomaininfo dominfo;
+    xen_getdomaininfo dominfo;
     int ret;
 
     if ((conn == NULL) || (conn->handle < 0))
         return (0);
 
-    memset(&dominfo, 0, sizeof(xen_v0_getdomaininfo));
+    XEN_GETDOMAININFO_CLEAR(dominfo);
 
-    dominfo.domain = id;
-    ret = virXen_getdomaininfolist(conn->handle, id, 1, &dominfo);
+    ret = virXen_getdomaininfo(conn->handle, id, &dominfo);
 
-    if ((ret < 0) || (dominfo.domain != id))
+    if ((ret < 0) || (XEN_GETDOMAININFO_DOMAIN(dominfo) != id))
         return (0);
 
-    return((unsigned long) dominfo.max_pages * 4);
+    return((unsigned long) XEN_GETDOMAININFO_MAX_PAGES(dominfo) * 4);
 }
 
 #ifndef PROXY
@@ -1379,21 +1487,21 @@
 int
 xenHypervisorGetDomInfo(virConnectPtr conn, int id, virDomainInfoPtr info)
 {
-    xen_v0_getdomaininfo dominfo;
+    xen_getdomaininfo dominfo;
     int ret;
 
     if ((conn == NULL) || (conn->handle < 0) || (info == NULL))
         return (-1);
 
     memset(info, 0, sizeof(virDomainInfo));
-    memset(&dominfo, 0, sizeof(xen_v0_getdomaininfo));
+    XEN_GETDOMAININFO_CLEAR(dominfo);
 
-    ret = virXen_getdomaininfolist(conn->handle, id, 1, &dominfo);
+    ret = virXen_getdomaininfo(conn->handle, id, &dominfo);
 
-    if ((ret < 0) || (dominfo.domain != id))
+    if ((ret < 0) || (XEN_GETDOMAININFO_DOMAIN(dominfo) != id))
         return (-1);
 
-    switch (dominfo.flags & 0xFF) {
+    switch (XEN_GETDOMAININFO_FLAGS(dominfo) & 0xFF) {
 	case DOMFLAGS_DYING:
 	    info->state = VIR_DOMAIN_SHUTDOWN;
 	    break;
@@ -1418,10 +1526,10 @@
      * convert to microseconds, same thing convert to
      * kilobytes from page counts
      */
-    info->cpuTime = dominfo.cpu_time;
-    info->memory = dominfo.tot_pages * 4;
-    info->maxMem = dominfo.max_pages * 4;
-    info->nrVirtCpu = dominfo.nr_online_vcpus;
+    info->cpuTime = XEN_GETDOMAININFO_CPUTIME(dominfo);
+    info->memory = XEN_GETDOMAININFO_TOT_PAGES(dominfo) * 4;
+    info->maxMem = XEN_GETDOMAININFO_MAX_PAGES(dominfo) * 4;
+    info->nrVirtCpu = XEN_GETDOMAININFO_CPUCOUNT(dominfo);
     return (0);
 }
 
@@ -1620,7 +1728,7 @@
 		      unsigned char *cpumaps, int maplen)
 {
 #ifndef PROXY
-    xen_v0_getdomaininfo dominfo;
+    xen_getdomaininfo dominfo;
     int ret;
 
     virVcpuInfoPtr ipt;
@@ -1634,13 +1742,13 @@
 	return -1;
 
     /* first get the number of virtual CPUs in this domain */
-    memset(&dominfo, 0, sizeof(xen_v0_getdomaininfo));
-    ret = virXen_getdomaininfolist(domain->conn->handle, domain->handle,
-                                   1, &dominfo);
+    XEN_GETDOMAININFO_CLEAR(dominfo);
+    ret = virXen_getdomaininfo(domain->conn->handle, domain->handle,
+                               &dominfo);
 
-    if ((ret < 0) || (dominfo.domain != domain->handle))
+    if ((ret < 0) || (XEN_GETDOMAININFO_DOMAIN(dominfo) != domain->handle))
         return (-1);
-    nbinfo = dominfo.max_vcpu_id + 1;
+    nbinfo = XEN_GETDOMAININFO_CPUCOUNT(dominfo) + 1;
     if (nbinfo > maxinfo) nbinfo = maxinfo;
 
     if (cpumaps != NULL)
@@ -1666,3 +1774,13 @@
     return(-1);
 #endif
 }
+
+
+/*
+ * Local variables:
+ *  indent-tabs-mode: nil
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */


More information about the libvir-list mailing list