X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fxen%2Fxenbus%2Fxenbus_probe.c;fp=drivers%2Fxen%2Fxenbus%2Fxenbus_probe.c;h=2ae941fa15961db990e959aa2112a2d619bc5a7e;hb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;hp=a9207228dc5dc1a11a51060a92bd12c55b8cb8bf;hpb=4e76c8a9fa413ccc09d3f7f664183dcce3555d57;p=linux-2.6.git diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index a9207228d..2ae941fa1 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -45,21 +45,37 @@ #include #include +#include #include #include +#include #include #include #include #include +#include #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) @@ -168,15 +184,17 @@ static int read_frontend_details(struct xenbus_device *xendev) /* 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/ */ .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", @@ -221,18 +239,18 @@ static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) 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// */ .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", @@ -302,8 +320,23 @@ static void otherend_changed(struct xenbus_watch *watch, 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); } @@ -334,7 +367,7 @@ static int xenbus_dev_probe(struct device *_dev) const struct xenbus_device_id *id; int err; - DPRINTK(""); + DPRINTK("%s", dev->nodename); if (!drv->probe) { err = -ENODEV; @@ -379,7 +412,7 @@ static int xenbus_dev_remove(struct device *_dev) 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); @@ -391,6 +424,27 @@ static int xenbus_dev_remove(struct device *_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) { @@ -399,8 +453,6 @@ static int xenbus_register_driver_common(struct xenbus_driver *drv, 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); @@ -508,27 +560,6 @@ static void xenbus_dev_release(struct device *dev) 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) { @@ -575,6 +606,7 @@ static int xenbus_probe_node(struct xen_bus_type *bus, tmpstring += strlen(tmpstring) + 1; strcpy(tmpstring, type); xendev->devicetype = tmpstring; + init_completion(&xendev->down); xendev->dev.parent = &bus->dev; xendev->dev.bus = &bus->bus; @@ -604,7 +636,7 @@ static int xenbus_probe_frontend(const char *type, const char *name) 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; @@ -623,7 +655,7 @@ static int xenbus_probe_backend_unit(const char *dir, char *nodename; int err; - nodename = kasprintf("%s/%s", dir, name); + nodename = kasprintf(GFP_KERNEL, "%s/%s", dir, name); if (!nodename) return -ENOMEM; @@ -644,7 +676,7 @@ static int xenbus_probe_backend(const char *type, const char *domid) 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; @@ -750,7 +782,7 @@ static void dev_changed(const char *node, struct xen_bus_type *bus) 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; @@ -840,7 +872,7 @@ static int resume_dev(struct device *dev, void *data) printk(KERN_WARNING "xenbus: resume %s failed: %i\n", dev->bus_id, err); - return err; + return err; } } @@ -852,7 +884,7 @@ static int resume_dev(struct device *dev, void *data) return err; } - return 0; + return 0; } void xenbus_suspend(void) @@ -928,8 +960,7 @@ static int xsd_kva_mmap(struct file *file, struct vm_area_struct *vma) 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; @@ -941,7 +972,7 @@ static int xsd_kva_read(char *page, char **start, off_t off, { 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; } @@ -951,16 +982,15 @@ static int xsd_port_read(char *page, char **start, off_t off, { 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(""); @@ -975,9 +1005,7 @@ static int __init xenbus_probe_init(void) /* * 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. */ @@ -985,7 +1013,7 @@ static int __init xenbus_probe_init(void) 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); @@ -998,7 +1026,8 @@ static int __init xenbus_probe_init(void) 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 */ @@ -1014,8 +1043,23 @@ static int __init xenbus_probe_init(void) 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(); @@ -1029,7 +1073,7 @@ static int __init xenbus_probe_init(void) device_register(&xenbus_frontend.dev); device_register(&xenbus_backend.dev); - if (!dom0) + if (!is_initial_xendomain()) xenbus_probe(NULL); return 0; @@ -1049,6 +1093,8 @@ static int __init xenbus_probe_init(void) postcore_initcall(xenbus_probe_init); +MODULE_LICENSE("Dual BSD/GPL"); + static int is_disconnected_device(struct device *dev, void *data) { @@ -1132,6 +1178,7 @@ static void wait_for_devices(struct xenbus_driver *xendrv) print_device_status); } +#ifndef MODULE static int __init boot_wait_for_devices(void) { ready_to_wait_for_devices = 1; @@ -1140,3 +1187,4 @@ static int __init boot_wait_for_devices(void) } late_initcall(boot_wait_for_devices); +#endif