765 lines
22 KiB
Diff
765 lines
22 KiB
Diff
# HG changeset patch
|
|
# User Ian Campbell <ian.campbell@xensource.com>
|
|
# Date Wed Oct 25 13:58:30 2006 +0100
|
|
# Node ID 47cc7392741ad120a0c5745f7aeaf00a1aefd538
|
|
# parent: 266aef9b0386b0742e05893e24e09375b31bf835
|
|
[LINUX] Move xenbus backend probing into a separate source file and
|
|
only build it when CONFIG_XEN_BACKEND is set.
|
|
|
|
This removes unused code from frontend only configurations and also
|
|
makes PV-on-HVM drivers on older kernels simpler by removing code
|
|
which would otherwise require extra code in the compatability shim.
|
|
|
|
Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
|
|
|
|
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/Makefile Wed Oct 25 13:58:30 2006 +0100
|
|
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/Makefile Wed Oct 25 13:58:30 2006 +0100
|
|
@@ -9,4 +9,5 @@ xenbus-objs += xenbus_comms.o
|
|
xenbus-objs += xenbus_comms.o
|
|
xenbus-objs += xenbus_xs.o
|
|
xenbus-objs += xenbus_probe.o
|
|
+obj-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o
|
|
obj-$(CONFIG_XEN_XENBUS_DEV) += xenbus_dev.o
|
|
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Wed Oct 25 13:58:30 2006 +0100
|
|
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Wed Oct 25 13:58:30 2006 +0100
|
|
@@ -56,6 +56,7 @@
|
|
#include <xen/hvm.h>
|
|
|
|
#include "xenbus_comms.h"
|
|
+#include "xenbus_probe.h"
|
|
|
|
int xen_store_evtchn;
|
|
struct xenstore_domain_interface *xen_store_interface;
|
|
@@ -68,12 +69,7 @@ static void wait_for_devices(struct xenb
|
|
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. */
|
|
@@ -87,7 +83,7 @@ match_device(const struct xenbus_device_
|
|
return NULL;
|
|
}
|
|
|
|
-static int xenbus_match(struct device *_dev, struct device_driver *_drv)
|
|
+int xenbus_match(struct device *_dev, struct device_driver *_drv)
|
|
{
|
|
struct xenbus_driver *drv = to_xenbus_driver(_drv);
|
|
|
|
@@ -96,17 +92,6 @@ static int xenbus_match(struct device *_
|
|
|
|
return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
|
|
}
|
|
-
|
|
-struct xen_bus_type
|
|
-{
|
|
- char *root;
|
|
- unsigned int levels;
|
|
- int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
|
|
- int (*probe)(const char *type, const char *dir);
|
|
- struct bus_type bus;
|
|
- struct device dev;
|
|
-};
|
|
-
|
|
|
|
/* device/<type>/<id> => <type>-<id> */
|
|
static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
|
|
@@ -144,7 +129,7 @@ static void free_otherend_watch(struct x
|
|
}
|
|
|
|
|
|
-static int read_otherend_details(struct xenbus_device *xendev,
|
|
+int read_otherend_details(struct xenbus_device *xendev,
|
|
char *id_node, char *path_node)
|
|
{
|
|
int err = xenbus_gather(XBT_NIL, xendev->nodename,
|
|
@@ -174,12 +159,6 @@ static int read_backend_details(struct x
|
|
static int read_backend_details(struct xenbus_device *xendev)
|
|
{
|
|
return read_otherend_details(xendev, "backend-id", "backend");
|
|
-}
|
|
-
|
|
-
|
|
-static int read_frontend_details(struct xenbus_device *xendev)
|
|
-{
|
|
- return read_otherend_details(xendev, "frontend-id", "frontend");
|
|
}
|
|
|
|
|
|
@@ -201,106 +180,6 @@ static struct xen_bus_type xenbus_fronte
|
|
},
|
|
};
|
|
|
|
-/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
|
|
-static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
|
|
-{
|
|
- int domid, err;
|
|
- const char *devid, *type, *frontend;
|
|
- unsigned int typelen;
|
|
-
|
|
- type = strchr(nodename, '/');
|
|
- if (!type)
|
|
- return -EINVAL;
|
|
- type++;
|
|
- typelen = strcspn(type, "/");
|
|
- if (!typelen || type[typelen] != '/')
|
|
- return -EINVAL;
|
|
-
|
|
- devid = strrchr(nodename, '/') + 1;
|
|
-
|
|
- err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid,
|
|
- "frontend", NULL, &frontend,
|
|
- NULL);
|
|
- if (err)
|
|
- return err;
|
|
- if (strlen(frontend) == 0)
|
|
- err = -ERANGE;
|
|
- if (!err && !xenbus_exists(XBT_NIL, frontend, ""))
|
|
- err = -ENOENT;
|
|
-
|
|
- kfree(frontend);
|
|
-
|
|
- if (err)
|
|
- return err;
|
|
-
|
|
- if (snprintf(bus_id, BUS_ID_SIZE,
|
|
- "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
|
|
- return -ENOSPC;
|
|
- return 0;
|
|
-}
|
|
-
|
|
-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,
|
|
- .probe = xenbus_dev_probe,
|
|
- .remove = xenbus_dev_remove,
|
|
-// .shutdown = xenbus_dev_shutdown,
|
|
- .uevent = xenbus_uevent_backend,
|
|
- },
|
|
- .dev = {
|
|
- .bus_id = "xen-backend",
|
|
- },
|
|
-};
|
|
-
|
|
-static int xenbus_uevent_backend(struct device *dev, char **envp,
|
|
- int num_envp, char *buffer, int buffer_size)
|
|
-{
|
|
- struct xenbus_device *xdev;
|
|
- struct xenbus_driver *drv;
|
|
- int i = 0;
|
|
- int length = 0;
|
|
-
|
|
- DPRINTK("");
|
|
-
|
|
- if (dev == NULL)
|
|
- return -ENODEV;
|
|
-
|
|
- xdev = to_xenbus_device(dev);
|
|
- if (xdev == NULL)
|
|
- return -ENODEV;
|
|
-
|
|
- /* stuff we want to pass to /sbin/hotplug */
|
|
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
|
|
- "XENBUS_TYPE=%s", xdev->devicetype);
|
|
-
|
|
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
|
|
- "XENBUS_PATH=%s", xdev->nodename);
|
|
-
|
|
- add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
|
|
- "XENBUS_BASE_PATH=%s", xenbus_backend.root);
|
|
-
|
|
- /* terminate, set to next free slot, shrink available space */
|
|
- envp[i] = NULL;
|
|
- envp = &envp[i];
|
|
- num_envp -= i;
|
|
- buffer = &buffer[length];
|
|
- buffer_size -= length;
|
|
-
|
|
- if (dev->driver) {
|
|
- drv = to_xenbus_driver(dev->driver);
|
|
- if (drv && drv->uevent)
|
|
- return drv->uevent(xdev, envp, num_envp, buffer,
|
|
- buffer_size);
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
static void otherend_changed(struct xenbus_watch *watch,
|
|
const char **vec, unsigned int len)
|
|
{
|
|
@@ -360,7 +239,7 @@ static int watch_otherend(struct xenbus_
|
|
}
|
|
|
|
|
|
-static int xenbus_dev_probe(struct device *_dev)
|
|
+int xenbus_dev_probe(struct device *_dev)
|
|
{
|
|
struct xenbus_device *dev = to_xenbus_device(_dev);
|
|
struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
|
|
@@ -407,7 +286,7 @@ fail:
|
|
return -ENODEV;
|
|
}
|
|
|
|
-static int xenbus_dev_remove(struct device *_dev)
|
|
+int xenbus_dev_remove(struct device *_dev)
|
|
{
|
|
struct xenbus_device *dev = to_xenbus_device(_dev);
|
|
struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
|
|
@@ -445,8 +324,8 @@ static void xenbus_dev_shutdown(struct d
|
|
put_device(&dev->dev);
|
|
}
|
|
|
|
-static int xenbus_register_driver_common(struct xenbus_driver *drv,
|
|
- struct xen_bus_type *bus)
|
|
+int xenbus_register_driver_common(struct xenbus_driver *drv,
|
|
+ struct xen_bus_type *bus)
|
|
{
|
|
int ret;
|
|
|
|
@@ -476,14 +355,6 @@ int xenbus_register_frontend(struct xenb
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_GPL(xenbus_register_frontend);
|
|
-
|
|
-int xenbus_register_backend(struct xenbus_driver *drv)
|
|
-{
|
|
- drv->read_otherend_details = read_frontend_details;
|
|
-
|
|
- return xenbus_register_driver_common(drv, &xenbus_backend);
|
|
-}
|
|
-EXPORT_SYMBOL_GPL(xenbus_register_backend);
|
|
|
|
void xenbus_unregister_driver(struct xenbus_driver *drv)
|
|
{
|
|
@@ -596,9 +467,9 @@ DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP |
|
|
DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL);
|
|
|
|
|
|
-static int xenbus_probe_node(struct xen_bus_type *bus,
|
|
- const char *type,
|
|
- const char *nodename)
|
|
+int xenbus_probe_node(struct xen_bus_type *bus,
|
|
+ const char *type,
|
|
+ const char *nodename)
|
|
{
|
|
int err;
|
|
struct xenbus_device *xendev;
|
|
@@ -668,55 +539,6 @@ static int xenbus_probe_frontend(const c
|
|
return err;
|
|
}
|
|
|
|
-/* backend/<typename>/<frontend-uuid>/<name> */
|
|
-static int xenbus_probe_backend_unit(const char *dir,
|
|
- const char *type,
|
|
- const char *name)
|
|
-{
|
|
- char *nodename;
|
|
- int err;
|
|
-
|
|
- nodename = kasprintf("%s/%s", dir, name);
|
|
- if (!nodename)
|
|
- return -ENOMEM;
|
|
-
|
|
- DPRINTK("%s\n", nodename);
|
|
-
|
|
- err = xenbus_probe_node(&xenbus_backend, type, nodename);
|
|
- kfree(nodename);
|
|
- return err;
|
|
-}
|
|
-
|
|
-/* backend/<typename>/<frontend-domid> */
|
|
-static int xenbus_probe_backend(const char *type, const char *domid)
|
|
-{
|
|
- char *nodename;
|
|
- int err = 0;
|
|
- char **dir;
|
|
- unsigned int i, dir_n = 0;
|
|
-
|
|
- DPRINTK("");
|
|
-
|
|
- nodename = kasprintf("%s/%s/%s", xenbus_backend.root, type, domid);
|
|
- if (!nodename)
|
|
- return -ENOMEM;
|
|
-
|
|
- dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n);
|
|
- if (IS_ERR(dir)) {
|
|
- kfree(nodename);
|
|
- return PTR_ERR(dir);
|
|
- }
|
|
-
|
|
- for (i = 0; i < dir_n; i++) {
|
|
- err = xenbus_probe_backend_unit(nodename, type, dir[i]);
|
|
- if (err)
|
|
- break;
|
|
- }
|
|
- kfree(dir);
|
|
- kfree(nodename);
|
|
- return err;
|
|
-}
|
|
-
|
|
static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
|
|
{
|
|
int err = 0;
|
|
@@ -737,7 +559,7 @@ static int xenbus_probe_device_type(stru
|
|
return err;
|
|
}
|
|
|
|
-static int xenbus_probe_devices(struct xen_bus_type *bus)
|
|
+int xenbus_probe_devices(struct xen_bus_type *bus)
|
|
{
|
|
int err = 0;
|
|
char **dir;
|
|
@@ -779,7 +601,7 @@ static int strsep_len(const char *str, c
|
|
return (len == 0) ? i : -ERANGE;
|
|
}
|
|
|
|
-static void dev_changed(const char *node, struct xen_bus_type *bus)
|
|
+void dev_changed(const char *node, struct xen_bus_type *bus)
|
|
{
|
|
int exists, rootlen;
|
|
struct xenbus_device *dev;
|
|
@@ -824,23 +646,10 @@ static void frontend_changed(struct xenb
|
|
dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend);
|
|
}
|
|
|
|
-static void backend_changed(struct xenbus_watch *watch,
|
|
- const char **vec, unsigned int len)
|
|
-{
|
|
- DPRINTK("");
|
|
-
|
|
- dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
|
|
-}
|
|
-
|
|
/* We watch for devices appearing and vanishing. */
|
|
static struct xenbus_watch fe_watch = {
|
|
.node = "device",
|
|
.callback = frontend_changed,
|
|
-};
|
|
-
|
|
-static struct xenbus_watch be_watch = {
|
|
- .node = "backend",
|
|
- .callback = backend_changed,
|
|
};
|
|
|
|
static int suspend_dev(struct device *dev, void *data)
|
|
@@ -913,7 +722,7 @@ void xenbus_suspend(void)
|
|
DPRINTK("");
|
|
|
|
bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
|
|
- bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev);
|
|
+ xenbus_backend_suspend(suspend_dev);
|
|
xs_suspend();
|
|
}
|
|
EXPORT_SYMBOL_GPL(xenbus_suspend);
|
|
@@ -923,7 +732,7 @@ void xenbus_resume(void)
|
|
xb_init_comms();
|
|
xs_resume();
|
|
bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
|
|
- bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev);
|
|
+ xenbus_backend_resume(resume_dev);
|
|
}
|
|
EXPORT_SYMBOL_GPL(xenbus_resume);
|
|
|
|
@@ -956,13 +765,10 @@ void xenbus_probe(void *unused)
|
|
{
|
|
BUG_ON((xenstored_ready <= 0));
|
|
|
|
- /* Enumerate devices in xenstore. */
|
|
+ /* Enumerate devices in xenstore and watch for changes. */
|
|
xenbus_probe_devices(&xenbus_frontend);
|
|
- xenbus_probe_devices(&xenbus_backend);
|
|
-
|
|
- /* Watch for changes. */
|
|
register_xenbus_watch(&fe_watch);
|
|
- register_xenbus_watch(&be_watch);
|
|
+ xenbus_backend_probe_and_watch();
|
|
|
|
/* Notify others that xenstore is up */
|
|
notifier_call_chain(&xenstore_chain, 0, NULL);
|
|
@@ -1021,7 +827,7 @@ static int __init xenbus_probe_init(void
|
|
|
|
/* Register ourselves with the kernel bus subsystem */
|
|
bus_register(&xenbus_frontend.bus);
|
|
- bus_register(&xenbus_backend.bus);
|
|
+ xenbus_backend_bus_register();
|
|
|
|
/*
|
|
* Domain0 doesn't have a store_evtchn or store_mfn yet.
|
|
@@ -1092,7 +898,7 @@ static int __init xenbus_probe_init(void
|
|
|
|
/* Register ourselves with the kernel device subsystem */
|
|
device_register(&xenbus_frontend.dev);
|
|
- device_register(&xenbus_backend.dev);
|
|
+ xenbus_backend_device_register();
|
|
|
|
if (!is_initial_xendomain())
|
|
xenbus_probe(NULL);
|
|
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
|
|
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.h Wed Oct 25 13:58:30 2006 +0100
|
|
@@ -0,0 +1,77 @@
|
|
+/******************************************************************************
|
|
+ * xenbus_probe.h
|
|
+ *
|
|
+ * Talks to Xen Store to figure out what devices we have.
|
|
+ *
|
|
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
|
|
+ * Copyright (C) 2005 XenSource Ltd.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU General Public License version 2
|
|
+ * as published by the Free Software Foundation; or, when distributed
|
|
+ * separately from the Linux kernel or incorporated into other
|
|
+ * software packages, subject to the following license:
|
|
+ *
|
|
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
+ * of this source file (the "Software"), to deal in the Software without
|
|
+ * restriction, including without limitation the rights to use, copy, modify,
|
|
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
|
+ * and to permit persons to whom the Software is furnished to do so, subject to
|
|
+ * the following conditions:
|
|
+ *
|
|
+ * The above copyright notice and this permission notice shall be included in
|
|
+ * all copies or substantial portions of the Software.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
+ * IN THE SOFTWARE.
|
|
+ */
|
|
+
|
|
+#ifndef _XENBUS_PROBE_H
|
|
+#define _XENBUS_PROBE_H
|
|
+
|
|
+#ifdef CONFIG_XEN_BACKEND
|
|
+extern void xenbus_backend_suspend(int (*fn)(struct device *, void *));
|
|
+extern void xenbus_backend_resume(int (*fn)(struct device *, void *));
|
|
+extern void xenbus_backend_probe_and_watch(void);
|
|
+extern void xenbus_backend_bus_register(void);
|
|
+extern void xenbus_backend_device_register(void);
|
|
+#else
|
|
+static inline void xenbus_backend_suspend(int (*fn)(struct device *, void *)) {}
|
|
+static inline void xenbus_backend_resume(int (*fn)(struct device *, void *)) {}
|
|
+static inline void xenbus_backend_probe_and_watch(void) {}
|
|
+static inline void xenbus_backend_bus_register(void) {}
|
|
+static inline void xenbus_backend_device_register(void) {}
|
|
+#endif
|
|
+
|
|
+struct xen_bus_type
|
|
+{
|
|
+ char *root;
|
|
+ unsigned int levels;
|
|
+ int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
|
|
+ int (*probe)(const char *type, const char *dir);
|
|
+ struct bus_type bus;
|
|
+ struct device dev;
|
|
+};
|
|
+
|
|
+extern int xenbus_match(struct device *_dev, struct device_driver *_drv);
|
|
+extern int xenbus_dev_probe(struct device *_dev);
|
|
+extern int xenbus_dev_remove(struct device *_dev);
|
|
+extern int xenbus_register_driver_common(struct xenbus_driver *drv,
|
|
+ struct xen_bus_type *bus);
|
|
+extern int xenbus_probe_node(struct xen_bus_type *bus,
|
|
+ const char *type,
|
|
+ const char *nodename);
|
|
+extern int xenbus_probe_devices(struct xen_bus_type *bus);
|
|
+
|
|
+extern void dev_changed(const char *node, struct xen_bus_type *bus);
|
|
+
|
|
+/* Simplified asprintf. Probably belongs in lib */
|
|
+extern char *kasprintf(const char *fmt, ...);
|
|
+
|
|
+#endif
|
|
+
|
|
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
|
|
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe_backend.c Wed Oct 25 13:58:30 2006 +0100
|
|
@@ -0,0 +1,271 @@
|
|
+/******************************************************************************
|
|
+ * Talks to Xen Store to figure out what devices we have (backend half).
|
|
+ *
|
|
+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
|
|
+ * Copyright (C) 2005 Mike Wray, Hewlett-Packard
|
|
+ * Copyright (C) 2005, 2006 XenSource Ltd
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU General Public License version 2
|
|
+ * as published by the Free Software Foundation; or, when distributed
|
|
+ * separately from the Linux kernel or incorporated into other
|
|
+ * software packages, subject to the following license:
|
|
+ *
|
|
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
+ * of this source file (the "Software"), to deal in the Software without
|
|
+ * restriction, including without limitation the rights to use, copy, modify,
|
|
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
|
+ * and to permit persons to whom the Software is furnished to do so, subject to
|
|
+ * the following conditions:
|
|
+ *
|
|
+ * The above copyright notice and this permission notice shall be included in
|
|
+ * all copies or substantial portions of the Software.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
+ * IN THE SOFTWARE.
|
|
+ */
|
|
+
|
|
+#define DPRINTK(fmt, args...) \
|
|
+ pr_debug("xenbus_probe (%s:%d) " fmt ".\n", \
|
|
+ __FUNCTION__, __LINE__, ##args)
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/ctype.h>
|
|
+#include <linux/fcntl.h>
|
|
+#include <linux/mm.h>
|
|
+#include <linux/notifier.h>
|
|
+#include <linux/kthread.h>
|
|
+
|
|
+#include <asm/io.h>
|
|
+#include <asm/page.h>
|
|
+#include <asm/maddr.h>
|
|
+#include <asm/pgtable.h>
|
|
+#include <asm/hypervisor.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"
|
|
+#include "xenbus_probe.h"
|
|
+
|
|
+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
|
|
+#include <xen/platform-compat.h>
|
|
+#endif
|
|
+
|
|
+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);
|
|
+
|
|
+extern int read_otherend_details(struct xenbus_device *xendev,
|
|
+ char *id_node, char *path_node);
|
|
+
|
|
+static int read_frontend_details(struct xenbus_device *xendev)
|
|
+{
|
|
+ return read_otherend_details(xendev, "frontend-id", "frontend");
|
|
+}
|
|
+
|
|
+/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
|
|
+static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
|
|
+{
|
|
+ int domid, err;
|
|
+ const char *devid, *type, *frontend;
|
|
+ unsigned int typelen;
|
|
+
|
|
+ type = strchr(nodename, '/');
|
|
+ if (!type)
|
|
+ return -EINVAL;
|
|
+ type++;
|
|
+ typelen = strcspn(type, "/");
|
|
+ if (!typelen || type[typelen] != '/')
|
|
+ return -EINVAL;
|
|
+
|
|
+ devid = strrchr(nodename, '/') + 1;
|
|
+
|
|
+ err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid,
|
|
+ "frontend", NULL, &frontend,
|
|
+ NULL);
|
|
+ if (err)
|
|
+ return err;
|
|
+ if (strlen(frontend) == 0)
|
|
+ err = -ERANGE;
|
|
+ if (!err && !xenbus_exists(XBT_NIL, frontend, ""))
|
|
+ err = -ENOENT;
|
|
+ kfree(frontend);
|
|
+
|
|
+ if (err)
|
|
+ return err;
|
|
+
|
|
+ if (snprintf(bus_id, BUS_ID_SIZE,
|
|
+ "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
|
|
+ return -ENOSPC;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+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,
|
|
+ .probe = xenbus_dev_probe,
|
|
+ .remove = xenbus_dev_remove,
|
|
+// .shutdown = xenbus_dev_shutdown,
|
|
+ .uevent = xenbus_uevent_backend,
|
|
+ },
|
|
+ .dev = {
|
|
+ .bus_id = "xen-backend",
|
|
+ },
|
|
+};
|
|
+
|
|
+static int xenbus_uevent_backend(struct device *dev, char **envp,
|
|
+ int num_envp, char *buffer, int buffer_size)
|
|
+{
|
|
+ struct xenbus_device *xdev;
|
|
+ struct xenbus_driver *drv;
|
|
+ int i = 0;
|
|
+ int length = 0;
|
|
+
|
|
+ DPRINTK("");
|
|
+
|
|
+ if (dev == NULL)
|
|
+ return -ENODEV;
|
|
+
|
|
+ xdev = to_xenbus_device(dev);
|
|
+ if (xdev == NULL)
|
|
+ return -ENODEV;
|
|
+
|
|
+ /* stuff we want to pass to /sbin/hotplug */
|
|
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
|
|
+ "XENBUS_TYPE=%s", xdev->devicetype);
|
|
+
|
|
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
|
|
+ "XENBUS_PATH=%s", xdev->nodename);
|
|
+
|
|
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
|
|
+ "XENBUS_BASE_PATH=%s", xenbus_backend.root);
|
|
+
|
|
+ /* terminate, set to next free slot, shrink available space */
|
|
+ envp[i] = NULL;
|
|
+ envp = &envp[i];
|
|
+ num_envp -= i;
|
|
+ buffer = &buffer[length];
|
|
+ buffer_size -= length;
|
|
+
|
|
+ if (dev->driver) {
|
|
+ drv = to_xenbus_driver(dev->driver);
|
|
+ if (drv && drv->uevent)
|
|
+ return drv->uevent(xdev, envp, num_envp, buffer,
|
|
+ buffer_size);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int xenbus_register_backend(struct xenbus_driver *drv)
|
|
+{
|
|
+ drv->read_otherend_details = read_frontend_details;
|
|
+
|
|
+ return xenbus_register_driver_common(drv, &xenbus_backend);
|
|
+}
|
|
+EXPORT_SYMBOL_GPL(xenbus_register_backend);
|
|
+
|
|
+/* backend/<typename>/<frontend-uuid>/<name> */
|
|
+static int xenbus_probe_backend_unit(const char *dir,
|
|
+ const char *type,
|
|
+ const char *name)
|
|
+{
|
|
+ char *nodename;
|
|
+ int err;
|
|
+
|
|
+ nodename = kasprintf("%s/%s", dir, name);
|
|
+ if (!nodename)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ DPRINTK("%s\n", nodename);
|
|
+
|
|
+ err = xenbus_probe_node(&xenbus_backend, type, nodename);
|
|
+ kfree(nodename);
|
|
+ return err;
|
|
+}
|
|
+
|
|
+/* backend/<typename>/<frontend-domid> */
|
|
+static int xenbus_probe_backend(const char *type, const char *domid)
|
|
+{
|
|
+ char *nodename;
|
|
+ int err = 0;
|
|
+ char **dir;
|
|
+ unsigned int i, dir_n = 0;
|
|
+
|
|
+ DPRINTK("");
|
|
+
|
|
+ nodename = kasprintf("%s/%s/%s", xenbus_backend.root, type, domid);
|
|
+ if (!nodename)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n);
|
|
+ if (IS_ERR(dir)) {
|
|
+ kfree(nodename);
|
|
+ return PTR_ERR(dir);
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < dir_n; i++) {
|
|
+ err = xenbus_probe_backend_unit(nodename, type, dir[i]);
|
|
+ if (err)
|
|
+ break;
|
|
+ }
|
|
+ kfree(dir);
|
|
+ kfree(nodename);
|
|
+ return err;
|
|
+}
|
|
+
|
|
+static void backend_changed(struct xenbus_watch *watch,
|
|
+ const char **vec, unsigned int len)
|
|
+{
|
|
+ DPRINTK("");
|
|
+
|
|
+ dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
|
|
+}
|
|
+
|
|
+static struct xenbus_watch be_watch = {
|
|
+ .node = "backend",
|
|
+ .callback = backend_changed,
|
|
+};
|
|
+
|
|
+void xenbus_backend_suspend(int (*fn)(struct device *, void *))
|
|
+{
|
|
+ DPRINTK("");
|
|
+ bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
|
|
+}
|
|
+
|
|
+void xenbus_backend_resume(int (*fn)(struct device *, void *))
|
|
+{
|
|
+ DPRINTK("");
|
|
+ bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
|
|
+}
|
|
+
|
|
+void xenbus_backend_probe_and_watch(void)
|
|
+{
|
|
+ xenbus_probe_devices(&xenbus_backend);
|
|
+ register_xenbus_watch(&be_watch);
|
|
+}
|
|
+
|
|
+void xenbus_backend_bus_register(void)
|
|
+{
|
|
+ bus_register(&xenbus_backend.bus);
|
|
+}
|
|
+
|
|
+void xenbus_backend_device_register(void)
|
|
+{
|
|
+ device_register(&xenbus_backend.dev);
|
|
+}
|
|
|