Merge branches 'stable/drivers-3.2', 'stable/drivers.bugfixes-3.2' and 'stable/pci.fixes-3.2' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen
* 'stable/drivers-3.2' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen: xenbus: don't rely on xen_initial_domain to detect local xenstore xenbus: Fix loopback event channel assuming domain 0 xen/pv-on-hvm:kexec: Fix implicit declaration of function 'xen_hvm_domain' xen/pv-on-hvm kexec: add xs_reset_watches to shutdown watches from old kernel xen/pv-on-hvm kexec: update xs_wire.h:xsd_sockmsg_type from xen-unstable xen/pv-on-hvm kexec+kdump: reset PV devices in kexec or crash kernel xen/pv-on-hvm kexec: rebind virqs to existing eventchannel ports xen/pv-on-hvm kexec: prevent crash in xenwatch_thread() when stale watch events arrive * 'stable/drivers.bugfixes-3.2' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen: xen/pciback: Check if the device is found instead of blindly assuming so. xen/pciback: Do not dereference psdev during printk when it is NULL. xen: remove XEN_PLATFORM_PCI config option xen: XEN_PVHVM depends on PCI xen/pciback: double lock typo xen/pciback: use mutex rather than spinlock in vpci backend xen/pciback: Use mutexes when working with Xenbus state transitions. xen/pciback: miscellaneous adjustments xen/pciback: use mutex rather than spinlock in passthrough backend xen/pciback: use resource_size() * 'stable/pci.fixes-3.2' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen: xen/pci: support multi-segment systems xen-swiotlb: When doing coherent alloc/dealloc check before swizzling the MFNs. xen/pci: make bus notifier handler return sane values xen-swiotlb: fix printk and panic args xen-swiotlb: Fix wrong panic. xen-swiotlb: Retry up three times to allocate Xen-SWIOTLB xen-pcifront: Update warning comment to use 'e820_host' option.
This commit is contained in:
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
xen_store_mfn = xen_start_info->store_mfn =
|
||||
pfn_to_mfn(virt_to_phys((void *)page) >>
|
||||
PAGE_SHIFT);
|
||||
|
||||
/* Next allocate a local port which xenstored can bind to */
|
||||
alloc_unbound.dom = DOMID_SELF;
|
||||
alloc_unbound.remote_dom = DOMID_SELF;
|
||||
|
||||
err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
|
||||
&alloc_unbound);
|
||||
if (err == -ENOSYS)
|
||||
goto out_err;
|
||||
|
||||
BUG_ON(err);
|
||||
xen_store_evtchn = xen_start_info->store_evtchn =
|
||||
alloc_unbound.port;
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
if (page != 0)
|
||||
free_page(page);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init xenbus_init(void)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
err = -ENODEV;
|
||||
if (!xen_domain())
|
||||
return err;
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Domain0 doesn't have a store_evtchn or store_mfn yet.
|
||||
*/
|
||||
if (xen_initial_domain()) {
|
||||
struct evtchn_alloc_unbound alloc_unbound;
|
||||
|
||||
/* Allocate Xenstore page */
|
||||
page = get_zeroed_page(GFP_KERNEL);
|
||||
if (!page)
|
||||
if (xen_hvm_domain()) {
|
||||
uint64_t v = 0;
|
||||
err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v);
|
||||
if (err)
|
||||
goto out_error;
|
||||
|
||||
xen_store_mfn = xen_start_info->store_mfn =
|
||||
pfn_to_mfn(virt_to_phys((void *)page) >>
|
||||
PAGE_SHIFT);
|
||||
|
||||
/* Next allocate a local port which xenstored can bind to */
|
||||
alloc_unbound.dom = DOMID_SELF;
|
||||
alloc_unbound.remote_dom = 0;
|
||||
|
||||
err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
|
||||
&alloc_unbound);
|
||||
if (err == -ENOSYS)
|
||||
xen_store_evtchn = (int)v;
|
||||
err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v);
|
||||
if (err)
|
||||
goto out_error;
|
||||
|
||||
BUG_ON(err);
|
||||
xen_store_evtchn = xen_start_info->store_evtchn =
|
||||
alloc_unbound.port;
|
||||
|
||||
xen_store_interface = mfn_to_virt(xen_store_mfn);
|
||||
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);
|
||||
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);
|
||||
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_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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user