Subject: 32-on-64 blkif protocol negotiation fallback for old guests. From: kraxel@suse.de References: 244055 Patch-mainline: never. See the comment below. Oh well. --- drivers/xen/blkback/xenbus.c | 8 +- drivers/xen/blktap/xenbus.c | 8 +- drivers/xen/core/Makefile | 2 drivers/xen/core/domctl.c | 133 +++++++++++++++++++++++++++++++++++++++++++ drivers/xen/core/domctl.h | 2 5 files changed, 146 insertions(+), 7 deletions(-) --- a/drivers/xen/blkback/xenbus.c 2007-08-27 14:01:27.000000000 -0400 +++ b/drivers/xen/blkback/xenbus.c 2007-08-27 14:01:47.000000000 -0400 @@ -21,6 +21,7 @@ #include #include #include "common.h" +#include "../core/domctl.h" #undef DPRINTK #define DPRINTK(fmt, args...) \ @@ -457,7 +458,6 @@ again: xenbus_transaction_end(xbt, 1); } - static int connect_ring(struct backend_info *be) { struct xenbus_device *dev = be->dev; @@ -480,8 +480,10 @@ static int connect_ring(struct backend_i be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; err = xenbus_gather(XBT_NIL, dev->otherend, "protocol", "%63s", protocol, NULL); - if (err) - strcpy(protocol, "unspecified, assuming native"); + if (err) { + strcpy(protocol, "unspecified"); + be->blkif->blk_protocol = xen_guest_blkif_protocol(be->blkif->domid); + } else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE)) be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32)) --- a/drivers/xen/blktap/xenbus.c 2007-08-27 14:01:27.000000000 -0400 +++ b/drivers/xen/blktap/xenbus.c 2007-08-27 14:01:27.000000000 -0400 @@ -39,6 +39,7 @@ #include #include #include "common.h" +#include "../core/domctl.h" struct backend_info @@ -397,7 +398,6 @@ static void connect(struct backend_info return; } - static int connect_ring(struct backend_info *be) { struct xenbus_device *dev = be->dev; @@ -420,8 +420,10 @@ static int connect_ring(struct backend_i be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; err = xenbus_gather(XBT_NIL, dev->otherend, "protocol", "%63s", protocol, NULL); - if (err) - strcpy(protocol, "unspecified, assuming native"); + if (err) { + strcpy(protocol, "unspecified"); + be->blkif->blk_protocol = xen_guest_blkif_protocol(be->blkif->domid); + } else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE)) be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE; else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32)) --- a/drivers/xen/core/Makefile 2007-08-27 14:01:25.000000000 -0400 +++ b/drivers/xen/core/Makefile 2007-08-27 14:01:27.000000000 -0400 @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -obj-y := evtchn.o gnttab.o features.o reboot.o machine_reboot.o firmware.o +obj-y := evtchn.o gnttab.o features.o reboot.o machine_reboot.o firmware.o domctl.o obj-$(CONFIG_PROC_FS) += xen_proc.o obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor_sysfs.o --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ b/drivers/xen/core/domctl.c 2007-08-27 14:01:27.000000000 -0400 @@ -0,0 +1,133 @@ +/* + * !!! dirty hack alert !!! + * + * Problem: old guests kernels don't have a "protocol" node + * in the frontend xenstore directory, so mixing + * 32 and 64bit domains doesn't work. + * + * Upstream plans to solve this in the tools, by letting them + * create a protocol node. Which certainly makes sense. + * But it isn't trivial and isn't done yet. Too bad. + * + * So for the time being we use the get_address_size domctl + * hypercall for a pretty good guess. Not nice as the domctl + * hypercall isn't supposed to be used by the kernel. Because + * we don't want to have dependencies between dom0 kernel and + * xen kernel versions. Now we have one. Ouch. + */ + +#include +#include +#include +#include + +#include "domctl.h" + +/* stuff copied from xen/interface/domctl.h, which we can't + * include directly for the reasons outlined above .... */ + +#define XEN_DOMCTL_set_address_size 35 +#define XEN_DOMCTL_get_address_size 36 +typedef struct xen_domctl_address_size { + uint32_t size; +} xen_domctl_address_size_t; + +#define native_address_size (sizeof(unsigned long)*8) + +/* v4: sles10 sp1: xen 3.0.4 + 32-on-64 patches */ +struct xen_domctl_v4 { + uint32_t cmd; + uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */ + domid_t domain; + union { + /* left out lots of other struct xen_domctl_foobar */ + struct xen_domctl_address_size address_size; + uint64_t dummy_align; + uint8_t dummy_pad[128]; + } u; +}; + +/* v5: upstream: xen 3.0.5 */ +typedef __attribute__((aligned(8))) uint64_t uint64_aligned_t; +struct xen_domctl_v5 { + uint32_t cmd; + uint32_t interface_version; + domid_t domain; + union { + struct xen_domctl_address_size address_size; + uint64_aligned_t dummy_align; + uint8_t dummy_pad[128]; + } u; +}; + +/* The actual code comes here */ + +static int xen_guest_address_size_v4(int domid) +{ + struct xen_domctl_v4 domctl; + int rc; + + memset(&domctl, 0, sizeof(domctl)); + domctl.cmd = XEN_DOMCTL_get_address_size; + domctl.interface_version = 4; + domctl.domain = domid; + if (0 != (rc = _hypercall1(int, domctl, &domctl))) + return rc; + return domctl.u.address_size.size; +} + +static int xen_guest_address_size_v5(int domid) +{ + struct xen_domctl_v5 domctl; + int rc; + + memset(&domctl, 0, sizeof(domctl)); + domctl.cmd = XEN_DOMCTL_get_address_size; + domctl.interface_version = 5; + domctl.domain = domid; + if (0 != (rc = _hypercall1(int, domctl, &domctl))) + return rc; + return domctl.u.address_size.size; +} + +int xen_guest_address_size(int domid) +{ + int ret; + + ret = xen_guest_address_size_v4(domid); + if (ret == 32 || ret == 64) { + printk("%s: v4 domctl worked ok: %d\n", __FUNCTION__, ret); + goto done; + } + + ret = xen_guest_address_size_v5(domid); + if (ret == 32 || ret == 64) { + printk("%s: v5 domctl worked ok: %d\n", __FUNCTION__, ret); + goto done; + } + + ret = native_address_size; + printk("%s: v4,v5 domctls failed, assuming native: %d\n", + __FUNCTION__, ret); + + done: + return ret; +} +EXPORT_SYMBOL_GPL(xen_guest_address_size); + +int xen_guest_blkif_protocol(int domid) +{ + int address_size; + + address_size = xen_guest_address_size(domid); + printk(KERN_DEBUG "%s: domain %d: got address size %d\n", + __FUNCTION__, domid, address_size); + if (address_size == native_address_size) + return BLKIF_PROTOCOL_NATIVE; + if (address_size == 32) + return BLKIF_PROTOCOL_X86_32; + if (address_size == 64) + return BLKIF_PROTOCOL_X86_64; + return BLKIF_PROTOCOL_NATIVE; +} +EXPORT_SYMBOL_GPL(xen_guest_blkif_protocol); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ b/drivers/xen/core/domctl.h 2007-08-27 14:01:27.000000000 -0400 @@ -0,0 +1,2 @@ +int xen_guest_address_size(int domid); +int xen_guest_blkif_protocol(int domid);