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. --- head-2010-04-29.orig/drivers/xen/Kconfig 2010-03-31 14:08:31.000000000 +0200 +++ head-2010-04-29/drivers/xen/Kconfig 2010-03-31 14:08:50.000000000 +0200 @@ -30,6 +30,9 @@ config XEN_PRIVCMD def_bool y depends on PROC_FS +config XEN_DOMCTL + tristate + config XEN_XENBUS_DEV def_bool y depends on PROC_FS @@ -49,6 +52,7 @@ config XEN_BLKDEV_BACKEND tristate "Block-device backend driver" depends on XEN_BACKEND default XEN_BACKEND + select XEN_DOMCTL help The block-device backend driver allows the kernel to export its block devices to other guests via a high-performance shared-memory @@ -58,6 +62,7 @@ config XEN_BLKDEV_TAP tristate "Block-device tap backend driver" depends on XEN_BACKEND default XEN_BACKEND + select XEN_DOMCTL help The block tap driver is an alternative to the block back driver and allows VM block requests to be redirected to userspace through --- head-2010-04-29.orig/drivers/xen/blkback/xenbus.c 2010-03-25 14:37:55.000000000 +0100 +++ head-2010-04-29/drivers/xen/blkback/xenbus.c 2010-03-25 14:37:59.000000000 +0100 @@ -21,6 +21,7 @@ #include #include #include "common.h" +#include "../core/domctl.h" #undef DPRINTK #define DPRINTK(fmt, args...) \ @@ -492,8 +493,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)) --- head-2010-04-29.orig/drivers/xen/blktap/xenbus.c 2010-04-29 10:15:25.000000000 +0200 +++ head-2010-04-29/drivers/xen/blktap/xenbus.c 2010-04-29 10:15:31.000000000 +0200 @@ -39,6 +39,7 @@ #include #include #include "common.h" +#include "../core/domctl.h" struct backend_info @@ -433,8 +434,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)) --- head-2010-04-29.orig/drivers/xen/core/Makefile 2010-04-19 14:52:49.000000000 +0200 +++ head-2010-04-29/drivers/xen/core/Makefile 2010-04-19 14:55:02.000000000 +0200 @@ -12,3 +12,6 @@ obj-$(CONFIG_XEN_SYSFS) += xen_sysfs.o obj-$(CONFIG_XEN_SMPBOOT) += smpboot.o obj-$(CONFIG_SMP) += spinlock.o obj-$(CONFIG_KEXEC) += machine_kexec.o +obj-$(CONFIG_XEN_DOMCTL) += domctl.o +CFLAGS_domctl.o := -D__XEN_PUBLIC_XEN_H__ -D__XEN_PUBLIC_GRANT_TABLE_H__ +CFLAGS_domctl.o += -D__XEN_TOOLS__ -imacros xen/interface/domctl.h --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ head-2010-04-29/drivers/xen/core/domctl.c 2010-05-07 12:12:03.000000000 +0200 @@ -0,0 +1,127 @@ +/* + * !!! 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. + */ +#undef __XEN_PUBLIC_XEN_H__ +#undef __XEN_PUBLIC_GRANT_TABLE_H__ +#undef __XEN_TOOLS__ +#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 .... */ + +typedef struct xen_domctl_address_size { + uint32_t size; +} xen_domctl_address_size_t; + +typedef __attribute__((aligned(8))) uint64_t uint64_aligned_t; + +union xen_domctl { + /* v4: sle10 sp1: xen 3.0.4 + 32-on-64 patches */ + struct { + uint32_t cmd; + uint32_t 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]; + }; + } v4; + + /* + * v5: upstream: xen 3.1 + * v6: upstream: xen 4.0 + * v7: sle11 sp1: xen 4.0 + cpupools patches + */ + struct { + 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]; + }; + } v5, v6, v7; +}; + +/* The actual code comes here */ + +static inline int hypervisor_domctl(void *domctl) +{ + return _hypercall1(int, domctl, domctl); +} + +int xen_guest_address_size(int domid) +{ + union xen_domctl domctl; + int low, ret; + +#define guest_address_size(ver) do { \ + memset(&domctl, 0, sizeof(domctl)); \ + domctl.v##ver.cmd = XEN_DOMCTL_get_address_size; \ + domctl.v##ver.interface_version = low = ver; \ + domctl.v##ver.domain = domid; \ + ret = hypervisor_domctl(&domctl) ?: domctl.v##ver.address_size.size; \ + if (ret == 32 || ret == 64) { \ + printk("v" #ver " domctl worked ok: dom%d is %d-bit\n", \ + domid, ret); \ + return ret; \ + } \ +} while (0) + + BUILD_BUG_ON(XEN_DOMCTL_INTERFACE_VERSION > 7); + guest_address_size(7); +#if CONFIG_XEN_COMPAT < 0x040100 + guest_address_size(6); +#endif +#if CONFIG_XEN_COMPAT < 0x040000 + guest_address_size(5); +#endif +#if CONFIG_XEN_COMPAT < 0x030100 + guest_address_size(4); +#endif + + ret = BITS_PER_LONG; + printk("v%d...7 domctls failed, assuming dom%d is native: %d\n", + low, domid, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(xen_guest_address_size); + +int xen_guest_blkif_protocol(int domid) +{ + int address_size = xen_guest_address_size(domid); + + if (address_size == BITS_PER_LONG) + 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); + +MODULE_LICENSE("GPL"); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ head-2010-04-29/drivers/xen/core/domctl.h 2010-03-25 14:37:59.000000000 +0100 @@ -0,0 +1,2 @@ +int xen_guest_address_size(int domid); +int xen_guest_blkif_protocol(int domid);