cl349@5598: /****************************************************************************** cl349@5598: * xenbus_xs.c cl349@5598: * cl349@5598: * This is the kernel equivalent of the "xs" library. We don't need everything cl349@5863: * and we use xenbus_comms for communication. cl349@5598: * cl349@5598: * Copyright (C) 2005 Rusty Russell, IBM Corporation cl349@5598: * cl349@5598: * This file may be distributed separately from the Linux kernel, or cl349@5598: * incorporated into other software packages, subject to the following license: cl349@5598: * cl349@5598: * Permission is hereby granted, free of charge, to any person obtaining a copy cl349@5598: * of this source file (the "Software"), to deal in the Software without cl349@5598: * restriction, including without limitation the rights to use, copy, modify, cl349@5598: * merge, publish, distribute, sublicense, and/or sell copies of the Software, cl349@5598: * and to permit persons to whom the Software is furnished to do so, subject to cl349@5598: * the following conditions: cl349@5598: * cl349@5598: * The above copyright notice and this permission notice shall be included in cl349@5598: * all copies or substantial portions of the Software. cl349@5598: * cl349@5598: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR cl349@5598: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, cl349@5598: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE cl349@5598: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER cl349@5598: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING cl349@5598: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS cl349@5598: * IN THE SOFTWARE. cl349@5598: */ cl349@5598: cl349@5598: #include cl349@5598: #include cl349@5598: #include cl349@5598: #include cl349@5598: #include cl349@5598: #include cl349@5598: #include cl349@5598: #include cl349@5598: #include cl349@5598: #include cl349@6751: #include cl349@5598: #include "xenbus_comms.h" cl349@5598: cl349@5598: #define streq(a, b) (strcmp((a), (b)) == 0) cl349@5598: cl349@5874: static char printf_buffer[4096]; cl349@5598: static LIST_HEAD(watches); kaf24@6480: cl349@5863: DECLARE_MUTEX(xenbus_lock); kaf24@6480: EXPORT_SYMBOL(xenbus_lock); cl349@5598: cl349@5598: static int get_error(const char *errorstring) cl349@5598: { cl349@5598: unsigned int i; cl349@5598: cl349@5598: for (i = 0; !streq(errorstring, xsd_errors[i].errstring); i++) { cl349@5598: if (i == ARRAY_SIZE(xsd_errors) - 1) { cl349@5670: printk(KERN_WARNING cl349@5670: "XENBUS xen store gave: unknown error %s", cl349@5598: errorstring); cl349@5598: return EINVAL; cl349@5598: } cl349@5598: } cl349@5598: return xsd_errors[i].errnum; cl349@5598: } cl349@5598: cl349@5598: static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) cl349@5598: { cl349@5598: struct xsd_sockmsg msg; cl349@5598: void *ret; cl349@5598: int err; cl349@5598: cl349@5902: err = xb_read(&msg, sizeof(msg)); cl349@5598: if (err) cl349@5598: return ERR_PTR(err); cl349@5598: cl349@5598: ret = kmalloc(msg.len + 1, GFP_KERNEL); cl349@5598: if (!ret) cl349@5598: return ERR_PTR(-ENOMEM); cl349@5598: cl349@5902: err = xb_read(ret, msg.len); cl349@5598: if (err) { cl349@5598: kfree(ret); cl349@5598: return ERR_PTR(err); cl349@5598: } cl349@5598: ((char*)ret)[msg.len] = '\0'; cl349@5598: cl349@5598: *type = msg.type; cl349@5598: if (len) cl349@5598: *len = msg.len; cl349@5598: return ret; cl349@5598: } cl349@5598: cl349@5747: /* Emergency write. */ cl349@5863: void xenbus_debug_write(const char *str, unsigned int count) cl349@5747: { cl349@5747: struct xsd_sockmsg msg; cl349@5747: cl349@5747: msg.type = XS_DEBUG; cl349@5747: msg.len = sizeof("print") + count + 1; cl349@5747: cl349@5902: xb_write(&msg, sizeof(msg)); cl349@5902: xb_write("print", sizeof("print")); cl349@5902: xb_write(str, count); cl349@5902: xb_write("", 1); cl349@5747: } cl349@5747: cl349@5598: /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ cl349@6749: static void *xs_talkv(enum xsd_sockmsg_type type, cl349@6749: const struct kvec *iovec, cl349@6749: unsigned int num_vecs, cl349@6749: unsigned int *len) cl349@5598: { cl349@5598: struct xsd_sockmsg msg; cl349@5598: void *ret = NULL; cl349@5598: unsigned int i; cl349@5598: int err; cl349@5598: cl349@5863: WARN_ON(down_trylock(&xenbus_lock) == 0); cl349@5598: cl349@5598: msg.type = type; cl349@5598: msg.len = 0; cl349@5598: for (i = 0; i < num_vecs; i++) cl349@5598: msg.len += iovec[i].iov_len; cl349@5598: cl349@5902: err = xb_write(&msg, sizeof(msg)); cl349@5598: if (err) cl349@5598: return ERR_PTR(err); cl349@5598: cl349@5598: for (i = 0; i < num_vecs; i++) { cl349@5902: err = xb_write(iovec[i].iov_base, iovec[i].iov_len);; cl349@5598: if (err) cl349@5598: return ERR_PTR(err); cl349@5598: } cl349@5598: cl349@5598: /* Watches can have fired before reply comes: daemon detects cl349@5598: * and re-transmits, so we can ignore this. */ cl349@5598: do { cl349@5598: kfree(ret); cl349@5598: ret = read_reply(&msg.type, len); cl349@5598: if (IS_ERR(ret)) cl349@5598: return ret; cl349@5598: } while (msg.type == XS_WATCH_EVENT); cl349@5598: cl349@5598: if (msg.type == XS_ERROR) { cl349@5598: err = get_error(ret); cl349@5598: kfree(ret); cl349@5598: return ERR_PTR(-err); cl349@5598: } cl349@5598: cl349@5598: BUG_ON(msg.type != type); cl349@5598: return ret; cl349@5598: } cl349@5598: cl349@5598: /* Simplified version of xs_talkv: single message. */ cl349@5598: static void *xs_single(enum xsd_sockmsg_type type, cl349@5598: const char *string, unsigned int *len) cl349@5598: { cl349@5598: struct kvec iovec; cl349@5598: cl349@5598: iovec.iov_base = (void *)string; cl349@5598: iovec.iov_len = strlen(string) + 1; cl349@5598: return xs_talkv(type, &iovec, 1, len); cl349@5598: } cl349@5598: cl349@5598: /* Many commands only need an ack, don't care what it says. */ cl349@5598: static int xs_error(char *reply) cl349@5598: { cl349@5598: if (IS_ERR(reply)) cl349@5598: return PTR_ERR(reply); cl349@5598: kfree(reply); cl349@5598: return 0; cl349@5598: } cl349@5598: cl349@5598: static unsigned int count_strings(const char *strings, unsigned int len) cl349@5598: { cl349@5598: unsigned int num; cl349@5598: const char *p; cl349@5598: cl349@5598: for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) cl349@5598: num++; cl349@5598: cl349@5598: return num; cl349@5598: } cl349@5598: cl349@5863: /* Return the path to dir with /name appended. */ cl349@5863: static char *join(const char *dir, const char *name) cl349@5863: { cl349@5863: static char buffer[4096]; cl349@5863: cl349@5863: BUG_ON(down_trylock(&xenbus_lock) == 0); cl349@6250: /* XXX FIXME: might not be correct if name == "" */ cl349@5863: BUG_ON(strlen(dir) + strlen("/") + strlen(name) + 1 > sizeof(buffer)); cl349@5863: cl349@5863: strcpy(buffer, dir); cl349@5863: if (!streq(name, "")) { cl349@5863: strcat(buffer, "/"); cl349@5863: strcat(buffer, name); cl349@5863: } cl349@5863: return buffer; cl349@5863: } cl349@5863: cl349@5863: char **xenbus_directory(const char *dir, const char *node, unsigned int *num) cl349@5598: { cl349@5598: char *strings, *p, **ret; cl349@5598: unsigned int len; cl349@5598: cl349@5863: strings = xs_single(XS_DIRECTORY, join(dir, node), &len); cl349@5598: if (IS_ERR(strings)) cl349@5598: return (char **)strings; cl349@5598: cl349@5598: /* Count the strings. */ cl349@5598: *num = count_strings(strings, len); cl349@5598: cl349@5598: /* Transfer to one big alloc for easy freeing. */ cl349@5598: ret = kmalloc(*num * sizeof(char *) + len, GFP_ATOMIC); cl349@5598: if (!ret) { cl349@5598: kfree(strings); cl349@5598: return ERR_PTR(-ENOMEM); cl349@5598: } cl349@5598: memcpy(&ret[*num], strings, len); cl349@5598: kfree(strings); cl349@5598: cl349@5598: strings = (char *)&ret[*num]; cl349@5598: for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1) cl349@5598: ret[(*num)++] = p; cl349@5598: return ret; cl349@5598: } kaf24@6480: EXPORT_SYMBOL(xenbus_directory); cl349@5598: cl349@5598: /* Check if a path exists. Return 1 if it does. */ cl349@5863: int xenbus_exists(const char *dir, const char *node) cl349@5598: { cl349@5863: char **d; cl349@5670: int dir_n; cl349@5598: cl349@5867: d = xenbus_directory(dir, node, &dir_n); cl349@5863: if (IS_ERR(d)) cl349@5670: return 0; cl349@5863: kfree(d); cl349@5670: return 1; cl349@5598: } kaf24@6480: EXPORT_SYMBOL(xenbus_exists); cl349@5598: cl349@5598: /* Get the value of a single file. cl349@5598: * Returns a kmalloced value: call free() on it after use. cl349@5598: * len indicates length in bytes. cl349@5598: */ cl349@5863: void *xenbus_read(const char *dir, const char *node, unsigned int *len) cl349@5598: { cl349@5863: return xs_single(XS_READ, join(dir, node), len); cl349@5598: } kaf24@6467: EXPORT_SYMBOL(xenbus_read); cl349@5598: cl349@5598: /* Write the value of a single file. cl349@5598: * Returns -err on failure. createflags can be 0, O_CREAT, or O_CREAT|O_EXCL. cl349@5598: */ cl349@5863: int xenbus_write(const char *dir, const char *node, cl349@5863: const char *string, int createflags) cl349@5598: { cl349@5863: const char *flags, *path; cl349@5598: struct kvec iovec[3]; cl349@5598: cl349@5863: path = join(dir, node); cl349@5598: /* Format: Flags (as string), path, data. */ cl349@5598: if (createflags == 0) cl349@5598: flags = XS_WRITE_NONE; cl349@5598: else if (createflags == O_CREAT) cl349@5598: flags = XS_WRITE_CREATE; cl349@5598: else if (createflags == (O_CREAT|O_EXCL)) cl349@5598: flags = XS_WRITE_CREATE_EXCL; cl349@5598: else cl349@5598: return -EINVAL; cl349@5598: cl349@5598: iovec[0].iov_base = (void *)path; cl349@5598: iovec[0].iov_len = strlen(path) + 1; cl349@5598: iovec[1].iov_base = (void *)flags; cl349@5598: iovec[1].iov_len = strlen(flags) + 1; cl349@5863: iovec[2].iov_base = (void *)string; cl349@5863: iovec[2].iov_len = strlen(string); cl349@5598: cl349@5598: return xs_error(xs_talkv(XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL)); cl349@5598: } kaf24@6480: EXPORT_SYMBOL(xenbus_write); cl349@5598: cl349@5598: /* Create a new directory. */ cl349@5863: int xenbus_mkdir(const char *dir, const char *node) cl349@5598: { cl349@5863: return xs_error(xs_single(XS_MKDIR, join(dir, node), NULL)); cl349@5598: } kaf24@6480: EXPORT_SYMBOL(xenbus_mkdir); cl349@5598: cl349@5598: /* Destroy a file or directory (directories must be empty). */ cl349@5863: int xenbus_rm(const char *dir, const char *node) cl349@5598: { cl349@5863: return xs_error(xs_single(XS_RM, join(dir, node), NULL)); cl349@5598: } kaf24@6480: EXPORT_SYMBOL(xenbus_rm); cl349@5598: cl349@5598: /* Start a transaction: changes by others will not be seen during this cl349@5598: * transaction, and changes will not be visible to others until end. cl349@5598: * Transaction only applies to the given subtree. cl349@5598: * You can only have one transaction at any time. cl349@5598: */ cl349@5863: int xenbus_transaction_start(const char *subtree) cl349@5598: { cl349@5598: return xs_error(xs_single(XS_TRANSACTION_START, subtree, NULL)); cl349@5598: } kaf24@6467: EXPORT_SYMBOL(xenbus_transaction_start); cl349@5598: cl349@5598: /* End a transaction. cl349@5598: * If abandon is true, transaction is discarded instead of committed. cl349@5598: */ cl349@5863: int xenbus_transaction_end(int abort) cl349@5598: { cl349@5598: char abortstr[2]; cl349@5598: cl349@5598: if (abort) cl349@5598: strcpy(abortstr, "F"); cl349@5598: else cl349@5598: strcpy(abortstr, "T"); cl349@5598: return xs_error(xs_single(XS_TRANSACTION_END, abortstr, NULL)); cl349@5598: } kaf24@6467: EXPORT_SYMBOL(xenbus_transaction_end); cl349@5598: cl349@5863: /* Single read and scanf: returns -errno or num scanned. */ cl349@5863: int xenbus_scanf(const char *dir, const char *node, const char *fmt, ...) cl349@5598: { cl349@5863: va_list ap; cl349@5863: int ret; cl349@5863: char *val; cl349@5863: cl349@5863: val = xenbus_read(dir, node, NULL); cl349@5863: if (IS_ERR(val)) cl349@5863: return PTR_ERR(val); cl349@5598: cl349@5863: va_start(ap, fmt); cl349@5863: ret = vsscanf(val, fmt, ap); cl349@5863: va_end(ap); cl349@5863: kfree(val); cl349@5863: /* Distinctive errno. */ cl349@5863: if (ret == 0) cl349@5863: return -ERANGE; cl349@5863: return ret; cl349@5863: } kaf24@6467: EXPORT_SYMBOL(xenbus_scanf); cl349@5863: cl349@5863: /* Single printf and write: returns -errno or 0. */ cl349@5863: int xenbus_printf(const char *dir, const char *node, const char *fmt, ...) cl349@5598: { cl349@5863: va_list ap; cl349@5863: int ret; cl349@5863: cl349@5863: BUG_ON(down_trylock(&xenbus_lock) == 0); cl349@5863: va_start(ap, fmt); cl349@5874: ret = vsnprintf(printf_buffer, sizeof(printf_buffer), fmt, ap); cl349@5863: va_end(ap); cl349@5863: cl349@5874: BUG_ON(ret > sizeof(printf_buffer)-1); cl349@5874: return xenbus_write(dir, node, printf_buffer, O_CREAT); cl349@5598: } kaf24@6467: EXPORT_SYMBOL(xenbus_printf); cl349@5598: cl349@5874: /* Report a (negative) errno into the store, with explanation. */ cl349@5874: void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...) cl349@5874: { cl349@5874: va_list ap; cl349@5874: int ret; cl349@5874: unsigned int len; cl349@5874: cl349@5874: BUG_ON(down_trylock(&xenbus_lock) == 0); cl349@5874: cl349@5874: len = sprintf(printf_buffer, "%i ", -err); cl349@5874: va_start(ap, fmt); cl349@5874: ret = vsnprintf(printf_buffer+len, sizeof(printf_buffer)-len, fmt, ap); cl349@5874: va_end(ap); cl349@5874: cl349@5874: BUG_ON(len + ret > sizeof(printf_buffer)-1); cl349@5874: dev->has_error = 1; cl349@5874: if (xenbus_write(dev->nodename, "error", printf_buffer, O_CREAT) != 0) cl349@5874: printk("xenbus: failed to write error node for %s (%s)\n", cl349@5874: dev->nodename, printf_buffer); cl349@5874: } kaf24@6467: EXPORT_SYMBOL(xenbus_dev_error); cl349@5874: cl349@5874: /* Clear any error. */ cl349@5874: void xenbus_dev_ok(struct xenbus_device *dev) cl349@5598: { cl349@5874: if (dev->has_error) { cl349@5874: if (xenbus_rm(dev->nodename, "error") != 0) cl349@5874: printk("xenbus: failed to clear error node for %s\n", cl349@5874: dev->nodename); cl349@5874: else cl349@5874: dev->has_error = 0; cl349@5874: } cl349@5874: } kaf24@6467: EXPORT_SYMBOL(xenbus_dev_ok); cl349@5874: cl349@5863: /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */ cl349@5863: int xenbus_gather(const char *dir, ...) cl349@5863: { cl349@5863: va_list ap; cl349@5863: const char *name; cl349@5863: int ret = 0; cl349@5598: cl349@5863: va_start(ap, dir); cl349@5863: while (ret == 0 && (name = va_arg(ap, char *)) != NULL) { cl349@5863: const char *fmt = va_arg(ap, char *); cl349@5863: void *result = va_arg(ap, void *); cl349@5863: char *p; cl349@5863: cl349@5863: p = xenbus_read(dir, name, NULL); cl349@5863: if (IS_ERR(p)) { cl349@5863: ret = PTR_ERR(p); cl349@5863: break; cl349@5863: } cl349@6250: if (fmt) { cl349@6250: if (sscanf(p, fmt, result) == 0) cl349@6250: ret = -EINVAL; cl349@6250: kfree(p); cl349@6250: } else cl349@6250: *(char **)result = p; cl349@5863: } cl349@5863: va_end(ap); cl349@5863: return ret; cl349@5598: } kaf24@6467: EXPORT_SYMBOL(xenbus_gather); cl349@5598: cl349@5876: static int xs_watch(const char *path, const char *token) cl349@5598: { cl349@5876: struct kvec iov[2]; cl349@5598: cl349@5598: iov[0].iov_base = (void *)path; cl349@5598: iov[0].iov_len = strlen(path) + 1; cl349@5598: iov[1].iov_base = (void *)token; cl349@5598: iov[1].iov_len = strlen(token) + 1; cl349@5598: cl349@5598: return xs_error(xs_talkv(XS_WATCH, iov, ARRAY_SIZE(iov), NULL)); cl349@5598: } cl349@5598: cl349@5598: static char *xs_read_watch(char **token) cl349@5598: { cl349@5598: enum xsd_sockmsg_type type; cl349@5598: char *ret; cl349@5598: cl349@5598: ret = read_reply(&type, NULL); cl349@5598: if (IS_ERR(ret)) cl349@5598: return ret; cl349@5598: cl349@5598: BUG_ON(type != XS_WATCH_EVENT); cl349@5598: *token = ret + strlen(ret) + 1; cl349@5598: return ret; cl349@5598: } cl349@5598: cl349@5598: static int xs_acknowledge_watch(const char *token) cl349@5598: { cl349@5598: return xs_error(xs_single(XS_WATCH_ACK, token, NULL)); cl349@5598: } cl349@5598: cl349@5598: static int xs_unwatch(const char *path, const char *token) cl349@5598: { cl349@5598: struct kvec iov[2]; cl349@5598: cl349@5598: iov[0].iov_base = (char *)path; cl349@5598: iov[0].iov_len = strlen(path) + 1; cl349@5598: iov[1].iov_base = (char *)token; cl349@5598: iov[1].iov_len = strlen(token) + 1; cl349@5598: cl349@5598: return xs_error(xs_talkv(XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL)); cl349@5598: } cl349@5598: cl349@5598: /* A little paranoia: we don't just trust token. */ cl349@5598: static struct xenbus_watch *find_watch(const char *token) cl349@5598: { cl349@5598: struct xenbus_watch *i, *cmp; cl349@5598: cl349@5598: cmp = (void *)simple_strtoul(token, NULL, 16); cl349@5598: cl349@5598: list_for_each_entry(i, &watches, list) cl349@5598: if (i == cmp) cl349@5598: return i; cl349@5598: return NULL; cl349@5598: } cl349@5598: cl349@5598: /* Register callback to watch this node. */ cl349@5598: int register_xenbus_watch(struct xenbus_watch *watch) cl349@5598: { cl349@5598: /* Pointer in ascii is the token. */ cl349@5598: char token[sizeof(watch) * 2 + 1]; cl349@5598: int err; cl349@5598: cl349@5598: sprintf(token, "%lX", (long)watch); cl349@5598: BUG_ON(find_watch(token)); cl349@5598: cl349@5876: err = xs_watch(watch->node, token); cl349@5598: if (!err) cl349@5598: list_add(&watch->list, &watches); cl349@5598: return err; cl349@5598: } kaf24@6467: EXPORT_SYMBOL(register_xenbus_watch); cl349@5598: cl349@5598: void unregister_xenbus_watch(struct xenbus_watch *watch) cl349@5598: { cl349@5598: char token[sizeof(watch) * 2 + 1]; cl349@5598: int err; cl349@5598: cl349@5598: sprintf(token, "%lX", (long)watch); cl349@5598: BUG_ON(!find_watch(token)); cl349@5598: cl349@5598: err = xs_unwatch(watch->node, token); cl349@5598: list_del(&watch->list); cl349@5598: cl349@5598: if (err) cl349@5903: printk(KERN_WARNING cl349@5903: "XENBUS Failed to release watch %s: %i\n", cl349@5598: watch->node, err); cl349@5598: } kaf24@6467: EXPORT_SYMBOL(unregister_xenbus_watch); cl349@5598: cl349@6209: /* Re-register callbacks to all watches. */ cl349@6209: void reregister_xenbus_watches(void) cl349@6209: { cl349@6209: struct xenbus_watch *watch; cl349@6209: char token[sizeof(watch) * 2 + 1]; cl349@6209: cl349@6209: list_for_each_entry(watch, &watches, list) { cl349@6209: sprintf(token, "%lX", (long)watch); cl349@6209: xs_watch(watch->node, token); cl349@6209: } cl349@6209: } cl349@6209: cl349@5598: static int watch_thread(void *unused) cl349@5598: { cl349@5598: for (;;) { cl349@5598: char *token; cl349@5598: char *node = NULL; cl349@5598: cl349@5902: wait_event(xb_waitq, xs_input_avail()); cl349@5598: cl349@5598: /* If this is a spurious wakeup caused by someone cl349@5598: * doing an op, they'll hold the lock and the buffer cl349@5598: * will be empty by the time we get there. cl349@5598: */ cl349@5863: down(&xenbus_lock); cl349@5902: if (xs_input_avail()) cl349@5598: node = xs_read_watch(&token); cl349@5747: cl349@5598: if (node && !IS_ERR(node)) { cl349@5598: struct xenbus_watch *w; cl349@5598: int err; cl349@5598: cl349@5903: err = xs_acknowledge_watch(token); cl349@5903: if (err) cl349@5903: printk(KERN_WARNING "XENBUS ack %s fail %i\n", cl349@5903: node, err); cl349@5598: w = find_watch(token); cl349@5598: BUG_ON(!w); cl349@5598: w->callback(w, node); cl349@5598: kfree(node); cl349@6600: } else if (node) cl349@5598: printk(KERN_WARNING "XENBUS xs_read_watch: %li\n", cl349@5598: PTR_ERR(node)); cl349@5863: up(&xenbus_lock); cl349@5598: } cl349@5598: } cl349@5598: cl349@5598: int xs_init(void) cl349@5598: { cl349@5598: int err; cl349@5598: struct task_struct *watcher; cl349@5598: cl349@5902: err = xb_init_comms(); cl349@5598: if (err) cl349@5598: return err; cl349@5598: cl349@5598: watcher = kthread_run(watch_thread, NULL, "kxbwatch"); cl349@5598: if (IS_ERR(watcher)) cl349@5598: return PTR_ERR(watcher); cl349@5598: return 0; cl349@5598: }