aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen
diff options
context:
space:
mode:
authorOlaf Hering <olaf@aepfle.de>2011-08-25 12:34:45 -0400
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2011-09-01 11:49:03 -0400
commit116df6f004af81925dcaa90d4a3b76da6b009427 (patch)
treed70f3a4166d021a59410e49cf8c5d3fbee6ee2b9 /drivers/xen
parent62cc5fc7b2e0218144e162afb8191db9b924b5e6 (diff)
xen/pv-on-hvm kexec+kdump: reset PV devices in kexec or crash kernel
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. A similar situation happens after a kexec boot, here the devices will be in the Closed state. With this change all frontend devices with state XenbusStateConnected or XenbusStateClosed 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@aepfle.de> [v2: - add timeout when waiting for backend state change (based on feedback from Ian Campell) - extent printk message to include backend string - add comment to fall-through case in xenbus_reset_frontend] Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/xen')
-rw-r--r--drivers/xen/xenbus/xenbus_comms.c4
-rw-r--r--drivers/xen/xenbus/xenbus_probe_frontend.c121
2 files changed, 124 insertions, 1 deletions
diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c
index 090c61ee8fd0..2eff7a6aaa20 100644
--- a/drivers/xen/xenbus/xenbus_comms.c
+++ b/drivers/xen/xenbus/xenbus_comms.c
@@ -212,7 +212,9 @@ int xb_init_comms(void)
212 printk(KERN_WARNING "XENBUS response ring is not quiescent " 212 printk(KERN_WARNING "XENBUS response ring is not quiescent "
213 "(%08x:%08x): fixing up\n", 213 "(%08x:%08x): fixing up\n",
214 intf->rsp_cons, intf->rsp_prod); 214 intf->rsp_cons, intf->rsp_prod);
215 intf->rsp_cons = intf->rsp_prod; 215 /* breaks kdump */
216 if (!reset_devices)
217 intf->rsp_cons = intf->rsp_prod;
216 } 218 }
217 219
218 if (xenbus_irq) { 220 if (xenbus_irq) {
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c
index b6a2690c9d49..b521ce43d325 100644
--- a/drivers/xen/xenbus/xenbus_probe_frontend.c
+++ b/drivers/xen/xenbus/xenbus_probe_frontend.c
@@ -252,10 +252,131 @@ int __xenbus_register_frontend(struct xenbus_driver *drv,
252} 252}
253EXPORT_SYMBOL_GPL(__xenbus_register_frontend); 253EXPORT_SYMBOL_GPL(__xenbus_register_frontend);
254 254
255static DECLARE_WAIT_QUEUE_HEAD(backend_state_wq);
256static int backend_state;
257
258static void xenbus_reset_backend_state_changed(struct xenbus_watch *w,
259 const char **v, unsigned int l)
260{
261 xenbus_scanf(XBT_NIL, v[XS_WATCH_PATH], "", "%i", &backend_state);
262 printk(KERN_DEBUG "XENBUS: backend %s %s\n",
263 v[XS_WATCH_PATH], xenbus_strstate(backend_state));
264 wake_up(&backend_state_wq);
265}
266
267static void xenbus_reset_wait_for_backend(char *be, int expected)
268{
269 long timeout;
270 timeout = wait_event_interruptible_timeout(backend_state_wq,
271 backend_state == expected, 5 * HZ);
272 if (timeout <= 0)
273 printk(KERN_INFO "XENBUS: backend %s timed out.\n", be);
274}
275
276/*
277 * Reset frontend if it is in Connected or Closed state.
278 * Wait for backend to catch up.
279 * State Connected happens during kdump, Closed after kexec.
280 */
281static void xenbus_reset_frontend(char *fe, char *be, int be_state)
282{
283 struct xenbus_watch be_watch;
284
285 printk(KERN_DEBUG "XENBUS: backend %s %s\n",
286 be, xenbus_strstate(be_state));
287
288 memset(&be_watch, 0, sizeof(be_watch));
289 be_watch.node = kasprintf(GFP_NOIO | __GFP_HIGH, "%s/state", be);
290 if (!be_watch.node)
291 return;
292
293 be_watch.callback = xenbus_reset_backend_state_changed;
294 backend_state = XenbusStateUnknown;
295
296 printk(KERN_INFO "XENBUS: triggering reconnect on %s\n", be);
297 register_xenbus_watch(&be_watch);
298
299 /* fall through to forward backend to state XenbusStateInitialising */
300 switch (be_state) {
301 case XenbusStateConnected:
302 xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateClosing);
303 xenbus_reset_wait_for_backend(be, XenbusStateClosing);
304
305 case XenbusStateClosing:
306 xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateClosed);
307 xenbus_reset_wait_for_backend(be, XenbusStateClosed);
308
309 case XenbusStateClosed:
310 xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateInitialising);
311 xenbus_reset_wait_for_backend(be, XenbusStateInitWait);
312 }
313
314 unregister_xenbus_watch(&be_watch);
315 printk(KERN_INFO "XENBUS: reconnect done on %s\n", be);
316 kfree(be_watch.node);
317}
318
319static void xenbus_check_frontend(char *class, char *dev)
320{
321 int be_state, fe_state, err;
322 char *backend, *frontend;
323
324 frontend = kasprintf(GFP_NOIO | __GFP_HIGH, "device/%s/%s", class, dev);
325 if (!frontend)
326 return;
327
328 err = xenbus_scanf(XBT_NIL, frontend, "state", "%i", &fe_state);
329 if (err != 1)
330 goto out;
331
332 switch (fe_state) {
333 case XenbusStateConnected:
334 case XenbusStateClosed:
335 printk(KERN_DEBUG "XENBUS: frontend %s %s\n",
336 frontend, xenbus_strstate(fe_state));
337 backend = xenbus_read(XBT_NIL, frontend, "backend", NULL);
338 if (!backend || IS_ERR(backend))
339 goto out;
340 err = xenbus_scanf(XBT_NIL, backend, "state", "%i", &be_state);
341 if (err == 1)
342 xenbus_reset_frontend(frontend, backend, be_state);
343 kfree(backend);
344 break;
345 default:
346 break;
347 }
348out:
349 kfree(frontend);
350}
351
352static void xenbus_reset_state(void)
353{
354 char **devclass, **dev;
355 int devclass_n, dev_n;
356 int i, j;
357
358 devclass = xenbus_directory(XBT_NIL, "device", "", &devclass_n);
359 if (IS_ERR(devclass))
360 return;
361
362 for (i = 0; i < devclass_n; i++) {
363 dev = xenbus_directory(XBT_NIL, "device", devclass[i], &dev_n);
364 if (IS_ERR(dev))
365 continue;
366 for (j = 0; j < dev_n; j++)
367 xenbus_check_frontend(devclass[i], dev[j]);
368 kfree(dev);
369 }
370 kfree(devclass);
371}
372
255static int frontend_probe_and_watch(struct notifier_block *notifier, 373static int frontend_probe_and_watch(struct notifier_block *notifier,
256 unsigned long event, 374 unsigned long event,
257 void *data) 375 void *data)
258{ 376{
377 /* reset devices in Connected or Closed state */
378 if (xen_hvm_domain())
379 xenbus_reset_state();
259 /* Enumerate devices in xenstore and watch for changes. */ 380 /* Enumerate devices in xenstore and watch for changes. */
260 xenbus_probe_devices(&xenbus_frontend); 381 xenbus_probe_devices(&xenbus_frontend);
261 register_xenbus_watch(&fe_watch); 382 register_xenbus_watch(&fe_watch);