xen-vtx-unstable
annotate linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c @ 6600:87ea297c1d3a
Add driver to use the kernel's xenbus connection from user-space.
The driver exports xs_talkv to user-space, allowing programs running in
the domain to use the kernel's xenbus connection. Intended use is driver
domain device configuration where the driver domain is not the domain
running xenstored.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
The driver exports xs_talkv to user-space, allowing programs running in
the domain to use the kernel's xenbus connection. Intended use is driver
domain device configuration where the driver domain is not the domain
running xenstored.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author | cl349@firebug.cl.cam.ac.uk |
---|---|
date | Sat Sep 03 16:52:12 2005 +0000 (2005-09-03) |
parents | dd668f7527cb |
children | f27205ea60ef |
rev | line source |
---|---|
cl349@5598 | 1 /****************************************************************************** |
cl349@5598 | 2 * xenbus_xs.c |
cl349@5598 | 3 * |
cl349@5598 | 4 * This is the kernel equivalent of the "xs" library. We don't need everything |
cl349@5863 | 5 * and we use xenbus_comms for communication. |
cl349@5598 | 6 * |
cl349@5598 | 7 * Copyright (C) 2005 Rusty Russell, IBM Corporation |
cl349@5598 | 8 * |
cl349@5598 | 9 * This file may be distributed separately from the Linux kernel, or |
cl349@5598 | 10 * incorporated into other software packages, subject to the following license: |
cl349@5598 | 11 * |
cl349@5598 | 12 * Permission is hereby granted, free of charge, to any person obtaining a copy |
cl349@5598 | 13 * of this source file (the "Software"), to deal in the Software without |
cl349@5598 | 14 * restriction, including without limitation the rights to use, copy, modify, |
cl349@5598 | 15 * merge, publish, distribute, sublicense, and/or sell copies of the Software, |
cl349@5598 | 16 * and to permit persons to whom the Software is furnished to do so, subject to |
cl349@5598 | 17 * the following conditions: |
cl349@5598 | 18 * |
cl349@5598 | 19 * The above copyright notice and this permission notice shall be included in |
cl349@5598 | 20 * all copies or substantial portions of the Software. |
cl349@5598 | 21 * |
cl349@5598 | 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
cl349@5598 | 23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
cl349@5598 | 24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
cl349@5598 | 25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
cl349@5598 | 26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
cl349@5598 | 27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
cl349@5598 | 28 * IN THE SOFTWARE. |
cl349@5598 | 29 */ |
cl349@5598 | 30 |
cl349@5598 | 31 #include <linux/errno.h> |
cl349@5598 | 32 #include <linux/types.h> |
cl349@5598 | 33 #include <linux/uio.h> |
cl349@5598 | 34 #include <linux/kernel.h> |
cl349@5598 | 35 #include <linux/string.h> |
cl349@5598 | 36 #include <linux/err.h> |
cl349@5598 | 37 #include <linux/slab.h> |
cl349@5598 | 38 #include <linux/fcntl.h> |
cl349@5598 | 39 #include <linux/kthread.h> |
cl349@5598 | 40 #include <asm-xen/xenbus.h> |
kaf24@6065 | 41 #include "xenstored.h" |
cl349@5598 | 42 #include "xenbus_comms.h" |
cl349@5598 | 43 |
cl349@5598 | 44 #define streq(a, b) (strcmp((a), (b)) == 0) |
cl349@5598 | 45 |
cl349@5874 | 46 static char printf_buffer[4096]; |
cl349@5598 | 47 static LIST_HEAD(watches); |
kaf24@6480 | 48 |
cl349@5863 | 49 DECLARE_MUTEX(xenbus_lock); |
kaf24@6480 | 50 EXPORT_SYMBOL(xenbus_lock); |
cl349@5598 | 51 |
cl349@5598 | 52 static int get_error(const char *errorstring) |
cl349@5598 | 53 { |
cl349@5598 | 54 unsigned int i; |
cl349@5598 | 55 |
cl349@5598 | 56 for (i = 0; !streq(errorstring, xsd_errors[i].errstring); i++) { |
cl349@5598 | 57 if (i == ARRAY_SIZE(xsd_errors) - 1) { |
cl349@5670 | 58 printk(KERN_WARNING |
cl349@5670 | 59 "XENBUS xen store gave: unknown error %s", |
cl349@5598 | 60 errorstring); |
cl349@5598 | 61 return EINVAL; |
cl349@5598 | 62 } |
cl349@5598 | 63 } |
cl349@5598 | 64 return xsd_errors[i].errnum; |
cl349@5598 | 65 } |
cl349@5598 | 66 |
cl349@5598 | 67 static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) |
cl349@5598 | 68 { |
cl349@5598 | 69 struct xsd_sockmsg msg; |
cl349@5598 | 70 void *ret; |
cl349@5598 | 71 int err; |
cl349@5598 | 72 |
cl349@5902 | 73 err = xb_read(&msg, sizeof(msg)); |
cl349@5598 | 74 if (err) |
cl349@5598 | 75 return ERR_PTR(err); |
cl349@5598 | 76 |
cl349@5598 | 77 ret = kmalloc(msg.len + 1, GFP_KERNEL); |
cl349@5598 | 78 if (!ret) |
cl349@5598 | 79 return ERR_PTR(-ENOMEM); |
cl349@5598 | 80 |
cl349@5902 | 81 err = xb_read(ret, msg.len); |
cl349@5598 | 82 if (err) { |
cl349@5598 | 83 kfree(ret); |
cl349@5598 | 84 return ERR_PTR(err); |
cl349@5598 | 85 } |
cl349@5598 | 86 ((char*)ret)[msg.len] = '\0'; |
cl349@5598 | 87 |
cl349@5598 | 88 *type = msg.type; |
cl349@5598 | 89 if (len) |
cl349@5598 | 90 *len = msg.len; |
cl349@5598 | 91 return ret; |
cl349@5598 | 92 } |
cl349@5598 | 93 |
cl349@5747 | 94 /* Emergency write. */ |
cl349@5863 | 95 void xenbus_debug_write(const char *str, unsigned int count) |
cl349@5747 | 96 { |
cl349@5747 | 97 struct xsd_sockmsg msg; |
cl349@5747 | 98 |
cl349@5747 | 99 msg.type = XS_DEBUG; |
cl349@5747 | 100 msg.len = sizeof("print") + count + 1; |
cl349@5747 | 101 |
cl349@5902 | 102 xb_write(&msg, sizeof(msg)); |
cl349@5902 | 103 xb_write("print", sizeof("print")); |
cl349@5902 | 104 xb_write(str, count); |
cl349@5902 | 105 xb_write("", 1); |
cl349@5747 | 106 } |
cl349@5747 | 107 |
cl349@5598 | 108 /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ |
cl349@6600 | 109 void *xs_talkv(enum xsd_sockmsg_type type, |
cl349@6600 | 110 const struct kvec *iovec, |
cl349@6600 | 111 unsigned int num_vecs, |
cl349@6600 | 112 unsigned int *len) |
cl349@5598 | 113 { |
cl349@5598 | 114 struct xsd_sockmsg msg; |
cl349@5598 | 115 void *ret = NULL; |
cl349@5598 | 116 unsigned int i; |
cl349@5598 | 117 int err; |
cl349@5598 | 118 |
cl349@5863 | 119 WARN_ON(down_trylock(&xenbus_lock) == 0); |
cl349@5598 | 120 |
cl349@5598 | 121 msg.type = type; |
cl349@5598 | 122 msg.len = 0; |
cl349@5598 | 123 for (i = 0; i < num_vecs; i++) |
cl349@5598 | 124 msg.len += iovec[i].iov_len; |
cl349@5598 | 125 |
cl349@5902 | 126 err = xb_write(&msg, sizeof(msg)); |
cl349@5598 | 127 if (err) |
cl349@5598 | 128 return ERR_PTR(err); |
cl349@5598 | 129 |
cl349@5598 | 130 for (i = 0; i < num_vecs; i++) { |
cl349@5902 | 131 err = xb_write(iovec[i].iov_base, iovec[i].iov_len);; |
cl349@5598 | 132 if (err) |
cl349@5598 | 133 return ERR_PTR(err); |
cl349@5598 | 134 } |
cl349@5598 | 135 |
cl349@5598 | 136 /* Watches can have fired before reply comes: daemon detects |
cl349@5598 | 137 * and re-transmits, so we can ignore this. */ |
cl349@5598 | 138 do { |
cl349@5598 | 139 kfree(ret); |
cl349@5598 | 140 ret = read_reply(&msg.type, len); |
cl349@5598 | 141 if (IS_ERR(ret)) |
cl349@5598 | 142 return ret; |
cl349@5598 | 143 } while (msg.type == XS_WATCH_EVENT); |
cl349@5598 | 144 |
cl349@5598 | 145 if (msg.type == XS_ERROR) { |
cl349@5598 | 146 err = get_error(ret); |
cl349@5598 | 147 kfree(ret); |
cl349@5598 | 148 return ERR_PTR(-err); |
cl349@5598 | 149 } |
cl349@5598 | 150 |
cl349@5598 | 151 BUG_ON(msg.type != type); |
cl349@5598 | 152 return ret; |
cl349@5598 | 153 } |
cl349@5598 | 154 |
cl349@5598 | 155 /* Simplified version of xs_talkv: single message. */ |
cl349@5598 | 156 static void *xs_single(enum xsd_sockmsg_type type, |
cl349@5598 | 157 const char *string, unsigned int *len) |
cl349@5598 | 158 { |
cl349@5598 | 159 struct kvec iovec; |
cl349@5598 | 160 |
cl349@5598 | 161 iovec.iov_base = (void *)string; |
cl349@5598 | 162 iovec.iov_len = strlen(string) + 1; |
cl349@5598 | 163 return xs_talkv(type, &iovec, 1, len); |
cl349@5598 | 164 } |
cl349@5598 | 165 |
cl349@5598 | 166 /* Many commands only need an ack, don't care what it says. */ |
cl349@5598 | 167 static int xs_error(char *reply) |
cl349@5598 | 168 { |
cl349@5598 | 169 if (IS_ERR(reply)) |
cl349@5598 | 170 return PTR_ERR(reply); |
cl349@5598 | 171 kfree(reply); |
cl349@5598 | 172 return 0; |
cl349@5598 | 173 } |
cl349@5598 | 174 |
cl349@5598 | 175 static unsigned int count_strings(const char *strings, unsigned int len) |
cl349@5598 | 176 { |
cl349@5598 | 177 unsigned int num; |
cl349@5598 | 178 const char *p; |
cl349@5598 | 179 |
cl349@5598 | 180 for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) |
cl349@5598 | 181 num++; |
cl349@5598 | 182 |
cl349@5598 | 183 return num; |
cl349@5598 | 184 } |
cl349@5598 | 185 |
cl349@5863 | 186 /* Return the path to dir with /name appended. */ |
cl349@5863 | 187 static char *join(const char *dir, const char *name) |
cl349@5863 | 188 { |
cl349@5863 | 189 static char buffer[4096]; |
cl349@5863 | 190 |
cl349@5863 | 191 BUG_ON(down_trylock(&xenbus_lock) == 0); |
cl349@6250 | 192 /* XXX FIXME: might not be correct if name == "" */ |
cl349@5863 | 193 BUG_ON(strlen(dir) + strlen("/") + strlen(name) + 1 > sizeof(buffer)); |
cl349@5863 | 194 |
cl349@5863 | 195 strcpy(buffer, dir); |
cl349@5863 | 196 if (!streq(name, "")) { |
cl349@5863 | 197 strcat(buffer, "/"); |
cl349@5863 | 198 strcat(buffer, name); |
cl349@5863 | 199 } |
cl349@5863 | 200 return buffer; |
cl349@5863 | 201 } |
cl349@5863 | 202 |
cl349@5863 | 203 char **xenbus_directory(const char *dir, const char *node, unsigned int *num) |
cl349@5598 | 204 { |
cl349@5598 | 205 char *strings, *p, **ret; |
cl349@5598 | 206 unsigned int len; |
cl349@5598 | 207 |
cl349@5863 | 208 strings = xs_single(XS_DIRECTORY, join(dir, node), &len); |
cl349@5598 | 209 if (IS_ERR(strings)) |
cl349@5598 | 210 return (char **)strings; |
cl349@5598 | 211 |
cl349@5598 | 212 /* Count the strings. */ |
cl349@5598 | 213 *num = count_strings(strings, len); |
cl349@5598 | 214 |
cl349@5598 | 215 /* Transfer to one big alloc for easy freeing. */ |
cl349@5598 | 216 ret = kmalloc(*num * sizeof(char *) + len, GFP_ATOMIC); |
cl349@5598 | 217 if (!ret) { |
cl349@5598 | 218 kfree(strings); |
cl349@5598 | 219 return ERR_PTR(-ENOMEM); |
cl349@5598 | 220 } |
cl349@5598 | 221 memcpy(&ret[*num], strings, len); |
cl349@5598 | 222 kfree(strings); |
cl349@5598 | 223 |
cl349@5598 | 224 strings = (char *)&ret[*num]; |
cl349@5598 | 225 for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1) |
cl349@5598 | 226 ret[(*num)++] = p; |
cl349@5598 | 227 return ret; |
cl349@5598 | 228 } |
kaf24@6480 | 229 EXPORT_SYMBOL(xenbus_directory); |
cl349@5598 | 230 |
cl349@5598 | 231 /* Check if a path exists. Return 1 if it does. */ |
cl349@5863 | 232 int xenbus_exists(const char *dir, const char *node) |
cl349@5598 | 233 { |
cl349@5863 | 234 char **d; |
cl349@5670 | 235 int dir_n; |
cl349@5598 | 236 |
cl349@5867 | 237 d = xenbus_directory(dir, node, &dir_n); |
cl349@5863 | 238 if (IS_ERR(d)) |
cl349@5670 | 239 return 0; |
cl349@5863 | 240 kfree(d); |
cl349@5670 | 241 return 1; |
cl349@5598 | 242 } |
kaf24@6480 | 243 EXPORT_SYMBOL(xenbus_exists); |
cl349@5598 | 244 |
cl349@5598 | 245 /* Get the value of a single file. |
cl349@5598 | 246 * Returns a kmalloced value: call free() on it after use. |
cl349@5598 | 247 * len indicates length in bytes. |
cl349@5598 | 248 */ |
cl349@5863 | 249 void *xenbus_read(const char *dir, const char *node, unsigned int *len) |
cl349@5598 | 250 { |
cl349@5863 | 251 return xs_single(XS_READ, join(dir, node), len); |
cl349@5598 | 252 } |
kaf24@6467 | 253 EXPORT_SYMBOL(xenbus_read); |
cl349@5598 | 254 |
cl349@5598 | 255 /* Write the value of a single file. |
cl349@5598 | 256 * Returns -err on failure. createflags can be 0, O_CREAT, or O_CREAT|O_EXCL. |
cl349@5598 | 257 */ |
cl349@5863 | 258 int xenbus_write(const char *dir, const char *node, |
cl349@5863 | 259 const char *string, int createflags) |
cl349@5598 | 260 { |
cl349@5863 | 261 const char *flags, *path; |
cl349@5598 | 262 struct kvec iovec[3]; |
cl349@5598 | 263 |
cl349@5863 | 264 path = join(dir, node); |
cl349@5598 | 265 /* Format: Flags (as string), path, data. */ |
cl349@5598 | 266 if (createflags == 0) |
cl349@5598 | 267 flags = XS_WRITE_NONE; |
cl349@5598 | 268 else if (createflags == O_CREAT) |
cl349@5598 | 269 flags = XS_WRITE_CREATE; |
cl349@5598 | 270 else if (createflags == (O_CREAT|O_EXCL)) |
cl349@5598 | 271 flags = XS_WRITE_CREATE_EXCL; |
cl349@5598 | 272 else |
cl349@5598 | 273 return -EINVAL; |
cl349@5598 | 274 |
cl349@5598 | 275 iovec[0].iov_base = (void *)path; |
cl349@5598 | 276 iovec[0].iov_len = strlen(path) + 1; |
cl349@5598 | 277 iovec[1].iov_base = (void *)flags; |
cl349@5598 | 278 iovec[1].iov_len = strlen(flags) + 1; |
cl349@5863 | 279 iovec[2].iov_base = (void *)string; |
cl349@5863 | 280 iovec[2].iov_len = strlen(string); |
cl349@5598 | 281 |
cl349@5598 | 282 return xs_error(xs_talkv(XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL)); |
cl349@5598 | 283 } |
kaf24@6480 | 284 EXPORT_SYMBOL(xenbus_write); |
cl349@5598 | 285 |
cl349@5598 | 286 /* Create a new directory. */ |
cl349@5863 | 287 int xenbus_mkdir(const char *dir, const char *node) |
cl349@5598 | 288 { |
cl349@5863 | 289 return xs_error(xs_single(XS_MKDIR, join(dir, node), NULL)); |
cl349@5598 | 290 } |
kaf24@6480 | 291 EXPORT_SYMBOL(xenbus_mkdir); |
cl349@5598 | 292 |
cl349@5598 | 293 /* Destroy a file or directory (directories must be empty). */ |
cl349@5863 | 294 int xenbus_rm(const char *dir, const char *node) |
cl349@5598 | 295 { |
cl349@5863 | 296 return xs_error(xs_single(XS_RM, join(dir, node), NULL)); |
cl349@5598 | 297 } |
kaf24@6480 | 298 EXPORT_SYMBOL(xenbus_rm); |
cl349@5598 | 299 |
cl349@5598 | 300 /* Start a transaction: changes by others will not be seen during this |
cl349@5598 | 301 * transaction, and changes will not be visible to others until end. |
cl349@5598 | 302 * Transaction only applies to the given subtree. |
cl349@5598 | 303 * You can only have one transaction at any time. |
cl349@5598 | 304 */ |
cl349@5863 | 305 int xenbus_transaction_start(const char *subtree) |
cl349@5598 | 306 { |
cl349@5598 | 307 return xs_error(xs_single(XS_TRANSACTION_START, subtree, NULL)); |
cl349@5598 | 308 } |
kaf24@6467 | 309 EXPORT_SYMBOL(xenbus_transaction_start); |
cl349@5598 | 310 |
cl349@5598 | 311 /* End a transaction. |
cl349@5598 | 312 * If abandon is true, transaction is discarded instead of committed. |
cl349@5598 | 313 */ |
cl349@5863 | 314 int xenbus_transaction_end(int abort) |
cl349@5598 | 315 { |
cl349@5598 | 316 char abortstr[2]; |
cl349@5598 | 317 |
cl349@5598 | 318 if (abort) |
cl349@5598 | 319 strcpy(abortstr, "F"); |
cl349@5598 | 320 else |
cl349@5598 | 321 strcpy(abortstr, "T"); |
cl349@5598 | 322 return xs_error(xs_single(XS_TRANSACTION_END, abortstr, NULL)); |
cl349@5598 | 323 } |
kaf24@6467 | 324 EXPORT_SYMBOL(xenbus_transaction_end); |
cl349@5598 | 325 |
cl349@5863 | 326 /* Single read and scanf: returns -errno or num scanned. */ |
cl349@5863 | 327 int xenbus_scanf(const char *dir, const char *node, const char *fmt, ...) |
cl349@5598 | 328 { |
cl349@5863 | 329 va_list ap; |
cl349@5863 | 330 int ret; |
cl349@5863 | 331 char *val; |
cl349@5863 | 332 |
cl349@5863 | 333 val = xenbus_read(dir, node, NULL); |
cl349@5863 | 334 if (IS_ERR(val)) |
cl349@5863 | 335 return PTR_ERR(val); |
cl349@5598 | 336 |
cl349@5863 | 337 va_start(ap, fmt); |
cl349@5863 | 338 ret = vsscanf(val, fmt, ap); |
cl349@5863 | 339 va_end(ap); |
cl349@5863 | 340 kfree(val); |
cl349@5863 | 341 /* Distinctive errno. */ |
cl349@5863 | 342 if (ret == 0) |
cl349@5863 | 343 return -ERANGE; |
cl349@5863 | 344 return ret; |
cl349@5863 | 345 } |
kaf24@6467 | 346 EXPORT_SYMBOL(xenbus_scanf); |
cl349@5863 | 347 |
cl349@5863 | 348 /* Single printf and write: returns -errno or 0. */ |
cl349@5863 | 349 int xenbus_printf(const char *dir, const char *node, const char *fmt, ...) |
cl349@5598 | 350 { |
cl349@5863 | 351 va_list ap; |
cl349@5863 | 352 int ret; |
cl349@5863 | 353 |
cl349@5863 | 354 BUG_ON(down_trylock(&xenbus_lock) == 0); |
cl349@5863 | 355 va_start(ap, fmt); |
cl349@5874 | 356 ret = vsnprintf(printf_buffer, sizeof(printf_buffer), fmt, ap); |
cl349@5863 | 357 va_end(ap); |
cl349@5863 | 358 |
cl349@5874 | 359 BUG_ON(ret > sizeof(printf_buffer)-1); |
cl349@5874 | 360 return xenbus_write(dir, node, printf_buffer, O_CREAT); |
cl349@5598 | 361 } |
kaf24@6467 | 362 EXPORT_SYMBOL(xenbus_printf); |
cl349@5598 | 363 |
cl349@5874 | 364 /* Report a (negative) errno into the store, with explanation. */ |
cl349@5874 | 365 void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...) |
cl349@5874 | 366 { |
cl349@5874 | 367 va_list ap; |
cl349@5874 | 368 int ret; |
cl349@5874 | 369 unsigned int len; |
cl349@5874 | 370 |
cl349@5874 | 371 BUG_ON(down_trylock(&xenbus_lock) == 0); |
cl349@5874 | 372 |
cl349@5874 | 373 len = sprintf(printf_buffer, "%i ", -err); |
cl349@5874 | 374 va_start(ap, fmt); |
cl349@5874 | 375 ret = vsnprintf(printf_buffer+len, sizeof(printf_buffer)-len, fmt, ap); |
cl349@5874 | 376 va_end(ap); |
cl349@5874 | 377 |
cl349@5874 | 378 BUG_ON(len + ret > sizeof(printf_buffer)-1); |
cl349@5874 | 379 dev->has_error = 1; |
cl349@5874 | 380 if (xenbus_write(dev->nodename, "error", printf_buffer, O_CREAT) != 0) |
cl349@5874 | 381 printk("xenbus: failed to write error node for %s (%s)\n", |
cl349@5874 | 382 dev->nodename, printf_buffer); |
cl349@5874 | 383 } |
kaf24@6467 | 384 EXPORT_SYMBOL(xenbus_dev_error); |
cl349@5874 | 385 |
cl349@5874 | 386 /* Clear any error. */ |
cl349@5874 | 387 void xenbus_dev_ok(struct xenbus_device *dev) |
cl349@5598 | 388 { |
cl349@5874 | 389 if (dev->has_error) { |
cl349@5874 | 390 if (xenbus_rm(dev->nodename, "error") != 0) |
cl349@5874 | 391 printk("xenbus: failed to clear error node for %s\n", |
cl349@5874 | 392 dev->nodename); |
cl349@5874 | 393 else |
cl349@5874 | 394 dev->has_error = 0; |
cl349@5874 | 395 } |
cl349@5874 | 396 } |
kaf24@6467 | 397 EXPORT_SYMBOL(xenbus_dev_ok); |
cl349@5874 | 398 |
cl349@5863 | 399 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ |
cl349@5863 | 400 int xenbus_gather(const char *dir, ...) |
cl349@5863 | 401 { |
cl349@5863 | 402 va_list ap; |
cl349@5863 | 403 const char *name; |
cl349@5863 | 404 int ret = 0; |
cl349@5598 | 405 |
cl349@5863 | 406 va_start(ap, dir); |
cl349@5863 | 407 while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { |
cl349@5863 | 408 const char *fmt = va_arg(ap, char *); |
cl349@5863 | 409 void *result = va_arg(ap, void *); |
cl349@5863 | 410 char *p; |
cl349@5863 | 411 |
cl349@5863 | 412 p = xenbus_read(dir, name, NULL); |
cl349@5863 | 413 if (IS_ERR(p)) { |
cl349@5863 | 414 ret = PTR_ERR(p); |
cl349@5863 | 415 break; |
cl349@5863 | 416 } |
cl349@6250 | 417 if (fmt) { |
cl349@6250 | 418 if (sscanf(p, fmt, result) == 0) |
cl349@6250 | 419 ret = -EINVAL; |
cl349@6250 | 420 kfree(p); |
cl349@6250 | 421 } else |
cl349@6250 | 422 *(char **)result = p; |
cl349@5863 | 423 } |
cl349@5863 | 424 va_end(ap); |
cl349@5863 | 425 return ret; |
cl349@5598 | 426 } |
kaf24@6467 | 427 EXPORT_SYMBOL(xenbus_gather); |
cl349@5598 | 428 |
cl349@5876 | 429 static int xs_watch(const char *path, const char *token) |
cl349@5598 | 430 { |
cl349@5876 | 431 struct kvec iov[2]; |
cl349@5598 | 432 |
cl349@5598 | 433 iov[0].iov_base = (void *)path; |
cl349@5598 | 434 iov[0].iov_len = strlen(path) + 1; |
cl349@5598 | 435 iov[1].iov_base = (void *)token; |
cl349@5598 | 436 iov[1].iov_len = strlen(token) + 1; |
cl349@5598 | 437 |
cl349@5598 | 438 return xs_error(xs_talkv(XS_WATCH, iov, ARRAY_SIZE(iov), NULL)); |
cl349@5598 | 439 } |
cl349@5598 | 440 |
cl349@5598 | 441 static char *xs_read_watch(char **token) |
cl349@5598 | 442 { |
cl349@5598 | 443 enum xsd_sockmsg_type type; |
cl349@5598 | 444 char *ret; |
cl349@5598 | 445 |
cl349@5598 | 446 ret = read_reply(&type, NULL); |
cl349@5598 | 447 if (IS_ERR(ret)) |
cl349@5598 | 448 return ret; |
cl349@5598 | 449 |
cl349@5598 | 450 BUG_ON(type != XS_WATCH_EVENT); |
cl349@5598 | 451 *token = ret + strlen(ret) + 1; |
cl349@5598 | 452 return ret; |
cl349@5598 | 453 } |
cl349@5598 | 454 |
cl349@5598 | 455 static int xs_acknowledge_watch(const char *token) |
cl349@5598 | 456 { |
cl349@5598 | 457 return xs_error(xs_single(XS_WATCH_ACK, token, NULL)); |
cl349@5598 | 458 } |
cl349@5598 | 459 |
cl349@5598 | 460 static int xs_unwatch(const char *path, const char *token) |
cl349@5598 | 461 { |
cl349@5598 | 462 struct kvec iov[2]; |
cl349@5598 | 463 |
cl349@5598 | 464 iov[0].iov_base = (char *)path; |
cl349@5598 | 465 iov[0].iov_len = strlen(path) + 1; |
cl349@5598 | 466 iov[1].iov_base = (char *)token; |
cl349@5598 | 467 iov[1].iov_len = strlen(token) + 1; |
cl349@5598 | 468 |
cl349@5598 | 469 return xs_error(xs_talkv(XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL)); |
cl349@5598 | 470 } |
cl349@5598 | 471 |
cl349@5598 | 472 /* A little paranoia: we don't just trust token. */ |
cl349@5598 | 473 static struct xenbus_watch *find_watch(const char *token) |
cl349@5598 | 474 { |
cl349@5598 | 475 struct xenbus_watch *i, *cmp; |
cl349@5598 | 476 |
cl349@5598 | 477 cmp = (void *)simple_strtoul(token, NULL, 16); |
cl349@5598 | 478 |
cl349@5598 | 479 list_for_each_entry(i, &watches, list) |
cl349@5598 | 480 if (i == cmp) |
cl349@5598 | 481 return i; |
cl349@5598 | 482 return NULL; |
cl349@5598 | 483 } |
cl349@5598 | 484 |
cl349@5598 | 485 /* Register callback to watch this node. */ |
cl349@5598 | 486 int register_xenbus_watch(struct xenbus_watch *watch) |
cl349@5598 | 487 { |
cl349@5598 | 488 /* Pointer in ascii is the token. */ |
cl349@5598 | 489 char token[sizeof(watch) * 2 + 1]; |
cl349@5598 | 490 int err; |
cl349@5598 | 491 |
cl349@5598 | 492 sprintf(token, "%lX", (long)watch); |
cl349@5598 | 493 BUG_ON(find_watch(token)); |
cl349@5598 | 494 |
cl349@5876 | 495 err = xs_watch(watch->node, token); |
cl349@5598 | 496 if (!err) |
cl349@5598 | 497 list_add(&watch->list, &watches); |
cl349@5598 | 498 return err; |
cl349@5598 | 499 } |
kaf24@6467 | 500 EXPORT_SYMBOL(register_xenbus_watch); |
cl349@5598 | 501 |
cl349@5598 | 502 void unregister_xenbus_watch(struct xenbus_watch *watch) |
cl349@5598 | 503 { |
cl349@5598 | 504 char token[sizeof(watch) * 2 + 1]; |
cl349@5598 | 505 int err; |
cl349@5598 | 506 |
cl349@5598 | 507 sprintf(token, "%lX", (long)watch); |
cl349@5598 | 508 BUG_ON(!find_watch(token)); |
cl349@5598 | 509 |
cl349@5598 | 510 err = xs_unwatch(watch->node, token); |
cl349@5598 | 511 list_del(&watch->list); |
cl349@5598 | 512 |
cl349@5598 | 513 if (err) |
cl349@5903 | 514 printk(KERN_WARNING |
cl349@5903 | 515 "XENBUS Failed to release watch %s: %i\n", |
cl349@5598 | 516 watch->node, err); |
cl349@5598 | 517 } |
kaf24@6467 | 518 EXPORT_SYMBOL(unregister_xenbus_watch); |
cl349@5598 | 519 |
cl349@6209 | 520 /* Re-register callbacks to all watches. */ |
cl349@6209 | 521 void reregister_xenbus_watches(void) |
cl349@6209 | 522 { |
cl349@6209 | 523 struct xenbus_watch *watch; |
cl349@6209 | 524 char token[sizeof(watch) * 2 + 1]; |
cl349@6209 | 525 |
cl349@6209 | 526 list_for_each_entry(watch, &watches, list) { |
cl349@6209 | 527 sprintf(token, "%lX", (long)watch); |
cl349@6209 | 528 xs_watch(watch->node, token); |
cl349@6209 | 529 } |
cl349@6209 | 530 } |
cl349@6209 | 531 |
cl349@5598 | 532 static int watch_thread(void *unused) |
cl349@5598 | 533 { |
cl349@5598 | 534 for (;;) { |
cl349@5598 | 535 char *token; |
cl349@5598 | 536 char *node = NULL; |
cl349@5598 | 537 |
cl349@5902 | 538 wait_event(xb_waitq, xs_input_avail()); |
cl349@5598 | 539 |
cl349@5598 | 540 /* If this is a spurious wakeup caused by someone |
cl349@5598 | 541 * doing an op, they'll hold the lock and the buffer |
cl349@5598 | 542 * will be empty by the time we get there. |
cl349@5598 | 543 */ |
cl349@5863 | 544 down(&xenbus_lock); |
cl349@5902 | 545 if (xs_input_avail()) |
cl349@5598 | 546 node = xs_read_watch(&token); |
cl349@5747 | 547 |
cl349@5598 | 548 if (node && !IS_ERR(node)) { |
cl349@5598 | 549 struct xenbus_watch *w; |
cl349@5598 | 550 int err; |
cl349@5598 | 551 |
cl349@5903 | 552 err = xs_acknowledge_watch(token); |
cl349@5903 | 553 if (err) |
cl349@5903 | 554 printk(KERN_WARNING "XENBUS ack %s fail %i\n", |
cl349@5903 | 555 node, err); |
cl349@5598 | 556 w = find_watch(token); |
cl349@5598 | 557 BUG_ON(!w); |
cl349@5598 | 558 w->callback(w, node); |
cl349@5598 | 559 kfree(node); |
cl349@6600 | 560 } else if (node) |
cl349@5598 | 561 printk(KERN_WARNING "XENBUS xs_read_watch: %li\n", |
cl349@5598 | 562 PTR_ERR(node)); |
cl349@5863 | 563 up(&xenbus_lock); |
cl349@5598 | 564 } |
cl349@5598 | 565 } |
cl349@5598 | 566 |
cl349@5598 | 567 int xs_init(void) |
cl349@5598 | 568 { |
cl349@5598 | 569 int err; |
cl349@5598 | 570 struct task_struct *watcher; |
cl349@5598 | 571 |
cl349@5902 | 572 err = xb_init_comms(); |
cl349@5598 | 573 if (err) |
cl349@5598 | 574 return err; |
cl349@5598 | 575 |
cl349@5598 | 576 watcher = kthread_run(watch_thread, NULL, "kxbwatch"); |
cl349@5598 | 577 if (IS_ERR(watcher)) |
cl349@5598 | 578 return PTR_ERR(watcher); |
cl349@5598 | 579 return 0; |
cl349@5598 | 580 } |