source: trunk/packages/xen-3.1/xen-3.1/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe_backend.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 7.5 KB
Line 
1/******************************************************************************
2 * Talks to Xen Store to figure out what devices we have (backend half).
3 *
4 * Copyright (C) 2005 Rusty Russell, IBM Corporation
5 * Copyright (C) 2005 Mike Wray, Hewlett-Packard
6 * Copyright (C) 2005, 2006 XenSource Ltd
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation; or, when distributed
11 * separately from the Linux kernel or incorporated into other
12 * software packages, subject to the following license:
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this source file (the "Software"), to deal in the Software without
16 * restriction, including without limitation the rights to use, copy, modify,
17 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18 * and to permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30 * IN THE SOFTWARE.
31 */
32
33#define DPRINTK(fmt, args...)                           \
34        pr_debug("xenbus_probe (%s:%d) " fmt ".\n",     \
35                 __FUNCTION__, __LINE__, ##args)
36
37#include <linux/kernel.h>
38#include <linux/err.h>
39#include <linux/string.h>
40#include <linux/ctype.h>
41#include <linux/fcntl.h>
42#include <linux/mm.h>
43#include <linux/notifier.h>
44#include <linux/kthread.h>
45
46#include <asm/io.h>
47#include <asm/page.h>
48#include <asm/maddr.h>
49#include <asm/pgtable.h>
50#include <asm/hypervisor.h>
51#include <xen/xenbus.h>
52#include <xen/xen_proc.h>
53#include <xen/evtchn.h>
54#include <xen/features.h>
55#include <xen/hvm.h>
56
57#include "xenbus_comms.h"
58#include "xenbus_probe.h"
59
60#ifdef HAVE_XEN_PLATFORM_COMPAT_H
61#include <xen/platform-compat.h>
62#endif
63
64static int xenbus_uevent_backend(struct device *dev, char **envp,
65                                 int num_envp, char *buffer, int buffer_size);
66static int xenbus_probe_backend(const char *type, const char *domid);
67
68extern int read_otherend_details(struct xenbus_device *xendev,
69                                 char *id_node, char *path_node);
70
71static int read_frontend_details(struct xenbus_device *xendev)
72{
73        return read_otherend_details(xendev, "frontend-id", "frontend");
74}
75
76/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
77static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
78{
79        int domid, err;
80        const char *devid, *type, *frontend;
81        unsigned int typelen;
82
83        type = strchr(nodename, '/');
84        if (!type)
85                return -EINVAL;
86        type++;
87        typelen = strcspn(type, "/");
88        if (!typelen || type[typelen] != '/')
89                return -EINVAL;
90
91        devid = strrchr(nodename, '/') + 1;
92
93        err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid,
94                            "frontend", NULL, &frontend,
95                            NULL);
96        if (err)
97                return err;
98        if (strlen(frontend) == 0)
99                err = -ERANGE;
100        if (!err && !xenbus_exists(XBT_NIL, frontend, ""))
101                err = -ENOENT;
102        kfree(frontend);
103
104        if (err)
105                return err;
106
107        if (snprintf(bus_id, BUS_ID_SIZE,
108                     "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
109                return -ENOSPC;
110        return 0;
111}
112
113static struct xen_bus_type xenbus_backend = {
114        .root = "backend",
115        .levels = 3,            /* backend/type/<frontend>/<id> */
116        .get_bus_id = backend_bus_id,
117        .probe = xenbus_probe_backend,
118        .bus = {
119                .name     = "xen-backend",
120                .match    = xenbus_match,
121                .probe    = xenbus_dev_probe,
122                .remove   = xenbus_dev_remove,
123//              .shutdown = xenbus_dev_shutdown,
124                .uevent   = xenbus_uevent_backend,
125        },
126        .dev = {
127                .bus_id = "xen-backend",
128        },
129};
130
131static int xenbus_uevent_backend(struct device *dev, char **envp,
132                                 int num_envp, char *buffer, int buffer_size)
133{
134        struct xenbus_device *xdev;
135        struct xenbus_driver *drv;
136        int i = 0;
137        int length = 0;
138
139        DPRINTK("");
140
141        if (dev == NULL)
142                return -ENODEV;
143
144        xdev = to_xenbus_device(dev);
145        if (xdev == NULL)
146                return -ENODEV;
147
148        /* stuff we want to pass to /sbin/hotplug */
149        add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
150                       "XENBUS_TYPE=%s", xdev->devicetype);
151
152        add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
153                       "XENBUS_PATH=%s", xdev->nodename);
154
155        add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
156                       "XENBUS_BASE_PATH=%s", xenbus_backend.root);
157
158        /* terminate, set to next free slot, shrink available space */
159        envp[i] = NULL;
160        envp = &envp[i];
161        num_envp -= i;
162        buffer = &buffer[length];
163        buffer_size -= length;
164
165        if (dev->driver) {
166                drv = to_xenbus_driver(dev->driver);
167                if (drv && drv->uevent)
168                        return drv->uevent(xdev, envp, num_envp, buffer,
169                                           buffer_size);
170        }
171
172        return 0;
173}
174
175int xenbus_register_backend(struct xenbus_driver *drv)
176{
177        drv->read_otherend_details = read_frontend_details;
178
179        return xenbus_register_driver_common(drv, &xenbus_backend);
180}
181EXPORT_SYMBOL_GPL(xenbus_register_backend);
182
183/* backend/<typename>/<frontend-uuid>/<name> */
184static int xenbus_probe_backend_unit(const char *dir,
185                                     const char *type,
186                                     const char *name)
187{
188        char *nodename;
189        int err;
190
191        nodename = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
192        if (!nodename)
193                return -ENOMEM;
194
195        DPRINTK("%s\n", nodename);
196
197        err = xenbus_probe_node(&xenbus_backend, type, nodename);
198        kfree(nodename);
199        return err;
200}
201
202/* backend/<typename>/<frontend-domid> */
203static int xenbus_probe_backend(const char *type, const char *domid)
204{
205        char *nodename;
206        int err = 0;
207        char **dir;
208        unsigned int i, dir_n = 0;
209
210        DPRINTK("");
211
212        nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", xenbus_backend.root, type, domid);
213        if (!nodename)
214                return -ENOMEM;
215
216        dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n);
217        if (IS_ERR(dir)) {
218                kfree(nodename);
219                return PTR_ERR(dir);
220        }
221
222        for (i = 0; i < dir_n; i++) {
223                err = xenbus_probe_backend_unit(nodename, type, dir[i]);
224                if (err)
225                        break;
226        }
227        kfree(dir);
228        kfree(nodename);
229        return err;
230}
231
232static void backend_changed(struct xenbus_watch *watch,
233                            const char **vec, unsigned int len)
234{
235        DPRINTK("");
236
237        dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
238}
239
240static struct xenbus_watch be_watch = {
241        .node = "backend",
242        .callback = backend_changed,
243};
244
245void xenbus_backend_suspend(int (*fn)(struct device *, void *))
246{
247        DPRINTK("");
248        if (!xenbus_backend.error)
249                bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
250}
251
252void xenbus_backend_resume(int (*fn)(struct device *, void *))
253{
254        DPRINTK("");
255        if (!xenbus_backend.error)
256                bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
257}
258
259void xenbus_backend_probe_and_watch(void)
260{
261        xenbus_probe_devices(&xenbus_backend);
262        register_xenbus_watch(&be_watch);
263}
264
265void xenbus_backend_bus_register(void)
266{
267        xenbus_backend.error = bus_register(&xenbus_backend.bus);
268        if (xenbus_backend.error)
269                printk(KERN_WARNING
270                       "XENBUS: Error registering backend bus: %i\n",
271                       xenbus_backend.error);
272}
273
274void xenbus_backend_device_register(void)
275{
276        if (xenbus_backend.error)
277                return;
278
279        xenbus_backend.error = device_register(&xenbus_backend.dev);
280        if (xenbus_backend.error) {
281                bus_unregister(&xenbus_backend.bus);
282                printk(KERN_WARNING
283                       "XENBUS: Error registering backend device: %i\n",
284                       xenbus_backend.error);
285        }
286}
Note: See TracBrowser for help on using the repository browser.