[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