#include <asm/io.h>
#include <asm/page.h>
+#include <asm/maddr.h>
#include <asm/pgtable.h>
#include <asm/hypervisor.h>
+#include <asm/hypercall.h>
#include <xen/xenbus.h>
#include <xen/xen_proc.h>
#include <xen/evtchn.h>
#include <xen/features.h>
+#include <xen/hvm.h>
#include "xenbus_comms.h"
+int xen_store_evtchn;
+struct xenstore_domain_interface *xen_store_interface;
+static unsigned long xen_store_mfn;
+
extern struct mutex xenwatch_mutex;
static BLOCKING_NOTIFIER_HEAD(xenstore_notifier_list);
static void wait_for_devices(struct xenbus_driver *xendrv);
+static int xenbus_probe_frontend(const char *type, const char *name);
+static int xenbus_uevent_backend(struct device *dev, char **envp,
+ int num_envp, char *buffer, int buffer_size);
+static int xenbus_probe_backend(const char *type, const char *domid);
+
+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 *
match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
/* Bus type for frontend drivers. */
-static int xenbus_probe_frontend(const char *type, const char *name);
static struct xen_bus_type xenbus_frontend = {
.root = "device",
.levels = 2, /* device/type/<id> */
.get_bus_id = frontend_bus_id,
.probe = xenbus_probe_frontend,
.bus = {
- .name = "xen",
- .match = xenbus_match,
+ .name = "xen",
+ .match = xenbus_match,
+ .probe = xenbus_dev_probe,
+ .remove = xenbus_dev_remove,
+ .shutdown = xenbus_dev_shutdown,
},
.dev = {
.bus_id = "xen",
return 0;
}
-static int xenbus_uevent_backend(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size);
-static int xenbus_probe_backend(const char *type, const char *domid);
static struct xen_bus_type xenbus_backend = {
.root = "backend",
.levels = 3, /* backend/type/<frontend>/<id> */
.get_bus_id = backend_bus_id,
.probe = xenbus_probe_backend,
.bus = {
- .name = "xen-backend",
- .match = xenbus_match,
- .uevent = xenbus_uevent_backend,
+ .name = "xen-backend",
+ .match = xenbus_match,
+ .probe = xenbus_dev_probe,
+ .remove = xenbus_dev_remove,
+// .shutdown = xenbus_dev_shutdown,
+ .uevent = xenbus_uevent_backend,
},
.dev = {
.bus_id = "xen-backend",
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 %d (%s), %s, %s", state, xenbus_strstate(state),
+ dev->otherend_watch.node, vec[XS_WATCH_PATH]);
+
+ /*
+ * Ignore xenbus transitions during shutdown. This prevents us doing
+ * work that can fail e.g., when the rootfs is gone.
+ */
+ if (system_state > SYSTEM_RUNNING) {
+ struct xen_bus_type *bus = bus;
+ bus = container_of(dev->dev.bus, struct xen_bus_type, bus);
+ /* If we're frontend, drive the state machine to Closed. */
+ /* This should cause the backend to release our resources. */
+ if ((bus == &xenbus_frontend) && (state == XenbusStateClosing))
+ xenbus_frontend_closed(dev);
+ return;
+ }
+
if (drv->otherend_changed)
drv->otherend_changed(dev, state);
}
const struct xenbus_device_id *id;
int err;
- DPRINTK("");
+ DPRINTK("%s", dev->nodename);
if (!drv->probe) {
err = -ENODEV;
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);
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,
struct xen_bus_type *bus)
{
drv->driver.name = drv->name;
drv->driver.bus = &bus->bus;
drv->driver.owner = drv->owner;
- drv->driver.probe = xenbus_dev_probe;
- drv->driver.remove = xenbus_dev_remove;
mutex_lock(&xenwatch_mutex);
ret = driver_register(&drv->driver);
kfree(to_xenbus_device(dev));
}
-/* Simplified asprintf. */
-char *kasprintf(const char *fmt, ...)
-{
- va_list ap;
- unsigned int len;
- char *p, dummy[1];
-
- va_start(ap, fmt);
- /* FIXME: vsnprintf has a bug, NULL should work */
- len = vsnprintf(dummy, 0, fmt, ap);
- va_end(ap);
-
- p = kmalloc(len + 1, GFP_KERNEL);
- if (!p)
- return NULL;
- va_start(ap, fmt);
- vsprintf(p, fmt, ap);
- va_end(ap);
- return p;
-}
-
static ssize_t xendev_show_nodename(struct device *dev,
struct device_attribute *attr, char *buf)
{
tmpstring += strlen(tmpstring) + 1;
strcpy(tmpstring, type);
xendev->devicetype = tmpstring;
+ init_completion(&xendev->down);
xendev->dev.parent = &bus->dev;
xendev->dev.bus = &bus->bus;
char *nodename;
int err;
- nodename = kasprintf("%s/%s/%s", xenbus_frontend.root, type, name);
+ nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", xenbus_frontend.root, type, name);
if (!nodename)
return -ENOMEM;
char *nodename;
int err;
- nodename = kasprintf("%s/%s", dir, name);
+ nodename = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
if (!nodename)
return -ENOMEM;
DPRINTK("");
- nodename = kasprintf("%s/%s/%s", xenbus_backend.root, type, domid);
+ nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", xenbus_backend.root, type, domid);
if (!nodename)
return -ENOMEM;
rootlen = strsep_len(node, '/', bus->levels);
if (rootlen < 0)
return;
- root = kasprintf("%.*s", rootlen, node);
+ root = kasprintf(GFP_KERNEL, "%.*s", rootlen, node);
if (!root)
return;
printk(KERN_WARNING
"xenbus: resume %s failed: %i\n",
dev->bus_id, err);
- return err;
+ return err;
}
}
return err;
}
- return 0;
+ return 0;
}
void xenbus_suspend(void)
if ((size > PAGE_SIZE) || (vma->vm_pgoff != 0))
return -EINVAL;
- if (remap_pfn_range(vma, vma->vm_start,
- mfn_to_pfn(xen_start_info->store_mfn),
+ if (remap_pfn_range(vma, vma->vm_start, mfn_to_pfn(xen_store_mfn),
size, vma->vm_page_prot))
return -EAGAIN;
{
int len;
- len = sprintf(page, "0x%p", mfn_to_virt(xen_start_info->store_mfn));
+ len = sprintf(page, "0x%p", xen_store_interface);
*eof = 1;
return len;
}
{
int len;
- len = sprintf(page, "%d", xen_start_info->store_evtchn);
+ len = sprintf(page, "%d", xen_store_evtchn);
*eof = 1;
return len;
}
#endif
-
static int __init xenbus_probe_init(void)
{
- int err = 0, dom0;
+ int err = 0;
unsigned long page = 0;
DPRINTK("");
/*
* Domain0 doesn't have a store_evtchn or store_mfn yet.
*/
- dom0 = (xen_start_info->store_evtchn == 0);
-
- if (dom0) {
+ if (is_initial_xendomain()) {
struct evtchn_alloc_unbound alloc_unbound;
/* Allocate page. */
if (!page)
return -ENOMEM;
- xen_start_info->store_mfn =
+ xen_store_mfn = xen_start_info->store_mfn =
pfn_to_mfn(virt_to_phys((void *)page) >>
PAGE_SHIFT);
if (err == -ENOSYS)
goto err;
BUG_ON(err);
- xen_start_info->store_evtchn = alloc_unbound.port;
+ xen_store_evtchn = xen_start_info->store_evtchn =
+ alloc_unbound.port;
#ifdef CONFIG_PROC_FS
/* And finally publish the above info in /proc/xen */
if (xsd_port_intf)
xsd_port_intf->read_proc = xsd_port_read;
#endif
- } else
+ xen_store_interface = mfn_to_virt(xen_store_mfn);
+ } else {
xenstored_ready = 1;
+#ifdef CONFIG_XEN
+ 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);
+#else
+ xen_store_evtchn = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN);
+ xen_store_mfn = hvm_get_parameter(HVM_PARAM_STORE_PFN);
+ xen_store_interface = ioremap(xen_store_mfn << PAGE_SHIFT,
+ PAGE_SIZE);
+#endif
+ }
+
+
+ xenbus_dev_init();
/* Initialize the interface to xenstore. */
err = xs_init();
device_register(&xenbus_frontend.dev);
device_register(&xenbus_backend.dev);
- if (!dom0)
+ if (!is_initial_xendomain())
xenbus_probe(NULL);
return 0;
postcore_initcall(xenbus_probe_init);
+MODULE_LICENSE("Dual BSD/GPL");
+
static int is_disconnected_device(struct device *dev, void *data)
{
print_device_status);
}
+#ifndef MODULE
static int __init boot_wait_for_devices(void)
{
ready_to_wait_for_devices = 1;
}
late_initcall(boot_wait_for_devices);
+#endif