diff options
Diffstat (limited to 'drivers/xen/xenbus')
| -rw-r--r-- | drivers/xen/xenbus/xenbus_comms.c | 4 | ||||
| -rw-r--r-- | drivers/xen/xenbus/xenbus_probe.c | 101 | ||||
| -rw-r--r-- | drivers/xen/xenbus/xenbus_probe_backend.c | 2 | ||||
| -rw-r--r-- | drivers/xen/xenbus/xenbus_probe_frontend.c | 121 | ||||
| -rw-r--r-- | drivers/xen/xenbus/xenbus_xs.c | 17 | 
5 files changed, 192 insertions, 53 deletions
diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c index 090c61ee8fd..2eff7a6aaa2 100644 --- a/drivers/xen/xenbus/xenbus_comms.c +++ b/drivers/xen/xenbus/xenbus_comms.c @@ -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) { diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index bd2f90c9ac8..cef9b0bf63d 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -684,64 +684,74 @@ static int __init xenbus_probe_initcall(void)  device_initcall(xenbus_probe_initcall); -static int __init xenbus_init(void) +/* Set up event channel for xenstored which is run as a local process + * (this is normally used only in dom0) + */ +static int __init xenstored_local_init(void)  {  	int err = 0;  	unsigned long page = 0; +	struct evtchn_alloc_unbound alloc_unbound; -	DPRINTK(""); +	/* Allocate Xenstore page */ +	page = get_zeroed_page(GFP_KERNEL); +	if (!page) +		goto out_err; -	err = -ENODEV; -	if (!xen_domain()) -		return err; +	xen_store_mfn = xen_start_info->store_mfn = +		pfn_to_mfn(virt_to_phys((void *)page) >> +			   PAGE_SHIFT); -	/* -	 * Domain0 doesn't have a store_evtchn or store_mfn yet. -	 */ -	if (xen_initial_domain()) { -		struct evtchn_alloc_unbound alloc_unbound; +	/* Next allocate a local port which xenstored can bind to */ +	alloc_unbound.dom        = DOMID_SELF; +	alloc_unbound.remote_dom = DOMID_SELF; -		/* Allocate Xenstore page */ -		page = get_zeroed_page(GFP_KERNEL); -		if (!page) -			goto out_error; +	err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, +					  &alloc_unbound); +	if (err == -ENOSYS) +		goto out_err; -		xen_store_mfn = xen_start_info->store_mfn = -			pfn_to_mfn(virt_to_phys((void *)page) >> -				   PAGE_SHIFT); +	BUG_ON(err); +	xen_store_evtchn = xen_start_info->store_evtchn = +		alloc_unbound.port; -		/* Next allocate a local port which xenstored can bind to */ -		alloc_unbound.dom        = DOMID_SELF; -		alloc_unbound.remote_dom = 0; +	return 0; -		err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, -						  &alloc_unbound); -		if (err == -ENOSYS) -			goto out_error; + out_err: +	if (page != 0) +		free_page(page); +	return err; +} -		BUG_ON(err); -		xen_store_evtchn = xen_start_info->store_evtchn = -			alloc_unbound.port; +static int __init xenbus_init(void) +{ +	int err = 0; -		xen_store_interface = mfn_to_virt(xen_store_mfn); +	if (!xen_domain()) +		return -ENODEV; + +	if (xen_hvm_domain()) { +		uint64_t v = 0; +		err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v); +		if (err) +			goto out_error; +		xen_store_evtchn = (int)v; +		err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v); +		if (err) +			goto out_error; +		xen_store_mfn = (unsigned long)v; +		xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT, PAGE_SIZE);  	} else { -		if (xen_hvm_domain()) { -			uint64_t v = 0; -			err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v); -			if (err) -				goto out_error; -			xen_store_evtchn = (int)v; -			err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v); +		xen_store_evtchn = xen_start_info->store_evtchn; +		xen_store_mfn = xen_start_info->store_mfn; +		if (xen_store_evtchn) +			xenstored_ready = 1; +		else { +			err = xenstored_local_init();  			if (err)  				goto out_error; -			xen_store_mfn = (unsigned long)v; -			xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT, PAGE_SIZE); -		} else { -			xen_store_evtchn = xen_start_info->store_evtchn; -			xen_store_mfn = xen_start_info->store_mfn; -			xen_store_interface = mfn_to_virt(xen_store_mfn); -			xenstored_ready = 1;  		} +		xen_store_interface = mfn_to_virt(xen_store_mfn);  	}  	/* Initialize the interface to xenstore. */ @@ -760,12 +770,7 @@ static int __init xenbus_init(void)  	proc_mkdir("xen", NULL);  #endif -	return 0; - -  out_error: -	if (page != 0) -		free_page(page); - + out_error:  	return err;  } diff --git a/drivers/xen/xenbus/xenbus_probe_backend.c b/drivers/xen/xenbus/xenbus_probe_backend.c index 60adf919d78..32417b5064f 100644 --- a/drivers/xen/xenbus/xenbus_probe_backend.c +++ b/drivers/xen/xenbus/xenbus_probe_backend.c @@ -104,8 +104,6 @@ static int xenbus_uevent_backend(struct device *dev,  	xdev = to_xenbus_device(dev);  	bus = container_of(xdev->dev.bus, struct xen_bus_type, bus); -	if (xdev == NULL) -		return -ENODEV;  	if (add_uevent_var(env, "MODALIAS=xen-backend:%s", xdev->devicetype))  		return -ENOMEM; diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c index ed2ba474a56..540587e18a9 100644 --- a/drivers/xen/xenbus/xenbus_probe_frontend.c +++ b/drivers/xen/xenbus/xenbus_probe_frontend.c @@ -248,10 +248,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); diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index 5534690075a..b3b8f2f3ad1 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -45,6 +45,7 @@  #include <linux/module.h>  #include <linux/mutex.h>  #include <xen/xenbus.h> +#include <xen/xen.h>  #include "xenbus_comms.h"  struct xs_stored_msg { @@ -620,6 +621,15 @@ static struct xenbus_watch *find_watch(const char *token)  	return NULL;  } +static void xs_reset_watches(void) +{ +	int err; + +	err = xs_error(xs_single(XBT_NIL, XS_RESET_WATCHES, "", NULL)); +	if (err && err != -EEXIST) +		printk(KERN_WARNING "xs_reset_watches failed: %d\n", err); +} +  /* Register callback to watch this node. */  int register_xenbus_watch(struct xenbus_watch *watch)  { @@ -638,8 +648,7 @@ int register_xenbus_watch(struct xenbus_watch *watch)  	err = xs_watch(watch->node, token); -	/* Ignore errors due to multiple registration. */ -	if ((err != 0) && (err != -EEXIST)) { +	if (err) {  		spin_lock(&watches_lock);  		list_del(&watch->list);  		spin_unlock(&watches_lock); @@ -897,5 +906,9 @@ int xs_init(void)  	if (IS_ERR(task))  		return PTR_ERR(task); +	/* shutdown watches for kexec boot */ +	if (xen_hvm_domain()) +		xs_reset_watches(); +  	return 0;  }  |