xen/hvm: add kexec/kdump support
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
@@ -877,11 +877,35 @@ static int bind_interdomain_evtchn_to_irreturn 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
@@ -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
@@ -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
@@ -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
@@ -620,6 +620,20 @@ static struct xenbus_watch *find_watch(creturn 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 ; }
Quoted 7 lines · Olaf Hering
- add
xs_introduce()inxs_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 theXS_INTRODUCEfrom a guest.
And this part may need more work because thexs_introducemay 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