xen-vtx-unstable
annotate linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c @ 5902:3be03cd7cd4c
Simplify code by making in and out pointers internal to xenbus_xs.c
Signed-off-by: Rusty Russel <rusty@rustcorp.com.au>
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
Signed-off-by: Rusty Russel <rusty@rustcorp.com.au>
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author | cl349@firebug.cl.cam.ac.uk |
---|---|
date | Thu Jul 28 12:25:13 2005 +0000 (2005-07-28) |
parents | de1207b85ef8 |
children | d24e1970c205 |
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 "xenstore/xenstored.h" |
cl349@5598 | 34 #include <linux/uio.h> |
cl349@5598 | 35 #include <linux/kernel.h> |
cl349@5598 | 36 #include <linux/string.h> |
cl349@5598 | 37 #include <linux/err.h> |
cl349@5598 | 38 #include <linux/slab.h> |
cl349@5598 | 39 #include <linux/fcntl.h> |
cl349@5598 | 40 #include <linux/kthread.h> |
cl349@5598 | 41 #include <asm-xen/xenbus.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); |
cl349@5863 | 48 DECLARE_MUTEX(xenbus_lock); |
cl349@5598 | 49 |
cl349@5598 | 50 static int get_error(const char *errorstring) |
cl349@5598 | 51 { |
cl349@5598 | 52 unsigned int i; |
cl349@5598 | 53 |
cl349@5598 | 54 for (i = 0; !streq(errorstring, xsd_errors[i].errstring); i++) { |
cl349@5598 | 55 if (i == ARRAY_SIZE(xsd_errors) - 1) { |
cl349@5670 | 56 printk(KERN_WARNING |
cl349@5670 | 57 "XENBUS xen store gave: unknown error %s", |
cl349@5598 | 58 errorstring); |
cl349@5598 | 59 return EINVAL; |
cl349@5598 | 60 } |
cl349@5598 | 61 } |
cl349@5598 | 62 return xsd_errors[i].errnum; |
cl349@5598 | 63 } |
cl349@5598 | 64 |
cl349@5598 | 65 static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) |
cl349@5598 | 66 { |
cl349@5598 | 67 struct xsd_sockmsg msg; |
cl349@5598 | 68 void *ret; |
cl349@5598 | 69 int err; |
cl349@5598 | 70 |
cl349@5902 | 71 err = xb_read(&msg, sizeof(msg)); |
cl349@5598 | 72 if (err) |
cl349@5598 | 73 return ERR_PTR(err); |
cl349@5598 | 74 |
cl349@5598 | 75 ret = kmalloc(msg.len + 1, GFP_KERNEL); |
cl349@5598 | 76 if (!ret) |
cl349@5598 | 77 return ERR_PTR(-ENOMEM); |
cl349@5598 | 78 |
cl349@5902 | 79 err = xb_read(ret, msg.len); |
cl349@5598 | 80 if (err) { |
cl349@5598 | 81 kfree(ret); |
cl349@5598 | 82 return ERR_PTR(err); |
cl349@5598 | 83 } |
cl349@5598 | 84 ((char*)ret)[msg.len] = '\0'; |
cl349@5598 | 85 |
cl349@5598 | 86 *type = msg.type; |
cl349@5598 | 87 if (len) |
cl349@5598 | 88 *len = msg.len; |
cl349@5598 | 89 return ret; |
cl349@5598 | 90 } |
cl349@5598 | 91 |
cl349@5747 | 92 /* Emergency write. */ |
cl349@5863 | 93 void xenbus_debug_write(const char *str, unsigned int count) |
cl349@5747 | 94 { |
cl349@5747 | 95 struct xsd_sockmsg msg; |
cl349@5747 | 96 |
cl349@5747 | 97 msg.type = XS_DEBUG; |
cl349@5747 | 98 msg.len = sizeof("print") + count + 1; |
cl349@5747 | 99 |
cl349@5902 | 100 xb_write(&msg, sizeof(msg)); |
cl349@5902 | 101 xb_write("print", sizeof("print")); |
cl349@5902 | 102 xb_write(str, count); |
cl349@5902 | 103 xb_write("", 1); |
cl349@5747 | 104 } |
cl349@5747 | 105 |
cl349@5598 | 106 /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ |
cl349@5598 | 107 static void *xs_talkv(enum xsd_sockmsg_type type, |
cl349@5598 | 108 const struct kvec *iovec, |
cl349@5598 | 109 unsigned int num_vecs, |
cl349@5598 | 110 unsigned int *len) |
cl349@5598 | 111 { |
cl349@5598 | 112 struct xsd_sockmsg msg; |
cl349@5598 | 113 void *ret = NULL; |
cl349@5598 | 114 unsigned int i; |
cl349@5598 | 115 int err; |
cl349@5598 | 116 |
cl349@5863 | 117 WARN_ON(down_trylock(&xenbus_lock) == 0); |
cl349@5598 | 118 |
cl349@5598 | 119 msg.type = type; |
cl349@5598 | 120 msg.len = 0; |
cl349@5598 | 121 for (i = 0; i < num_vecs; i++) |
cl349@5598 | 122 msg.len += iovec[i].iov_len; |
cl349@5598 | 123 |
cl349@5902 | 124 err = xb_write(&msg, sizeof(msg)); |
cl349@5598 | 125 if (err) |
cl349@5598 | 126 return ERR_PTR(err); |
cl349@5598 | 127 |
cl349@5598 | 128 for (i = 0; i < num_vecs; i++) { |
cl349@5902 | 129 err = xb_write(iovec[i].iov_base, iovec[i].iov_len);; |
cl349@5598 | 130 if (err) |
cl349@5598 | 131 return ERR_PTR(err); |
cl349@5598 | 132 } |
cl349@5598 | 133 |
cl349@5598 | 134 /* Watches can have fired before reply comes: daemon detects |
cl349@5598 | 135 * and re-transmits, so we can ignore this. */ |
cl349@5598 | 136 do { |
cl349@5598 | 137 kfree(ret); |
cl349@5598 | 138 ret = read_reply(&msg.type, len); |
cl349@5598 | 139 if (IS_ERR(ret)) |
cl349@5598 | 140 return ret; |
cl349@5598 | 141 } while (msg.type == XS_WATCH_EVENT); |
cl349@5598 | 142 |
cl349@5598 | 143 if (msg.type == XS_ERROR) { |
cl349@5598 | 144 err = get_error(ret); |
cl349@5598 | 145 kfree(ret); |
cl349@5598 | 146 return ERR_PTR(-err); |
cl349@5598 | 147 } |
cl349@5598 | 148 |
cl349@5598 | 149 BUG_ON(msg.type != type); |
cl349@5598 | 150 return ret; |
cl349@5598 | 151 } |
cl349@5598 | 152 |
cl349@5598 | 153 /* Simplified version of xs_talkv: single message. */ |
cl349@5598 | 154 static void *xs_single(enum xsd_sockmsg_type type, |
cl349@5598 | 155 const char *string, unsigned int *len) |
cl349@5598 | 156 { |
cl349@5598 | 157 struct kvec iovec; |
cl349@5598 | 158 |
cl349@5598 | 159 iovec.iov_base = (void *)string; |
cl349@5598 | 160 iovec.iov_len = strlen(string) + 1; |
cl349@5598 | 161 return xs_talkv(type, &iovec, 1, len); |
cl349@5598 | 162 } |
cl349@5598 | 163 |
cl349@5598 | 164 /* Many commands only need an ack, don't care what it says. */ |
cl349@5598 | 165 static int xs_error(char *reply) |
cl349@5598 | 166 { |
cl349@5598 | 167 if (IS_ERR(reply)) |
cl349@5598 | 168 return PTR_ERR(reply); |
cl349@5598 | 169 kfree(reply); |
cl349@5598 | 170 return 0; |
cl349@5598 | 171 } |
cl349@5598 | 172 |
cl349@5598 | 173 static unsigned int count_strings(const char *strings, unsigned int len) |
cl349@5598 | 174 { |
cl349@5598 | 175 unsigned int num; |
cl349@5598 | 176 const char *p; |
cl349@5598 | 177 |
cl349@5598 | 178 for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) |
cl349@5598 | 179 num++; |
cl349@5598 | 180 |
cl349@5598 | 181 return num; |
cl349@5598 | 182 } |
cl349@5598 | 183 |
cl349@5863 | 184 /* Return the path to dir with /name appended. */ |
cl349@5863 | 185 static char *join(const char *dir, const char *name) |
cl349@5863 | 186 { |
cl349@5863 | 187 static char buffer[4096]; |
cl349@5863 | 188 |
cl349@5863 | 189 BUG_ON(down_trylock(&xenbus_lock) == 0); |
cl349@5863 | 190 BUG_ON(strlen(dir) + strlen("/") + strlen(name) + 1 > sizeof(buffer)); |
cl349@5863 | 191 |
cl349@5863 | 192 strcpy(buffer, dir); |
cl349@5863 | 193 if (!streq(name, "")) { |
cl349@5863 | 194 strcat(buffer, "/"); |
cl349@5863 | 195 strcat(buffer, name); |
cl349@5863 | 196 } |
cl349@5863 | 197 return buffer; |
cl349@5863 | 198 } |
cl349@5863 | 199 |
cl349@5863 | 200 char **xenbus_directory(const char *dir, const char *node, unsigned int *num) |
cl349@5598 | 201 { |
cl349@5598 | 202 char *strings, *p, **ret; |
cl349@5598 | 203 unsigned int len; |
cl349@5598 | 204 |
cl349@5863 | 205 strings = xs_single(XS_DIRECTORY, join(dir, node), &len); |
cl349@5598 | 206 if (IS_ERR(strings)) |
cl349@5598 | 207 return (char **)strings; |
cl349@5598 | 208 |
cl349@5598 | 209 /* Count the strings. */ |
cl349@5598 | 210 *num = count_strings(strings, len); |
cl349@5598 | 211 |
cl349@5598 | 212 /* Transfer to one big alloc for easy freeing. */ |
cl349@5598 | 213 ret = kmalloc(*num * sizeof(char *) + len, GFP_ATOMIC); |
cl349@5598 | 214 if (!ret) { |
cl349@5598 | 215 kfree(strings); |
cl349@5598 | 216 return ERR_PTR(-ENOMEM); |
cl349@5598 | 217 } |
cl349@5598 | 218 memcpy(&ret[*num], strings, len); |
cl349@5598 | 219 kfree(strings); |
cl349@5598 | 220 |
cl349@5598 | 221 strings = (char *)&ret[*num]; |
cl349@5598 | 222 for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1) |
cl349@5598 | 223 ret[(*num)++] = p; |
cl349@5598 | 224 return ret; |
cl349@5598 | 225 } |
cl349@5598 | 226 |
cl349@5598 | 227 /* Check if a path exists. Return 1 if it does. */ |
cl349@5863 | 228 int xenbus_exists(const char *dir, const char *node) |
cl349@5598 | 229 { |
cl349@5863 | 230 char **d; |
cl349@5670 | 231 int dir_n; |
cl349@5598 | 232 |
cl349@5867 | 233 d = xenbus_directory(dir, node, &dir_n); |
cl349@5863 | 234 if (IS_ERR(d)) |
cl349@5670 | 235 return 0; |
cl349@5863 | 236 kfree(d); |
cl349@5670 | 237 return 1; |
cl349@5598 | 238 } |
cl349@5598 | 239 |
cl349@5598 | 240 /* Get the value of a single file. |
cl349@5598 | 241 * Returns a kmalloced value: call free() on it after use. |
cl349@5598 | 242 * len indicates length in bytes. |
cl349@5598 | 243 */ |
cl349@5863 | 244 void *xenbus_read(const char *dir, const char *node, unsigned int *len) |
cl349@5598 | 245 { |
cl349@5863 | 246 return xs_single(XS_READ, join(dir, node), len); |
cl349@5598 | 247 } |
cl349@5598 | 248 |
cl349@5598 | 249 /* Write the value of a single file. |
cl349@5598 | 250 * Returns -err on failure. createflags can be 0, O_CREAT, or O_CREAT|O_EXCL. |
cl349@5598 | 251 */ |
cl349@5863 | 252 int xenbus_write(const char *dir, const char *node, |
cl349@5863 | 253 const char *string, int createflags) |
cl349@5598 | 254 { |
cl349@5863 | 255 const char *flags, *path; |
cl349@5598 | 256 struct kvec iovec[3]; |
cl349@5598 | 257 |
cl349@5863 | 258 path = join(dir, node); |
cl349@5598 | 259 /* Format: Flags (as string), path, data. */ |
cl349@5598 | 260 if (createflags == 0) |
cl349@5598 | 261 flags = XS_WRITE_NONE; |
cl349@5598 | 262 else if (createflags == O_CREAT) |
cl349@5598 | 263 flags = XS_WRITE_CREATE; |
cl349@5598 | 264 else if (createflags == (O_CREAT|O_EXCL)) |
cl349@5598 | 265 flags = XS_WRITE_CREATE_EXCL; |
cl349@5598 | 266 else |
cl349@5598 | 267 return -EINVAL; |
cl349@5598 | 268 |
cl349@5598 | 269 iovec[0].iov_base = (void *)path; |
cl349@5598 | 270 iovec[0].iov_len = strlen(path) + 1; |
cl349@5598 | 271 iovec[1].iov_base = (void *)flags; |
cl349@5598 | 272 iovec[1].iov_len = strlen(flags) + 1; |
cl349@5863 | 273 iovec[2].iov_base = (void *)string; |
cl349@5863 | 274 iovec[2].iov_len = strlen(string); |
cl349@5598 | 275 |
cl349@5598 | 276 return xs_error(xs_talkv(XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL)); |
cl349@5598 | 277 } |
cl349@5598 | 278 |
cl349@5598 | 279 /* Create a new directory. */ |
cl349@5863 | 280 int xenbus_mkdir(const char *dir, const char *node) |
cl349@5598 | 281 { |
cl349@5863 | 282 return xs_error(xs_single(XS_MKDIR, join(dir, node), NULL)); |
cl349@5598 | 283 } |
cl349@5598 | 284 |
cl349@5598 | 285 /* Destroy a file or directory (directories must be empty). */ |
cl349@5863 | 286 int xenbus_rm(const char *dir, const char *node) |
cl349@5598 | 287 { |
cl349@5863 | 288 return xs_error(xs_single(XS_RM, join(dir, node), NULL)); |
cl349@5598 | 289 } |
cl349@5598 | 290 |
cl349@5598 | 291 /* Start a transaction: changes by others will not be seen during this |
cl349@5598 | 292 * transaction, and changes will not be visible to others until end. |
cl349@5598 | 293 * Transaction only applies to the given subtree. |
cl349@5598 | 294 * You can only have one transaction at any time. |
cl349@5598 | 295 */ |
cl349@5863 | 296 int xenbus_transaction_start(const char *subtree) |
cl349@5598 | 297 { |
cl349@5598 | 298 return xs_error(xs_single(XS_TRANSACTION_START, subtree, NULL)); |
cl349@5598 | 299 } |
cl349@5598 | 300 |
cl349@5598 | 301 /* End a transaction. |
cl349@5598 | 302 * If abandon is true, transaction is discarded instead of committed. |
cl349@5598 | 303 */ |
cl349@5863 | 304 int xenbus_transaction_end(int abort) |
cl349@5598 | 305 { |
cl349@5598 | 306 char abortstr[2]; |
cl349@5598 | 307 |
cl349@5598 | 308 if (abort) |
cl349@5598 | 309 strcpy(abortstr, "F"); |
cl349@5598 | 310 else |
cl349@5598 | 311 strcpy(abortstr, "T"); |
cl349@5598 | 312 return xs_error(xs_single(XS_TRANSACTION_END, abortstr, NULL)); |
cl349@5598 | 313 } |
cl349@5598 | 314 |
cl349@5863 | 315 /* Single read and scanf: returns -errno or num scanned. */ |
cl349@5863 | 316 int xenbus_scanf(const char *dir, const char *node, const char *fmt, ...) |
cl349@5598 | 317 { |
cl349@5863 | 318 va_list ap; |
cl349@5863 | 319 int ret; |
cl349@5863 | 320 char *val; |
cl349@5863 | 321 |
cl349@5863 | 322 val = xenbus_read(dir, node, NULL); |
cl349@5863 | 323 if (IS_ERR(val)) |
cl349@5863 | 324 return PTR_ERR(val); |
cl349@5598 | 325 |
cl349@5863 | 326 va_start(ap, fmt); |
cl349@5863 | 327 ret = vsscanf(val, fmt, ap); |
cl349@5863 | 328 va_end(ap); |
cl349@5863 | 329 kfree(val); |
cl349@5863 | 330 /* Distinctive errno. */ |
cl349@5863 | 331 if (ret == 0) |
cl349@5863 | 332 return -ERANGE; |
cl349@5863 | 333 return ret; |
cl349@5863 | 334 } |
cl349@5863 | 335 |
cl349@5863 | 336 /* Single printf and write: returns -errno or 0. */ |
cl349@5863 | 337 int xenbus_printf(const char *dir, const char *node, const char *fmt, ...) |
cl349@5598 | 338 { |
cl349@5863 | 339 va_list ap; |
cl349@5863 | 340 int ret; |
cl349@5863 | 341 |
cl349@5863 | 342 BUG_ON(down_trylock(&xenbus_lock) == 0); |
cl349@5863 | 343 va_start(ap, fmt); |
cl349@5874 | 344 ret = vsnprintf(printf_buffer, sizeof(printf_buffer), fmt, ap); |
cl349@5863 | 345 va_end(ap); |
cl349@5863 | 346 |
cl349@5874 | 347 BUG_ON(ret > sizeof(printf_buffer)-1); |
cl349@5874 | 348 return xenbus_write(dir, node, printf_buffer, O_CREAT); |
cl349@5598 | 349 } |
cl349@5598 | 350 |
cl349@5874 | 351 /* Report a (negative) errno into the store, with explanation. */ |
cl349@5874 | 352 void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...) |
cl349@5874 | 353 { |
cl349@5874 | 354 va_list ap; |
cl349@5874 | 355 int ret; |
cl349@5874 | 356 unsigned int len; |
cl349@5874 | 357 |
cl349@5874 | 358 BUG_ON(down_trylock(&xenbus_lock) == 0); |
cl349@5874 | 359 |
cl349@5874 | 360 len = sprintf(printf_buffer, "%i ", -err); |
cl349@5874 | 361 va_start(ap, fmt); |
cl349@5874 | 362 ret = vsnprintf(printf_buffer+len, sizeof(printf_buffer)-len, fmt, ap); |
cl349@5874 | 363 va_end(ap); |
cl349@5874 | 364 |
cl349@5874 | 365 BUG_ON(len + ret > sizeof(printf_buffer)-1); |
cl349@5874 | 366 dev->has_error = 1; |
cl349@5874 | 367 if (xenbus_write(dev->nodename, "error", printf_buffer, O_CREAT) != 0) |
cl349@5874 | 368 printk("xenbus: failed to write error node for %s (%s)\n", |
cl349@5874 | 369 dev->nodename, printf_buffer); |
cl349@5874 | 370 } |
cl349@5874 | 371 |
cl349@5874 | 372 /* Clear any error. */ |
cl349@5874 | 373 void xenbus_dev_ok(struct xenbus_device *dev) |
cl349@5598 | 374 { |
cl349@5874 | 375 if (dev->has_error) { |
cl349@5874 | 376 if (xenbus_rm(dev->nodename, "error") != 0) |
cl349@5874 | 377 printk("xenbus: failed to clear error node for %s\n", |
cl349@5874 | 378 dev->nodename); |
cl349@5874 | 379 else |
cl349@5874 | 380 dev->has_error = 0; |
cl349@5874 | 381 } |
cl349@5874 | 382 } |
cl349@5874 | 383 |
cl349@5863 | 384 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ |
cl349@5863 | 385 int xenbus_gather(const char *dir, ...) |
cl349@5863 | 386 { |
cl349@5863 | 387 va_list ap; |
cl349@5863 | 388 const char *name; |
cl349@5863 | 389 int ret = 0; |
cl349@5598 | 390 |
cl349@5863 | 391 va_start(ap, dir); |
cl349@5863 | 392 while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { |
cl349@5863 | 393 const char *fmt = va_arg(ap, char *); |
cl349@5863 | 394 void *result = va_arg(ap, void *); |
cl349@5863 | 395 char *p; |
cl349@5863 | 396 |
cl349@5863 | 397 p = xenbus_read(dir, name, NULL); |
cl349@5863 | 398 if (IS_ERR(p)) { |
cl349@5863 | 399 ret = PTR_ERR(p); |
cl349@5863 | 400 break; |
cl349@5863 | 401 } |
cl349@5863 | 402 if (sscanf(p, fmt, result) == 0) |
cl349@5863 | 403 ret = -EINVAL; |
cl349@5863 | 404 kfree(p); |
cl349@5863 | 405 } |
cl349@5863 | 406 va_end(ap); |
cl349@5863 | 407 return ret; |
cl349@5598 | 408 } |
cl349@5598 | 409 |
cl349@5876 | 410 static int xs_watch(const char *path, const char *token) |
cl349@5598 | 411 { |
cl349@5876 | 412 struct kvec iov[2]; |
cl349@5598 | 413 |
cl349@5598 | 414 iov[0].iov_base = (void *)path; |
cl349@5598 | 415 iov[0].iov_len = strlen(path) + 1; |
cl349@5598 | 416 iov[1].iov_base = (void *)token; |
cl349@5598 | 417 iov[1].iov_len = strlen(token) + 1; |
cl349@5598 | 418 |
cl349@5598 | 419 return xs_error(xs_talkv(XS_WATCH, iov, ARRAY_SIZE(iov), NULL)); |
cl349@5598 | 420 } |
cl349@5598 | 421 |
cl349@5598 | 422 static char *xs_read_watch(char **token) |
cl349@5598 | 423 { |
cl349@5598 | 424 enum xsd_sockmsg_type type; |
cl349@5598 | 425 char *ret; |
cl349@5598 | 426 |
cl349@5598 | 427 ret = read_reply(&type, NULL); |
cl349@5598 | 428 if (IS_ERR(ret)) |
cl349@5598 | 429 return ret; |
cl349@5598 | 430 |
cl349@5598 | 431 BUG_ON(type != XS_WATCH_EVENT); |
cl349@5598 | 432 *token = ret + strlen(ret) + 1; |
cl349@5598 | 433 return ret; |
cl349@5598 | 434 } |
cl349@5598 | 435 |
cl349@5598 | 436 static int xs_acknowledge_watch(const char *token) |
cl349@5598 | 437 { |
cl349@5598 | 438 return xs_error(xs_single(XS_WATCH_ACK, token, NULL)); |
cl349@5598 | 439 } |
cl349@5598 | 440 |
cl349@5598 | 441 static int xs_unwatch(const char *path, const char *token) |
cl349@5598 | 442 { |
cl349@5598 | 443 struct kvec iov[2]; |
cl349@5598 | 444 |
cl349@5598 | 445 iov[0].iov_base = (char *)path; |
cl349@5598 | 446 iov[0].iov_len = strlen(path) + 1; |
cl349@5598 | 447 iov[1].iov_base = (char *)token; |
cl349@5598 | 448 iov[1].iov_len = strlen(token) + 1; |
cl349@5598 | 449 |
cl349@5598 | 450 return xs_error(xs_talkv(XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL)); |
cl349@5598 | 451 } |
cl349@5598 | 452 |
cl349@5598 | 453 /* A little paranoia: we don't just trust token. */ |
cl349@5598 | 454 static struct xenbus_watch *find_watch(const char *token) |
cl349@5598 | 455 { |
cl349@5598 | 456 struct xenbus_watch *i, *cmp; |
cl349@5598 | 457 |
cl349@5598 | 458 cmp = (void *)simple_strtoul(token, NULL, 16); |
cl349@5598 | 459 |
cl349@5598 | 460 list_for_each_entry(i, &watches, list) |
cl349@5598 | 461 if (i == cmp) |
cl349@5598 | 462 return i; |
cl349@5598 | 463 return NULL; |
cl349@5598 | 464 } |
cl349@5598 | 465 |
cl349@5598 | 466 /* Register callback to watch this node. */ |
cl349@5598 | 467 int register_xenbus_watch(struct xenbus_watch *watch) |
cl349@5598 | 468 { |
cl349@5598 | 469 /* Pointer in ascii is the token. */ |
cl349@5598 | 470 char token[sizeof(watch) * 2 + 1]; |
cl349@5598 | 471 int err; |
cl349@5598 | 472 |
cl349@5598 | 473 sprintf(token, "%lX", (long)watch); |
cl349@5598 | 474 BUG_ON(find_watch(token)); |
cl349@5598 | 475 |
cl349@5876 | 476 err = xs_watch(watch->node, token); |
cl349@5598 | 477 if (!err) |
cl349@5598 | 478 list_add(&watch->list, &watches); |
cl349@5598 | 479 return err; |
cl349@5598 | 480 } |
cl349@5598 | 481 |
cl349@5875 | 482 static struct xenbus_watch *watch_callback; |
cl349@5875 | 483 |
cl349@5598 | 484 void unregister_xenbus_watch(struct xenbus_watch *watch) |
cl349@5598 | 485 { |
cl349@5598 | 486 char token[sizeof(watch) * 2 + 1]; |
cl349@5598 | 487 int err; |
cl349@5598 | 488 |
cl349@5598 | 489 sprintf(token, "%lX", (long)watch); |
cl349@5598 | 490 BUG_ON(!find_watch(token)); |
cl349@5598 | 491 |
cl349@5598 | 492 err = xs_unwatch(watch->node, token); |
cl349@5598 | 493 list_del(&watch->list); |
cl349@5598 | 494 |
cl349@5875 | 495 /* Make sure watch thread knows we unwatched, so don't ack. */ |
cl349@5875 | 496 if (watch_callback == watch) |
cl349@5875 | 497 watch_callback = NULL; |
cl349@5875 | 498 |
cl349@5598 | 499 if (err) |
cl349@5598 | 500 printk(KERN_WARNING "XENBUS Failed to release watch %s: %i\n", |
cl349@5598 | 501 watch->node, err); |
cl349@5598 | 502 } |
cl349@5598 | 503 |
cl349@5598 | 504 static int watch_thread(void *unused) |
cl349@5598 | 505 { |
cl349@5598 | 506 for (;;) { |
cl349@5598 | 507 char *token; |
cl349@5598 | 508 char *node = NULL; |
cl349@5598 | 509 |
cl349@5902 | 510 wait_event(xb_waitq, xs_input_avail()); |
cl349@5598 | 511 |
cl349@5598 | 512 /* If this is a spurious wakeup caused by someone |
cl349@5598 | 513 * doing an op, they'll hold the lock and the buffer |
cl349@5598 | 514 * will be empty by the time we get there. |
cl349@5598 | 515 */ |
cl349@5863 | 516 down(&xenbus_lock); |
cl349@5902 | 517 if (xs_input_avail()) |
cl349@5598 | 518 node = xs_read_watch(&token); |
cl349@5747 | 519 |
cl349@5598 | 520 if (node && !IS_ERR(node)) { |
cl349@5598 | 521 struct xenbus_watch *w; |
cl349@5598 | 522 int err; |
cl349@5598 | 523 |
cl349@5598 | 524 w = find_watch(token); |
cl349@5598 | 525 BUG_ON(!w); |
cl349@5875 | 526 watch_callback = w; |
cl349@5598 | 527 w->callback(w, node); |
cl349@5875 | 528 |
cl349@5875 | 529 if (watch_callback) { |
cl349@5875 | 530 err = xs_acknowledge_watch(token); |
cl349@5875 | 531 if (err) |
cl349@5875 | 532 printk(KERN_WARNING |
cl349@5875 | 533 "XENBUS ack %s fail %i\n", |
cl349@5875 | 534 node, err); |
cl349@5875 | 535 } |
cl349@5598 | 536 kfree(node); |
cl349@5598 | 537 } else |
cl349@5598 | 538 printk(KERN_WARNING "XENBUS xs_read_watch: %li\n", |
cl349@5598 | 539 PTR_ERR(node)); |
cl349@5863 | 540 up(&xenbus_lock); |
cl349@5598 | 541 } |
cl349@5598 | 542 } |
cl349@5598 | 543 |
cl349@5598 | 544 int xs_init(void) |
cl349@5598 | 545 { |
cl349@5598 | 546 int err; |
cl349@5598 | 547 struct task_struct *watcher; |
cl349@5598 | 548 |
cl349@5902 | 549 err = xb_init_comms(); |
cl349@5598 | 550 if (err) |
cl349@5598 | 551 return err; |
cl349@5598 | 552 |
cl349@5598 | 553 watcher = kthread_run(watch_thread, NULL, "kxbwatch"); |
cl349@5598 | 554 if (IS_ERR(watcher)) |
cl349@5598 | 555 return PTR_ERR(watcher); |
cl349@5598 | 556 return 0; |
cl349@5598 | 557 } |