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.orig/drivers/xen/Kconfig 2012-02-10 11:56:27.000000000 +0100
+++ head/drivers/xen/Kconfig 2012-02-17 14:38:40.000000000 +0100
@@ -23,6 +23,9 @@ config XEN_UNPRIVILEGED_GUEST
select PM
select SUSPEND
+config XEN_DOMCTL
+ tristate
+
config XEN_XENBUS_DEV
def_bool y
depends on PROC_FS
@@ -42,6 +45,7 @@ config XEN_BLKDEV_BACKEND
tristate "Block-device backend driver"
depends on BLOCK && 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
@@ -51,6 +55,7 @@ config XEN_BLKDEV_TAP
tristate "Block-device tap backend driver"
depends on BLOCK && 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.orig/drivers/xen/blkback/xenbus.c 2012-03-26 15:49:36.000000000 +0200
+++ head/drivers/xen/blkback/xenbus.c 2012-03-26 15:54:30.000000000 +0200
@@ -20,6 +20,7 @@
#include <stdarg.h>
#include <linux/kthread.h>
#include "common.h"
+#include "../core/domctl.h"
#undef DPRINTK
#define DPRINTK(fmt, args...) \
@@ -546,24 +547,25 @@ static int connect_ring(struct backend_i
be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
protocol = xenbus_read(XBT_NIL, dev->otherend, "protocol", NULL);
- if (IS_ERR(protocol))
+ if (IS_ERR(protocol)) {
protocol = NULL;
+ be->blkif->blk_protocol = xen_guest_blkif_protocol(be->blkif->domid);
#ifndef CONFIG_X86_32
- else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32))
+ } else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32)) {
be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32;
#endif
#ifndef CONFIG_X86_64
- else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64))
+ } else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64)) {
be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64;
#endif
- else if (0 != strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE)) {
+ } else if (0 != strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE)) {
xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol);
kfree(protocol);
return -1;
}
pr_info("blkback: ring-ref %u, event-channel %u, protocol %d (%s)\n",
ring_ref, evtchn, be->blkif->blk_protocol,
- protocol ?: "unspecified, assuming native");
+ protocol ?: "unspecified");
kfree(protocol);
/* Map the shared frame, irq etc. */
--- head.orig/drivers/xen/blktap/xenbus.c 2012-03-26 15:50:12.000000000 +0200
+++ head/drivers/xen/blktap/xenbus.c 2012-03-26 15:54:07.000000000 +0200
@@ -38,6 +38,7 @@
#include <linux/kthread.h>
#include <xen/xenbus.h>
#include "common.h"
+#include "../core/domctl.h"
struct backend_info
@@ -441,24 +442,25 @@ static int connect_ring(struct backend_i
be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
protocol = xenbus_read(XBT_NIL, dev->otherend, "protocol", NULL);
- if (IS_ERR(protocol))
+ if (IS_ERR(protocol)) {
protocol = NULL;
+ be->blkif->blk_protocol = xen_guest_blkif_protocol(be->blkif->domid);
#ifndef CONFIG_X86_32
- else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32))
+ } else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32)) {
be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32;
#endif
#ifndef CONFIG_X86_64
- else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64))
+ } else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64)) {
be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64;
#endif
- else if (0 != strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE)) {
+ } else if (0 != strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE)) {
xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol);
kfree(protocol);
return -1;
}
pr_info("blktap: ring-ref %u, event-channel %u, protocol %d (%s)\n",
ring_ref, evtchn, be->blkif->blk_protocol,
- protocol ?: "unspecified, assuming native");
+ protocol ?: "unspecified");
kfree(protocol);
/* Map the shared frame, irq etc. */
--- head.orig/drivers/xen/core/Makefile 2012-02-17 14:37:50.000000000 +0100
+++ head/drivers/xen/core/Makefile 2012-02-17 14:38:43.000000000 +0100
@@ -11,3 +11,6 @@ obj-$(CONFIG_XEN_SMPBOOT) += smpboot.o
obj-$(CONFIG_SMP) += spinlock.o
obj-$(CONFIG_KEXEC) += machine_kexec.o
obj-$(CONFIG_GENERIC_CLOCKEVENTS) += clockevents.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/drivers/xen/core/domctl.c 2011-10-04 17:01:11.000000000 +0200
@@ -0,0 +1,131 @@
+/*
+ * !!! 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/hypervisor.h>
+#include <xen/blkif.h>
+
+#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: upstream: xen 4.1; sle11 sp1: xen 4.0 + cpupools patches
+ * v8: upstream: xen 4.2
+ */
+ 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, v8;
+};
+
+/* 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) { \
+ pr_info("v" #ver " domctl worked ok: dom%d is %d-bit\n",\
+ domid, ret); \
+ return ret; \
+ } \
+} while (0)
+
+ BUILD_BUG_ON(XEN_DOMCTL_INTERFACE_VERSION > 8);
+ guest_address_size(8);
+#if CONFIG_XEN_COMPAT < 0x040200
+ guest_address_size(7);
+#endif
+#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;
+ pr_warn("v%d...%d domctls failed, assuming dom%d is native: %d\n",
+ low, XEN_DOMCTL_INTERFACE_VERSION, 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/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);