Skip to contentSkip to conversation

xen/hvm: add kexec/kdump support

PATCH In review Olaf Hering 1 participant 2 messages Aug 1, 2011 Xen hypervisor interface

lore
Share & tools
lore
#0 lore raw

PATCH v3 1/1 xen/hvm: add kexec/kdump support

One more attempt to add kexec/kdump support for a PVonHVM guest. This is one large patch, if the approach is ok I will split it into three parts:

- rebind virq during boot to avoid BUG in bind_virq_to_irq, required for the timer and debugirq. Loop through all ports to find the virq/cpu combo.

- add xs_introduce() in xs_init() to shutdown all open watches that the previous kernel had registered. Without this change the kexec may crash due to unexpected watch events.
This depends on a xenstored change which has to allow the XS_INTRODUCE from a guest.
And this part may need more work because the xs_introduce may hang forever on an old dom0 tool stack

- reset backend state if the frontend devices are either in Connected (kdump) or Closed (kexec) state.

---
 drivers/xen/events.c                       |   40 ++++++++--
 drivers/xen/xenbus/xenbus_comms.c          |    4 -
 drivers/xen/xenbus/xenbus_comms.h          |    2 
 drivers/xen/xenbus/xenbus_probe.c          |    2 
 drivers/xen/xenbus/xenbus_probe_frontend.c |  116 +++++++++++++++++++++++++++++
 drivers/xen/xenbus/xenbus_xs.c             |   24 +++++-
 6 files changed, 179 insertions(+), 9 deletions(-)
drivers/xen/events.c +35 -5
Index: linux-3.0/drivers/xen/events.c
===================================================================
@@ -877,11 +877,35 @@ static int bind_interdomain_evtchn_to_ir
 	return err ? : bind_evtchn_to_irq(bind_interdomain.local_port);
 }
 
+/* BITS_PER_LONG is used in Xen */
+#define MAX_EVTCHNS (64 * 64)
+
+static int find_virq(unsigned int virq, unsigned int cpu)
+{
+	struct evtchn_status status;
+	int port, rc = -ENOENT;
+
+	memset(&status, 0, sizeof(status));
+	for (port = 0; port <= MAX_EVTCHNS; port++) {
+		status.dom = DOMID_SELF;
+		status.port = port;
+		rc = HYPERVISOR_event_channel_op(EVTCHNOP_status, &status);
+		if (rc < 0)
+			continue;
+		if (status.status != EVTCHNSTAT_virq)
+			continue;
+		if (status.u.virq == virq && status.vcpu == cpu) {
+			rc = port;
+			break;
+		}
+	}
+	return rc;
+}
 
 int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
 {
 	struct evtchn_bind_virq bind_virq;
-	int evtchn, irq;
+	int evtchn, irq, ret;
 
 	spin_lock(&irq_mapping_update_lock);
 
@@ -897,10 +921,16 @@ int bind_virq_to_irq(unsigned int virq,
 
 		bind_virq.virq = virq;
 		bind_virq.vcpu = cpu;
-		if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
-						&bind_virq) != 0)
-			BUG();
-		evtchn = bind_virq.port;
+		ret = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
+						&bind_virq);
+		if (ret == 0)
+			evtchn = bind_virq.port;
+		else {
+			if (ret == -EEXIST)
+				ret = find_virq(virq, cpu);
+			BUG_ON(ret < 0);
+			evtchn = ret;
+		}
 
 		xen_irq_info_virq_init(cpu, irq, evtchn, virq);
 
drivers/xen/xenbus/xenbus_comms.c +3 -1
Index: linux-3.0/drivers/xen/xenbus/xenbus_comms.c
===================================================================
@@ -212,7 +212,9 @@ int xb_init_comms(void)
 		printk(KERN_WARNING "XENBUS response ring is not quiescent "
 		       "(%08x:%08x): fixing up\n",
 		       intf->rsp_cons, intf->rsp_prod);
