[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 11/11] xen/hvm kdump: reset PV devices in crash kernel
(this is actually a forward port of rev 1079 from 2.6.18.hg, untested because kdump just hangs before (or while) entering the crash kernel in 3.0) After triggering a crash dump in a HVM guest, the PV backend drivers will remain in connected state. When the kdump kernel starts the PV drivers will skip such devices. As a result, no root device is found and the vmcore cant be saved. With this change all frontend devices with state XenbusStateConnected will be reset by changing the state file to Closing/Closed/Initializing. This will trigger a disconnect in the backend drivers. Now the frontend drivers will find the backend drivers in state Initwait and can connect. Signed-off-by: Olaf Hering <olaf@xxxxxxxxx> --- drivers/xen/xenbus/xenbus_comms.c | 4 - drivers/xen/xenbus/xenbus_probe_frontend.c | 97 +++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) Index: linux-3.0/drivers/xen/xenbus/xenbus_comms.c =================================================================== --- linux-3.0.orig/drivers/xen/xenbus/xenbus_comms.c +++ 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) { Index: linux-3.0/drivers/xen/xenbus/xenbus_probe_frontend.c =================================================================== --- linux-3.0.orig/drivers/xen/xenbus/xenbus_probe_frontend.c +++ linux-3.0/drivers/xen/xenbus/xenbus_probe_frontend.c @@ -254,10 +254,107 @@ int __xenbus_register_frontend(struct xe } EXPORT_SYMBOL_GPL(__xenbus_register_frontend); +#ifdef CONFIG_CRASH_DUMP +static DECLARE_WAIT_QUEUE_HEAD(be_state_wq); +static int be_state; + +static void xenbus_reset_state_changed(struct xenbus_watch *w, const char **v, unsigned int l) +{ + xenbus_scanf(XBT_NIL, v[XS_WATCH_PATH], "", "%i", &be_state); + printk(KERN_INFO "XENBUS: %s %s\n", v[XS_WATCH_PATH], xenbus_strstate(be_state)); + wake_up(&be_state_wq); +} + +static int xenbus_reset_check_final(int *st) +{ + return *st == XenbusStateInitialising || *st == XenbusStateInitWait; +} + +static void xenbus_reset_frontend_state(char *backend, char *frontend) +{ + struct xenbus_watch watch; + + memset(&watch, 0, sizeof(watch)); + watch.node = kasprintf(GFP_NOIO | __GFP_HIGH, "%s/state", backend); + if (!watch.node) + return; + + watch.callback = xenbus_reset_state_changed; + be_state = XenbusStateUnknown; + + printk(KERN_INFO "XENBUS: triggering reconnect on %s\n", backend); + register_xenbus_watch(&watch); + + xenbus_printf(XBT_NIL, frontend, "state", "%d", XenbusStateClosing); + wait_event_interruptible(be_state_wq, be_state == XenbusStateClosing); + + xenbus_printf(XBT_NIL, frontend, "state", "%d", XenbusStateClosed); + wait_event_interruptible(be_state_wq, be_state == XenbusStateClosed); + + xenbus_printf(XBT_NIL, frontend, "state", "%d", XenbusStateInitialising); + wait_event_interruptible(be_state_wq, xenbus_reset_check_final(&be_state)); + + unregister_xenbus_watch(&watch); + printk(KERN_INFO "XENBUS: reconnect done on %s\n", backend); + kfree(watch.node); +} + +static void xenbus_reset_check_state(char *class, char *dev) +{ + int state, err; + char *backend, *frontend; + + frontend = kasprintf(GFP_NOIO | __GFP_HIGH, "device/%s/%s", class, dev); + if (!frontend) + return; + + err = xenbus_scanf(XBT_NIL, frontend, "state", "%i", &state); + /* frontend connected? */ + if (err == 1 && state == XenbusStateConnected) { + backend = xenbus_read(XBT_NIL, frontend, "backend", NULL); + if (!backend || IS_ERR(backend)) + goto out; + err = xenbus_scanf(XBT_NIL, backend, "state", "%i", &state); + /* backend connected? */ + if (err == 1 && state == XenbusStateConnected) + xenbus_reset_frontend_state(backend, frontend); + kfree(backend); + } +out: + kfree(frontend); +} + +static void xenbus_reset_state(void) +{ + char **devclass, **dev; + int devclass_n, dev_n; + int i, j; + + devclass = xenbus_directory(XBT_NIL, "device", "", &devclass_n); + if (IS_ERR(devclass)) + return; + + for (i = 0; i < devclass_n; i++) { + dev = xenbus_directory(XBT_NIL, "device", devclass[i], &dev_n); + if (IS_ERR(dev)) + continue; + for (j = 0; j < dev_n; j++) + xenbus_reset_check_state(devclass[i], dev[j]); + kfree(dev); + } + kfree(devclass); +} +#endif + static int frontend_probe_and_watch(struct notifier_block *notifier, unsigned long event, void *data) { +#ifdef CONFIG_CRASH_DUMP + /* reset devices in XenbusStateConnected state */ + if (!xen_initial_domain() && reset_devices) + xenbus_reset_state(); +#endif /* Enumerate devices in xenstore and watch for changes. */ xenbus_probe_devices(&xenbus_frontend); register_xenbus_watch(&fe_watch); _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |