From e39088e3f74699cc1dec97665b1a06c8955006b7 Mon Sep 17 00:00:00 2001 From: t_jeang Date: Tue, 6 Jan 2009 12:06:02 +0000 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 45a1d55a..78d9702a 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -132,6 +132,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; } } @@ -215,23 +220,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), @@ -257,6 +251,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) { @@ -271,8 +292,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 753ebb5f..c5bd548f 100644 --- a/include/xen/xenbus.h +++ b/include/xen/xenbus.h @@ -75,6 +75,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