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

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

Add xen and xen-common

File size: 7.6 KB
Line 
1/******************************************************************************
2 * Client-facing interface for the Xenbus driver.  In other words, the
3 * interface between the Xenbus and the device-specific code, be it the
4 * frontend or the backend of that driver.
5 *
6 * Copyright (C) 2005 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#include <xen/evtchn.h>
34#include <xen/gnttab.h>
35#include <xen/xenbus.h>
36#include <xen/driver_util.h>
37
38#ifdef HAVE_XEN_PLATFORM_COMPAT_H
39#include <xen/platform-compat.h>
40#endif
41
42#define DPRINTK(fmt, args...) \
43    pr_debug("xenbus_client (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
44
45const char *xenbus_strstate(enum xenbus_state state)
46{
47        static const char *const name[] = {
48                [ XenbusStateUnknown      ] = "Unknown",
49                [ XenbusStateInitialising ] = "Initialising",
50                [ XenbusStateInitWait     ] = "InitWait",
51                [ XenbusStateInitialised  ] = "Initialised",
52                [ XenbusStateConnected    ] = "Connected",
53                [ XenbusStateClosing      ] = "Closing",
54                [ XenbusStateClosed       ] = "Closed",
55        };
56        return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
57}
58EXPORT_SYMBOL_GPL(xenbus_strstate);
59
60int xenbus_watch_path(struct xenbus_device *dev, const char *path,
61                      struct xenbus_watch *watch,
62                      void (*callback)(struct xenbus_watch *,
63                                       const char **, unsigned int))
64{
65        int err;
66
67        watch->node = path;
68        watch->callback = callback;
69
70        err = register_xenbus_watch(watch);
71
72        if (err) {
73                watch->node = NULL;
74                watch->callback = NULL;
75                xenbus_dev_fatal(dev, err, "adding watch on %s", path);
76        }
77
78        return err;
79}
80EXPORT_SYMBOL_GPL(xenbus_watch_path);
81
82
83int xenbus_watch_path2(struct xenbus_device *dev, const char *path,
84                       const char *path2, struct xenbus_watch *watch,
85                       void (*callback)(struct xenbus_watch *,
86                                        const char **, unsigned int))
87{
88        int err;
89        char *state = kasprintf(GFP_KERNEL, "%s/%s", path, path2);
90        if (!state) {
91                xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch");
92                return -ENOMEM;
93        }
94        err = xenbus_watch_path(dev, state, watch, callback);
95
96        if (err)
97                kfree(state);
98        return err;
99}
100EXPORT_SYMBOL_GPL(xenbus_watch_path2);
101
102
103int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state)
104{
105        /* We check whether the state is currently set to the given value, and
106           if not, then the state is set.  We don't want to unconditionally
107           write the given state, because we don't want to fire watches
108           unnecessarily.  Furthermore, if the node has gone, we don't write
109           to it, as the device will be tearing down, and we don't want to
110           resurrect that directory.
111
112           Note that, because of this cached value of our state, this function
113           will not work inside a Xenstore transaction (something it was
114           trying to in the past) because dev->state would not get reset if
115           the transaction was aborted.
116
117         */
118
119        int current_state;
120        int err;
121
122        if (state == dev->state)
123                return 0;
124
125        err = xenbus_scanf(XBT_NIL, dev->nodename, "state", "%d",
126                           &current_state);
127        if (err != 1)
128                return 0;
129
130        err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%d", state);
131        if (err) {
132                if (state != XenbusStateClosing) /* Avoid looping */
133                        xenbus_dev_fatal(dev, err, "writing new state");
134                return err;
135        }
136
137        dev->state = state;
138
139        return 0;
140}
141EXPORT_SYMBOL_GPL(xenbus_switch_state);
142
143int xenbus_frontend_closed(struct xenbus_device *dev)
144{
145        xenbus_switch_state(dev, XenbusStateClosed);
146        complete(&dev->down);
147        return 0;
148}
149EXPORT_SYMBOL_GPL(xenbus_frontend_closed);
150
151/**
152 * Return the path to the error node for the given device, or NULL on failure.
153 * If the value returned is non-NULL, then it is the caller's to kfree.
154 */
155static char *error_path(struct xenbus_device *dev)
156{
157        return kasprintf(GFP_KERNEL, "error/%s", dev->nodename);
158}
159
160
161void _dev_error(struct xenbus_device *dev, int err, const char *fmt,
162                va_list ap)
163{
164        int ret;
165        unsigned int len;
166        char *printf_buffer = NULL, *path_buffer = NULL;
167
168#define PRINTF_BUFFER_SIZE 4096
169        printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
170        if (printf_buffer == NULL)
171                goto fail;
172
173        len = sprintf(printf_buffer, "%i ", -err);
174        ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
175
176        BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1);
177
178        dev_err(&dev->dev, "%s\n", printf_buffer);
179
180        path_buffer = error_path(dev);
181
182        if (path_buffer == NULL) {
183                printk("xenbus: failed to write error node for %s (%s)\n",
184                       dev->nodename, printf_buffer);
185                goto fail;
186        }
187
188        if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) {
189                printk("xenbus: failed to write error node for %s (%s)\n",
190                       dev->nodename, printf_buffer);
191                goto fail;
192        }
193
194fail:
195        if (printf_buffer)
196                kfree(printf_buffer);
197        if (path_buffer)
198                kfree(path_buffer);
199}
200
201
202void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt,
203                      ...)
204{
205        va_list ap;
206
207        va_start(ap, fmt);
208        _dev_error(dev, err, fmt, ap);
209        va_end(ap);
210}
211EXPORT_SYMBOL_GPL(xenbus_dev_error);
212
213
214void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt,
215                      ...)
216{
217        va_list ap;
218
219        va_start(ap, fmt);
220        _dev_error(dev, err, fmt, ap);
221        va_end(ap);
222
223        xenbus_switch_state(dev, XenbusStateClosing);
224}
225EXPORT_SYMBOL_GPL(xenbus_dev_fatal);
226
227
228int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn)
229{
230        int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0);
231        if (err < 0)
232                xenbus_dev_fatal(dev, err, "granting access to ring page");
233        return err;
234}
235EXPORT_SYMBOL_GPL(xenbus_grant_ring);
236
237
238int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
239{
240        struct evtchn_alloc_unbound alloc_unbound;
241        int err;
242
243        alloc_unbound.dom        = DOMID_SELF;
244        alloc_unbound.remote_dom = dev->otherend_id;
245
246        err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
247                                          &alloc_unbound);
248        if (err)
249                xenbus_dev_fatal(dev, err, "allocating event channel");
250        else
251                *port = alloc_unbound.port;
252
253        return err;
254}
255EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn);
256
257
258int xenbus_free_evtchn(struct xenbus_device *dev, int port)
259{
260        struct evtchn_close close;
261        int err;
262
263        close.port = port;
264
265        err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
266        if (err)
267                xenbus_dev_error(dev, err, "freeing event channel %d", port);
268
269        return err;
270}
271EXPORT_SYMBOL_GPL(xenbus_free_evtchn);
272
273
274enum xenbus_state xenbus_read_driver_state(const char *path)
275{
276        enum xenbus_state result;
277        int err = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL);
278        if (err)
279                result = XenbusStateUnknown;
280
281        return result;
282}
283EXPORT_SYMBOL_GPL(xenbus_read_driver_state);
Note: See TracBrowser for help on using the repository browser.