-		intf->rsp_cons = intf->rsp_prod;
+		/* breaks kdump */
+		if (!reset_devices)
+			intf->rsp_cons = intf->rsp_prod;
 	}
 
 	if (xenbus_irq) {
drivers/xen/xenbus/xenbus_comms.h +1 -1
Index: linux-3.0/drivers/xen/xenbus/xenbus_comms.h
===================================================================
@@ -31,7 +31,7 @@
 #ifndef _XENBUS_COMMS_H
 #define _XENBUS_COMMS_H
 
-int xs_init(void);
+int xs_init(unsigned long xen_store_mfn);
 int xb_init_comms(void);
 
 /* Low level routines. */
drivers/xen/xenbus/xenbus_probe.c +1 -1
Index: linux-3.0/drivers/xen/xenbus/xenbus_probe.c
===================================================================
@@ -757,7 +757,7 @@ static int __init xenbus_init(void)
 	}
 
 	/* Initialize the interface to xenstore. */
-	err = xs_init();
+	err = xs_init(xen_store_mfn);
 	if (err) {
 		printk(KERN_WARNING
 		       "XENBUS: Error initializing xenstore comms: %i\n", err);
drivers/xen/xenbus/xenbus_probe_frontend.c +116 -0

126 lines not on this page · raw message

drivers/xen/xenbus/xenbus_xs.c +23 -1
Index: linux-3.0/drivers/xen/xenbus/xenbus_xs.c
===================================================================
@@ -620,6 +620,20 @@ static struct xenbus_watch *find_watch(c
 	return NULL;
 }
 
+static int xs_introduce(const char *domid, const char *mfn, const char *port)
+{
+	struct kvec iov[3];
+
+	iov[0].iov_base = (char *)domid;
+	iov[0].iov_len = strlen(domid) + 1;
+	iov[1].iov_base = (char *)mfn;
+	iov[1].iov_len = strlen(mfn) + 1;
+	iov[2].iov_base = (char *)port;
+	iov[2].iov_len = strlen(port) + 1;
+
+	return xs_error(xs_talkv(XBT_NIL, XS_INTRODUCE, iov,
+				 ARRAY_SIZE(iov), NULL));
+}
 /* Register callback to watch this node. */
 int register_xenbus_watch(struct xenbus_watch *watch)
 {
@@ -867,10 +881,11 @@ static int xenbus_thread(void *unused)
 	return 0;
 }
 
-int xs_init(void)
+int xs_init(unsigned long xen_store_mfn)
 {
 	int err;
 	struct task_struct *task;
+	char domid[12], mfn[24], port[24];
 
 	INIT_LIST_HEAD(&xs_state.reply_list);
 	spin_lock_init(&xs_state.reply_lock);
@@ -897,5 +912,12 @@ int xs_init(void)
 	if (IS_ERR(task))
 		return PTR_ERR(task);
 
+	snprintf(domid, sizeof(domid), "%u", DOMID_SELF);
+	snprintf(mfn, sizeof(mfn), "%lu", xen_store_mfn);
+	snprintf(port, sizeof(port), "%d", xen_store_evtchn);
+	err = xs_introduce(domid, mfn, port);
+	if (err)
+		printk(KERN_ALERT "%s: introduce failed: %d\n", __func__, err);
+
 	return 0;
 }
#1 lore raw
Quoted 7 lines · Olaf Hering

- add xs_introduce() in xs_init() to shutdown all open watches that the previous kernel had registered. Without this change the kexec may crash due to unexpected watch events.
This depends on a xenstored change which has to allow the XS_INTRODUCE from a guest.
And this part may need more work because the xs_introduce may hang forever on an old dom0 tool stack

The hang I encountered last week was due to a bug in the new xs_introduce() function. "iov[2].iov_len" was by accident written as "iov[3].iov_len", which left the iov_len uninitialized. Then xenstored got a huge iov_len, returned an error which the kernel received. But the process_msg() did not wakeup read_reply() for some reason.

Today an unmodified sles11sp1 dom0 can boot a 3.0 kernel with the kexec/kdump patch applied.

Olaf