From b2a4be27c747e1c35a5480d883054fb385d11219 Mon Sep 17 00:00:00 2001 From: Steven Smith Date: Tue, 30 Jun 2009 12:55:48 +0100 Subject: [PATCH] Watch the online node in the backend area, as well as the state node in the frontend area, and fire the frontend state changed watch whenever it changes. This allows us to catch the case where a device shuts down in a domU and then gets xm detach'd from in dom0. Otherwise, the backend doesn't shut down correctly, since online was set when the frontend shut down and we don't get another kick when it becomes unset. --- drivers/xen/xenbus/xenbus_probe.c | 57 +++++++++++++++++++++++-------- include/xen/xenbus.h | 1 + 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 3cfc5c64..3f7ea040 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -133,6 +133,11 @@ static void free_otherend_watch(struct xenbus_device *dev) unregister_xenbus_watch(&dev->otherend_watch); kfree(dev->otherend_watch.node); dev->otherend_watch.node = NULL; + } + if (dev->online_watch.node) { + unregister_xenbus_watch(&dev->online_watch); + kfree(dev->online_watch.node); + dev->online_watch.node = NULL; } } @@ -211,23 +216,12 @@ static struct xen_bus_type xenbus_frontend = { }, }; -static void otherend_changed(struct xenbus_watch *watch, - const char **vec, unsigned int len) +static void otherend_changed_common(struct xenbus_device *dev, + const char **vec, unsigned int len) { - struct xenbus_device *dev = - container_of(watch, struct xenbus_device, otherend_watch); struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver); enum xenbus_state state; - /* Protect us against watches firing on old details when the otherend - details change, say immediately after a resume. */ - if (!dev->otherend || - strncmp(dev->otherend, vec[XS_WATCH_PATH], - strlen(dev->otherend))) { - DPRINTK("Ignoring watch at %s", vec[XS_WATCH_PATH]); - return; - } - state = xenbus_read_driver_state(dev->otherend); DPRINTK("state is %d (%s), %s, %s", state, xenbus_strstate(state), @@ -253,6 +247,33 @@ static void otherend_changed(struct xenbus_watch *watch, drv->otherend_changed(dev, state); } +static void online_changed(struct xenbus_watch *watch, + const char **vec, unsigned int len) +{ + struct xenbus_device *dev = + container_of(watch, struct xenbus_device, online_watch); + + otherend_changed_common(dev, vec, len); +} + +static void otherend_changed(struct xenbus_watch *watch, + const char **vec, unsigned int len) +{ + struct xenbus_device *dev = + container_of(watch, struct xenbus_device, otherend_watch); + + /* Protect us against watches firing on old details when the otherend + details change, say immediately after a resume. */ + if (!dev->otherend || + strncmp(dev->otherend, vec[XS_WATCH_PATH], + strlen(dev->otherend))) { + DPRINTK("Ignoring watch at %s", vec[XS_WATCH_PATH]); + return; + } + + otherend_changed_common(dev, vec, len); +} + static int talk_to_otherend(struct xenbus_device *dev) { @@ -267,8 +288,14 @@ static int talk_to_otherend(struct xenbus_device *dev) static int watch_otherend(struct xenbus_device *dev) { - return xenbus_watch_path2(dev, dev->otherend, "state", - &dev->otherend_watch, otherend_changed); + int i; + i = xenbus_watch_path2(dev, dev->otherend, "state", + &dev->otherend_watch, otherend_changed); + if (i >= 0) { + i = xenbus_watch_path2(dev, dev->nodename, "online", + &dev->online_watch, online_changed); + } + return i; } diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h index a0de4bad..c062dd5b 100644 --- a/include/xen/xenbus.h +++ b/include/xen/xenbus.h @@ -79,6 +79,7 @@ struct xenbus_device { const char *otherend; int otherend_id; struct xenbus_watch otherend_watch; + struct xenbus_watch online_watch; struct device dev; enum xenbus_state state; struct completion down; -- 2.39.5