diff options
| -rw-r--r-- | drivers/xen/Makefile | 1 | ||||
| -rw-r--r-- | drivers/xen/xenbus/Makefile | 7 | ||||
| -rw-r--r-- | drivers/xen/xenbus/xenbus_client.c | 569 | ||||
| -rw-r--r-- | drivers/xen/xenbus/xenbus_comms.c | 233 | ||||
| -rw-r--r-- | drivers/xen/xenbus/xenbus_comms.h | 46 | ||||
| -rw-r--r-- | drivers/xen/xenbus/xenbus_probe.c | 935 | ||||
| -rw-r--r-- | drivers/xen/xenbus/xenbus_probe.h | 74 | ||||
| -rw-r--r-- | drivers/xen/xenbus/xenbus_xs.c | 861 | ||||
| -rw-r--r-- | include/asm-i386/xen/hypervisor.h | 1 | ||||
| -rw-r--r-- | include/xen/xenbus.h | 234 |
10 files changed, 2961 insertions, 0 deletions
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index eb42b521eef9..56592f0d6cef 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile | |||
| @@ -1 +1,2 @@ | |||
| 1 | obj-y += grant-table.o | 1 | obj-y += grant-table.o |
| 2 | obj-y += xenbus/ | ||
diff --git a/drivers/xen/xenbus/Makefile b/drivers/xen/xenbus/Makefile new file mode 100644 index 000000000000..5571f5b84223 --- /dev/null +++ b/drivers/xen/xenbus/Makefile | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | obj-y += xenbus.o | ||
| 2 | |||
| 3 | xenbus-objs = | ||
| 4 | xenbus-objs += xenbus_client.o | ||
| 5 | xenbus-objs += xenbus_comms.o | ||
| 6 | xenbus-objs += xenbus_xs.o | ||
| 7 | xenbus-objs += xenbus_probe.o | ||
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c new file mode 100644 index 000000000000..9fd2f70ab46d --- /dev/null +++ b/drivers/xen/xenbus/xenbus_client.c | |||
| @@ -0,0 +1,569 @@ | |||
| 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 <linux/types.h> | ||
| 34 | #include <linux/vmalloc.h> | ||
| 35 | #include <asm/xen/hypervisor.h> | ||
| 36 | #include <xen/interface/xen.h> | ||
| 37 | #include <xen/interface/event_channel.h> | ||
| 38 | #include <xen/events.h> | ||
| 39 | #include <xen/grant_table.h> | ||
| 40 | #include <xen/xenbus.h> | ||
| 41 | |||
| 42 | const char *xenbus_strstate(enum xenbus_state state) | ||
| 43 | { | ||
| 44 | static const char *const name[] = { | ||
| 45 | [ XenbusStateUnknown ] = "Unknown", | ||
| 46 | [ XenbusStateInitialising ] = "Initialising", | ||
| 47 | [ XenbusStateInitWait ] = "InitWait", | ||
| 48 | [ XenbusStateInitialised ] = "Initialised", | ||
| 49 | [ XenbusStateConnected ] = "Connected", | ||
| 50 | [ XenbusStateClosing ] = "Closing", | ||
| 51 | [ XenbusStateClosed ] = "Closed", | ||
| 52 | }; | ||
| 53 | return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID"; | ||
| 54 | } | ||
| 55 | EXPORT_SYMBOL_GPL(xenbus_strstate); | ||
| 56 | |||
| 57 | /** | ||
| 58 | * xenbus_watch_path - register a watch | ||
| 59 | * @dev: xenbus device | ||
| 60 | * @path: path to watch | ||
| 61 | * @watch: watch to register | ||
| 62 | * @callback: callback to register | ||
| 63 | * | ||
| 64 | * Register a @watch on the given path, using the given xenbus_watch structure | ||
| 65 | * for storage, and the given @callback function as the callback. Return 0 on | ||
| 66 | * success, or -errno on error. On success, the given @path will be saved as | ||
| 67 | * @watch->node, and remains the caller's to free. On error, @watch->node will | ||
| 68 | * be NULL, the device will switch to %XenbusStateClosing, and the error will | ||
| 69 | * be saved in the store. | ||
| 70 | */ | ||
| 71 | int xenbus_watch_path(struct xenbus_device *dev, const char *path, | ||
| 72 | struct xenbus_watch *watch, | ||
| 73 | void (*callback)(struct xenbus_watch *, | ||
| 74 | const char **, unsigned int)) | ||
| 75 | { | ||
| 76 | int err; | ||
| 77 | |||
| 78 | watch->node = path; | ||
| 79 | watch->callback = callback; | ||
| 80 | |||
| 81 | err = register_xenbus_watch(watch); | ||
| 82 | |||
| 83 | if (err) { | ||
| 84 | watch->node = NULL; | ||
| 85 | watch->callback = NULL; | ||
| 86 | xenbus_dev_fatal(dev, err, "adding watch on %s", path); | ||
| 87 | } | ||
| 88 | |||
| 89 | return err; | ||
| 90 | } | ||
| 91 | EXPORT_SYMBOL_GPL(xenbus_watch_path); | ||
| 92 | |||
| 93 | |||
| 94 | /** | ||
| 95 | * xenbus_watch_pathfmt - register a watch on a sprintf-formatted path | ||
| 96 | * @dev: xenbus device | ||
| 97 | * @watch: watch to register | ||
| 98 | * @callback: callback to register | ||
| 99 | * @pathfmt: format of path to watch | ||
| 100 | * | ||
| 101 | * Register a watch on the given @path, using the given xenbus_watch | ||
| 102 | * structure for storage, and the given @callback function as the callback. | ||
| 103 | * Return 0 on success, or -errno on error. On success, the watched path | ||
| 104 | * (@path/@path2) will be saved as @watch->node, and becomes the caller's to | ||
| 105 | * kfree(). On error, watch->node will be NULL, so the caller has nothing to | ||
| 106 | * free, the device will switch to %XenbusStateClosing, and the error will be | ||
| 107 | * saved in the store. | ||
| 108 | */ | ||
| 109 | int xenbus_watch_pathfmt(struct xenbus_device *dev, | ||
| 110 | struct xenbus_watch *watch, | ||
| 111 | void (*callback)(struct xenbus_watch *, | ||
| 112 | const char **, unsigned int), | ||
| 113 | const char *pathfmt, ...) | ||
| 114 | { | ||
| 115 | int err; | ||
| 116 | va_list ap; | ||
| 117 | char *path; | ||
| 118 | |||
| 119 | va_start(ap, pathfmt); | ||
| 120 | path = kvasprintf(GFP_KERNEL, pathfmt, ap); | ||
| 121 | va_end(ap); | ||
| 122 | |||
| 123 | if (!path) { | ||
| 124 | xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch"); | ||
| 125 | return -ENOMEM; | ||
| 126 | } | ||
| 127 | err = xenbus_watch_path(dev, path, watch, callback); | ||
| 128 | |||
| 129 | if (err) | ||
| 130 | kfree(path); | ||
| 131 | return err; | ||
| 132 | } | ||
| 133 | EXPORT_SYMBOL_GPL(xenbus_watch_pathfmt); | ||
| 134 | |||
| 135 | |||
| 136 | /** | ||
| 137 | * xenbus_switch_state | ||
| 138 | * @dev: xenbus device | ||
| 139 | * @xbt: transaction handle | ||
| 140 | * @state: new state | ||
| 141 | * | ||
| 142 | * Advertise in the store a change of the given driver to the given new_state. | ||
| 143 | * Return 0 on success, or -errno on error. On error, the device will switch | ||
| 144 | * to XenbusStateClosing, and the error will be saved in the store. | ||
| 145 | */ | ||
| 146 | int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state state) | ||
| 147 | { | ||
| 148 | /* We check whether the state is currently set to the given value, and | ||
| 149 | if not, then the state is set. We don't want to unconditionally | ||
| 150 | write the given state, because we don't want to fire watches | ||
| 151 | unnecessarily. Furthermore, if the node has gone, we don't write | ||
| 152 | to it, as the device will be tearing down, and we don't want to | ||
| 153 | resurrect that directory. | ||
| 154 | |||
| 155 | Note that, because of this cached value of our state, this function | ||
| 156 | will not work inside a Xenstore transaction (something it was | ||
| 157 | trying to in the past) because dev->state would not get reset if | ||
| 158 | the transaction was aborted. | ||
| 159 | |||
| 160 | */ | ||
| 161 | |||
| 162 | int current_state; | ||
| 163 | int err; | ||
| 164 | |||
| 165 | if (state == dev->state) | ||
| 166 | return 0; | ||
| 167 | |||
| 168 | err = xenbus_scanf(XBT_NIL, dev->nodename, "state", "%d", | ||
| 169 | ¤t_state); | ||
| 170 | if (err != 1) | ||
| 171 | return 0; | ||
| 172 | |||
| 173 | err = xenbus_printf(XBT_NIL, dev->nodename, "state", "%d", state); | ||
| 174 | if (err) { | ||
| 175 | if (state != XenbusStateClosing) /* Avoid looping */ | ||
| 176 | xenbus_dev_fatal(dev, err, "writing new state"); | ||
| 177 | return err; | ||
| 178 | } | ||
| 179 | |||
| 180 | dev->state = state; | ||
| 181 | |||
| 182 | return 0; | ||
| 183 | } | ||
| 184 | EXPORT_SYMBOL_GPL(xenbus_switch_state); | ||
| 185 | |||
| 186 | int xenbus_frontend_closed(struct xenbus_device *dev) | ||
| 187 | { | ||
| 188 | xenbus_switch_state(dev, XenbusStateClosed); | ||
| 189 | complete(&dev->down); | ||
| 190 | return 0; | ||
| 191 | } | ||
| 192 | EXPORT_SYMBOL_GPL(xenbus_frontend_closed); | ||
| 193 | |||
| 194 | /** | ||
| 195 | * Return the path to the error node for the given device, or NULL on failure. | ||
| 196 | * If the value returned is non-NULL, then it is the caller's to kfree. | ||
| 197 | */ | ||
| 198 | static char *error_path(struct xenbus_device *dev) | ||
| 199 | { | ||
| 200 | return kasprintf(GFP_KERNEL, "error/%s", dev->nodename); | ||
| 201 | } | ||
| 202 | |||
| 203 | |||
| 204 | static void xenbus_va_dev_error(struct xenbus_device *dev, int err, | ||
| 205 | const char *fmt, va_list ap) | ||
| 206 | { | ||
| 207 | int ret; | ||
| 208 | unsigned int len; | ||
| 209 | char *printf_buffer = NULL; | ||
| 210 | char *path_buffer = NULL; | ||
| 211 | |||
| 212 | #define PRINTF_BUFFER_SIZE 4096 | ||
| 213 | printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); | ||
| 214 | if (printf_buffer == NULL) | ||
| 215 | goto fail; | ||
| 216 | |||
| 217 | len = sprintf(printf_buffer, "%i ", -err); | ||
| 218 | ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap); | ||
| 219 | |||
| 220 | BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1); | ||
| 221 | |||
| 222 | dev_err(&dev->dev, "%s\n", printf_buffer); | ||
| 223 | |||
| 224 | path_buffer = error_path(dev); | ||
| 225 | |||
| 226 | if (path_buffer == NULL) { | ||
| 227 | dev_err(&dev->dev, "failed to write error node for %s (%s)\n", | ||
| 228 | dev->nodename, printf_buffer); | ||
| 229 | goto fail; | ||
| 230 | } | ||
| 231 | |||
| 232 | if (xenbus_write(XBT_NIL, path_buffer, "error", printf_buffer) != 0) { | ||
| 233 | dev_err(&dev->dev, "failed to write error node for %s (%s)\n", | ||
| 234 | dev->nodename, printf_buffer); | ||
| 235 | goto fail; | ||
| 236 | } | ||
| 237 | |||
| 238 | fail: | ||
| 239 | kfree(printf_buffer); | ||
| 240 | kfree(path_buffer); | ||
| 241 | } | ||
| 242 | |||
| 243 | |||
| 244 | /** | ||
| 245 | * xenbus_dev_error | ||
| 246 | * @dev: xenbus device | ||
| 247 | * @err: error to report | ||
| 248 | * @fmt: error message format | ||
| 249 | * | ||
| 250 | * Report the given negative errno into the store, along with the given | ||
| 251 | * formatted message. | ||
| 252 | */ | ||
| 253 | void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...) | ||
| 254 | { | ||
| 255 | va_list ap; | ||
| 256 | |||
| 257 | va_start(ap, fmt); | ||
| 258 | xenbus_va_dev_error(dev, err, fmt, ap); | ||
| 259 | va_end(ap); | ||
| 260 | } | ||
| 261 | EXPORT_SYMBOL_GPL(xenbus_dev_error); | ||
| 262 | |||
| 263 | /** | ||
| 264 | * xenbus_dev_fatal | ||
| 265 | * @dev: xenbus device | ||
| 266 | * @err: error to report | ||
| 267 | * @fmt: error message format | ||
| 268 | * | ||
| 269 | * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by | ||
| 270 | * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly | ||
| 271 | * closedown of this driver and its peer. | ||
| 272 | */ | ||
| 273 | |||
| 274 | void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...) | ||
| 275 | { | ||
| 276 | va_list ap; | ||
| 277 | |||
| 278 | va_start(ap, fmt); | ||
| 279 | xenbus_va_dev_error(dev, err, fmt, ap); | ||
| 280 | va_end(ap); | ||
| 281 | |||
| 282 | xenbus_switch_state(dev, XenbusStateClosing); | ||
| 283 | } | ||
| 284 | EXPORT_SYMBOL_GPL(xenbus_dev_fatal); | ||
| 285 | |||
| 286 | /** | ||
| 287 | * xenbus_grant_ring | ||
| 288 | * @dev: xenbus device | ||
| 289 | * @ring_mfn: mfn of ring to grant | ||
| 290 | |||
| 291 | * Grant access to the given @ring_mfn to the peer of the given device. Return | ||
| 292 | * 0 on success, or -errno on error. On error, the device will switch to | ||
| 293 | * XenbusStateClosing, and the error will be saved in the store. | ||
| 294 | */ | ||
| 295 | int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn) | ||
| 296 | { | ||
| 297 | int err = gnttab_grant_foreign_access(dev->otherend_id, ring_mfn, 0); | ||
| 298 | if (err < 0) | ||
| 299 | xenbus_dev_fatal(dev, err, "granting access to ring page"); | ||
| 300 | return err; | ||
| 301 | } | ||
| 302 | EXPORT_SYMBOL_GPL(xenbus_grant_ring); | ||
| 303 | |||
| 304 | |||
| 305 | /** | ||
| 306 | * Allocate an event channel for the given xenbus_device, assigning the newly | ||
| 307 | * created local port to *port. Return 0 on success, or -errno on error. On | ||
| 308 | * error, the device will switch to XenbusStateClosing, and the error will be | ||
| 309 | * saved in the store. | ||
| 310 | */ | ||
| 311 | int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port) | ||
| 312 | { | ||
| 313 | struct evtchn_alloc_unbound alloc_unbound; | ||
| 314 | int err; | ||
| 315 | |||
| 316 | alloc_unbound.dom = DOMID_SELF; | ||
| 317 | alloc_unbound.remote_dom = dev->otherend_id; | ||
| 318 | |||
| 319 | err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, | ||
| 320 | &alloc_unbound); | ||
| 321 | if (err) | ||
| 322 | xenbus_dev_fatal(dev, err, "allocating event channel"); | ||
| 323 | else | ||
| 324 | *port = alloc_unbound.port; | ||
| 325 | |||
| 326 | return err; | ||
| 327 | } | ||
| 328 | EXPORT_SYMBOL_GPL(xenbus_alloc_evtchn); | ||
| 329 | |||
| 330 | |||
| 331 | /** | ||
| 332 | * Bind to an existing interdomain event channel in another domain. Returns 0 | ||
| 333 | * on success and stores the local port in *port. On error, returns -errno, | ||
| 334 | * switches the device to XenbusStateClosing, and saves the error in XenStore. | ||
| 335 | */ | ||
| 336 | int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port) | ||
| 337 | { | ||
| 338 | struct evtchn_bind_interdomain bind_interdomain; | ||
| 339 | int err; | ||
| 340 | |||
| 341 | bind_interdomain.remote_dom = dev->otherend_id; | ||
| 342 | bind_interdomain.remote_port = remote_port; | ||
| 343 | |||
| 344 | err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, | ||
| 345 | &bind_interdomain); | ||
| 346 | if (err) | ||
| 347 | xenbus_dev_fatal(dev, err, | ||
| 348 | "binding to event channel %d from domain %d", | ||
| 349 | remote_port, dev->otherend_id); | ||
| 350 | else | ||
| 351 | *port = bind_interdomain.local_port; | ||
| 352 | |||
| 353 | return err; | ||
| 354 | } | ||
| 355 | EXPORT_SYMBOL_GPL(xenbus_bind_evtchn); | ||
| 356 | |||
| 357 | |||
| 358 | /** | ||
| 359 | * Free an existing event channel. Returns 0 on success or -errno on error. | ||
| 360 | */ | ||
| 361 | int xenbus_free_evtchn(struct xenbus_device *dev, int port) | ||
| 362 | { | ||
| 363 | struct evtchn_close close; | ||
| 364 | int err; | ||
| 365 | |||
| 366 | close.port = port; | ||
| 367 | |||
| 368 | err = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); | ||
| 369 | if (err) | ||
| 370 | xenbus_dev_error(dev, err, "freeing event channel %d", port); | ||
| 371 | |||
| 372 | return err; | ||
| 373 | } | ||
| 374 | EXPORT_SYMBOL_GPL(xenbus_free_evtchn); | ||
| 375 | |||
| 376 | |||
| 377 | /** | ||
| 378 | * xenbus_map_ring_valloc | ||
| 379 | * @dev: xenbus device | ||
| 380 | * @gnt_ref: grant reference | ||
| 381 | * @vaddr: pointer to address to be filled out by mapping | ||
| 382 | * | ||
| 383 | * Based on Rusty Russell's skeleton driver's map_page. | ||
| 384 | * Map a page of memory into this domain from another domain's grant table. | ||
| 385 | * xenbus_map_ring_valloc allocates a page of virtual address space, maps the | ||
| 386 | * page to that address, and sets *vaddr to that address. | ||
| 387 | * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) | ||
| 388 | * or -ENOMEM on error. If an error is returned, device will switch to | ||
| 389 | * XenbusStateClosing and the error message will be saved in XenStore. | ||
| 390 | */ | ||
| 391 | int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) | ||
| 392 | { | ||
| 393 | struct gnttab_map_grant_ref op = { | ||
| 394 | .flags = GNTMAP_host_map, | ||
| 395 | .ref = gnt_ref, | ||
| 396 | .dom = dev->otherend_id, | ||
| 397 | }; | ||
| 398 | struct vm_struct *area; | ||
| 399 | |||
| 400 | *vaddr = NULL; | ||
| 401 | |||
| 402 | area = alloc_vm_area(PAGE_SIZE); | ||
| 403 | if (!area) | ||
| 404 | return -ENOMEM; | ||
| 405 | |||
| 406 | op.host_addr = (unsigned long)area->addr; | ||
| 407 | |||
| 408 | if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) | ||
| 409 | BUG(); | ||
| 410 | |||
| 411 | if (op.status != GNTST_okay) { | ||
| 412 | free_vm_area(area); | ||
| 413 | xenbus_dev_fatal(dev, op.status, | ||
| 414 | "mapping in shared page %d from domain %d", | ||
| 415 | gnt_ref, dev->otherend_id); | ||
| 416 | return op.status; | ||
| 417 | } | ||
| 418 | |||
| 419 | /* Stuff the handle in an unused field */ | ||
| 420 | area->phys_addr = (unsigned long)op.handle; | ||
| 421 | |||
| 422 | *vaddr = area->addr; | ||
| 423 | return 0; | ||
| 424 | } | ||
| 425 | EXPORT_SYMBOL_GPL(xenbus_map_ring_valloc); | ||
| 426 | |||
| 427 | |||
| 428 | /** | ||
| 429 | * xenbus_map_ring | ||
| 430 | * @dev: xenbus device | ||
| 431 | * @gnt_ref: grant reference | ||
| 432 | * @handle: pointer to grant handle to be filled | ||
| 433 | * @vaddr: address to be mapped to | ||
| 434 | * | ||
| 435 | * Map a page of memory into this domain from another domain's grant table. | ||
| 436 | * xenbus_map_ring does not allocate the virtual address space (you must do | ||
| 437 | * this yourself!). It only maps in the page to the specified address. | ||
| 438 | * Returns 0 on success, and GNTST_* (see xen/include/interface/grant_table.h) | ||
| 439 | * or -ENOMEM on error. If an error is returned, device will switch to | ||
| 440 | * XenbusStateClosing and the error message will be saved in XenStore. | ||
| 441 | */ | ||
| 442 | int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref, | ||
| 443 | grant_handle_t *handle, void *vaddr) | ||
| 444 | { | ||
| 445 | struct gnttab_map_grant_ref op = { | ||
| 446 | .host_addr = (unsigned long)vaddr, | ||
| 447 | .flags = GNTMAP_host_map, | ||
| 448 | .ref = gnt_ref, | ||
| 449 | .dom = dev->otherend_id, | ||
| 450 | }; | ||
| 451 | |||
| 452 | if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) | ||
| 453 | BUG(); | ||
| 454 | |||
| 455 | if (op.status != GNTST_okay) { | ||
| 456 | xenbus_dev_fatal(dev, op.status, | ||
| 457 | "mapping in shared page %d from domain %d", | ||
| 458 | gnt_ref, dev->otherend_id); | ||
| 459 | } else | ||
| 460 | *handle = op.handle; | ||
| 461 | |||
| 462 | return op.status; | ||
| 463 | } | ||
| 464 | EXPORT_SYMBOL_GPL(xenbus_map_ring); | ||
| 465 | |||
| 466 | |||
| 467 | /** | ||
| 468 | * xenbus_unmap_ring_vfree | ||
| 469 | * @dev: xenbus device | ||
| 470 | * @vaddr: addr to unmap | ||
| 471 | * | ||
| 472 | * Based on Rusty Russell's skeleton driver's unmap_page. | ||
| 473 | * Unmap a page of memory in this domain that was imported from another domain. | ||
| 474 | * Use xenbus_unmap_ring_vfree if you mapped in your memory with | ||
| 475 | * xenbus_map_ring_valloc (it will free the virtual address space). | ||
| 476 | * Returns 0 on success and returns GNTST_* on error | ||
| 477 | * (see xen/include/interface/grant_table.h). | ||
| 478 | */ | ||
| 479 | int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) | ||
| 480 | { | ||
| 481 | struct vm_struct *area; | ||
| 482 | struct gnttab_unmap_grant_ref op = { | ||
| 483 | .host_addr = (unsigned long)vaddr, | ||
| 484 | }; | ||
| 485 | |||
| 486 | /* It'd be nice if linux/vmalloc.h provided a find_vm_area(void *addr) | ||
| 487 | * method so that we don't have to muck with vmalloc internals here. | ||
| 488 | * We could force the user to hang on to their struct vm_struct from | ||
| 489 | * xenbus_map_ring_valloc, but these 6 lines considerably simplify | ||
| 490 | * this API. | ||
| 491 | */ | ||
| 492 | read_lock(&vmlist_lock); | ||
| 493 | for (area = vmlist; area != NULL; area = area->next) { | ||
| 494 | if (area->addr == vaddr) | ||
| 495 | break; | ||
| 496 | } | ||
| 497 | read_unlock(&vmlist_lock); | ||
| 498 | |||
| 499 | if (!area) { | ||
| 500 | xenbus_dev_error(dev, -ENOENT, | ||
| 501 | "can't find mapped virtual address %p", vaddr); | ||
| 502 | return GNTST_bad_virt_addr; | ||
| 503 | } | ||
| 504 | |||
| 505 | op.handle = (grant_handle_t)area->phys_addr; | ||
| 506 | |||
| 507 | if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) | ||
| 508 | BUG(); | ||
| 509 | |||
| 510 | if (op.status == GNTST_okay) | ||
| 511 | free_vm_area(area); | ||
| 512 | else | ||
| 513 | xenbus_dev_error(dev, op.status, | ||
| 514 | "unmapping page at handle %d error %d", | ||
| 515 | (int16_t)area->phys_addr, op.status); | ||
| 516 | |||
| 517 | return op.status; | ||
| 518 | } | ||
| 519 | EXPORT_SYMBOL_GPL(xenbus_unmap_ring_vfree); | ||
| 520 | |||
| 521 | |||
| 522 | /** | ||
| 523 | * xenbus_unmap_ring | ||
| 524 | * @dev: xenbus device | ||
| 525 | * @handle: grant handle | ||
| 526 | * @vaddr: addr to unmap | ||
| 527 | * | ||
| 528 | * Unmap a page of memory in this domain that was imported from another domain. | ||
| 529 | * Returns 0 on success and returns GNTST_* on error | ||
| 530 | * (see xen/include/interface/grant_table.h). | ||
| 531 | */ | ||
| 532 | int xenbus_unmap_ring(struct xenbus_device *dev, | ||
| 533 | grant_handle_t handle, void *vaddr) | ||
| 534 | { | ||
| 535 | struct gnttab_unmap_grant_ref op = { | ||
| 536 | .host_addr = (unsigned long)vaddr, | ||
| 537 | .handle = handle, | ||
| 538 | }; | ||
| 539 | |||
| 540 | if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) | ||
| 541 | BUG(); | ||
| 542 | |||
| 543 | if (op.status != GNTST_okay) | ||
| 544 | xenbus_dev_error(dev, op.status, | ||
| 545 | "unmapping page at handle %d error %d", | ||
| 546 | handle, op.status); | ||
| 547 | |||
| 548 | return op.status; | ||
| 549 | } | ||
| 550 | EXPORT_SYMBOL_GPL(xenbus_unmap_ring); | ||
| 551 | |||
| 552 | |||
| 553 | /** | ||
| 554 | * xenbus_read_driver_state | ||
| 555 | * @path: path for driver | ||
| 556 | * | ||
| 557 | * Return the state of the driver rooted at the given store path, or | ||
| 558 | * XenbusStateUnknown if no state can be read. | ||
| 559 | */ | ||
| 560 | enum xenbus_state xenbus_read_driver_state(const char *path) | ||
| 561 | { | ||
| 562 | enum xenbus_state result; | ||
| 563 | int err = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL); | ||
| 564 | if (err) | ||
| 565 | result = XenbusStateUnknown; | ||
| 566 | |||
| 567 | return result; | ||
| 568 | } | ||
| 569 | EXPORT_SYMBOL_GPL(xenbus_read_driver_state); | ||
diff --git a/drivers/xen/xenbus/xenbus_comms.c b/drivers/xen/xenbus/xenbus_comms.c new file mode 100644 index 000000000000..6efbe3f29ca5 --- /dev/null +++ b/drivers/xen/xenbus/xenbus_comms.c | |||
| @@ -0,0 +1,233 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | * xenbus_comms.c | ||
| 3 | * | ||
| 4 | * Low level code to talks to Xen Store: ringbuffer and event channel. | ||
| 5 | * | ||
| 6 | * Copyright (C) 2005 Rusty Russell, IBM Corporation | ||
| 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 <linux/wait.h> | ||
| 34 | #include <linux/interrupt.h> | ||
| 35 | #include <linux/sched.h> | ||
| 36 | #include <linux/err.h> | ||
| 37 | #include <xen/xenbus.h> | ||
| 38 | #include <asm/xen/hypervisor.h> | ||
| 39 | #include <xen/events.h> | ||
| 40 | #include <xen/page.h> | ||
| 41 | #include "xenbus_comms.h" | ||
| 42 | |||
| 43 | static int xenbus_irq; | ||
| 44 | |||
| 45 | static DECLARE_WORK(probe_work, xenbus_probe); | ||
| 46 | |||
| 47 | static DECLARE_WAIT_QUEUE_HEAD(xb_waitq); | ||
| 48 | |||
| 49 | static irqreturn_t wake_waiting(int irq, void *unused) | ||
| 50 | { | ||
| 51 | if (unlikely(xenstored_ready == 0)) { | ||
| 52 | xenstored_ready = 1; | ||
| 53 | schedule_work(&probe_work); | ||
| 54 | } | ||
| 55 | |||
| 56 | wake_up(&xb_waitq); | ||
| 57 | return IRQ_HANDLED; | ||
| 58 | } | ||
| 59 | |||
| 60 | static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod) | ||
| 61 | { | ||
| 62 | return ((prod - cons) <= XENSTORE_RING_SIZE); | ||
| 63 | } | ||
| 64 | |||
| 65 | static void *get_output_chunk(XENSTORE_RING_IDX cons, | ||
| 66 | XENSTORE_RING_IDX prod, | ||
| 67 | char *buf, uint32_t *len) | ||
| 68 | { | ||
| 69 | *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod); | ||
| 70 | if ((XENSTORE_RING_SIZE - (prod - cons)) < *len) | ||
| 71 | *len = XENSTORE_RING_SIZE - (prod - cons); | ||
| 72 | return buf + MASK_XENSTORE_IDX(prod); | ||
| 73 | } | ||
| 74 | |||
| 75 | static const void *get_input_chunk(XENSTORE_RING_IDX cons, | ||
| 76 | XENSTORE_RING_IDX prod, | ||
| 77 | const char *buf, uint32_t *len) | ||
| 78 | { | ||
| 79 | *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons); | ||
| 80 | if ((prod - cons) < *len) | ||
| 81 | *len = prod - cons; | ||
| 82 | return buf + MASK_XENSTORE_IDX(cons); | ||
| 83 | } | ||
| 84 | |||
| 85 | /** | ||
| 86 | * xb_write - low level write | ||
| 87 | * @data: buffer to send | ||
| 88 | * @len: length of buffer | ||
| 89 | * | ||
| 90 | * Returns 0 on success, error otherwise. | ||
| 91 | */ | ||
| 92 | int xb_write(const void *data, unsigned len) | ||
| 93 | { | ||
| 94 | struct xenstore_domain_interface *intf = xen_store_interface; | ||
| 95 | XENSTORE_RING_IDX cons, prod; | ||
| 96 | int rc; | ||
| 97 | |||
| 98 | while (len != 0) { | ||
| 99 | void *dst; | ||
| 100 | unsigned int avail; | ||
| 101 | |||
| 102 | rc = wait_event_interruptible( | ||
| 103 | xb_waitq, | ||
| 104 | (intf->req_prod - intf->req_cons) != | ||
| 105 | XENSTORE_RING_SIZE); | ||
| 106 | if (rc < 0) | ||
| 107 | return rc; | ||
| 108 | |||
| 109 | /* Read indexes, then verify. */ | ||
| 110 | cons = intf->req_cons; | ||
| 111 | prod = intf->req_prod; | ||
| 112 | if (!check_indexes(cons, prod)) { | ||
| 113 | intf->req_cons = intf->req_prod = 0; | ||
| 114 | return -EIO; | ||
| 115 | } | ||
| 116 | |||
| 117 | dst = get_output_chunk(cons, prod, intf->req, &avail); | ||
| 118 | if (avail == 0) | ||
| 119 | continue; | ||
| 120 | if (avail > len) | ||
| 121 | avail = len; | ||
| 122 | |||
| 123 | /* Must write data /after/ reading the consumer index. */ | ||
| 124 | mb(); | ||
| 125 | |||
| 126 | memcpy(dst, data, avail); | ||
| 127 | data += avail; | ||
| 128 | len -= avail; | ||
| 129 | |||
| 130 | /* Other side must not see new producer until data is there. */ | ||
| 131 | wmb(); | ||
| 132 | intf->req_prod += avail; | ||
| 133 | |||
| 134 | /* Implies mb(): other side will see the updated producer. */ | ||
| 135 | notify_remote_via_evtchn(xen_store_evtchn); | ||
| 136 | } | ||
| 137 | |||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | int xb_data_to_read(void) | ||
| 142 | { | ||
| 143 | struct xenstore_domain_interface *intf = xen_store_interface; | ||
| 144 | return (intf->rsp_cons != intf->rsp_prod); | ||
| 145 | } | ||
| 146 | |||
| 147 | int xb_wait_for_data_to_read(void) | ||
| 148 | { | ||
| 149 | return wait_event_interruptible(xb_waitq, xb_data_to_read()); | ||
| 150 | } | ||
| 151 | |||
| 152 | int xb_read(void *data, unsigned len) | ||
| 153 | { | ||
| 154 | struct xenstore_domain_interface *intf = xen_store_interface; | ||
| 155 | XENSTORE_RING_IDX cons, prod; | ||
| 156 | int rc; | ||
| 157 | |||
| 158 | while (len != 0) { | ||
| 159 | unsigned int avail; | ||
| 160 | const char *src; | ||
| 161 | |||
| 162 | rc = xb_wait_for_data_to_read(); | ||
| 163 | if (rc < 0) | ||
| 164 | return rc; | ||
| 165 | |||
| 166 | /* Read indexes, then verify. */ | ||
| 167 | cons = intf->rsp_cons; | ||
| 168 | prod = intf->rsp_prod; | ||
| 169 | if (!check_indexes(cons, prod)) { | ||
| 170 | intf->rsp_cons = intf->rsp_prod = 0; | ||
| 171 | return -EIO; | ||
| 172 | } | ||
| 173 | |||
| 174 | src = get_input_chunk(cons, prod, intf->rsp, &avail); | ||
| 175 | if (avail == 0) | ||
| 176 | continue; | ||
| 177 | if (avail > len) | ||
| 178 | avail = len; | ||
| 179 | |||
| 180 | /* Must read data /after/ reading the producer index. */ | ||
| 181 | rmb(); | ||
| 182 | |||
| 183 | memcpy(data, src, avail); | ||
| 184 | data += avail; | ||
| 185 | len -= avail; | ||
| 186 | |||
| 187 | /* Other side must not see free space until we've copied out */ | ||
| 188 | mb(); | ||
| 189 | intf->rsp_cons += avail; | ||
| 190 | |||
| 191 | pr_debug("Finished read of %i bytes (%i to go)\n", avail, len); | ||
| 192 | |||
| 193 | /* Implies mb(): other side will see the updated consumer. */ | ||
| 194 | notify_remote_via_evtchn(xen_store_evtchn); | ||
| 195 | } | ||
| 196 | |||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | /** | ||
| 201 | * xb_init_comms - Set up interrupt handler off store event channel. | ||
| 202 | */ | ||
| 203 | int xb_init_comms(void) | ||
| 204 | { | ||
| 205 | struct xenstore_domain_interface *intf = xen_store_interface; | ||
| 206 | int err; | ||
| 207 | |||
| 208 | if (intf->req_prod != intf->req_cons) | ||
| 209 | printk(KERN_ERR "XENBUS request ring is not quiescent " | ||
| 210 | "(%08x:%08x)!\n", intf->req_cons, intf->req_prod); | ||
| 211 | |||
| 212 | if (intf->rsp_prod != intf->rsp_cons) { | ||
| 213 | printk(KERN_WARNING "XENBUS response ring is not quiescent " | ||
| 214 | "(%08x:%08x): fixing up\n", | ||
| 215 | intf->rsp_cons, intf->rsp_prod); | ||
| 216 | intf->rsp_cons = intf->rsp_prod; | ||
| 217 | } | ||
| 218 | |||
| 219 | if (xenbus_irq) | ||
| 220 | unbind_from_irqhandler(xenbus_irq, &xb_waitq); | ||
| 221 | |||
| 222 | err = bind_evtchn_to_irqhandler( | ||
| 223 | xen_store_evtchn, wake_waiting, | ||
| 224 | 0, "xenbus", &xb_waitq); | ||
| 225 | if (err <= 0) { | ||
| 226 | printk(KERN_ERR "XENBUS request irq failed %i\n", err); | ||
| 227 | return err; | ||
| 228 | } | ||
| 229 | |||
| 230 | xenbus_irq = err; | ||
| 231 | |||
| 232 | return 0; | ||
| 233 | } | ||
diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h new file mode 100644 index 000000000000..c21db7513736 --- /dev/null +++ b/drivers/xen/xenbus/xenbus_comms.h | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | /* | ||
| 2 | * Private include for xenbus communications. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2005 Rusty Russell, IBM Corporation | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License version 2 | ||
| 8 | * as published by the Free Software Foundation; or, when distributed | ||
| 9 | * separately from the Linux kernel or incorporated into other | ||
| 10 | * software packages, subject to the following license: | ||
| 11 | * | ||
| 12 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 13 | * of this source file (the "Software"), to deal in the Software without | ||
| 14 | * restriction, including without limitation the rights to use, copy, modify, | ||
| 15 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, | ||
| 16 | * and to permit persons to whom the Software is furnished to do so, subject to | ||
| 17 | * the following conditions: | ||
| 18 | * | ||
| 19 | * The above copyright notice and this permission notice shall be included in | ||
| 20 | * all copies or substantial portions of the Software. | ||
| 21 | * | ||
| 22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 23 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 24 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 25 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 26 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 27 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
| 28 | * IN THE SOFTWARE. | ||
| 29 | */ | ||
| 30 | |||
| 31 | #ifndef _XENBUS_COMMS_H | ||
| 32 | #define _XENBUS_COMMS_H | ||
| 33 | |||
| 34 | int xs_init(void); | ||
| 35 | int xb_init_comms(void); | ||
| 36 | |||
| 37 | /* Low level routines. */ | ||
| 38 | int xb_write(const void *data, unsigned len); | ||
| 39 | int xb_read(void *data, unsigned len); | ||
| 40 | int xb_data_to_read(void); | ||
| 41 | int xb_wait_for_data_to_read(void); | ||
| 42 | int xs_input_avail(void); | ||
| 43 | extern struct xenstore_domain_interface *xen_store_interface; | ||
| 44 | extern int xen_store_evtchn; | ||
| 45 | |||
| 46 | #endif /* _XENBUS_COMMS_H */ | ||
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c new file mode 100644 index 000000000000..0b769f7c4a48 --- /dev/null +++ b/drivers/xen/xenbus/xenbus_probe.c | |||
| @@ -0,0 +1,935 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | * Talks to Xen Store to figure out what devices we have. | ||
| 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 | __func__, __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 | #include <linux/mutex.h> | ||
| 46 | #include <linux/io.h> | ||
| 47 | |||
| 48 | #include <asm/page.h> | ||
| 49 | #include <asm/pgtable.h> | ||
| 50 | #include <asm/xen/hypervisor.h> | ||
| 51 | #include <xen/xenbus.h> | ||
| 52 | #include <xen/events.h> | ||
| 53 | #include <xen/page.h> | ||
| 54 | |||
| 55 | #include "xenbus_comms.h" | ||
| 56 | #include "xenbus_probe.h" | ||
| 57 | |||
| 58 | int xen_store_evtchn; | ||
| 59 | struct xenstore_domain_interface *xen_store_interface; | ||
| 60 | static unsigned long xen_store_mfn; | ||
| 61 | |||
| 62 | static BLOCKING_NOTIFIER_HEAD(xenstore_chain); | ||
| 63 | |||
| 64 | static void wait_for_devices(struct xenbus_driver *xendrv); | ||
| 65 | |||
| 66 | static int xenbus_probe_frontend(const char *type, const char *name); | ||
| 67 | |||
| 68 | static void xenbus_dev_shutdown(struct device *_dev); | ||
| 69 | |||
| 70 | /* If something in array of ids matches this device, return it. */ | ||
| 71 | static const struct xenbus_device_id * | ||
| 72 | match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev) | ||
| 73 | { | ||
| 74 | for (; *arr->devicetype != '\0'; arr++) { | ||
| 75 | if (!strcmp(arr->devicetype, dev->devicetype)) | ||
| 76 | return arr; | ||
| 77 | } | ||
| 78 | return NULL; | ||
| 79 | } | ||
| 80 | |||
| 81 | int xenbus_match(struct device *_dev, struct device_driver *_drv) | ||
| 82 | { | ||
| 83 | struct xenbus_driver *drv = to_xenbus_driver(_drv); | ||
| 84 | |||
| 85 | if (!drv->ids) | ||
| 86 | return 0; | ||
| 87 | |||
| 88 | return match_device(drv->ids, to_xenbus_device(_dev)) != NULL; | ||
| 89 | } | ||
| 90 | |||
| 91 | /* device/<type>/<id> => <type>-<id> */ | ||
| 92 | static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) | ||
| 93 | { | ||
| 94 | nodename = strchr(nodename, '/'); | ||
| 95 | if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) { | ||
| 96 | printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename); | ||
| 97 | return -EINVAL; | ||
| 98 | } | ||
| 99 | |||
| 100 | strlcpy(bus_id, nodename + 1, BUS_ID_SIZE); | ||
| 101 | if (!strchr(bus_id, '/')) { | ||
| 102 | printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id); | ||
| 103 | return -EINVAL; | ||
| 104 | } | ||
| 105 | *strchr(bus_id, '/') = '-'; | ||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | |||
| 109 | |||
| 110 | static void free_otherend_details(struct xenbus_device *dev) | ||
| 111 | { | ||
| 112 | kfree(dev->otherend); | ||
| 113 | dev->otherend = NULL; | ||
| 114 | } | ||
| 115 | |||
| 116 | |||
| 117 | static void free_otherend_watch(struct xenbus_device *dev) | ||
| 118 | { | ||
| 119 | if (dev->otherend_watch.node) { | ||
| 120 | unregister_xenbus_watch(&dev->otherend_watch); | ||
| 121 | kfree(dev->otherend_watch.node); | ||
| 122 | dev->otherend_watch.node = NULL; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | |||
| 126 | |||
| 127 | int read_otherend_details(struct xenbus_device *xendev, | ||
| 128 | char *id_node, char *path_node) | ||
| 129 | { | ||
| 130 | int err = xenbus_gather(XBT_NIL, xendev->nodename, | ||
| 131 | id_node, "%i", &xendev->otherend_id, | ||
| 132 | path_node, NULL, &xendev->otherend, | ||
| 133 | NULL); | ||
| 134 | if (err) { | ||
| 135 | xenbus_dev_fatal(xendev, err, | ||
| 136 | "reading other end details from %s", | ||
| 137 | xendev->nodename); | ||
| 138 | return err; | ||
| 139 | } | ||
| 140 | if (strlen(xendev->otherend) == 0 || | ||
| 141 | !xenbus_exists(XBT_NIL, xendev->otherend, "")) { | ||
| 142 | xenbus_dev_fatal(xendev, -ENOENT, | ||
| 143 | "unable to read other end from %s. " | ||
| 144 | "missing or inaccessible.", | ||
| 145 | xendev->nodename); | ||
| 146 | free_otherend_details(xendev); | ||
| 147 | return -ENOENT; | ||
| 148 | } | ||
| 149 | |||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | |||
| 154 | static int read_backend_details(struct xenbus_device *xendev) | ||
| 155 | { | ||
| 156 | return read_otherend_details(xendev, "backend-id", "backend"); | ||
| 157 | } | ||
| 158 | |||
| 159 | |||
| 160 | /* Bus type for frontend drivers. */ | ||
| 161 | static struct xen_bus_type xenbus_frontend = { | ||
| 162 | .root = "device", | ||
| 163 | .levels = 2, /* device/type/<id> */ | ||
| 164 | .get_bus_id = frontend_bus_id, | ||
| 165 | .probe = xenbus_probe_frontend, | ||
| 166 | .bus = { | ||
| 167 | .name = "xen", | ||
| 168 | .match = xenbus_match, | ||
| 169 | .probe = xenbus_dev_probe, | ||
| 170 | .remove = xenbus_dev_remove, | ||
| 171 | .shutdown = xenbus_dev_shutdown, | ||
| 172 | }, | ||
| 173 | }; | ||
| 174 | |||
| 175 | static void otherend_changed(struct xenbus_watch *watch, | ||
| 176 | const char **vec, unsigned int len) | ||
| 177 | { | ||
| 178 | struct xenbus_device *dev = | ||
| 179 | container_of(watch, struct xenbus_device, otherend_watch); | ||
| 180 | struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver); | ||
| 181 | enum xenbus_state state; | ||
| 182 | |||
| 183 | /* Protect us against watches firing on old details when the otherend | ||
| 184 | details change, say immediately after a resume. */ | ||
| 185 | if (!dev->otherend || | ||
| 186 | strncmp(dev->otherend, vec[XS_WATCH_PATH], | ||
| 187 | strlen(dev->otherend))) { | ||
| 188 | dev_dbg(&dev->dev, "Ignoring watch at %s", vec[XS_WATCH_PATH]); | ||
| 189 | return; | ||
| 190 | } | ||
| 191 | |||
| 192 | state = xenbus_read_driver_state(dev->otherend); | ||
| 193 | |||
| 194 | dev_dbg(&dev->dev, "state is %d, (%s), %s, %s", | ||
| 195 | state, xenbus_strstate(state), dev->otherend_watch.node, | ||
| 196 | vec[XS_WATCH_PATH]); | ||
| 197 | |||
| 198 | /* | ||
| 199 | * Ignore xenbus transitions during shutdown. This prevents us doing | ||
| 200 | * work that can fail e.g., when the rootfs is gone. | ||
| 201 | */ | ||
| 202 | if (system_state > SYSTEM_RUNNING) { | ||
| 203 | struct xen_bus_type *bus = bus; | ||
| 204 | bus = container_of(dev->dev.bus, struct xen_bus_type, bus); | ||
| 205 | /* If we're frontend, drive the state machine to Closed. */ | ||
| 206 | /* This should cause the backend to release our resources. */ | ||
| 207 | if ((bus == &xenbus_frontend) && (state == XenbusStateClosing)) | ||
| 208 | xenbus_frontend_closed(dev); | ||
| 209 | return; | ||
| 210 | } | ||
| 211 | |||
| 212 | if (drv->otherend_changed) | ||
| 213 | drv->otherend_changed(dev, state); | ||
| 214 | } | ||
| 215 | |||
| 216 | |||
| 217 | static int talk_to_otherend(struct xenbus_device *dev) | ||
| 218 | { | ||
| 219 | struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver); | ||
| 220 | |||
| 221 | free_otherend_watch(dev); | ||
| 222 | free_otherend_details(dev); | ||
| 223 | |||
| 224 | return drv->read_otherend_details(dev); | ||
| 225 | } | ||
| 226 | |||
| 227 | |||
| 228 | static int watch_otherend(struct xenbus_device *dev) | ||
| 229 | { | ||
| 230 | return xenbus_watch_pathfmt(dev, &dev->otherend_watch, otherend_changed, | ||
| 231 | "%s/%s", dev->otherend, "state"); | ||
| 232 | } | ||
| 233 | |||
| 234 | |||
| 235 | int xenbus_dev_probe(struct device *_dev) | ||
| 236 | { | ||
| 237 | struct xenbus_device *dev = to_xenbus_device(_dev); | ||
| 238 | struct xenbus_driver *drv = to_xenbus_driver(_dev->driver); | ||
| 239 | const struct xenbus_device_id *id; | ||
| 240 | int err; | ||
| 241 | |||
| 242 | DPRINTK("%s", dev->nodename); | ||
| 243 | |||
| 244 | if (!drv->probe) { | ||
| 245 | err = -ENODEV; | ||
| 246 | goto fail; | ||
| 247 | } | ||
| 248 | |||
| 249 | id = match_device(drv->ids, dev); | ||
| 250 | if (!id) { | ||
| 251 | err = -ENODEV; | ||
| 252 | goto fail; | ||
| 253 | } | ||
| 254 | |||
| 255 | err = talk_to_otherend(dev); | ||
| 256 | if (err) { | ||
| 257 | dev_warn(&dev->dev, "talk_to_otherend on %s failed.\n", | ||
| 258 | dev->nodename); | ||
| 259 | return err; | ||
| 260 | } | ||
| 261 | |||
| 262 | err = drv->probe(dev, id); | ||
| 263 | if (err) | ||
| 264 | goto fail; | ||
| 265 | |||
| 266 | err = watch_otherend(dev); | ||
| 267 | if (err) { | ||
| 268 | dev_warn(&dev->dev, "watch_otherend on %s failed.\n", | ||
| 269 | dev->nodename); | ||
| 270 | return err; | ||
| 271 | } | ||
| 272 | |||
| 273 | return 0; | ||
| 274 | fail: | ||
| 275 | xenbus_dev_error(dev, err, "xenbus_dev_probe on %s", dev->nodename); | ||
| 276 | xenbus_switch_state(dev, XenbusStateClosed); | ||
| 277 | return -ENODEV; | ||
| 278 | } | ||
| 279 | |||
| 280 | int xenbus_dev_remove(struct device *_dev) | ||
| 281 | { | ||
| 282 | struct xenbus_device *dev = to_xenbus_device(_dev); | ||
| 283 | struct xenbus_driver *drv = to_xenbus_driver(_dev->driver); | ||
| 284 | |||
| 285 | DPRINTK("%s", dev->nodename); | ||
| 286 | |||
| 287 | free_otherend_watch(dev); | ||
| 288 | free_otherend_details(dev); | ||
| 289 | |||
| 290 | if (drv->remove) | ||
| 291 | drv->remove(dev); | ||
| 292 | |||
| 293 | xenbus_switch_state(dev, XenbusStateClosed); | ||
| 294 | return 0; | ||
| 295 | } | ||
| 296 | |||
| 297 | static void xenbus_dev_shutdown(struct device *_dev) | ||
| 298 | { | ||
| 299 | struct xenbus_device *dev = to_xenbus_device(_dev); | ||
| 300 | unsigned long timeout = 5*HZ; | ||
| 301 | |||
| 302 | DPRINTK("%s", dev->nodename); | ||
| 303 | |||
| 304 | get_device(&dev->dev); | ||
| 305 | if (dev->state != XenbusStateConnected) { | ||
| 306 | printk(KERN_INFO "%s: %s: %s != Connected, skipping\n", __func__, | ||
| 307 | dev->nodename, xenbus_strstate(dev->state)); | ||
| 308 | goto out; | ||
| 309 | } | ||
| 310 | xenbus_switch_state(dev, XenbusStateClosing); | ||
| 311 | timeout = wait_for_completion_timeout(&dev->down, timeout); | ||
| 312 | if (!timeout) | ||
| 313 | printk(KERN_INFO "%s: %s timeout closing device\n", | ||
| 314 | __func__, dev->nodename); | ||
| 315 | out: | ||
| 316 | put_device(&dev->dev); | ||
| 317 | } | ||
| 318 | |||
| 319 | int xenbus_register_driver_common(struct xenbus_driver *drv, | ||
| 320 | struct xen_bus_type *bus, | ||
| 321 | struct module *owner, | ||
| 322 | const char *mod_name) | ||
| 323 | { | ||
| 324 | drv->driver.name = drv->name; | ||
| 325 | drv->driver.bus = &bus->bus; | ||
| 326 | drv->driver.owner = owner; | ||
| 327 | drv->driver.mod_name = mod_name; | ||
| 328 | |||
| 329 | return driver_register(&drv->driver); | ||
| 330 | } | ||
| 331 | |||
| 332 | int __xenbus_register_frontend(struct xenbus_driver *drv, | ||
| 333 | struct module *owner, const char *mod_name) | ||
| 334 | { | ||
| 335 | int ret; | ||
| 336 | |||
| 337 | drv->read_otherend_details = read_backend_details; | ||
| 338 | |||
| 339 | ret = xenbus_register_driver_common(drv, &xenbus_frontend, | ||
| 340 | owner, mod_name); | ||
| 341 | if (ret) | ||
| 342 | return ret; | ||
| 343 | |||
| 344 | /* If this driver is loaded as a module wait for devices to attach. */ | ||
| 345 | wait_for_devices(drv); | ||
| 346 | |||
| 347 | return 0; | ||
| 348 | } | ||
| 349 | EXPORT_SYMBOL_GPL(__xenbus_register_frontend); | ||
| 350 | |||
| 351 | void xenbus_unregister_driver(struct xenbus_driver *drv) | ||
| 352 | { | ||
| 353 | driver_unregister(&drv->driver); | ||
| 354 | } | ||
| 355 | EXPORT_SYMBOL_GPL(xenbus_unregister_driver); | ||
| 356 | |||
| 357 | struct xb_find_info | ||
| 358 | { | ||
| 359 | struct xenbus_device *dev; | ||
| 360 | const char *nodename; | ||
| 361 | }; | ||
| 362 | |||
| 363 | static int cmp_dev(struct device *dev, void *data) | ||
| 364 | { | ||
| 365 | struct xenbus_device *xendev = to_xenbus_device(dev); | ||
| 366 | struct xb_find_info *info = data; | ||
| 367 | |||
| 368 | if (!strcmp(xendev->nodename, info->nodename)) { | ||
| 369 | info->dev = xendev; | ||
| 370 | get_device(dev); | ||
| 371 | return 1; | ||
| 372 | } | ||
| 373 | return 0; | ||
| 374 | } | ||
| 375 | |||
| 376 | struct xenbus_device *xenbus_device_find(const char *nodename, | ||
| 377 | struct bus_type *bus) | ||
| 378 | { | ||
| 379 | struct xb_find_info info = { .dev = NULL, .nodename = nodename }; | ||
| 380 | |||
| 381 | bus_for_each_dev(bus, NULL, &info, cmp_dev); | ||
| 382 | return info.dev; | ||
| 383 | } | ||
| 384 | |||
| 385 | static int cleanup_dev(struct device *dev, void *data) | ||
| 386 | { | ||
| 387 | struct xenbus_device *xendev = to_xenbus_device(dev); | ||
| 388 | struct xb_find_info *info = data; | ||
| 389 | int len = strlen(info->nodename); | ||
| 390 | |||
| 391 | DPRINTK("%s", info->nodename); | ||
| 392 | |||
| 393 | /* Match the info->nodename path, or any subdirectory of that path. */ | ||
| 394 | if (strncmp(xendev->nodename, info->nodename, len)) | ||
| 395 | return 0; | ||
| 396 | |||
| 397 | /* If the node name is longer, ensure it really is a subdirectory. */ | ||
| 398 | if ((strlen(xendev->nodename) > len) && (xendev->nodename[len] != '/')) | ||
| 399 | return 0; | ||
| 400 | |||
| 401 | info->dev = xendev; | ||
| 402 | get_device(dev); | ||
| 403 | return 1; | ||
| 404 | } | ||
| 405 | |||
| 406 | static void xenbus_cleanup_devices(const char *path, struct bus_type *bus) | ||
| 407 | { | ||
| 408 | struct xb_find_info info = { .nodename = path }; | ||
| 409 | |||
| 410 | do { | ||
| 411 | info.dev = NULL; | ||
| 412 | bus_for_each_dev(bus, NULL, &info, cleanup_dev); | ||
| 413 | if (info.dev) { | ||
| 414 | device_unregister(&info.dev->dev); | ||
| 415 | put_device(&info.dev->dev); | ||
| 416 | } | ||
| 417 | } while (info.dev); | ||
| 418 | } | ||
| 419 | |||
| 420 | static void xenbus_dev_release(struct device *dev) | ||
| 421 | { | ||
| 422 | if (dev) | ||
| 423 | kfree(to_xenbus_device(dev)); | ||
| 424 | } | ||
| 425 | |||
| 426 | static ssize_t xendev_show_nodename(struct device *dev, | ||
| 427 | struct device_attribute *attr, char *buf) | ||
| 428 | { | ||
| 429 | return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename); | ||
| 430 | } | ||
| 431 | DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL); | ||
| 432 | |||
| 433 | static ssize_t xendev_show_devtype(struct device *dev, | ||
| 434 | struct device_attribute *attr, char *buf) | ||
| 435 | { | ||
| 436 | return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype); | ||
| 437 | } | ||
| 438 | DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL); | ||
| 439 | |||
| 440 | |||
| 441 | int xenbus_probe_node(struct xen_bus_type *bus, | ||
| 442 | const char *type, | ||
| 443 | const char *nodename) | ||
| 444 | { | ||
| 445 | int err; | ||
| 446 | struct xenbus_device *xendev; | ||
| 447 | size_t stringlen; | ||
| 448 | char *tmpstring; | ||
| 449 | |||
| 450 | enum xenbus_state state = xenbus_read_driver_state(nodename); | ||
| 451 | |||
| 452 | if (state != XenbusStateInitialising) { | ||
| 453 | /* Device is not new, so ignore it. This can happen if a | ||
| 454 | device is going away after switching to Closed. */ | ||
| 455 | return 0; | ||
| 456 | } | ||
| 457 | |||
| 458 | stringlen = strlen(nodename) + 1 + strlen(type) + 1; | ||
| 459 | xendev = kzalloc(sizeof(*xendev) + stringlen, GFP_KERNEL); | ||
| 460 | if (!xendev) | ||
| 461 | return -ENOMEM; | ||
| 462 | |||
| 463 | xendev->state = XenbusStateInitialising; | ||
| 464 | |||
| 465 | /* Copy the strings into the extra space. */ | ||
| 466 | |||
| 467 | tmpstring = (char *)(xendev + 1); | ||
| 468 | strcpy(tmpstring, nodename); | ||
| 469 | xendev->nodename = tmpstring; | ||
| 470 | |||
| 471 | tmpstring += strlen(tmpstring) + 1; | ||
| 472 | strcpy(tmpstring, type); | ||
| 473 | xendev->devicetype = tmpstring; | ||
| 474 | init_completion(&xendev->down); | ||
| 475 | |||
| 476 | xendev->dev.bus = &bus->bus; | ||
| 477 | xendev->dev.release = xenbus_dev_release; | ||
| 478 | |||
| 479 | err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename); | ||
| 480 | if (err) | ||
| 481 | goto fail; | ||
| 482 | |||
| 483 | /* Register with generic device framework. */ | ||
| 484 | err = device_register(&xendev->dev); | ||
| 485 | if (err) | ||
| 486 | goto fail; | ||
| 487 | |||
| 488 | err = device_create_file(&xendev->dev, &dev_attr_nodename); | ||
| 489 | if (err) | ||
| 490 | goto fail_unregister; | ||
| 491 | |||
| 492 | err = device_create_file(&xendev->dev, &dev_attr_devtype); | ||
| 493 | if (err) | ||
| 494 | goto fail_remove_file; | ||
| 495 | |||
| 496 | return 0; | ||
| 497 | fail_remove_file: | ||
| 498 | device_remove_file(&xendev->dev, &dev_attr_nodename); | ||
| 499 | fail_unregister: | ||
| 500 | device_unregister(&xendev->dev); | ||
| 501 | fail: | ||
| 502 | kfree(xendev); | ||
| 503 | return err; | ||
| 504 | } | ||
| 505 | |||
| 506 | /* device/<typename>/<name> */ | ||
| 507 | static int xenbus_probe_frontend(const char *type, const char *name) | ||
| 508 | { | ||
| 509 | char *nodename; | ||
| 510 | int err; | ||
| 511 | |||
| 512 | nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", | ||
| 513 | xenbus_frontend.root, type, name); | ||
| 514 | if (!nodename) | ||
| 515 | return -ENOMEM; | ||
| 516 | |||
| 517 | DPRINTK("%s", nodename); | ||
| 518 | |||
| 519 | err = xenbus_probe_node(&xenbus_frontend, type, nodename); | ||
| 520 | kfree(nodename); | ||
| 521 | return err; | ||
| 522 | } | ||
| 523 | |||
| 524 | static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type) | ||
| 525 | { | ||
| 526 | int err = 0; | ||
| 527 | char **dir; | ||
| 528 | unsigned int dir_n = 0; | ||
| 529 | int i; | ||
| 530 | |||
| 531 | dir = xenbus_directory(XBT_NIL, bus->root, type, &dir_n); | ||
| 532 | if (IS_ERR(dir)) | ||
| 533 | return PTR_ERR(dir); | ||
| 534 | |||
| 535 | for (i = 0; i < dir_n; i++) { | ||
| 536 | err = bus->probe(type, dir[i]); | ||
| 537 | if (err) | ||
| 538 | break; | ||
| 539 | } | ||
| 540 | kfree(dir); | ||
| 541 | return err; | ||
| 542 | } | ||
| 543 | |||
| 544 | int xenbus_probe_devices(struct xen_bus_type *bus) | ||
| 545 | { | ||
| 546 | int err = 0; | ||
| 547 | char **dir; | ||
| 548 | unsigned int i, dir_n; | ||
| 549 | |||
| 550 | dir = xenbus_directory(XBT_NIL, bus->root, "", &dir_n); | ||
| 551 | if (IS_ERR(dir)) | ||
| 552 | return PTR_ERR(dir); | ||
| 553 | |||
| 554 | for (i = 0; i < dir_n; i++) { | ||
| 555 | err = xenbus_probe_device_type(bus, dir[i]); | ||
| 556 | if (err) | ||
| 557 | break; | ||
| 558 | } | ||
| 559 | kfree(dir); | ||
| 560 | return err; | ||
| 561 | } | ||
| 562 | |||
| 563 | static unsigned int char_count(const char *str, char c) | ||
| 564 | { | ||
| 565 | unsigned int i, ret = 0; | ||
| 566 | |||
| 567 | for (i = 0; str[i]; i++) | ||
| 568 | if (str[i] == c) | ||
| 569 | ret++; | ||
| 570 | return ret; | ||
| 571 | } | ||
| 572 | |||
| 573 | static int strsep_len(const char *str, char c, unsigned int len) | ||
| 574 | { | ||
| 575 | unsigned int i; | ||
| 576 | |||
| 577 | for (i = 0; str[i]; i++) | ||
| 578 | if (str[i] == c) { | ||
| 579 | if (len == 0) | ||
| 580 | return i; | ||
| 581 | len--; | ||
| 582 | } | ||
| 583 | return (len == 0) ? i : -ERANGE; | ||
| 584 | } | ||
| 585 | |||
| 586 | void xenbus_dev_changed(const char *node, struct xen_bus_type *bus) | ||
| 587 | { | ||
| 588 | int exists, rootlen; | ||
| 589 | struct xenbus_device *dev; | ||
| 590 | char type[BUS_ID_SIZE]; | ||
| 591 | const char *p, *root; | ||
| 592 | |||
| 593 | if (char_count(node, '/') < 2) | ||
| 594 | return; | ||
| 595 | |||
| 596 | exists = xenbus_exists(XBT_NIL, node, ""); | ||
| 597 | if (!exists) { | ||
| 598 | xenbus_cleanup_devices(node, &bus->bus); | ||
| 599 | return; | ||
| 600 | } | ||
| 601 | |||
| 602 | /* backend/<type>/... or device/<type>/... */ | ||
| 603 | p = strchr(node, '/') + 1; | ||
| 604 | snprintf(type, BUS_ID_SIZE, "%.*s", (int)strcspn(p, "/"), p); | ||
| 605 | type[BUS_ID_SIZE-1] = '\0'; | ||
| 606 | |||
| 607 | rootlen = strsep_len(node, '/', bus->levels); | ||
| 608 | if (rootlen < 0) | ||
| 609 | return; | ||
| 610 | root = kasprintf(GFP_KERNEL, "%.*s", rootlen, node); | ||
| 611 | if (!root) | ||
| 612 | return; | ||
| 613 | |||
| 614 | dev = xenbus_device_find(root, &bus->bus); | ||
| 615 | if (!dev) | ||
| 616 | xenbus_probe_node(bus, type, root); | ||
| 617 | else | ||
| 618 | put_device(&dev->dev); | ||
| 619 | |||
| 620 | kfree(root); | ||
| 621 | } | ||
| 622 | |||
| 623 | static void frontend_changed(struct xenbus_watch *watch, | ||
| 624 | const char **vec, unsigned int len) | ||
| 625 | { | ||
| 626 | DPRINTK(""); | ||
| 627 | |||
| 628 | xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend); | ||
| 629 | } | ||
| 630 | |||
| 631 | /* We watch for devices appearing and vanishing. */ | ||
| 632 | static struct xenbus_watch fe_watch = { | ||
| 633 | .node = "device", | ||
| 634 | .callback = frontend_changed, | ||
| 635 | }; | ||
| 636 | |||
| 637 | static int suspend_dev(struct device *dev, void *data) | ||
| 638 | { | ||
| 639 | int err = 0; | ||
| 640 | struct xenbus_driver *drv; | ||
| 641 | struct xenbus_device *xdev; | ||
| 642 | |||
| 643 | DPRINTK(""); | ||
| 644 | |||
| 645 | if (dev->driver == NULL) | ||
| 646 | return 0; | ||
| 647 | drv = to_xenbus_driver(dev->driver); | ||
| 648 | xdev = container_of(dev, struct xenbus_device, dev); | ||
| 649 | if (drv->suspend) | ||
| 650 | err = drv->suspend(xdev); | ||
| 651 | if (err) | ||
| 652 | printk(KERN_WARNING | ||
| 653 | "xenbus: suspend %s failed: %i\n", dev->bus_id, err); | ||
| 654 | return 0; | ||
| 655 | } | ||
| 656 | |||
| 657 | static int suspend_cancel_dev(struct device *dev, void *data) | ||
| 658 | { | ||
| 659 | int err = 0; | ||
| 660 | struct xenbus_driver *drv; | ||
| 661 | struct xenbus_device *xdev; | ||
| 662 | |||
| 663 | DPRINTK(""); | ||
| 664 | |||
| 665 | if (dev->driver == NULL) | ||
| 666 | return 0; | ||
| 667 | drv = to_xenbus_driver(dev->driver); | ||
| 668 | xdev = container_of(dev, struct xenbus_device, dev); | ||
| 669 | if (drv->suspend_cancel) | ||
| 670 | err = drv->suspend_cancel(xdev); | ||
| 671 | if (err) | ||
| 672 | printk(KERN_WARNING | ||
| 673 | "xenbus: suspend_cancel %s failed: %i\n", | ||
| 674 | dev->bus_id, err); | ||
| 675 | return 0; | ||
| 676 | } | ||
| 677 | |||
| 678 | static int resume_dev(struct device *dev, void *data) | ||
| 679 | { | ||
| 680 | int err; | ||
| 681 | struct xenbus_driver *drv; | ||
| 682 | struct xenbus_device *xdev; | ||
| 683 | |||
| 684 | DPRINTK(""); | ||
| 685 | |||
| 686 | if (dev->driver == NULL) | ||
| 687 | return 0; | ||
| 688 | |||
| 689 | drv = to_xenbus_driver(dev->driver); | ||
| 690 | xdev = container_of(dev, struct xenbus_device, dev); | ||
| 691 | |||
| 692 | err = talk_to_otherend(xdev); | ||
| 693 | if (err) { | ||
| 694 | printk(KERN_WARNING | ||
| 695 | "xenbus: resume (talk_to_otherend) %s failed: %i\n", | ||
| 696 | dev->bus_id, err); | ||
| 697 | return err; | ||
| 698 | } | ||
| 699 | |||
| 700 | xdev->state = XenbusStateInitialising; | ||
| 701 | |||
| 702 | if (drv->resume) { | ||
| 703 | err = drv->resume(xdev); | ||
| 704 | if (err) { | ||
| 705 | printk(KERN_WARNING | ||
| 706 | "xenbus: resume %s failed: %i\n", | ||
| 707 | dev->bus_id, err); | ||
| 708 | return err; | ||
| 709 | } | ||
| 710 | } | ||
| 711 | |||
| 712 | err = watch_otherend(xdev); | ||
| 713 | if (err) { | ||
| 714 | printk(KERN_WARNING | ||
| 715 | "xenbus_probe: resume (watch_otherend) %s failed: " | ||
| 716 | "%d.\n", dev->bus_id, err); | ||
| 717 | return err; | ||
| 718 | } | ||
| 719 | |||
| 720 | return 0; | ||
| 721 | } | ||
| 722 | |||
| 723 | void xenbus_suspend(void) | ||
| 724 | { | ||
| 725 | DPRINTK(""); | ||
| 726 | |||
| 727 | bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev); | ||
| 728 | xenbus_backend_suspend(suspend_dev); | ||
| 729 | xs_suspend(); | ||
| 730 | } | ||
| 731 | EXPORT_SYMBOL_GPL(xenbus_suspend); | ||
| 732 | |||
| 733 | void xenbus_resume(void) | ||
| 734 | { | ||
| 735 | xb_init_comms(); | ||
| 736 | xs_resume(); | ||
| 737 | bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev); | ||
| 738 | xenbus_backend_resume(resume_dev); | ||
| 739 | } | ||
| 740 | EXPORT_SYMBOL_GPL(xenbus_resume); | ||
| 741 | |||
| 742 | void xenbus_suspend_cancel(void) | ||
| 743 | { | ||
| 744 | xs_suspend_cancel(); | ||
| 745 | bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_cancel_dev); | ||
| 746 | xenbus_backend_resume(suspend_cancel_dev); | ||
| 747 | } | ||
| 748 | EXPORT_SYMBOL_GPL(xenbus_suspend_cancel); | ||
| 749 | |||
| 750 | /* A flag to determine if xenstored is 'ready' (i.e. has started) */ | ||
| 751 | int xenstored_ready = 0; | ||
| 752 | |||
| 753 | |||
| 754 | int register_xenstore_notifier(struct notifier_block *nb) | ||
| 755 | { | ||
| 756 | int ret = 0; | ||
| 757 | |||
| 758 | if (xenstored_ready > 0) | ||
| 759 | ret = nb->notifier_call(nb, 0, NULL); | ||
| 760 | else | ||
| 761 | blocking_notifier_chain_register(&xenstore_chain, nb); | ||
| 762 | |||
| 763 | return ret; | ||
| 764 | } | ||
| 765 | EXPORT_SYMBOL_GPL(register_xenstore_notifier); | ||
| 766 | |||
| 767 | void unregister_xenstore_notifier(struct notifier_block *nb) | ||
| 768 | { | ||
| 769 | blocking_notifier_chain_unregister(&xenstore_chain, nb); | ||
| 770 | } | ||
| 771 | EXPORT_SYMBOL_GPL(unregister_xenstore_notifier); | ||
| 772 | |||
| 773 | void xenbus_probe(struct work_struct *unused) | ||
| 774 | { | ||
| 775 | BUG_ON((xenstored_ready <= 0)); | ||
| 776 | |||
| 777 | /* Enumerate devices in xenstore and watch for changes. */ | ||
| 778 | xenbus_probe_devices(&xenbus_frontend); | ||
| 779 | register_xenbus_watch(&fe_watch); | ||
| 780 | xenbus_backend_probe_and_watch(); | ||
| 781 | |||
| 782 | /* Notify others that xenstore is up */ | ||
| 783 | blocking_notifier_call_chain(&xenstore_chain, 0, NULL); | ||
| 784 | } | ||
| 785 | |||
| 786 | static int __init xenbus_probe_init(void) | ||
| 787 | { | ||
| 788 | int err = 0; | ||
| 789 | |||
| 790 | DPRINTK(""); | ||
| 791 | |||
| 792 | err = -ENODEV; | ||
| 793 | if (!is_running_on_xen()) | ||
| 794 | goto out_error; | ||
| 795 | |||
| 796 | /* Register ourselves with the kernel bus subsystem */ | ||
| 797 | err = bus_register(&xenbus_frontend.bus); | ||
| 798 | if (err) | ||
| 799 | goto out_error; | ||
| 800 | |||
| 801 | err = xenbus_backend_bus_register(); | ||
| 802 | if (err) | ||
| 803 | goto out_unreg_front; | ||
| 804 | |||
| 805 | /* | ||
| 806 | * Domain0 doesn't have a store_evtchn or store_mfn yet. | ||
| 807 | */ | ||
| 808 | if (is_initial_xendomain()) { | ||
| 809 | /* dom0 not yet supported */ | ||
| 810 | } else { | ||
| 811 | xenstored_ready = 1; | ||
| 812 | xen_store_evtchn = xen_start_info->store_evtchn; | ||
| 813 | xen_store_mfn = xen_start_info->store_mfn; | ||
| 814 | } | ||
| 815 | xen_store_interface = mfn_to_virt(xen_store_mfn); | ||
| 816 | |||
| 817 | /* Initialize the interface to xenstore. */ | ||
| 818 | err = xs_init(); | ||
| 819 | if (err) { | ||
| 820 | printk(KERN_WARNING | ||
| 821 | "XENBUS: Error initializing xenstore comms: %i\n", err); | ||
| 822 | goto out_unreg_back; | ||
| 823 | } | ||
| 824 | |||
| 825 | if (!is_initial_xendomain()) | ||
| 826 | xenbus_probe(NULL); | ||
| 827 | |||
| 828 | return 0; | ||
| 829 | |||
| 830 | out_unreg_back: | ||
| 831 | xenbus_backend_bus_unregister(); | ||
| 832 | |||
| 833 | out_unreg_front: | ||
| 834 | bus_unregister(&xenbus_frontend.bus); | ||
| 835 | |||
| 836 | out_error: | ||
| 837 | return err; | ||
| 838 | } | ||
| 839 | |||
| 840 | postcore_initcall(xenbus_probe_init); | ||
| 841 | |||
| 842 | MODULE_LICENSE("GPL"); | ||
| 843 | |||
| 844 | static int is_disconnected_device(struct device *dev, void *data) | ||
| 845 | { | ||
| 846 | struct xenbus_device *xendev = to_xenbus_device(dev); | ||
| 847 | struct device_driver *drv = data; | ||
| 848 | |||
| 849 | /* | ||
| 850 | * A device with no driver will never connect. We care only about | ||
| 851 | * devices which should currently be in the process of connecting. | ||
| 852 | */ | ||
| 853 | if (!dev->driver) | ||
| 854 | return 0; | ||
| 855 | |||
| 856 | /* Is this search limited to a particular driver? */ | ||
| 857 | if (drv && (dev->driver != drv)) | ||
| 858 | return 0; | ||
| 859 | |||
| 860 | return (xendev->state != XenbusStateConnected); | ||
| 861 | } | ||
| 862 | |||
| 863 | static int exists_disconnected_device(struct device_driver *drv) | ||
| 864 | { | ||
| 865 | return bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, | ||
| 866 | is_disconnected_device); | ||
| 867 | } | ||
| 868 | |||
| 869 | static int print_device_status(struct device *dev, void *data) | ||
| 870 | { | ||
| 871 | struct xenbus_device *xendev = to_xenbus_device(dev); | ||
| 872 | struct device_driver *drv = data; | ||
| 873 | |||
| 874 | /* Is this operation limited to a particular driver? */ | ||
| 875 | if (drv && (dev->driver != drv)) | ||
| 876 | return 0; | ||
| 877 | |||
| 878 | if (!dev->driver) { | ||
| 879 | /* Information only: is this too noisy? */ | ||
| 880 | printk(KERN_INFO "XENBUS: Device with no driver: %s\n", | ||
| 881 | xendev->nodename); | ||
| 882 | } else if (xendev->state != XenbusStateConnected) { | ||
| 883 | printk(KERN_WARNING "XENBUS: Timeout connecting " | ||
| 884 | "to device: %s (state %d)\n", | ||
| 885 | xendev->nodename, xendev->state); | ||
| 886 | } | ||
| 887 | |||
| 888 | return 0; | ||
| 889 | } | ||
| 890 | |||
| 891 | /* We only wait for device setup after most initcalls have run. */ | ||
| 892 | static int ready_to_wait_for_devices; | ||
| 893 | |||
| 894 | /* | ||
| 895 | * On a 10 second timeout, wait for all devices currently configured. We need | ||
| 896 | * to do this to guarantee that the filesystems and / or network devices | ||
| 897 | * needed for boot are available, before we can allow the boot to proceed. | ||
| 898 | * | ||
| 899 | * This needs to be on a late_initcall, to happen after the frontend device | ||
| 900 | * drivers have been initialised, but before the root fs is mounted. | ||
| 901 | * | ||
| 902 | * A possible improvement here would be to have the tools add a per-device | ||
| 903 | * flag to the store entry, indicating whether it is needed at boot time. | ||
| 904 | * This would allow people who knew what they were doing to accelerate their | ||
| 905 | * boot slightly, but of course needs tools or manual intervention to set up | ||
| 906 | * those flags correctly. | ||
| 907 | */ | ||
| 908 | static void wait_for_devices(struct xenbus_driver *xendrv) | ||
| 909 | { | ||
| 910 | unsigned long timeout = jiffies + 10*HZ; | ||
| 911 | struct device_driver *drv = xendrv ? &xendrv->driver : NULL; | ||
| 912 | |||
| 913 | if (!ready_to_wait_for_devices || !is_running_on_xen()) | ||
| 914 | return; | ||
| 915 | |||
| 916 | while (exists_disconnected_device(drv)) { | ||
| 917 | if (time_after(jiffies, timeout)) | ||
| 918 | break; | ||
| 919 | schedule_timeout_interruptible(HZ/10); | ||
| 920 | } | ||
| 921 | |||
| 922 | bus_for_each_dev(&xenbus_frontend.bus, NULL, drv, | ||
| 923 | print_device_status); | ||
| 924 | } | ||
| 925 | |||
| 926 | #ifndef MODULE | ||
| 927 | static int __init boot_wait_for_devices(void) | ||
| 928 | { | ||
| 929 | ready_to_wait_for_devices = 1; | ||
| 930 | wait_for_devices(NULL); | ||
| 931 | return 0; | ||
| 932 | } | ||
| 933 | |||
| 934 | late_initcall(boot_wait_for_devices); | ||
| 935 | #endif | ||
diff --git a/drivers/xen/xenbus/xenbus_probe.h b/drivers/xen/xenbus/xenbus_probe.h new file mode 100644 index 000000000000..e09b19415a40 --- /dev/null +++ b/drivers/xen/xenbus/xenbus_probe.h | |||
| @@ -0,0 +1,74 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | * xenbus_probe.h | ||
| 3 | * | ||
| 4 | * Talks to Xen Store to figure out what devices we have. | ||
| 5 | * | ||
| 6 | * Copyright (C) 2005 Rusty Russell, IBM Corporation | ||
| 7 | * Copyright (C) 2005 XenSource Ltd. | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU General Public License version 2 | ||
| 11 | * as published by the Free Software Foundation; or, when distributed | ||
| 12 | * separately from the Linux kernel or incorporated into other | ||
| 13 | * software packages, subject to the following license: | ||
| 14 | * | ||
| 15 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 16 | * of this source file (the "Software"), to deal in the Software without | ||
| 17 | * restriction, including without limitation the rights to use, copy, modify, | ||
| 18 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, | ||
| 19 | * and to permit persons to whom the Software is furnished to do so, subject to | ||
| 20 | * the following conditions: | ||
| 21 | * | ||
| 22 | * The above copyright notice and this permission notice shall be included in | ||
| 23 | * all copies or substantial portions of the Software. | ||
| 24 | * | ||
| 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 26 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 27 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 28 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 29 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 30 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
| 31 | * IN THE SOFTWARE. | ||
| 32 | */ | ||
| 33 | |||
| 34 | #ifndef _XENBUS_PROBE_H | ||
| 35 | #define _XENBUS_PROBE_H | ||
| 36 | |||
| 37 | #ifdef CONFIG_XEN_BACKEND | ||
| 38 | extern void xenbus_backend_suspend(int (*fn)(struct device *, void *)); | ||
| 39 | extern void xenbus_backend_resume(int (*fn)(struct device *, void *)); | ||
| 40 | extern void xenbus_backend_probe_and_watch(void); | ||
| 41 | extern int xenbus_backend_bus_register(void); | ||
| 42 | extern void xenbus_backend_bus_unregister(void); | ||
| 43 | #else | ||
| 44 | static inline void xenbus_backend_suspend(int (*fn)(struct device *, void *)) {} | ||
| 45 | static inline void xenbus_backend_resume(int (*fn)(struct device *, void *)) {} | ||
| 46 | static inline void xenbus_backend_probe_and_watch(void) {} | ||
| 47 | static inline int xenbus_backend_bus_register(void) { return 0; } | ||
| 48 | static inline void xenbus_backend_bus_unregister(void) {} | ||
| 49 | #endif | ||
| 50 | |||
| 51 | struct xen_bus_type | ||
| 52 | { | ||
| 53 | char *root; | ||
| 54 | unsigned int levels; | ||
| 55 | int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename); | ||
| 56 | int (*probe)(const char *type, const char *dir); | ||
| 57 | struct bus_type bus; | ||
| 58 | }; | ||
| 59 | |||
| 60 | extern int xenbus_match(struct device *_dev, struct device_driver *_drv); | ||
| 61 | extern int xenbus_dev_probe(struct device *_dev); | ||
| 62 | extern int xenbus_dev_remove(struct device *_dev); | ||
| 63 | extern int xenbus_register_driver_common(struct xenbus_driver *drv, | ||
| 64 | struct xen_bus_type *bus, | ||
| 65 | struct module *owner, | ||
| 66 | const char *mod_name); | ||
| 67 | extern int xenbus_probe_node(struct xen_bus_type *bus, | ||
| 68 | const char *type, | ||
| 69 | const char *nodename); | ||
| 70 | extern int xenbus_probe_devices(struct xen_bus_type *bus); | ||
| 71 | |||
| 72 | extern void xenbus_dev_changed(const char *node, struct xen_bus_type *bus); | ||
| 73 | |||
| 74 | #endif | ||
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c new file mode 100644 index 000000000000..9e943fbce81b --- /dev/null +++ b/drivers/xen/xenbus/xenbus_xs.c | |||
| @@ -0,0 +1,861 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | * xenbus_xs.c | ||
| 3 | * | ||
| 4 | * This is the kernel equivalent of the "xs" library. We don't need everything | ||
| 5 | * and we use xenbus_comms for communication. | ||
| 6 | * | ||
| 7 | * Copyright (C) 2005 Rusty Russell, IBM Corporation | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU General Public License version 2 | ||
| 11 | * as published by the Free Software Foundation; or, when distributed | ||
| 12 | * separately from the Linux kernel or incorporated into other | ||
| 13 | * software packages, subject to the following license: | ||
| 14 | * | ||
| 15 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 16 | * of this source file (the "Software"), to deal in the Software without | ||
| 17 | * restriction, including without limitation the rights to use, copy, modify, | ||
| 18 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, | ||
| 19 | * and to permit persons to whom the Software is furnished to do so, subject to | ||
| 20 | * the following conditions: | ||
| 21 | * | ||
| 22 | * The above copyright notice and this permission notice shall be included in | ||
| 23 | * all copies or substantial portions of the Software. | ||
| 24 | * | ||
| 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 26 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 27 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 28 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 29 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 30 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
| 31 | * IN THE SOFTWARE. | ||
| 32 | */ | ||
| 33 | |||
| 34 | #include <linux/unistd.h> | ||
| 35 | #include <linux/errno.h> | ||
| 36 | #include <linux/types.h> | ||
| 37 | #include <linux/uio.h> | ||
| 38 | #include <linux/kernel.h> | ||
| 39 | #include <linux/string.h> | ||
| 40 | #include <linux/err.h> | ||
| 41 | #include <linux/slab.h> | ||
| 42 | #include <linux/fcntl.h> | ||
| 43 | #include <linux/kthread.h> | ||
| 44 | #include <linux/rwsem.h> | ||
| 45 | #include <linux/module.h> | ||
| 46 | #include <linux/mutex.h> | ||
| 47 | #include <xen/xenbus.h> | ||
| 48 | #include "xenbus_comms.h" | ||
| 49 | |||
| 50 | struct xs_stored_msg { | ||
| 51 | struct list_head list; | ||
| 52 | |||
| 53 | struct xsd_sockmsg hdr; | ||
| 54 | |||
| 55 | union { | ||
| 56 | /* Queued replies. */ | ||
| 57 | struct { | ||
| 58 | char *body; | ||
| 59 | } reply; | ||
| 60 | |||
| 61 | /* Queued watch events. */ | ||
| 62 | struct { | ||
| 63 | struct xenbus_watch *handle; | ||
| 64 | char **vec; | ||
| 65 | unsigned int vec_size; | ||
| 66 | } watch; | ||
| 67 | } u; | ||
| 68 | }; | ||
| 69 | |||
| 70 | struct xs_handle { | ||
| 71 | /* A list of replies. Currently only one will ever be outstanding. */ | ||
| 72 | struct list_head reply_list; | ||
| 73 | spinlock_t reply_lock; | ||
| 74 | wait_queue_head_t reply_waitq; | ||
| 75 | |||
| 76 | /* | ||
| 77 | * Mutex ordering: transaction_mutex -> watch_mutex -> request_mutex. | ||
| 78 | * response_mutex is never taken simultaneously with the other three. | ||
| 79 | */ | ||
| 80 | |||
| 81 | /* One request at a time. */ | ||
| 82 | struct mutex request_mutex; | ||
| 83 | |||
| 84 | /* Protect xenbus reader thread against save/restore. */ | ||
| 85 | struct mutex response_mutex; | ||
| 86 | |||
| 87 | /* Protect transactions against save/restore. */ | ||
| 88 | struct rw_semaphore transaction_mutex; | ||
| 89 | |||
| 90 | /* Protect watch (de)register against save/restore. */ | ||
| 91 | struct rw_semaphore watch_mutex; | ||
| 92 | }; | ||
| 93 | |||
| 94 | static struct xs_handle xs_state; | ||
| 95 | |||
| 96 | /* List of registered watches, and a lock to protect it. */ | ||
| 97 | static LIST_HEAD(watches); | ||
| 98 | static DEFINE_SPINLOCK(watches_lock); | ||
| 99 | |||
| 100 | /* List of pending watch callback events, and a lock to protect it. */ | ||
| 101 | static LIST_HEAD(watch_events); | ||
| 102 | static DEFINE_SPINLOCK(watch_events_lock); | ||
| 103 | |||
| 104 | /* | ||
| 105 | * Details of the xenwatch callback kernel thread. The thread waits on the | ||
| 106 | * watch_events_waitq for work to do (queued on watch_events list). When it | ||
| 107 | * wakes up it acquires the xenwatch_mutex before reading the list and | ||
| 108 | * carrying out work. | ||
| 109 | */ | ||
| 110 | static pid_t xenwatch_pid; | ||
| 111 | static DEFINE_MUTEX(xenwatch_mutex); | ||
| 112 | static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq); | ||
| 113 | |||
| 114 | static int get_error(const char *errorstring) | ||
| 115 | { | ||
| 116 | unsigned int i; | ||
| 117 | |||
| 118 | for (i = 0; strcmp(errorstring, xsd_errors[i].errstring) != 0; i++) { | ||
| 119 | if (i == ARRAY_SIZE(xsd_errors) - 1) { | ||
| 120 | printk(KERN_WARNING | ||
| 121 | "XENBUS xen store gave: unknown error %s", | ||
| 122 | errorstring); | ||
| 123 | return EINVAL; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | return xsd_errors[i].errnum; | ||
| 127 | } | ||
| 128 | |||
| 129 | static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) | ||
| 130 | { | ||
| 131 | struct xs_stored_msg *msg; | ||
| 132 | char *body; | ||
| 133 | |||
| 134 | spin_lock(&xs_state.reply_lock); | ||
| 135 | |||
| 136 | while (list_empty(&xs_state.reply_list)) { | ||
| 137 | spin_unlock(&xs_state.reply_lock); | ||
| 138 | /* XXX FIXME: Avoid synchronous wait for response here. */ | ||
| 139 | wait_event(xs_state.reply_waitq, | ||
| 140 | !list_empty(&xs_state.reply_list)); | ||
| 141 | spin_lock(&xs_state.reply_lock); | ||
| 142 | } | ||
| 143 | |||
| 144 | msg = list_entry(xs_state.reply_list.next, | ||
| 145 | struct xs_stored_msg, list); | ||
| 146 | list_del(&msg->list); | ||
| 147 | |||
| 148 | spin_unlock(&xs_state.reply_lock); | ||
| 149 | |||
| 150 | *type = msg->hdr.type; | ||
| 151 | if (len) | ||
| 152 | *len = msg->hdr.len; | ||
| 153 | body = msg->u.reply.body; | ||
| 154 | |||
| 155 | kfree(msg); | ||
| 156 | |||
| 157 | return body; | ||
| 158 | } | ||
| 159 | |||
| 160 | void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) | ||
| 161 | { | ||
| 162 | void *ret; | ||
| 163 | struct xsd_sockmsg req_msg = *msg; | ||
| 164 | int err; | ||
| 165 | |||
| 166 | if (req_msg.type == XS_TRANSACTION_START) | ||
| 167 | down_read(&xs_state.transaction_mutex); | ||
| 168 | |||
| 169 | mutex_lock(&xs_state.request_mutex); | ||
| 170 | |||
| 171 | err = xb_write(msg, sizeof(*msg) + msg->len); | ||
| 172 | if (err) { | ||
| 173 | msg->type = XS_ERROR; | ||
| 174 | ret = ERR_PTR(err); | ||
| 175 | } else | ||
| 176 | ret = read_reply(&msg->type, &msg->len); | ||
| 177 | |||
| 178 | mutex_unlock(&xs_state.request_mutex); | ||
| 179 | |||
| 180 | if ((msg->type == XS_TRANSACTION_END) || | ||
| 181 | ((req_msg.type == XS_TRANSACTION_START) && | ||
| 182 | (msg->type == XS_ERROR))) | ||
| 183 | up_read(&xs_state.transaction_mutex); | ||
| 184 | |||
| 185 | return ret; | ||
| 186 | } | ||
| 187 | |||
| 188 | /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ | ||
| 189 | static void *xs_talkv(struct xenbus_transaction t, | ||
| 190 | enum xsd_sockmsg_type type, | ||
| 191 | const struct kvec *iovec, | ||
| 192 | unsigned int num_vecs, | ||
| 193 | unsigned int *len) | ||
| 194 | { | ||
| 195 | struct xsd_sockmsg msg; | ||
| 196 | void *ret = NULL; | ||
| 197 | unsigned int i; | ||
| 198 | int err; | ||
| 199 | |||
| 200 | msg.tx_id = t.id; | ||
| 201 | msg.req_id = 0; | ||
| 202 | msg.type = type; | ||
| 203 | msg.len = 0; | ||
| 204 | for (i = 0; i < num_vecs; i++) | ||
| 205 | msg.len += iovec[i].iov_len; | ||
| 206 | |||
| 207 | mutex_lock(&xs_state.request_mutex); | ||
| 208 | |||
| 209 | err = xb_write(&msg, sizeof(msg)); | ||
| 210 | if (err) { | ||
| 211 | mutex_unlock(&xs_state.request_mutex); | ||
| 212 | return ERR_PTR(err); | ||
| 213 | } | ||
| 214 | |||
| 215 | for (i = 0; i < num_vecs; i++) { | ||
| 216 | err = xb_write(iovec[i].iov_base, iovec[i].iov_len); | ||
| 217 | if (err) { | ||
| 218 | mutex_unlock(&xs_state.request_mutex); | ||
| 219 | return ERR_PTR(err); | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | ret = read_reply(&msg.type, len); | ||
| 224 | |||
| 225 | mutex_unlock(&xs_state.request_mutex); | ||
| 226 | |||
| 227 | if (IS_ERR(ret)) | ||
| 228 | return ret; | ||
| 229 | |||
| 230 | if (msg.type == XS_ERROR) { | ||
| 231 | err = get_error(ret); | ||
| 232 | kfree(ret); | ||
| 233 | return ERR_PTR(-err); | ||
| 234 | } | ||
| 235 | |||
| 236 | if (msg.type != type) { | ||
| 237 | if (printk_ratelimit()) | ||
| 238 | printk(KERN_WARNING | ||
| 239 | "XENBUS unexpected type [%d], expected [%d]\n", | ||
| 240 | msg.type, type); | ||
| 241 | kfree(ret); | ||
| 242 | return ERR_PTR(-EINVAL); | ||
| 243 | } | ||
| 244 | return ret; | ||
| 245 | } | ||
| 246 | |||
| 247 | /* Simplified version of xs_talkv: single message. */ | ||
| 248 | static void *xs_single(struct xenbus_transaction t, | ||
| 249 | enum xsd_sockmsg_type type, | ||
| 250 | const char *string, | ||
| 251 | unsigned int *len) | ||
| 252 | { | ||
| 253 | struct kvec iovec; | ||
| 254 | |||
| 255 | iovec.iov_base = (void *)string; | ||
| 256 | iovec.iov_len = strlen(string) + 1; | ||
| 257 | return xs_talkv(t, type, &iovec, 1, len); | ||
| 258 | } | ||
| 259 | |||
| 260 | /* Many commands only need an ack, don't care what it says. */ | ||
| 261 | static int xs_error(char *reply) | ||
| 262 | { | ||
| 263 | if (IS_ERR(reply)) | ||
| 264 | return PTR_ERR(reply); | ||
| 265 | kfree(reply); | ||
| 266 | return 0; | ||
| 267 | } | ||
| 268 | |||
| 269 | static unsigned int count_strings(const char *strings, unsigned int len) | ||
| 270 | { | ||
| 271 | unsigned int num; | ||
| 272 | const char *p; | ||
| 273 | |||
| 274 | for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) | ||
| 275 | num++; | ||
| 276 | |||
| 277 | return num; | ||
| 278 | } | ||
| 279 | |||
| 280 | /* Return the path to dir with /name appended. Buffer must be kfree()'ed. */ | ||
| 281 | static char *join(const char *dir, const char *name) | ||
| 282 | { | ||
| 283 | char *buffer; | ||
| 284 | |||
| 285 | if (strlen(name) == 0) | ||
| 286 | buffer = kasprintf(GFP_KERNEL, "%s", dir); | ||
| 287 | else | ||
| 288 | buffer = kasprintf(GFP_KERNEL, "%s/%s", dir, name); | ||
| 289 | return (!buffer) ? ERR_PTR(-ENOMEM) : buffer; | ||
| 290 | } | ||
| 291 | |||
| 292 | static char **split(char *strings, unsigned int len, unsigned int *num) | ||
| 293 | { | ||
| 294 | char *p, **ret; | ||
| 295 | |||
| 296 | /* Count the strings. */ | ||
| 297 | *num = count_strings(strings, len); | ||
| 298 | |||
| 299 | /* Transfer to one big alloc for easy freeing. */ | ||
| 300 | ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL); | ||
| 301 | if (!ret) { | ||
| 302 | kfree(strings); | ||
| 303 | return ERR_PTR(-ENOMEM); | ||
| 304 | } | ||
| 305 | memcpy(&ret[*num], strings, len); | ||
| 306 | kfree(strings); | ||
| 307 | |||
| 308 | strings = (char *)&ret[*num]; | ||
| 309 | for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1) | ||
| 310 | ret[(*num)++] = p; | ||
| 311 | |||
| 312 | return ret; | ||
| 313 | } | ||
| 314 | |||
| 315 | char **xenbus_directory(struct xenbus_transaction t, | ||
| 316 | const char *dir, const char *node, unsigned int *num) | ||
| 317 | { | ||
| 318 | char *strings, *path; | ||
| 319 | unsigned int len; | ||
| 320 | |||
| 321 | path = join(dir, node); | ||
| 322 | if (IS_ERR(path)) | ||
| 323 | return (char **)path; | ||
| 324 | |||
| 325 | strings = xs_single(t, XS_DIRECTORY, path, &len); | ||
| 326 | kfree(path); | ||
| 327 | if (IS_ERR(strings)) | ||
| 328 | return (char **)strings; | ||
| 329 | |||
| 330 | return split(strings, len, num); | ||
| 331 | } | ||
| 332 | EXPORT_SYMBOL_GPL(xenbus_directory); | ||
| 333 | |||
| 334 | /* Check if a path exists. Return 1 if it does. */ | ||
| 335 | int xenbus_exists(struct xenbus_transaction t, | ||
| 336 | const char *dir, const char *node) | ||
| 337 | { | ||
| 338 | char **d; | ||
| 339 | int dir_n; | ||
| 340 | |||
| 341 | d = xenbus_directory(t, dir, node, &dir_n); | ||
| 342 | if (IS_ERR(d)) | ||
| 343 | return 0; | ||
| 344 | kfree(d); | ||
| 345 | return 1; | ||
| 346 | } | ||
| 347 | EXPORT_SYMBOL_GPL(xenbus_exists); | ||
| 348 | |||
| 349 | /* Get the value of a single file. | ||
| 350 | * Returns a kmalloced value: call free() on it after use. | ||
| 351 | * len indicates length in bytes. | ||
| 352 | */ | ||
| 353 | void *xenbus_read(struct xenbus_transaction t, | ||
| 354 | const char *dir, const char *node, unsigned int *len) | ||
| 355 | { | ||
| 356 | char *path; | ||
| 357 | void *ret; | ||
| 358 | |||
| 359 | path = join(dir, node); | ||
| 360 | if (IS_ERR(path)) | ||
| 361 | return (void *)path; | ||
| 362 | |||
| 363 | ret = xs_single(t, XS_READ, path, len); | ||
| 364 | kfree(path); | ||
| 365 | return ret; | ||
| 366 | } | ||
| 367 | EXPORT_SYMBOL_GPL(xenbus_read); | ||
| 368 | |||
| 369 | /* Write the value of a single file. | ||
| 370 | * Returns -err on failure. | ||
| 371 | */ | ||
| 372 | int xenbus_write(struct xenbus_transaction t, | ||
| 373 | const char *dir, const char *node, const char *string) | ||
| 374 | { | ||
| 375 | const char *path; | ||
| 376 | struct kvec iovec[2]; | ||
| 377 | int ret; | ||
| 378 | |||
| 379 | path = join(dir, node); | ||
| 380 | if (IS_ERR(path)) | ||
| 381 | return PTR_ERR(path); | ||
| 382 | |||
| 383 | iovec[0].iov_base = (void *)path; | ||
| 384 | iovec[0].iov_len = strlen(path) + 1; | ||
| 385 | iovec[1].iov_base = (void *)string; | ||
| 386 | iovec[1].iov_len = strlen(string); | ||
| 387 | |||
| 388 | ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL)); | ||
| 389 | kfree(path); | ||
| 390 | return ret; | ||
| 391 | } | ||
| 392 | EXPORT_SYMBOL_GPL(xenbus_write); | ||
| 393 | |||
| 394 | /* Create a new directory. */ | ||
| 395 | int xenbus_mkdir(struct xenbus_transaction t, | ||
| 396 | const char *dir, const char *node) | ||
| 397 | { | ||
| 398 | char *path; | ||
| 399 | int ret; | ||
| 400 | |||
| 401 | path = join(dir, node); | ||
| 402 | if (IS_ERR(path)) | ||
| 403 | return PTR_ERR(path); | ||
| 404 | |||
| 405 | ret = xs_error(xs_single(t, XS_MKDIR, path, NULL)); | ||
| 406 | kfree(path); | ||
| 407 | return ret; | ||
| 408 | } | ||
| 409 | EXPORT_SYMBOL_GPL(xenbus_mkdir); | ||
| 410 | |||
| 411 | /* Destroy a file or directory (directories must be empty). */ | ||
| 412 | int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node) | ||
| 413 | { | ||
| 414 | char *path; | ||
| 415 | int ret; | ||
| 416 | |||
| 417 | path = join(dir, node); | ||
| 418 | if (IS_ERR(path)) | ||
| 419 | return PTR_ERR(path); | ||
| 420 | |||
| 421 | ret = xs_error(xs_single(t, XS_RM, path, NULL)); | ||
| 422 | kfree(path); | ||
| 423 | return ret; | ||
| 424 | } | ||
| 425 | EXPORT_SYMBOL_GPL(xenbus_rm); | ||
| 426 | |||
| 427 | /* Start a transaction: changes by others will not be seen during this | ||
| 428 | * transaction, and changes will not be visible to others until end. | ||
| 429 | */ | ||
| 430 | int xenbus_transaction_start(struct xenbus_transaction *t) | ||
| 431 | { | ||
| 432 | char *id_str; | ||
| 433 | |||
| 434 | down_read(&xs_state.transaction_mutex); | ||
| 435 | |||
| 436 | id_str = xs_single(XBT_NIL, XS_TRANSACTION_START, "", NULL); | ||
| 437 | if (IS_ERR(id_str)) { | ||
| 438 | up_read(&xs_state.transaction_mutex); | ||
| 439 | return PTR_ERR(id_str); | ||
| 440 | } | ||
| 441 | |||
| 442 | t->id = simple_strtoul(id_str, NULL, 0); | ||
| 443 | kfree(id_str); | ||
| 444 | return 0; | ||
| 445 | } | ||
| 446 | EXPORT_SYMBOL_GPL(xenbus_transaction_start); | ||
| 447 | |||
| 448 | /* End a transaction. | ||
| 449 | * If abandon is true, transaction is discarded instead of committed. | ||
| 450 | */ | ||
| 451 | int xenbus_transaction_end(struct xenbus_transaction t, int abort) | ||
| 452 | { | ||
| 453 | char abortstr[2]; | ||
| 454 | int err; | ||
| 455 | |||
| 456 | if (abort) | ||
| 457 | strcpy(abortstr, "F"); | ||
| 458 | else | ||
| 459 | strcpy(abortstr, "T"); | ||
| 460 | |||
| 461 | err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL)); | ||
| 462 | |||
| 463 | up_read(&xs_state.transaction_mutex); | ||
| 464 | |||
| 465 | return err; | ||
| 466 | } | ||
| 467 | EXPORT_SYMBOL_GPL(xenbus_transaction_end); | ||
| 468 | |||
| 469 | /* Single read and scanf: returns -errno or num scanned. */ | ||
| 470 | int xenbus_scanf(struct xenbus_transaction t, | ||
| 471 | const char *dir, const char *node, const char *fmt, ...) | ||
| 472 | { | ||
| 473 | va_list ap; | ||
| 474 | int ret; | ||
| 475 | char *val; | ||
| 476 | |||
| 477 | val = xenbus_read(t, dir, node, NULL); | ||
| 478 | if (IS_ERR(val)) | ||
| 479 | return PTR_ERR(val); | ||
| 480 | |||
| 481 | va_start(ap, fmt); | ||
| 482 | ret = vsscanf(val, fmt, ap); | ||
| 483 | va_end(ap); | ||
| 484 | kfree(val); | ||
| 485 | /* Distinctive errno. */ | ||
| 486 | if (ret == 0) | ||
| 487 | return -ERANGE; | ||
| 488 | return ret; | ||
| 489 | } | ||
| 490 | EXPORT_SYMBOL_GPL(xenbus_scanf); | ||
| 491 | |||
| 492 | /* Single printf and write: returns -errno or 0. */ | ||
| 493 | int xenbus_printf(struct xenbus_transaction t, | ||
| 494 | const char *dir, const char *node, const char *fmt, ...) | ||
| 495 | { | ||
| 496 | va_list ap; | ||
| 497 | int ret; | ||
| 498 | #define PRINTF_BUFFER_SIZE 4096 | ||
| 499 | char *printf_buffer; | ||
| 500 | |||
| 501 | printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL); | ||
| 502 | if (printf_buffer == NULL) | ||
| 503 | return -ENOMEM; | ||
| 504 | |||
| 505 | va_start(ap, fmt); | ||
| 506 | ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap); | ||
| 507 | va_end(ap); | ||
| 508 | |||
| 509 | BUG_ON(ret > PRINTF_BUFFER_SIZE-1); | ||
| 510 | ret = xenbus_write(t, dir, node, printf_buffer); | ||
| 511 | |||
| 512 | kfree(printf_buffer); | ||
| 513 | |||
| 514 | return ret; | ||
| 515 | } | ||
| 516 | EXPORT_SYMBOL_GPL(xenbus_printf); | ||
| 517 | |||
| 518 | /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ | ||
| 519 | int xenbus_gather(struct xenbus_transaction t, const char *dir, ...) | ||
| 520 | { | ||
| 521 | va_list ap; | ||
| 522 | const char *name; | ||
| 523 | int ret = 0; | ||
| 524 | |||
| 525 | va_start(ap, dir); | ||
| 526 | while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { | ||
| 527 | const char *fmt = va_arg(ap, char *); | ||
| 528 | void *result = va_arg(ap, void *); | ||
| 529 | char *p; | ||
| 530 | |||
| 531 | p = xenbus_read(t, dir, name, NULL); | ||
| 532 | if (IS_ERR(p)) { | ||
| 533 | ret = PTR_ERR(p); | ||
| 534 | break; | ||
| 535 | } | ||
| 536 | if (fmt) { | ||
| 537 | if (sscanf(p, fmt, result) == 0) | ||
| 538 | ret = -EINVAL; | ||
| 539 | kfree(p); | ||
| 540 | } else | ||
| 541 | *(char **)result = p; | ||
| 542 | } | ||
| 543 | va_end(ap); | ||
| 544 | return ret; | ||
| 545 | } | ||
| 546 | EXPORT_SYMBOL_GPL(xenbus_gather); | ||
| 547 | |||
| 548 | static int xs_watch(const char *path, const char *token) | ||
| 549 | { | ||
| 550 | struct kvec iov[2]; | ||
| 551 | |||
| 552 | iov[0].iov_base = (void *)path; | ||
| 553 | iov[0].iov_len = strlen(path) + 1; | ||
| 554 | iov[1].iov_base = (void *)token; | ||
| 555 | iov[1].iov_len = strlen(token) + 1; | ||
| 556 | |||
| 557 | return xs_error(xs_talkv(XBT_NIL, XS_WATCH, iov, | ||
| 558 | ARRAY_SIZE(iov), NULL)); | ||
| 559 | } | ||
| 560 | |||
| 561 | static int xs_unwatch(const char *path, const char *token) | ||
| 562 | { | ||
| 563 | struct kvec iov[2]; | ||
| 564 | |||
| 565 | iov[0].iov_base = (char *)path; | ||
| 566 | iov[0].iov_len = strlen(path) + 1; | ||
| 567 | iov[1].iov_base = (char *)token; | ||
| 568 | iov[1].iov_len = strlen(token) + 1; | ||
| 569 | |||
| 570 | return xs_error(xs_talkv(XBT_NIL, XS_UNWATCH, iov, | ||
| 571 | ARRAY_SIZE(iov), NULL)); | ||
| 572 | } | ||
| 573 | |||
| 574 | static struct xenbus_watch *find_watch(const char *token) | ||
| 575 | { | ||
| 576 | struct xenbus_watch *i, *cmp; | ||
| 577 | |||
| 578 | cmp = (void *)simple_strtoul(token, NULL, 16); | ||
| 579 | |||
| 580 | list_for_each_entry(i, &watches, list) | ||
| 581 | if (i == cmp) | ||
| 582 | return i; | ||
| 583 | |||
| 584 | return NULL; | ||
| 585 | } | ||
| 586 | |||
| 587 | /* Register callback to watch this node. */ | ||
| 588 | int register_xenbus_watch(struct xenbus_watch *watch) | ||
| 589 | { | ||
| 590 | /* Pointer in ascii is the token. */ | ||
| 591 | char token[sizeof(watch) * 2 + 1]; | ||
| 592 | int err; | ||
| 593 | |||
| 594 | sprintf(token, "%lX", (long)watch); | ||
| 595 | |||
| 596 | down_read(&xs_state.watch_mutex); | ||
| 597 | |||
| 598 | spin_lock(&watches_lock); | ||
| 599 | BUG_ON(find_watch(token)); | ||
| 600 | list_add(&watch->list, &watches); | ||
| 601 | spin_unlock(&watches_lock); | ||
| 602 | |||
| 603 | err = xs_watch(watch->node, token); | ||
| 604 | |||
| 605 | /* Ignore errors due to multiple registration. */ | ||
| 606 | if ((err != 0) && (err != -EEXIST)) { | ||
| 607 | spin_lock(&watches_lock); | ||
| 608 | list_del(&watch->list); | ||
| 609 | spin_unlock(&watches_lock); | ||
| 610 | } | ||
| 611 | |||
| 612 | up_read(&xs_state.watch_mutex); | ||
| 613 | |||
| 614 | return err; | ||
| 615 | } | ||
| 616 | EXPORT_SYMBOL_GPL(register_xenbus_watch); | ||
| 617 | |||
| 618 | void unregister_xenbus_watch(struct xenbus_watch *watch) | ||
| 619 | { | ||
| 620 | struct xs_stored_msg *msg, *tmp; | ||
| 621 | char token[sizeof(watch) * 2 + 1]; | ||
| 622 | int err; | ||
| 623 | |||
| 624 | sprintf(token, "%lX", (long)watch); | ||
| 625 | |||
| 626 | down_read(&xs_state.watch_mutex); | ||
| 627 | |||
| 628 | spin_lock(&watches_lock); | ||
| 629 | BUG_ON(!find_watch(token)); | ||
| 630 | list_del(&watch->list); | ||
| 631 | spin_unlock(&watches_lock); | ||
| 632 | |||
| 633 | err = xs_unwatch(watch->node, token); | ||
| 634 | if (err) | ||
| 635 | printk(KERN_WARNING | ||
| 636 | "XENBUS Failed to release watch %s: %i\n", | ||
| 637 | watch->node, err); | ||
| 638 | |||
| 639 | up_read(&xs_state.watch_mutex); | ||
| 640 | |||
| 641 | /* Make sure there are no callbacks running currently (unless | ||
| 642 | its us) */ | ||
| 643 | if (current->pid != xenwatch_pid) | ||
| 644 | mutex_lock(&xenwatch_mutex); | ||
| 645 | |||
| 646 | /* Cancel pending watch events. */ | ||
| 647 | spin_lock(&watch_events_lock); | ||
| 648 | list_for_each_entry_safe(msg, tmp, &watch_events, list) { | ||
| 649 | if (msg->u.watch.handle != watch) | ||
| 650 | continue; | ||
| 651 | list_del(&msg->list); | ||
| 652 | kfree(msg->u.watch.vec); | ||
| 653 | kfree(msg); | ||
| 654 | } | ||
| 655 | spin_unlock(&watch_events_lock); | ||
| 656 | |||
| 657 | if (current->pid != xenwatch_pid) | ||
| 658 | mutex_unlock(&xenwatch_mutex); | ||
| 659 | } | ||
| 660 | EXPORT_SYMBOL_GPL(unregister_xenbus_watch); | ||
| 661 | |||
| 662 | void xs_suspend(void) | ||
| 663 | { | ||
| 664 | down_write(&xs_state.transaction_mutex); | ||
| 665 | down_write(&xs_state.watch_mutex); | ||
| 666 | mutex_lock(&xs_state.request_mutex); | ||
| 667 | mutex_lock(&xs_state.response_mutex); | ||
| 668 | } | ||
| 669 | |||
| 670 | void xs_resume(void) | ||
| 671 | { | ||
| 672 | struct xenbus_watch *watch; | ||
| 673 | char token[sizeof(watch) * 2 + 1]; | ||
| 674 | |||
| 675 | mutex_unlock(&xs_state.response_mutex); | ||
| 676 | mutex_unlock(&xs_state.request_mutex); | ||
| 677 | up_write(&xs_state.transaction_mutex); | ||
| 678 | |||
| 679 | /* No need for watches_lock: the watch_mutex is sufficient. */ | ||
| 680 | list_for_each_entry(watch, &watches, list) { | ||
| 681 | sprintf(token, "%lX", (long)watch); | ||
| 682 | xs_watch(watch->node, token); | ||
| 683 | } | ||
| 684 | |||
| 685 | up_write(&xs_state.watch_mutex); | ||
| 686 | } | ||
| 687 | |||
| 688 | void xs_suspend_cancel(void) | ||
| 689 | { | ||
| 690 | mutex_unlock(&xs_state.response_mutex); | ||
| 691 | mutex_unlock(&xs_state.request_mutex); | ||
| 692 | up_write(&xs_state.watch_mutex); | ||
| 693 | up_write(&xs_state.transaction_mutex); | ||
| 694 | } | ||
| 695 | |||
| 696 | static int xenwatch_thread(void *unused) | ||
| 697 | { | ||
| 698 | struct list_head *ent; | ||
| 699 | struct xs_stored_msg *msg; | ||
| 700 | |||
| 701 | for (;;) { | ||
| 702 | wait_event_interruptible(watch_events_waitq, | ||
| 703 | !list_empty(&watch_events)); | ||
| 704 | |||
| 705 | if (kthread_should_stop()) | ||
| 706 | break; | ||
| 707 | |||
| 708 | mutex_lock(&xenwatch_mutex); | ||
| 709 | |||
| 710 | spin_lock(&watch_events_lock); | ||
| 711 | ent = watch_events.next; | ||
| 712 | if (ent != &watch_events) | ||
| 713 | list_del(ent); | ||
| 714 | spin_unlock(&watch_events_lock); | ||
| 715 | |||
| 716 | if (ent != &watch_events) { | ||
| 717 | msg = list_entry(ent, struct xs_stored_msg, list); | ||
| 718 | msg->u.watch.handle->callback( | ||
| 719 | msg->u.watch.handle, | ||
| 720 | (const char **)msg->u.watch.vec, | ||
| 721 | msg->u.watch.vec_size); | ||
| 722 | kfree(msg->u.watch.vec); | ||
| 723 | kfree(msg); | ||
| 724 | } | ||
| 725 | |||
| 726 | mutex_unlock(&xenwatch_mutex); | ||
| 727 | } | ||
| 728 | |||
| 729 | return 0; | ||
| 730 | } | ||
| 731 | |||
| 732 | static int process_msg(void) | ||
| 733 | { | ||
| 734 | struct xs_stored_msg *msg; | ||
| 735 | char *body; | ||
| 736 | int err; | ||
| 737 | |||
| 738 | /* | ||
| 739 | * We must disallow save/restore while reading a xenstore message. | ||
| 740 | * A partial read across s/r leaves us out of sync with xenstored. | ||
| 741 | */ | ||
| 742 | for (;;) { | ||
| 743 | err = xb_wait_for_data_to_read(); | ||
| 744 | if (err) | ||
| 745 | return err; | ||
| 746 | mutex_lock(&xs_state.response_mutex); | ||
| 747 | if (xb_data_to_read()) | ||
| 748 | break; | ||
| 749 | /* We raced with save/restore: pending data 'disappeared'. */ | ||
| 750 | mutex_unlock(&xs_state.response_mutex); | ||
| 751 | } | ||
| 752 | |||
| 753 | |||
| 754 | msg = kmalloc(sizeof(*msg), GFP_KERNEL); | ||
| 755 | if (msg == NULL) { | ||
| 756 | err = -ENOMEM; | ||
| 757 | goto out; | ||
| 758 | } | ||
| 759 | |||
| 760 | err = xb_read(&msg->hdr, sizeof(msg->hdr)); | ||
| 761 | if (err) { | ||
| 762 | kfree(msg); | ||
| 763 | goto out; | ||
| 764 | } | ||
| 765 | |||
| 766 | body = kmalloc(msg->hdr.len + 1, GFP_KERNEL); | ||
| 767 | if (body == NULL) { | ||
| 768 | kfree(msg); | ||
| 769 | err = -ENOMEM; | ||
| 770 | goto out; | ||
| 771 | } | ||
| 772 | |||
| 773 | err = xb_read(body, msg->hdr.len); | ||
| 774 | if (err) { | ||
| 775 | kfree(body); | ||
| 776 | kfree(msg); | ||
| 777 | goto out; | ||
| 778 | } | ||
| 779 | body[msg->hdr.len] = '\0'; | ||
| 780 | |||
| 781 | if (msg->hdr.type == XS_WATCH_EVENT) { | ||
| 782 | msg->u.watch.vec = split(body, msg->hdr.len, | ||
| 783 | &msg->u.watch.vec_size); | ||
| 784 | if (IS_ERR(msg->u.watch.vec)) { | ||
| 785 | kfree(msg); | ||
| 786 | err = PTR_ERR(msg->u.watch.vec); | ||
| 787 | goto out; | ||
| 788 | } | ||
| 789 | |||
| 790 | spin_lock(&watches_lock); | ||
| 791 | msg->u.watch.handle = find_watch( | ||
| 792 | msg->u.watch.vec[XS_WATCH_TOKEN]); | ||
| 793 | if (msg->u.watch.handle != NULL) { | ||
| 794 | spin_lock(&watch_events_lock); | ||
| 795 | list_add_tail(&msg->list, &watch_events); | ||
| 796 | wake_up(&watch_events_waitq); | ||
| 797 | spin_unlock(&watch_events_lock); | ||
| 798 | } else { | ||
| 799 | kfree(msg->u.watch.vec); | ||
| 800 | kfree(msg); | ||
| 801 | } | ||
| 802 | spin_unlock(&watches_lock); | ||
| 803 | } else { | ||
| 804 | msg->u.reply.body = body; | ||
| 805 | spin_lock(&xs_state.reply_lock); | ||
| 806 | list_add_tail(&msg->list, &xs_state.reply_list); | ||
| 807 | spin_unlock(&xs_state.reply_lock); | ||
| 808 | wake_up(&xs_state.reply_waitq); | ||
| 809 | } | ||
| 810 | |||
| 811 | out: | ||
| 812 | mutex_unlock(&xs_state.response_mutex); | ||
| 813 | return err; | ||
| 814 | } | ||
| 815 | |||
| 816 | static int xenbus_thread(void *unused) | ||
| 817 | { | ||
| 818 | int err; | ||
| 819 | |||
| 820 | for (;;) { | ||
| 821 | err = process_msg(); | ||
| 822 | if (err) | ||
| 823 | printk(KERN_WARNING "XENBUS error %d while reading " | ||
| 824 | "message\n", err); | ||
| 825 | if (kthread_should_stop()) | ||
| 826 | break; | ||
| 827 | } | ||
| 828 | |||
| 829 | return 0; | ||
| 830 | } | ||
| 831 | |||
| 832 | int xs_init(void) | ||
| 833 | { | ||
| 834 | int err; | ||
| 835 | struct task_struct *task; | ||
| 836 | |||
| 837 | INIT_LIST_HEAD(&xs_state.reply_list); | ||
| 838 | spin_lock_init(&xs_state.reply_lock); | ||
| 839 | init_waitqueue_head(&xs_state.reply_waitq); | ||
| 840 | |||
| 841 | mutex_init(&xs_state.request_mutex); | ||
| 842 | mutex_init(&xs_state.response_mutex); | ||
| 843 | init_rwsem(&xs_state.transaction_mutex); | ||
| 844 | init_rwsem(&xs_state.watch_mutex); | ||
| 845 | |||
| 846 | /* Initialize the shared memory rings to talk to xenstored */ | ||
| 847 | err = xb_init_comms(); | ||
| 848 | if (err) | ||
| 849 | return err; | ||
| 850 | |||
| 851 | task = kthread_run(xenwatch_thread, NULL, "xenwatch"); | ||
| 852 | if (IS_ERR(task)) | ||
| 853 | return PTR_ERR(task); | ||
| 854 | xenwatch_pid = task->pid; | ||
| 855 | |||
| 856 | task = kthread_run(xenbus_thread, NULL, "xenbus"); | ||
| 857 | if (IS_ERR(task)) | ||
| 858 | return PTR_ERR(task); | ||
| 859 | |||
| 860 | return 0; | ||
| 861 | } | ||
diff --git a/include/asm-i386/xen/hypervisor.h b/include/asm-i386/xen/hypervisor.h index ebfa7e063088..8e15dd28c91f 100644 --- a/include/asm-i386/xen/hypervisor.h +++ b/include/asm-i386/xen/hypervisor.h | |||
| @@ -42,6 +42,7 @@ | |||
| 42 | 42 | ||
| 43 | #include <asm/ptrace.h> | 43 | #include <asm/ptrace.h> |
| 44 | #include <asm/page.h> | 44 | #include <asm/page.h> |
| 45 | #include <asm/desc.h> | ||
| 45 | #if defined(__i386__) | 46 | #if defined(__i386__) |
| 46 | # ifdef CONFIG_X86_PAE | 47 | # ifdef CONFIG_X86_PAE |
| 47 | # include <asm-generic/pgtable-nopud.h> | 48 | # include <asm-generic/pgtable-nopud.h> |
diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h new file mode 100644 index 000000000000..6f7c290651ae --- /dev/null +++ b/include/xen/xenbus.h | |||
| @@ -0,0 +1,234 @@ | |||
| 1 | /****************************************************************************** | ||
| 2 | * xenbus.h | ||
| 3 | * | ||
| 4 | * Talks to Xen Store to figure out what devices we have. | ||
| 5 | * | ||
| 6 | * Copyright (C) 2005 Rusty Russell, IBM Corporation | ||
| 7 | * Copyright (C) 2005 XenSource Ltd. | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU General Public License version 2 | ||
| 11 | * as published by the Free Software Foundation; or, when distributed | ||
| 12 | * separately from the Linux kernel or incorporated into other | ||
| 13 | * software packages, subject to the following license: | ||
| 14 | * | ||
| 15 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 16 | * of this source file (the "Software"), to deal in the Software without | ||
| 17 | * restriction, including without limitation the rights to use, copy, modify, | ||
| 18 | * merge, publish, distribute, sublicense, and/or sell copies of the Software, | ||
| 19 | * and to permit persons to whom the Software is furnished to do so, subject to | ||
| 20 | * the following conditions: | ||
| 21 | * | ||
| 22 | * The above copyright notice and this permission notice shall be included in | ||
| 23 | * all copies or substantial portions of the Software. | ||
| 24 | * | ||
| 25 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 26 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 27 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 28 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 29 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| 30 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS | ||
| 31 | * IN THE SOFTWARE. | ||
| 32 | */ | ||
| 33 | |||
| 34 | #ifndef _XEN_XENBUS_H | ||
| 35 | #define _XEN_XENBUS_H | ||
| 36 | |||
| 37 | #include <linux/device.h> | ||
| 38 | #include <linux/notifier.h> | ||
| 39 | #include <linux/mutex.h> | ||
| 40 | #include <linux/completion.h> | ||
| 41 | #include <linux/init.h> | ||
| 42 | #include <xen/interface/xen.h> | ||
| 43 | #include <xen/interface/grant_table.h> | ||
| 44 | #include <xen/interface/io/xenbus.h> | ||
| 45 | #include <xen/interface/io/xs_wire.h> | ||
| 46 | |||
| 47 | /* Register callback to watch this node. */ | ||
| 48 | struct xenbus_watch | ||
| 49 | { | ||
| 50 | struct list_head list; | ||
| 51 | |||
| 52 | /* Path being watched. */ | ||
| 53 | const char *node; | ||
| 54 | |||
| 55 | /* Callback (executed in a process context with no locks held). */ | ||
| 56 | void (*callback)(struct xenbus_watch *, | ||
| 57 | const char **vec, unsigned int len); | ||
| 58 | }; | ||
| 59 | |||
| 60 | |||
| 61 | /* A xenbus device. */ | ||
| 62 | struct xenbus_device { | ||
| 63 | const char *devicetype; | ||
| 64 | const char *nodename; | ||
| 65 | const char *otherend; | ||
| 66 | int otherend_id; | ||
| 67 | struct xenbus_watch otherend_watch; | ||
| 68 | struct device dev; | ||
| 69 | enum xenbus_state state; | ||
| 70 | struct completion down; | ||
| 71 | }; | ||
| 72 | |||
| 73 | static inline struct xenbus_device *to_xenbus_device(struct device *dev) | ||
| 74 | { | ||
| 75 | return container_of(dev, struct xenbus_device, dev); | ||
| 76 | } | ||
| 77 | |||
| 78 | struct xenbus_device_id | ||
| 79 | { | ||
| 80 | /* .../device/<device_type>/<identifier> */ | ||
| 81 | char devicetype[32]; /* General class of device. */ | ||
| 82 | }; | ||
| 83 | |||
| 84 | /* A xenbus driver. */ | ||
| 85 | struct xenbus_driver { | ||
| 86 | char *name; | ||
| 87 | struct module *owner; | ||
| 88 | const struct xenbus_device_id *ids; | ||
| 89 | int (*probe)(struct xenbus_device *dev, | ||
| 90 | const struct xenbus_device_id *id); | ||
| 91 | void (*otherend_changed)(struct xenbus_device *dev, | ||
| 92 | enum xenbus_state backend_state); | ||
| 93 | int (*remove)(struct xenbus_device *dev); | ||
| 94 | int (*suspend)(struct xenbus_device *dev); | ||
| 95 | int (*suspend_cancel)(struct xenbus_device *dev); | ||
| 96 | int (*resume)(struct xenbus_device *dev); | ||
| 97 | int (*uevent)(struct xenbus_device *, char **, int, char *, int); | ||
| 98 | struct device_driver driver; | ||
| 99 | int (*read_otherend_details)(struct xenbus_device *dev); | ||
| 100 | }; | ||
| 101 | |||
| 102 | static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv) | ||
| 103 | { | ||
| 104 | return container_of(drv, struct xenbus_driver, driver); | ||
| 105 | } | ||
| 106 | |||
| 107 | int __must_check __xenbus_register_frontend(struct xenbus_driver *drv, | ||
| 108 | struct module *owner, | ||
| 109 | const char *mod_name); | ||
| 110 | |||
| 111 | static inline int __must_check | ||
| 112 | xenbus_register_frontend(struct xenbus_driver *drv) | ||
| 113 | { | ||
| 114 | WARN_ON(drv->owner != THIS_MODULE); | ||
| 115 | return __xenbus_register_frontend(drv, THIS_MODULE, KBUILD_MODNAME); | ||
| 116 | } | ||
| 117 | |||
| 118 | int __must_check __xenbus_register_backend(struct xenbus_driver *drv, | ||
| 119 | struct module *owner, | ||
| 120 | const char *mod_name); | ||
| 121 | static inline int __must_check | ||
| 122 | xenbus_register_backend(struct xenbus_driver *drv) | ||
| 123 | { | ||
| 124 | WARN_ON(drv->owner != THIS_MODULE); | ||
| 125 | return __xenbus_register_backend(drv, THIS_MODULE, KBUILD_MODNAME); | ||
| 126 | } | ||
| 127 | |||
| 128 | void xenbus_unregister_driver(struct xenbus_driver *drv); | ||
| 129 | |||
| 130 | struct xenbus_transaction | ||
| 131 | { | ||
| 132 | u32 id; | ||
| 133 | }; | ||
| 134 | |||
| 135 | /* Nil transaction ID. */ | ||
| 136 | #define XBT_NIL ((struct xenbus_transaction) { 0 }) | ||
| 137 | |||
| 138 | int __init xenbus_dev_init(void); | ||
| 139 | |||
| 140 | char **xenbus_directory(struct xenbus_transaction t, | ||
| 141 | const char *dir, const char *node, unsigned int *num); | ||
| 142 | void *xenbus_read(struct xenbus_transaction t, | ||
| 143 | const char *dir, const char *node, unsigned int *len); | ||
| 144 | int xenbus_write(struct xenbus_transaction t, | ||
| 145 | const char *dir, const char *node, const char *string); | ||
| 146 | int xenbus_mkdir(struct xenbus_transaction t, | ||
| 147 | const char *dir, const char *node); | ||
| 148 | int xenbus_exists(struct xenbus_transaction t, | ||
| 149 | const char *dir, const char *node); | ||
| 150 | int xenbus_rm(struct xenbus_transaction t, const char *dir, const char *node); | ||
| 151 | int xenbus_transaction_start(struct xenbus_transaction *t); | ||
| 152 | int xenbus_transaction_end(struct xenbus_transaction t, int abort); | ||
| 153 | |||
| 154 | /* Single read and scanf: returns -errno or num scanned if > 0. */ | ||
| 155 | int xenbus_scanf(struct xenbus_transaction t, | ||
| 156 | const char *dir, const char *node, const char *fmt, ...) | ||
| 157 | __attribute__((format(scanf, 4, 5))); | ||
| 158 | |||
| 159 | /* Single printf and write: returns -errno or 0. */ | ||
| 160 | int xenbus_printf(struct xenbus_transaction t, | ||
| 161 | const char *dir, const char *node, const char *fmt, ...) | ||
| 162 | __attribute__((format(printf, 4, 5))); | ||
| 163 | |||
| 164 | /* Generic read function: NULL-terminated triples of name, | ||
| 165 | * sprintf-style type string, and pointer. Returns 0 or errno.*/ | ||
| 166 | int xenbus_gather(struct xenbus_transaction t, const char *dir, ...); | ||
| 167 | |||
| 168 | /* notifer routines for when the xenstore comes up */ | ||
| 169 | extern int xenstored_ready; | ||
| 170 | int register_xenstore_notifier(struct notifier_block *nb); | ||
| 171 | void unregister_xenstore_notifier(struct notifier_block *nb); | ||
| 172 | |||
| 173 | int register_xenbus_watch(struct xenbus_watch *watch); | ||
| 174 | void unregister_xenbus_watch(struct xenbus_watch *watch); | ||
| 175 | void xs_suspend(void); | ||
| 176 | void xs_resume(void); | ||
| 177 | void xs_suspend_cancel(void); | ||
| 178 | |||
| 179 | /* Used by xenbus_dev to borrow kernel's store connection. */ | ||
| 180 | void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg); | ||
| 181 | |||
| 182 | struct work_struct; | ||
| 183 | |||
| 184 | /* Prepare for domain suspend: then resume or cancel the suspend. */ | ||
| 185 | void xenbus_suspend(void); | ||
| 186 | void xenbus_resume(void); | ||
| 187 | void xenbus_probe(struct work_struct *); | ||
| 188 | void xenbus_suspend_cancel(void); | ||
| 189 | |||
| 190 | #define XENBUS_IS_ERR_READ(str) ({ \ | ||
| 191 | if (!IS_ERR(str) && strlen(str) == 0) { \ | ||
| 192 | kfree(str); \ | ||
| 193 | str = ERR_PTR(-ERANGE); \ | ||
| 194 | } \ | ||
| 195 | IS_ERR(str); \ | ||
| 196 | }) | ||
| 197 | |||
| 198 | #define XENBUS_EXIST_ERR(err) ((err) == -ENOENT || (err) == -ERANGE) | ||
| 199 | |||
| 200 | int xenbus_watch_path(struct xenbus_device *dev, const char *path, | ||
| 201 | struct xenbus_watch *watch, | ||
| 202 | void (*callback)(struct xenbus_watch *, | ||
| 203 | const char **, unsigned int)); | ||
| 204 | int xenbus_watch_pathfmt(struct xenbus_device *dev, struct xenbus_watch *watch, | ||
| 205 | void (*callback)(struct xenbus_watch *, | ||
| 206 | const char **, unsigned int), | ||
| 207 | const char *pathfmt, ...) | ||
| 208 | __attribute__ ((format (printf, 4, 5))); | ||
| 209 | |||
| 210 | int xenbus_switch_state(struct xenbus_device *dev, enum xenbus_state new_state); | ||
| 211 | int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn); | ||
| 212 | int xenbus_map_ring_valloc(struct xenbus_device *dev, | ||
| 213 | int gnt_ref, void **vaddr); | ||
| 214 | int xenbus_map_ring(struct xenbus_device *dev, int gnt_ref, | ||
| 215 | grant_handle_t *handle, void *vaddr); | ||
| 216 | |||
| 217 | int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr); | ||
| 218 | int xenbus_unmap_ring(struct xenbus_device *dev, | ||
| 219 | grant_handle_t handle, void *vaddr); | ||
| 220 | |||
| 221 | int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port); | ||
| 222 | int xenbus_bind_evtchn(struct xenbus_device *dev, int remote_port, int *port); | ||
| 223 | int xenbus_free_evtchn(struct xenbus_device *dev, int port); | ||
| 224 | |||
| 225 | enum xenbus_state xenbus_read_driver_state(const char *path); | ||
| 226 | |||
| 227 | void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...); | ||
| 228 | void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt, ...); | ||
| 229 | |||
| 230 | const char *xenbus_strstate(enum xenbus_state state); | ||
| 231 | int xenbus_dev_is_online(struct xenbus_device *dev); | ||
| 232 | int xenbus_frontend_closed(struct xenbus_device *dev); | ||
| 233 | |||
| 234 | #endif /* _XEN_XENBUS_H */ | ||
