Hi,
>> 1. Always enter Closed state, and then run a cleanup phase in the kexec
>> code which iterates over xenstore device directories, switching
>> Closed->Initialising.
> I'll try (1). I don't expect it being that hard, I expect doing that in
> the old kernel _after_ unregistering the watches should work just fine.
Here we go, changes:
* new helper function xenbus_strstate() for more readable debug output.
* some of the DPRINK()'s got some more info to print added (device
node, state on state changes).
* Both sides will happily enter "Closed" state without deleting the
device.
* There is a new helper function xenbus_reinit_frontend_devices() for
kexec: It unregisteres the watch (to prevent the device from being
reinitialized in the old kernel) and moves devices from Closed back
to Initialising state.
cheers,
Gerd
--
Gerd Hoffmann <kraxel@xxxxxxx>
http://www.suse.de/~kraxel/julika-dora.jpeg
Signed-off-by: Gerd Hoffmann <kraxel@xxxxxxx>
diff -r f681ffc9b01a linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c
--- a/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c Mon Aug 21 12:05:11
2006 -0400
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c Tue Aug 22 11:34:33
2006 +0200
@@ -301,11 +301,11 @@ static void frontend_changed(struct xenb
struct backend_info *be = dev->dev.driver_data;
int err;
- DPRINTK("");
+ DPRINTK("%s", xenbus_strstate(frontend_state));
switch (frontend_state) {
case XenbusStateInitialising:
- if (dev->state == XenbusStateClosing) {
+ if (dev->state == XenbusStateClosed) {
printk("%s: %s: prepare for reconnect\n",
__FUNCTION__, dev->nodename);
xenbus_switch_state(dev, XenbusStateInitWait);
@@ -331,8 +331,11 @@ static void frontend_changed(struct xenb
xenbus_switch_state(dev, XenbusStateClosing);
break;
+ case XenbusStateClosed:
+ xenbus_switch_state(dev, XenbusStateClosed);
+ break;
+
case XenbusStateUnknown:
- case XenbusStateClosed:
device_unregister(&dev->dev);
break;
diff -r f681ffc9b01a linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c
--- a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c Mon Aug 21
12:05:11 2006 -0400
+++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c Tue Aug 22
11:51:22 2006 +0200
@@ -273,7 +273,7 @@ static void backend_changed(struct xenbu
xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
down(&bd->bd_sem);
- if (info->users > 0)
+ if (info->users > 0 && system_state == SYSTEM_RUNNING)
xenbus_dev_error(dev, -EBUSY,
"Device in use; refusing to close");
else
@@ -360,7 +360,7 @@ static void blkfront_closing(struct xenb
xlvbd_del(info);
- xenbus_switch_state(dev, XenbusStateClosed);
+ xenbus_closing_done(dev);
}
diff -r f681ffc9b01a linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c
--- a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c Mon Aug 21 12:05:11
2006 -0400
+++ b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c Tue Aug 22 11:34:33
2006 +0200
@@ -228,13 +228,13 @@ static void frontend_changed(struct xenb
{
struct backend_info *be = dev->dev.driver_data;
- DPRINTK("");
+ DPRINTK("%s", xenbus_strstate(frontend_state));
be->frontend_state = frontend_state;
switch (frontend_state) {
case XenbusStateInitialising:
- if (dev->state == XenbusStateClosing) {
+ if (dev->state == XenbusStateClosed) {
printk("%s: %s: prepare for reconnect\n",
__FUNCTION__, dev->nodename);
if (be->netif) {
@@ -260,8 +260,11 @@ static void frontend_changed(struct xenb
xenbus_switch_state(dev, XenbusStateClosing);
break;
+ case XenbusStateClosed:
+ xenbus_switch_state(dev, XenbusStateClosed);
+ break;
+
case XenbusStateUnknown:
- case XenbusStateClosed:
if (be->netif != NULL)
kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
device_unregister(&dev->dev);
diff -r f681ffc9b01a linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c
--- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c Mon Aug 21
12:05:11 2006 -0400
+++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c Tue Aug 22
11:52:13 2006 +0200
@@ -478,7 +478,7 @@ static void backend_changed(struct xenbu
struct netfront_info *np = dev->dev.driver_data;
struct net_device *netdev = np->netdev;
- DPRINTK("\n");
+ DPRINTK("%s\n", xenbus_strstate(backend_state));
switch (backend_state) {
case XenbusStateInitialising:
@@ -1946,11 +1946,10 @@ static void netfront_closing(struct xenb
{
struct netfront_info *info = dev->dev.driver_data;
- DPRINTK("netfront_closing: %s removed\n", dev->nodename);
+ DPRINTK("%s\n", dev->nodename);
close_netdev(info);
-
- xenbus_switch_state(dev, XenbusStateClosed);
+ xenbus_closing_done(dev);
}
diff -r f681ffc9b01a linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c Mon Aug 21
12:05:11 2006 -0400
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_client.c Tue Aug 22
11:53:16 2006 +0200
@@ -41,6 +41,21 @@ extern char *kasprintf(const char *fmt,
#define DPRINTK(fmt, args...) \
pr_debug("xenbus_client (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__,
##args)
+char *xenbus_strstate(enum xenbus_state state)
+{
+ static char *name[] = {
+ [ XenbusStateUnknown ] = "Unknown",
+ [ XenbusStateInitialising ] = "Initialising",
+ [ XenbusStateInitWait ] = "InitWait",
+ [ XenbusStateInitialised ] = "Initialised",
+ [ XenbusStateConnected ] = "Connected",
+ [ XenbusStateClosing ] = "Closing",
+ [ XenbusStateClosed ] = "Closed",
+ };
+ return state < sizeof(name)/sizeof(name[0])
+ ? name[state] : "INVALID";
+}
+
int xenbus_watch_path(struct xenbus_device *dev, const char *path,
struct xenbus_watch *watch,
void (*callback)(struct xenbus_watch *,
@@ -124,6 +139,13 @@ int xenbus_switch_state(struct xenbus_de
}
EXPORT_SYMBOL_GPL(xenbus_switch_state);
+int xenbus_closing_done(struct xenbus_device *dev)
+{
+ xenbus_switch_state(dev, XenbusStateClosed);
+ complete(&dev->down);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xenbus_closing_done);
/**
* Return the path to the error node for the given device, or NULL on failure.
diff -r f681ffc9b01a linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Mon Aug 21
12:05:11 2006 -0400
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Tue Aug 22
11:56:32 2006 +0200
@@ -73,6 +73,7 @@ static int xenbus_probe_backend(const ch
static int xenbus_dev_probe(struct device *_dev);
static int xenbus_dev_remove(struct device *_dev);
+static void xenbus_dev_shutdown(struct device *_dev);
/* If something in array of ids matches this device, return it. */
static const struct xenbus_device_id *
@@ -192,6 +193,7 @@ static struct xen_bus_type xenbus_fronte
.match = xenbus_match,
.probe = xenbus_dev_probe,
.remove = xenbus_dev_remove,
+ .shutdown = xenbus_dev_shutdown,
},
.dev = {
.bus_id = "xen",
@@ -246,6 +248,7 @@ static struct xen_bus_type xenbus_backen
.match = xenbus_match,
.probe = xenbus_dev_probe,
.remove = xenbus_dev_remove,
+// .shutdown = xenbus_dev_shutdown,
.uevent = xenbus_uevent_backend,
},
.dev = {
@@ -316,8 +319,8 @@ static void otherend_changed(struct xenb
state = xenbus_read_driver_state(dev->otherend);
- DPRINTK("state is %d, %s, %s",
- state, dev->otherend_watch.node, vec[XS_WATCH_PATH]);
+ DPRINTK("state is %s, %s, %s", xenbus_strstate(state),
+ dev->otherend_watch.node, vec[XS_WATCH_PATH]);
if (drv->otherend_changed)
drv->otherend_changed(dev, state);
}
@@ -348,7 +351,7 @@ static int xenbus_dev_probe(struct devic
const struct xenbus_device_id *id;
int err;
- DPRINTK("");
+ DPRINTK("%s", dev->nodename);
if (!drv->probe) {
err = -ENODEV;
@@ -393,7 +396,7 @@ static int xenbus_dev_remove(struct devi
struct xenbus_device *dev = to_xenbus_device(_dev);
struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
- DPRINTK("");
+ DPRINTK("%s", dev->nodename);
free_otherend_watch(dev);
free_otherend_details(dev);
@@ -403,6 +406,27 @@ static int xenbus_dev_remove(struct devi
xenbus_switch_state(dev, XenbusStateClosed);
return 0;
+}
+
+static void xenbus_dev_shutdown(struct device *_dev)
+{
+ struct xenbus_device *dev = to_xenbus_device(_dev);
+ unsigned long timeout = 5*HZ;
+
+ DPRINTK("%s", dev->nodename);
+
+ get_device(&dev->dev);
+ if (dev->state != XenbusStateConnected) {
+ printk("%s: %s: %s != Connected, skipping\n", __FUNCTION__,
+ dev->nodename, xenbus_strstate(dev->state));
+ goto out;
+ }
+ xenbus_switch_state(dev, XenbusStateClosing);
+ timeout = wait_for_completion_timeout(&dev->down, timeout);
+ if (!timeout)
+ printk("%s: %s timeout closing device\n", __FUNCTION__,
dev->nodename);
+ out:
+ put_device(&dev->dev);
}
static int xenbus_register_driver_common(struct xenbus_driver *drv,
@@ -587,6 +611,7 @@ static int xenbus_probe_node(struct xen_
tmpstring += strlen(tmpstring) + 1;
strcpy(tmpstring, type);
xendev->devicetype = tmpstring;
+ init_completion(&xendev->down);
xendev->dev.parent = &bus->dev;
xendev->dev.bus = &bus->bus;
@@ -1168,3 +1193,23 @@ static int __init boot_wait_for_devices(
late_initcall(boot_wait_for_devices);
#endif
+
+#ifdef CONFIG_KEXEC
+static int xenbus_reinit_device(struct device *dev, void *data)
+{
+ struct xenbus_device *xendev = to_xenbus_device(dev);
+
+ if (xendev->state != XenbusStateClosed)
+ return 0;
+ free_otherend_watch(xendev);
+ xenbus_switch_state(xendev, XenbusStateInitialising);
+ return 0;
+}
+
+int xenbus_reinit_frontend_devices(void)
+{
+ DPRINTK("");
+ return bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL,
+ xenbus_reinit_device);
+}
+#endif
diff -r f681ffc9b01a linux-2.6-xen-sparse/include/xen/xenbus.h
--- a/linux-2.6-xen-sparse/include/xen/xenbus.h Mon Aug 21 12:05:11 2006 -0400
+++ b/linux-2.6-xen-sparse/include/xen/xenbus.h Tue Aug 22 11:34:33 2006 +0200
@@ -37,6 +37,7 @@
#include <linux/device.h>
#include <linux/notifier.h>
#include <linux/mutex.h>
+#include <linux/completion.h>
#include <xen/interface/xen.h>
#include <xen/interface/grant_table.h>
#include <xen/interface/io/xenbus.h>
@@ -74,6 +75,7 @@ struct xenbus_device {
struct xenbus_watch otherend_watch;
struct device dev;
enum xenbus_state state;
+ struct completion down;
};
static inline struct xenbus_device *to_xenbus_device(struct device *dev)
@@ -297,4 +299,8 @@ void xenbus_dev_fatal(struct xenbus_devi
int __init xenbus_dev_init(void);
+int xenbus_closing_done(struct xenbus_device *dev);
+char *xenbus_strstate(enum xenbus_state state);
+int xenbus_reinit_frontend_devices(void);
+
#endif /* _XEN_XENBUS_H */
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|