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