diff --git a/ChangeLog b/ChangeLog index 50b91f9930..aa520a49e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Wed Jun 21 12:23:15 EDT 2006 Daniel Veillard + + * src/xen_internal.c: try to autodetect the Xen hypervisor version + used and switch automatically. A bit nasty though. + Tue Jun 20 16:14:26 EDT 2006 Daniel Veillard * src/xen_internal.c: fix breakage introduced in Xen changeset 10277 diff --git a/src/xen_internal.c b/src/xen_internal.c index e56a3b920b..209265bf6d 100644 --- a/src/xen_internal.c +++ b/src/xen_internal.c @@ -27,18 +27,21 @@ #include #include -#if 0 /* #ifndef __LINUX_PUBLIC_PRIVCMD_H__ */ -typedef struct hypercall_struct { - __u64 op; - __u64 arg[5]; -} hypercall_t; -#define XEN_IOCTL_HYPERCALL_CMD _IOC(_IOC_NONE, 'P', 0, sizeof(hypercall_t)) -#else +typedef struct old_hypercall_struct { + unsigned long op; + unsigned long arg[5]; +} old_hypercall_t; +#define XEN_OLD_IOCTL_HYPERCALL_CMD \ + _IOC(_IOC_NONE, 'P', 0, sizeof(old_hypercall_t)) + typedef struct privcmd_hypercall hypercall_t; #define XEN_IOCTL_HYPERCALL_CMD IOCTL_PRIVCMD_HYPERCALL -#endif +static int xen_ioctl_hypercall_cmd = 0; +static int old_hypervisor = 0; +static int initialized = 0; +static int hv_version = 0; #include "internal.h" #include "driver.h" @@ -48,13 +51,14 @@ typedef struct privcmd_hypercall hypercall_t; static const char * xenHypervisorGetType(virConnectPtr conn); static unsigned long xenHypervisorGetMaxMemory(virDomainPtr domain); +static int xenHypervisorInit(void); static virDriver xenHypervisorDriver = { "Xen", (DOM0_INTERFACE_VERSION >> 24) * 1000000 + ((DOM0_INTERFACE_VERSION >> 16) & 0xFF) * 1000 + (DOM0_INTERFACE_VERSION & 0xFFFF), - NULL, /* init */ + xenHypervisorInit, /* init */ xenHypervisorOpen, /* open */ xenHypervisorClose, /* close */ xenHypervisorGetType, /* type */ @@ -84,16 +88,6 @@ static virDriver xenHypervisorDriver = { NULL /* domainRestore */ }; -/** - * xenHypervisorRegister: - * - * Registers the xenHypervisor driver - */ -void xenHypervisorRegister(void) -{ - virRegisterDriver(&xenHypervisorDriver); -} - /** * virXenError: * @conn: the connection if available @@ -115,6 +109,84 @@ virXenError(virErrorNumber error, const char *info, int value) errmsg, info, NULL, value, 0, errmsg, info, value); } +/** + * xenHypervisorInit: + * + * Initialize the hypervisor layer. Try to detect the kind of interface + * used i.e. pre or post changeset 10277 + */ +int xenHypervisorInit(void) +{ + int fd, ret, cmd; + hypercall_t hc; + old_hypercall_t old_hc; + + if (initialized) { + if (old_hypervisor == -1) + return(-1); + return(0); + } + initialized = 1; + + ret = open(XEN_HYPERVISOR_SOCKET, O_RDWR); + if (ret < 0) { + old_hypervisor = -1; + return (-1); + } + fd = ret; + + hc.op = __HYPERVISOR_xen_version; + hc.arg[0] = (unsigned long) XENVER_version; + hc.arg[1] = 0; + + cmd = IOCTL_PRIVCMD_HYPERCALL; + ret = ioctl(fd, cmd, (unsigned long) &hc); + + if ((ret != -1) && (ret != 0)) { + fprintf(stderr, "Using new hypervisor call: %X\n", ret); + hv_version = ret; + xen_ioctl_hypercall_cmd = cmd; + old_hypervisor = 0; + goto done; + } + + old_hc.op = __HYPERVISOR_xen_version; + old_hc.arg[0] = (unsigned long) XENVER_version; + old_hc.arg[1] = 0; + cmd = _IOC(_IOC_NONE, 'P', 0, sizeof(old_hypercall_t)); + ret = ioctl(fd, cmd, (unsigned long) &old_hc); + if ((ret != -1) && (ret != 0)) { + fprintf(stderr, "Using old hypervisor call: %X\n", ret); + hv_version = ret; + xen_ioctl_hypercall_cmd = cmd; + old_hypervisor = 1; + goto done; + } + + old_hypervisor = -1; + virXenError(VIR_ERR_XEN_CALL, " ioctl ", IOCTL_PRIVCMD_HYPERCALL); + close(fd); + return(-1); + +done: + close(fd); + return(0); + +} + +/** + * xenHypervisorRegister: + * + * Registers the xenHypervisor driver + */ +void xenHypervisorRegister(void) +{ + if (initialized == 0) + xenHypervisorInit(); + + virRegisterDriver(&xenHypervisorDriver); +} + /** * xenHypervisorOpen: * @conn: pointer to the connection block @@ -130,6 +202,9 @@ xenHypervisorOpen(virConnectPtr conn, const char *name, int flags) { int ret; + if (initialized == 0) + xenHypervisorInit(); + if ((name != NULL) && (strcasecmp(name, "xen"))) return(-1); @@ -168,6 +243,47 @@ xenHypervisorClose(virConnectPtr conn) return (0); } +/** + * xenHypervisorDoOldOp: + * @handle: the handle to the Xen hypervisor + * @op: pointer to the hyperviros operation structure + * + * Do an hypervisor operation though the old interface, + * this leads to an hypervisor call through ioctl. + * + * Returns 0 in case of success and -1 in case of error. + */ +static int +xenHypervisorDoOldOp(int handle, dom0_op_t * op) +{ + int ret; + old_hypercall_t hc; + + memset(&hc, 0, sizeof(hc)); + op->interface_version = hv_version << 8; + hc.op = __HYPERVISOR_dom0_op; + hc.arg[0] = (unsigned long) op; + + if (mlock(op, sizeof(dom0_op_t)) < 0) { + virXenError(VIR_ERR_XEN_CALL, " locking", sizeof(dom0_op_t)); + return (-1); + } + + ret = ioctl(handle, xen_ioctl_hypercall_cmd, (unsigned long) &hc); + if (ret < 0) { + virXenError(VIR_ERR_XEN_CALL, " ioctl ", xen_ioctl_hypercall_cmd); + } + + if (munlock(op, sizeof(dom0_op_t)) < 0) { + virXenError(VIR_ERR_XEN_CALL, " releasing", sizeof(dom0_op_t)); + ret = -1; + } + + if (ret < 0) + return (-1); + + return (0); +} /** * xenHypervisorDoOp: * @handle: the handle to the Xen hypervisor @@ -181,9 +297,12 @@ static int xenHypervisorDoOp(int handle, dom0_op_t * op) { int ret; - unsigned int cmd; hypercall_t hc; + if (old_hypervisor) + return(xenHypervisorDoOldOp(handle, op)); + + memset(&hc, 0, sizeof(hc)); op->interface_version = DOM0_INTERFACE_VERSION; hc.op = __HYPERVISOR_dom0_op; hc.arg[0] = (unsigned long) op; @@ -193,10 +312,9 @@ xenHypervisorDoOp(int handle, dom0_op_t * op) return (-1); } - cmd = XEN_IOCTL_HYPERCALL_CMD; - ret = ioctl(handle, cmd, (unsigned long) &hc); + ret = ioctl(handle, xen_ioctl_hypercall_cmd, (unsigned long) &hc); if (ret < 0) { - virXenError(VIR_ERR_XEN_CALL, " ioctl ", cmd); + virXenError(VIR_ERR_XEN_CALL, " ioctl ", xen_ioctl_hypercall_cmd); } if (munlock(op, sizeof(dom0_op_t)) < 0) { @@ -242,26 +360,9 @@ xenHypervisorGetType(virConnectPtr conn) int xenHypervisorGetVersion(virConnectPtr conn, unsigned long *hvVer) { - int ret; - unsigned int cmd; - hypercall_t hc; - if ((conn == NULL) || (conn->handle < 0) || (hvVer == NULL)) return (-1); - *hvVer = 0; - - hc.op = __HYPERVISOR_xen_version; - hc.arg[0] = (unsigned long) XENVER_version; - hc.arg[1] = 0; - - cmd = XEN_IOCTL_HYPERCALL_CMD; - ret = ioctl(conn->handle, cmd, (unsigned long) &hc); - - if (ret < 0) { - virXenError(VIR_ERR_XEN_CALL, " getting version ", XENVER_version); - return (-1); - } - *hvVer = (ret >> 16) * 1000000 + (ret & 0xFFFF) * 1000; + *hvVer = (hv_version >> 16) * 1000000 + (hv_version & 0xFFFF) * 1000; return(0); }