Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 264444
b: refs/heads/master
c: 116df6f
h: refs/heads/master
v: v3
  • Loading branch information
Olaf Hering authored and Konrad Rzeszutek Wilk committed Sep 1, 2011
1 parent cbd4db2 commit 955a634
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 62cc5fc7b2e0218144e162afb8191db9b924b5e6
refs/heads/master: 116df6f004af81925dcaa90d4a3b76da6b009427
4 changes: 3 additions & 1 deletion trunk/drivers/xen/xenbus/xenbus_comms.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
121 changes: 121 additions & 0 deletions trunk/drivers/xen/xenbus/xenbus_probe_frontend.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,131 @@ int __xenbus_register_frontend(struct xenbus_driver *drv,
}
EXPORT_SYMBOL_GPL(__xenbus_register_frontend);

static DECLARE_WAIT_QUEUE_HEAD(backend_state_wq);
static int backend_state;

static void xenbus_reset_backend_state_changed(struct xenbus_watch *w,
const char **v, unsigned int l)
{
xenbus_scanf(XBT_NIL, v[XS_WATCH_PATH], "", "%i", &backend_state);
printk(KERN_DEBUG "XENBUS: backend %s %s\n",
v[XS_WATCH_PATH], xenbus_strstate(backend_state));
wake_up(&backend_state_wq);
}

static void xenbus_reset_wait_for_backend(char *be, int expected)
{
long timeout;
timeout = wait_event_interruptible_timeout(backend_state_wq,
backend_state == expected, 5 * HZ);
if (timeout <= 0)
printk(KERN_INFO "XENBUS: backend %s timed out.\n", be);
}

/*
* Reset frontend if it is in Connected or Closed state.
* Wait for backend to catch up.
* State Connected happens during kdump, Closed after kexec.
*/
static void xenbus_reset_frontend(char *fe, char *be, int be_state)
{
struct xenbus_watch be_watch;

printk(KERN_DEBUG "XENBUS: backend %s %s\n",
be, xenbus_strstate(be_state));

memset(&be_watch, 0, sizeof(be_watch));
be_watch.node = kasprintf(GFP_NOIO | __GFP_HIGH, "%s/state", be);
if (!be_watch.node)
return;

be_watch.callback = xenbus_reset_backend_state_changed;
backend_state = XenbusStateUnknown;

printk(KERN_INFO "XENBUS: triggering reconnect on %s\n", be);
register_xenbus_watch(&be_watch);

/* fall through to forward backend to state XenbusStateInitialising */
switch (be_state) {
case XenbusStateConnected:
xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateClosing);
xenbus_reset_wait_for_backend(be, XenbusStateClosing);

case XenbusStateClosing:
xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateClosed);
xenbus_reset_wait_for_backend(be, XenbusStateClosed);

case XenbusStateClosed:
xenbus_printf(XBT_NIL, fe, "state", "%d", XenbusStateInitialising);
xenbus_reset_wait_for_backend(be, XenbusStateInitWait);
}

unregister_xenbus_watch(&be_watch);
printk(KERN_INFO "XENBUS: reconnect done on %s\n", be);
kfree(be_watch.node);
}

static void xenbus_check_frontend(char *class, char *dev)
{
int be_state, fe_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", &fe_state);
if (err != 1)
goto out;

switch (fe_state) {
case XenbusStateConnected:
case XenbusStateClosed:
printk(KERN_DEBUG "XENBUS: frontend %s %s\n",
frontend, xenbus_strstate(fe_state));
backend = xenbus_read(XBT_NIL, frontend, "backend", NULL);
if (!backend || IS_ERR(backend))
goto out;
err = xenbus_scanf(XBT_NIL, backend, "state", "%i", &be_state);
if (err == 1)
xenbus_reset_frontend(frontend, backend, be_state);
kfree(backend);
break;
default:
break;
}
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_check_frontend(devclass[i], dev[j]);
kfree(dev);
}
kfree(devclass);
}

static int frontend_probe_and_watch(struct notifier_block *notifier,
unsigned long event,
void *data)
{
/* reset devices in Connected or Closed state */
if (xen_hvm_domain())
xenbus_reset_state();
/* Enumerate devices in xenstore and watch for changes. */
xenbus_probe_devices(&xenbus_frontend);
register_xenbus_watch(&fe_watch);
Expand Down

0 comments on commit 955a634

Please sign in to comment.