From a575a4a3a8917a7249751537752831cc53cf573f Mon Sep 17 00:00:00 2001 From: "cl349@firebug.cl.cam.ac.uk" Date: Tue, 28 Jun 2005 15:44:49 +0000 Subject: bitkeeper revision 1.1766 (42c17071SPDLo7qPlXAiQzrKjMu6Mw) Add xenbus driver. XendDomainInfo.py: Connect/Disconnect domains to/from store. Signed-off-by: Rusty Russel (authored) Signed-off-by: Mike Wray Signed-off-by: Christian Limpach --- .rootkeys | 6 + linux-2.6.11-xen-sparse/drivers/xen/Makefile | 1 + .../drivers/xen/xenbus/Makefile | 10 + .../drivers/xen/xenbus/xenbus_comms.c | 208 +++++ .../drivers/xen/xenbus/xenbus_comms.h | 14 + .../drivers/xen/xenbus/xenbus_probe.c | 870 +++++++++++++++++++++ .../drivers/xen/xenbus/xenbus_xs.c | 488 ++++++++++++ linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h | 143 ++++ tools/python/xen/xend/XendDomainInfo.py | 18 +- 9 files changed, 1749 insertions(+), 9 deletions(-) create mode 100644 linux-2.6.11-xen-sparse/drivers/xen/xenbus/Makefile create mode 100644 linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.c create mode 100644 linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.h create mode 100644 linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_probe.c create mode 100644 linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_xs.c create mode 100644 linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h diff --git a/.rootkeys b/.rootkeys index 0263593bc7..eabfd517d7 100644 --- a/.rootkeys +++ b/.rootkeys @@ -346,6 +346,11 @@ 41ee5e8bglvqKvZSY5uJ5JGQejEwyQ linux-2.6.11-xen-sparse/drivers/xen/usbback/usbback.c 41ee5e8ckZ9xVNvu9NHIZDK7JqApmQ linux-2.6.11-xen-sparse/drivers/xen/usbfront/usbfront.c 41ee5e8ck9scpGirfqEZRARbGDyTXA linux-2.6.11-xen-sparse/drivers/xen/usbfront/xhci.h +42c16ff4NMHjAt9hJHldXC-4_A6HRw linux-2.6.11-xen-sparse/drivers/xen/xenbus/Makefile +42c16ff4IWzDjvg0o08Nt-JrmuoJsA linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.c +42c16ff4DukLxK4_pUAN0Gv0jLNaZQ linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.h +42c16ff4fR8SNUirS3q19HNzTVoDXw linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_probe.c +42c16ff4goC8GfJvEqNFgE1Y8fNs5g linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_xs.c 412f47e4RKD-R5IS5gEXvcT8L4v8gA linux-2.6.11-xen-sparse/include/asm-generic/pgtable.h 42400318xlBIV46qyxLTaDepPLNyhg linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/agp.h 40f56239YAjS52QG2FIAQpHDZAdGHg linux-2.6.11-xen-sparse/include/asm-xen/asm-i386/desc.h @@ -420,6 +425,7 @@ 4122466356eIBnC9ot44WSVVIFyhQA linux-2.6.11-xen-sparse/include/asm-xen/queues.h 42a885cawNQ18_b7i5-G7ekMsZ48hw linux-2.6.11-xen-sparse/include/asm-xen/synch_bitops.h 3f689063BoW-HWV3auUJ-OqXfcGArw linux-2.6.11-xen-sparse/include/asm-xen/xen_proc.h +42c16ff4t7djt61KEsejdrL8gNfQSA linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h 419b4e93z2S0gR17XTy8wg09JEwAhg linux-2.6.11-xen-sparse/include/linux/gfp.h 42305f545Vc5SLCUewZ2-n-P9JJhEQ linux-2.6.11-xen-sparse/include/linux/highmem.h 419dfc609zbti8rqL60tL2dHXQ_rvQ linux-2.6.11-xen-sparse/include/linux/irq.h diff --git a/linux-2.6.11-xen-sparse/drivers/xen/Makefile b/linux-2.6.11-xen-sparse/drivers/xen/Makefile index 50e13067a3..d3bb24a201 100644 --- a/linux-2.6.11-xen-sparse/drivers/xen/Makefile +++ b/linux-2.6.11-xen-sparse/drivers/xen/Makefile @@ -4,6 +4,7 @@ obj-y += console/ obj-y += evtchn/ obj-y += balloon/ obj-y += privcmd/ +obj-y += xenbus/ obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/ obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/ diff --git a/linux-2.6.11-xen-sparse/drivers/xen/xenbus/Makefile b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/Makefile new file mode 100644 index 0000000000..fc36f5ded6 --- /dev/null +++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/Makefile @@ -0,0 +1,10 @@ +obj-y += xenbus.o + +xenbus-objs = +xenbus-objs += xenbus_comms.o +xenbus-objs += xenbus_xs.o +xenbus-objs += xenbus_probe.o + +XEN_TOOLS_DIR := "../tools" +vpath %.h $(XEN_TOOLS_DIR) +EXTRA_CFLAGS += -I $(XEN_TOOLS_DIR) diff --git a/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.c b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.c new file mode 100644 index 0000000000..67146efea8 --- /dev/null +++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.c @@ -0,0 +1,208 @@ +/****************************************************************************** + * xenbus_comms.c + * + * Low level code to talks to Xen Store: ringbuffer and event channel. + * + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +//#define DEBUG + +#include +#include +#include +#include +#include +#include +#include "xenbus_comms.h" + +#define RINGBUF_DATASIZE ((PAGE_SIZE / 2) - sizeof(struct ringbuf_head)) +struct ringbuf_head +{ + u32 write; /* Next place to write to */ + u32 read; /* Next place to read from */ + u8 flags; + char buf[0]; +} __attribute__((packed)); + +DECLARE_WAIT_QUEUE_HEAD(xb_waitq); + +static irqreturn_t wake_waiting(int irq, void *unused, struct pt_regs *regs) +{ + wake_up(&xb_waitq); + return IRQ_HANDLED; +} + +static int check_buffer(const struct ringbuf_head *h) +{ + return (h->write < RINGBUF_DATASIZE && h->read < RINGBUF_DATASIZE); +} + +/* We can't fill last byte: would look like empty buffer. */ +static void *get_output_chunk(const struct ringbuf_head *h, + void *buf, u32 *len) +{ + u32 read_mark; + + if (h->read == 0) + read_mark = RINGBUF_DATASIZE - 1; + else + read_mark = h->read - 1; + + /* Here to the end of buffer, unless they haven't read some out. */ + *len = RINGBUF_DATASIZE - h->write; + if (read_mark >= h->write) + *len = read_mark - h->write; + return buf + h->write; +} + +static const void *get_input_chunk(const struct ringbuf_head *h, + const void *buf, u32 *len) +{ + /* Here to the end of buffer, unless they haven't written some. */ + *len = RINGBUF_DATASIZE - h->read; + if (h->write >= h->read) + *len = h->write - h->read; + return buf + h->read; +} + +static void update_output_chunk(struct ringbuf_head *h, u32 len) +{ + h->write += len; + if (h->write == RINGBUF_DATASIZE) + h->write = 0; +} + +static void update_input_chunk(struct ringbuf_head *h, u32 len) +{ + h->read += len; + if (h->read == RINGBUF_DATASIZE) + h->read = 0; +} + +static int output_avail(struct ringbuf_head *out) +{ + unsigned int avail; + + get_output_chunk(out, out->buf, &avail); + return avail != 0; +} + +int xb_write(struct ringbuf_head *out, const void *data, unsigned len) +{ + struct ringbuf_head h; + + do { + void *dst; + unsigned int avail; + + wait_event(xb_waitq, output_avail(out)); + + /* Read, then check: not that we don't trust store. + * Hell, some of my best friends are daemons. But, + * in this post-911 world... */ + h = *out; + mb(); + if (!check_buffer(&h)) { + set_current_state(TASK_RUNNING); + return -EIO; /* ETERRORIST! */ + } + + dst = get_output_chunk(&h, out->buf, &avail); + if (avail > len) + avail = len; + memcpy(dst, data, avail); + data += avail; + len -= avail; + update_output_chunk(out, avail); + notify_via_evtchn(xen_start_info.store_evtchn); + } while (len != 0); + + return 0; +} + +int xs_input_avail(struct ringbuf_head *in) +{ + unsigned int avail; + + get_input_chunk(in, in->buf, &avail); + return avail != 0; +} + +int xb_read(struct ringbuf_head *in, void *data, unsigned len) +{ + struct ringbuf_head h; + int was_full; + + while (len != 0) { + unsigned int avail; + const char *src; + + wait_event(xb_waitq, xs_input_avail(in)); + h = *in; + mb(); + if (!check_buffer(&h)) { + set_current_state(TASK_RUNNING); + return -EIO; + } + + src = get_input_chunk(&h, in->buf, &avail); + if (avail > len) + avail = len; + was_full = !output_avail(&h); + + memcpy(data, src, avail); + data += avail; + len -= avail; + update_input_chunk(in, avail); + pr_debug("Finished read of %i bytes (%i to go)\n", avail, len); + /* If it was full, tell them we've taken some. */ + if (was_full) + notify_via_evtchn(xen_start_info.store_evtchn); + } + + /* If we left something, wake watch thread to deal with it. */ + if (xs_input_avail(in)) + wake_up(&xb_waitq); + + return 0; +} + +/* Set up interrpt handler off store event channel. */ +int xb_init_comms(void **in, void **out) +{ + int err, irq; + + irq = bind_evtchn_to_irq(xen_start_info.store_evtchn); + + err = request_irq(irq, wake_waiting, SA_SHIRQ, "xenbus", &xb_waitq); + if (err) { + printk(KERN_ERR "XENBUS request irq failed %i\n", err); + unbind_evtchn_from_irq(xen_start_info.store_evtchn); + return err; + } + + *out = (void *)xen_start_info.store_page; + *in = (void *)xen_start_info.store_page + PAGE_SIZE/2; + return 0; +} diff --git a/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.h b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.h new file mode 100644 index 0000000000..0967863000 --- /dev/null +++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.h @@ -0,0 +1,14 @@ +/* Private include for xenbus communications. */ +#ifndef _XENBUS_COMMS_H +#define _XENBUS_COMMS_H +int xs_init(void); +int xb_init_comms(void **in, void **out); + +/* Low level routines. */ +struct ringbuf_head; +int xb_write(struct ringbuf_head *out, const void *data, unsigned len); +int xb_read(struct ringbuf_head *in, void *data, unsigned len); +int xs_input_avail(struct ringbuf_head *in); +extern wait_queue_head_t xb_waitq; + +#endif /* _XENBUS_COMMS_H */ diff --git a/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_probe.c b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_probe.c new file mode 100644 index 0000000000..2ee59a3084 --- /dev/null +++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @@ -0,0 +1,870 @@ +/****************************************************************************** + * Talks to Xen Store to figure out what devices we have. + * Currently experiment code, but when I grow up I'll be a bus driver! + * + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * Copyright (C) 2005 Mike Wray, Hewlett-Packard + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "xenbus_comms.h" + +/* Directory inside a domain containing devices. */ +#define XENBUS_DEVICE_DIR "device" + +/* Directory inside a domain containing backends. */ +#define XENBUS_BACKEND_DIR "backend" + +/* Name of field containing device id. */ +#define XENBUS_DEVICE_ID "id" + +/* Name of field containing device type. */ +#define XENBUS_DEVICE_TYPE "type" + +//#define DEBUG + +#ifdef DEBUG +#define dprintf(_fmt, _args...) \ +printk(KERN_INFO __stringify(KBUILD_MODNAME) " [DBG] %s" _fmt, __FUNCTION__, ##_args) +#else +#define dprintf(_fmt, _args...) do { } while(0) +#endif + +static int xs_init_done = 0; + +/* Return the path to dir with /name appended. + * If name is null or empty returns a copy of dir. + */ +char *xenbus_path(const char *dir, const char *name) +{ + char *ret; + if(name && strlen(name)){ + ret = kmalloc(strlen(dir) + 1 + strlen(name) + 1, GFP_KERNEL); + if (!ret) + return NULL; + strcpy(ret, dir); + strcat(ret, "/"); + strcat(ret, name); + } else { + ret = kmalloc(strlen(dir) + 1, GFP_KERNEL); + if (!ret) + return NULL; + strcpy(ret, dir); + } + return ret; +} + +#define streq(a, b) (strcmp((a), (b)) == 0) + +char *xenbus_read(const char *dir, const char *name, unsigned int *data_n) +{ + int err = 0; + char *data = NULL; + char *path = xenbus_path(dir, name); + int n = 0; + + if (!path) { + err = -ENOMEM; + goto out; + } + data = xs_read(path, &n); + if (IS_ERR(data)){ + err = PTR_ERR(data); + if(err == -EISDIR){ + err = -ENOENT; + } + } else if(n == 0){ + err = -ENOENT; + kfree(data); + } else if(data[n - 1] != '\0') { + /* This shouldn't happen: everything is supposed to be a string. */ + printk("XENBUS: Reading path %s: missing null terminator len=%i\n", path, n); + err = -EINVAL; + kfree(data); + n = 0; + } + kfree(path); + out: + if(data_n) + *data_n = n; + return (err ? ERR_PTR(err) : data); +} + +int xenbus_write(const char *dir, const char *name, const char *data, int data_n) +{ + int err = 0; + char *path = xenbus_path(dir, name); + + if (!path) + return -ENOMEM; + err = xs_write(path, data, data_n, O_CREAT); + kfree(path); + return err; +} + +int xenbus_read_string(const char *dir, const char *name, char **val) +{ + int err = 0; + + *val = xenbus_read(dir, name, NULL); + if (IS_ERR(*val)) { + err = PTR_ERR(*val); + *val = NULL; + } + return err; +} + +int xenbus_write_string(const char *dir, const char *name, const char *val) +{ + return xenbus_write(dir, name, val, strlen(val) + 1); +} + +int xenbus_read_ulong(const char *dir, const char *name, unsigned long *val) +{ + int err = 0; + char *data = NULL, *end = NULL; + unsigned int data_n = 0; + + data = xenbus_read(dir, name, &data_n); + if (IS_ERR(data)) { + err = PTR_ERR(data); + goto out; + } + if (data_n <= 1) { + err = -ENOENT; + goto free_data; + } + *val = simple_strtoul(data, &end, 10); + if (end != data + data_n - 1) { + printk("XENBUS: Path %s/%s, bad parse of '%s' as ulong\n", + dir, name, data); + err = -EINVAL; + } + free_data: + kfree(data); + out: + if (err) + *val = 0; + return err; +} + +int xenbus_write_ulong(const char *dir, const char *name, unsigned long val) +{ + char data[32] = {}; + + snprintf(data, sizeof(data), "%lu", val); + return xenbus_write(dir, name, data, strlen(data) + 1); +} + +int xenbus_read_long(const char *dir, const char *name, long *val) +{ + int err = 0; + char *data = NULL, *end = NULL; + unsigned int data_n = 0; + + data = xenbus_read(dir, name, &data_n); + if (IS_ERR(data)) { + err = PTR_ERR(data); + goto out; + } + if (data_n <= 1) { + err = -ENOENT; + goto free_data; + } + *val = simple_strtol(data, &end, 10); + if (end != data + data_n - 1) { + printk("XENBUS: Path %s/%s, bad parse of '%s' as long\n", + dir, name, data); + err = -EINVAL; + } + free_data: + kfree(data); + out: + if (err) + *val = 0; + return err; +} + +int xenbus_write_long(const char *dir, const char *name, long val) +{ + char data[32] = {}; + + snprintf(data, sizeof(data), "%li", val); + return xenbus_write(dir, name, data, strlen(data) + 1); +} + +/* Number of characters in string form of a MAC address. */ +#define MAC_LENGTH 17 + +/** Convert a mac address from a string of the form + * XX:XX:XX:XX:XX:XX to numerical form (an array of 6 unsigned chars). + * Each X denotes a hex digit: 0..9, a..f, A..F. + * Also supports using '-' as the separator instead of ':'. + */ +static int mac_aton(const char *macstr, unsigned int n, unsigned char mac[6]){ + int err = -EINVAL; + int i, j; + const char *p; + char sep = 0; + + if(!macstr || n != MAC_LENGTH){ + goto exit; + } + for(i = 0, p = macstr; i < 6; i++){ + unsigned char d = 0; + if(i){ + if(!sep){ + if(*p == ':' || *p == '-') sep = *p; + } + if(sep && *p == sep){ + p++; + } else { + goto exit; + } + } + for(j = 0; j < 2; j++, p++){ + if(j) d <<= 4; + if(isdigit(*p)){ + d += *p - '0'; + } else if(isxdigit(*p)){ + d += toupper(*p) - 'A' + 10; + } else { + goto exit; + } + } + mac[i] = d; + } + err = 0; + exit: + return err; +} + +int xenbus_read_mac(const char *dir, const char *name, unsigned char mac[6]) +{ + int err = 0; + char *data = 0; + unsigned int data_n = 0; + + data = xenbus_read(dir, name, &data_n); + if (IS_ERR(data)) { + err = PTR_ERR(data); + goto out; + } + if (data_n <= 1) { + err = -ENOENT; + goto free_data; + } + err = mac_aton(data, data_n - 1, mac); + if (err) { + printk("XENBUS: Path %s/%s, bad parse of '%s' as mac\n", + dir, name, data); + err = -EINVAL; + } + free_data: + kfree(data); + out: + if(err) + memset(mac, 0, sizeof(mac)); + return err; +} + +int xenbus_write_mac(const char *dir, const char *name, const unsigned char mac[6]) +{ + char buf[MAC_LENGTH + 1] = {}; + int buf_n = sizeof(buf); + + snprintf(buf, buf_n, "%02x:%02x:%02x:%02x:%02x:%02x", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + buf[buf_n - 1] = '\0'; + return xenbus_write(dir, name, buf, buf_n); +} + +/* Read event channel information from xenstore. + * + * Event channel xenstore fields: + * dom1 - backend domain id (int) + * port1 - backend port (int) + * dom2 - frontend domain id (int) + * port2 - frontend port (int) + */ +int xenbus_read_evtchn(const char *dir, const char *name, struct xenbus_evtchn *evtchn) +{ + int err = 0; + char *evtchn_path = xenbus_path(dir, name); + + if (!evtchn_path) { + err = -ENOMEM; + goto out; + } + err = xenbus_read_ulong(evtchn_path, "dom1", &evtchn->dom1); + if(err) + goto free_evtchn_path; + err = xenbus_read_ulong(evtchn_path, "port1", &evtchn->port1); + if(err) + goto free_evtchn_path; + err = xenbus_read_ulong(evtchn_path, "dom2", &evtchn->dom2); + if(err) + goto free_evtchn_path; + err = xenbus_read_ulong(evtchn_path, "port2", &evtchn->port2); + + free_evtchn_path: + kfree(evtchn_path); + out: + if (err) + *evtchn = (struct xenbus_evtchn){}; + return err; +} + +/* Write a message to 'dir'. + * The data is 'val' followed by parameter names and values, + * terminated by NULL. + */ +int xenbus_message(const char *dir, const char *val, ...) +{ + static const char *mid_name = "@mid"; + va_list args; + int err = 0; + char *mid_path = NULL; + char *msg_path = NULL; + char mid_str[32] = {}; + long mid = 0; + int i; + + va_start(args, val); + mid_path = xenbus_path(dir, mid_name); + if (!mid_path) { + err = -ENOMEM; + goto out; + } + err = xenbus_read_long(dir, mid_name, &mid); + if(err != -ENOENT) + goto out; + mid++; + err = xenbus_write_long(dir, mid_name, mid); + if(err) + goto out; + sprintf(mid_str, "%li", mid); + msg_path = xenbus_path(dir, mid_str); + if (!mid_path) { + err = -ENOMEM; + goto out; + } + + for(i = 0; i < 16; i++){ + char *k, *v; + k = va_arg(args, char *); + if(!k) + break; + v = va_arg(args, char *); + if(!v) + break; + err = xenbus_write_string(msg_path, k, v); + if(err) + goto out; + } + err = xenbus_write_string(msg_path, NULL, val); + + out: + kfree(msg_path); + kfree(mid_path); + va_end(args); + return err; +} + +/* If something in array of ids matches this device, return it. */ +static const struct xenbus_device_id * +match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev) +{ + for( ; !streq(arr->devicetype, ""); arr++) { + if (!streq(arr->devicetype, dev->devicetype)) + continue; + + if (streq(arr->subtype, "") + || streq(arr->subtype, dev->subtype)) { + return arr; + } + } + return NULL; +} + +static int xenbus_match(struct device *_dev, struct device_driver *_drv) +{ + struct xenbus_driver *drv = to_xenbus_driver(_drv); + + if (!drv->ids) + return 0; + + return match_device(drv->ids, to_xenbus_device(_dev)) != NULL; +} + +/* Bus type for frontend drivers. */ +static struct bus_type xenbus_type = { + .name = "xenbus", + .match = xenbus_match, +}; + + +/* Bus type for backend drivers. */ +static struct bus_type xenback_type = { + .name = "xenback", + .match = xenbus_match, +}; + +struct xenbus_for_dev { + int (*fn)(struct xenbus_device *, void *); + void *data; +}; + +static int for_dev(struct device *_dev, void *_data) +{ + struct xenbus_device *dev = to_xenbus_device(_dev); + struct xenbus_for_dev *data = _data; + dev = to_xenbus_device(_dev); + return data->fn(dev, data->data); +} + +int xenbus_for_each_dev(struct xenbus_device * start, void * data, + int (*fn)(struct xenbus_device *, void *)) +{ + struct xenbus_for_dev for_data = { + .fn = fn, + .data = data, + }; + if(!fn) + return -EINVAL; + printk("%s> data=%p fn=%p for_data=%p\n", __FUNCTION__, + data, fn, &for_data); + return bus_for_each_dev(&xenbus_type, + (start ? &start->dev : NULL), + &for_data, for_dev); +} + +struct xenbus_for_drv { + int (*fn)(struct xenbus_driver *, void *); + void *data; +}; + +static int for_drv(struct device_driver *_drv, void *_data) +{ + struct xenbus_driver *drv = to_xenbus_driver(_drv); + struct xenbus_for_drv *data = _data; + return data->fn(drv, data->data); +} + +int xenbus_for_each_drv(struct xenbus_driver * start, void * data, + int (*fn)(struct xenbus_driver *, void *)) +{ + struct xenbus_for_drv for_data = { + .fn = fn, + .data = data, + }; + if(!fn) + return -EINVAL; + return bus_for_each_drv(&xenbus_type, + (start ? &start->driver: NULL), + &for_data, for_drv); +} + +static int xenbus_dev_probe(struct device *_dev) +{ + struct xenbus_device *dev = to_xenbus_device(_dev); + struct xenbus_driver *drv = to_xenbus_driver(_dev->driver); + const struct xenbus_device_id *id; + + if (!drv->probe) + return -ENODEV; + + id = match_device(drv->ids, dev); + if (!id) + return -ENODEV; + return drv->probe(dev, id); +} + +static int xenbus_dev_remove(struct device *_dev) +{ + struct xenbus_device *dev = to_xenbus_device(_dev); + struct xenbus_driver *drv = to_xenbus_driver(_dev->driver); + + if(!drv->remove) + return 0; + return drv->remove(dev); +} + +int xenbus_register_driver(struct xenbus_driver *drv) +{ + int err = 0; + + printk("%s> frontend driver %p %s\n", __FUNCTION__, + drv, drv->name); + drv->driver.name = drv->name; + drv->driver.bus = &xenbus_type; + drv->driver.owner = drv->owner; + drv->driver.probe = xenbus_dev_probe; + drv->driver.remove = xenbus_dev_remove; + + err = driver_register(&drv->driver); + if(err == 0 && xs_init_done && drv->connect){ + printk("%s> connecting driver %p %s\n", __FUNCTION__, + drv, drv->name); + drv->connect(drv); + } + return err; +} + +void xenbus_unregister_driver(struct xenbus_driver *drv) +{ + driver_unregister(&drv->driver); +} + +static int xenbus_probe_device(const char *dir, const char *name) +{ + int err; + struct xenbus_device *xendev; + unsigned int xendev_n; + long id; + char *nodename, *devicetype; + unsigned int devicetype_n; + + dprintf("> dir=%s name=%s\n", dir, name); + nodename = xenbus_path(dir, name); + if (!nodename) + return -ENOMEM; + + devicetype = xenbus_read(nodename, XENBUS_DEVICE_TYPE, &devicetype_n); + if (IS_ERR(devicetype)) { + err = PTR_ERR(devicetype); + goto free_nodename; + } + + err = xenbus_read_long(nodename, XENBUS_DEVICE_ID, &id); + if (err == -ENOENT) { + id = 0; + } else if (err != 0) { + goto free_devicetype; + } + + dprintf("> devicetype='%s' name='%s' id=%ld\n", devicetype, name, id); + /* FIXME: This could be a rescan. Don't re-register existing devices. */ + + /* Add space for the strings. */ + xendev_n = sizeof(*xendev) + strlen(nodename) + strlen(devicetype) + 2; + xendev = kmalloc(xendev_n, GFP_KERNEL); + if (!xendev) { + err = -ENOMEM; + goto free_devicetype; + } + memset(xendev, 0, xendev_n); + + snprintf(xendev->dev.bus_id, BUS_ID_SIZE, "%s-%s", devicetype, name); + xendev->dev.bus = &xenbus_type; + + xendev->id = id; + + /* Copy the strings into the extra space. */ + xendev->nodename = (char *)(xendev + 1); + strcpy(xendev->nodename, nodename); + xendev->devicetype = xendev->nodename + strlen(xendev->nodename) + 1; + strcpy(xendev->devicetype, devicetype); + + /* Register with generic device framework. */ + printk("XENBUS: Registering device %s\n", xendev->dev.bus_id); + err = device_register(&xendev->dev); + if (err) { + printk("XENBUS: Registering device %s: error %i\n", + xendev->dev.bus_id, err); + } + if (err) + kfree(xendev); + +free_devicetype: + kfree(devicetype); +free_nodename: + kfree(nodename); + dprintf("< err=%i\n", err); + return err; +} + +static int xenbus_probe_device_type(const char *dirpath, const char *typename) +{ + int err = 0; + char **dir; + char *path; + unsigned int dir_n = 0; + int i; + + dprintf("> dirpath=%s typename=%s\n", dirpath, typename); + path = xenbus_path(dirpath, typename); + if (!path) + return -ENOMEM; + + dir = xs_directory(path, &dir_n); + if (IS_ERR(dir)) { + err = PTR_ERR(dir); + goto out; + } + + for (i = 0; i < dir_n; i++) { + err = xenbus_probe_device(path, dir[i]); + if (err) + break; + } + kfree(dir); +out: + kfree(path); + dprintf("< err=%i\n", err); + return err; +} + +static int xenbus_probe_devices(const char *path) +{ + int err = 0; + char **dir; + unsigned int i, dir_n; + + dprintf("> path=%s\n", path); + down(&xs_lock); + dir = xs_directory(path, &dir_n); + if (IS_ERR(dir)) { + err = PTR_ERR(dir); + goto unlock; + } + for (i = 0; i < dir_n; i++) { + err = xenbus_probe_device_type(path, dir[i]); + if (err) + break; + } + kfree(dir); +unlock: + up(&xs_lock); + dprintf("< err=%i\n", err); + return err; +} + + +static int xenbus_probe_backend(const char *dir, const char *name) +{ + int err = 0; + struct xenbus_device *xendev = NULL; + unsigned int xendev_n = 0; + char *nodename = NULL, *devicetype = NULL; + unsigned int devicetype_n = 0; + + dprintf("> dir=%s name=%s\n", dir, name); + nodename = xenbus_path(dir, name); + if (!nodename) + return -ENOMEM; + + devicetype = xenbus_read(nodename, XENBUS_DEVICE_TYPE, &devicetype_n); + if (IS_ERR(devicetype)) { + err = PTR_ERR(devicetype); + goto free_nodename; + } + + dprintf("> devicetype='%s'\n", devicetype); + /* FIXME: This could be a rescan. Don't re-register existing devices. */ + + /* Add space for the strings. */ + xendev_n = sizeof(*xendev) + strlen(nodename) + strlen(devicetype) + 2; + xendev = kmalloc(xendev_n, GFP_KERNEL); + if (!xendev) { + err = -ENOMEM; + goto free_devicetype; + } + memset(xendev, 0, xendev_n); + + snprintf(xendev->dev.bus_id, BUS_ID_SIZE, "%s", devicetype); + xendev->dev.bus = &xenback_type; + + /* Copy the strings into the extra space. */ + xendev->nodename = (char *)(xendev + 1); + strcpy(xendev->nodename, nodename); + xendev->devicetype = xendev->nodename + strlen(xendev->nodename) + 1; + strcpy(xendev->devicetype, devicetype); + + /* Register with generic device framework. */ + printk("XENBUS: Registering backend %s\n", xendev->dev.bus_id); + err = device_register(&xendev->dev); + if (err) { + printk("XENBUS: Registering device %s: error %i\n", + xendev->dev.bus_id, err); + } + if (err) + kfree(xendev); + +free_devicetype: + kfree(devicetype); +free_nodename: + kfree(nodename); + dprintf("< err=%i\n", err); + return err; +} + +static int xenbus_probe_backends(const char *path) +{ + int err = 0; + char **dir; + unsigned int i, dir_n; + + dprintf("> path=%s\n", path); + down(&xs_lock); + dir = xs_directory(path, &dir_n); + if (IS_ERR(dir)) { + err = PTR_ERR(dir); + goto unlock; + } + for (i = 0; i < dir_n; i++) { + err = xenbus_probe_backend(path, dir[i]); + if (err) + break; + } + kfree(dir); +unlock: + up(&xs_lock); + dprintf("< err=%i\n", err); + return err; +} + +int xenbus_register_backend(struct xenbus_driver *drv) +{ + int err = 0; + + printk("%s> backend driver %p %s\n", __FUNCTION__, + drv, drv->name); + drv->driver.name = drv->name; + drv->driver.bus = &xenback_type; + drv->driver.owner = drv->owner; + drv->driver.probe = xenbus_dev_probe; + drv->driver.remove = xenbus_dev_remove; + + err = driver_register(&drv->driver); + if(err == 0 && xs_init_done && drv->connect){ + printk("%s> connecting driver %p %s\n", __FUNCTION__, + drv, drv->name); + drv->connect(drv); + } + return err; +} + +void xenbus_unregister_backend(struct xenbus_driver *drv) +{ + driver_unregister(&drv->driver); +} + +int xenbus_for_each_backend(struct xenbus_driver * start, void * data, + int (*fn)(struct xenbus_driver *, void *)) +{ + struct xenbus_for_drv for_data = { + .fn = fn, + .data = data, + }; + if(!fn) + return -EINVAL; + return bus_for_each_drv(&xenback_type, + (start ? &start->driver: NULL), + &for_data, for_drv); +} + +static void test_callback(struct xenbus_watch *w, const char *node) +{ + printk("test_callback: got watch hit for %s\n", node); +} + +static void test_watch(void) +{ + static int init_done = 0; + static struct xenbus_watch watch = { .node = "/", + .priority = 0, + .callback = test_callback }; + + if(init_done) return; + printk("registering watch %lX = %i\n", + (long)&watch, + register_xenbus_watch(&watch)); + init_done = 1; +} + +static int xenbus_driver_connect(struct xenbus_driver *drv, void *data) +{ + printk("%s> driver %p %s\n", __FUNCTION__, drv, drv->name); + if (drv->connect) { + printk("%s> connecting driver %p %s\n", __FUNCTION__, + drv, drv->name); + drv->connect(drv); + } + printk("%s< driver %p %s\n", __FUNCTION__, drv, drv->name); + return 0; +} + +int do_xenbus_connect(void *unused) +{ + int err = 0; + + printk("%s> xs_init_done=%d\n", __FUNCTION__, xs_init_done); + if (xs_init_done) + goto exit; + /* Initialize xenstore comms unless already done. */ + printk("store_evtchn = %i\n", xen_start_info.store_evtchn); + err = xs_init(); + if (err) { + printk("XENBUS: Error initializing xenstore comms:" + " %i\n", err); + goto exit; + } + xs_init_done = 1; + + /* Notify drivers that xenstore has connected. */ + test_watch(); + printk("%s> connect drivers...\n", __FUNCTION__); + xenbus_for_each_drv(NULL, NULL, xenbus_driver_connect); + printk("%s> connect backends...\n", __FUNCTION__); + xenbus_for_each_backend(NULL, NULL, xenbus_driver_connect); + + /* Enumerate devices and backends in xenstore. */ + xenbus_probe_devices(XENBUS_DEVICE_DIR); + xenbus_probe_backends(XENBUS_BACKEND_DIR); + +exit: + printk("%s< err=%d\n", __FUNCTION__, err); + return err; +} + +static int __init xenbus_probe_init(void) +{ + bus_register(&xenbus_type); + bus_register(&xenback_type); + + if (!xen_start_info.store_evtchn) + return 0; + + do_xenbus_connect(NULL); + return 0; +} + +postcore_initcall(xenbus_probe_init); diff --git a/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_xs.c b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_xs.c new file mode 100644 index 0000000000..4151864121 --- /dev/null +++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_xs.c @@ -0,0 +1,488 @@ +/****************************************************************************** + * xenbus_xs.c + * + * This is the kernel equivalent of the "xs" library. We don't need everything + * and we use xenbus_comms to communication. + * + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include "xenstore/xenstored.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "xenbus_comms.h" + +#define streq(a, b) (strcmp((a), (b)) == 0) + +static void *xs_in, *xs_out; +static LIST_HEAD(watches); +static DECLARE_MUTEX(watches_lock); +DECLARE_MUTEX(xs_lock); + +static int get_error(const char *errorstring) +{ + unsigned int i; + + for (i = 0; !streq(errorstring, xsd_errors[i].errstring); i++) { + if (i == ARRAY_SIZE(xsd_errors) - 1) { + printk(KERN_WARNING "XENBUS xen store gave: unknown error %s", + errorstring); + return EINVAL; + } + } + return xsd_errors[i].errnum; +} + +static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) +{ + struct xsd_sockmsg msg; + void *ret; + int err; + + err = xb_read(xs_in, &msg, sizeof(msg)); + if (err) + return ERR_PTR(err); + + ret = kmalloc(msg.len + 1, GFP_KERNEL); + if (!ret) + return ERR_PTR(-ENOMEM); + + err = xb_read(xs_in, ret, msg.len); + if (err) { + kfree(ret); + return ERR_PTR(err); + } + ((char*)ret)[msg.len] = '\0'; + + *type = msg.type; + if (len) + *len = msg.len; + return ret; +} + +/* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ +static void *xs_talkv(enum xsd_sockmsg_type type, + const struct kvec *iovec, + unsigned int num_vecs, + unsigned int *len) +{ + struct xsd_sockmsg msg; + void *ret = NULL; + unsigned int i; + int err; + + WARN_ON(down_trylock(&xs_lock) == 0); + + msg.type = type; + msg.len = 0; + for (i = 0; i < num_vecs; i++) + msg.len += iovec[i].iov_len; + + err = xb_write(xs_out, &msg, sizeof(msg)); + if (err) + return ERR_PTR(err); + + for (i = 0; i < num_vecs; i++) { + err = xb_write(xs_out, iovec[i].iov_base, iovec[i].iov_len);; + if (err) + return ERR_PTR(err); + } + + /* Watches can have fired before reply comes: daemon detects + * and re-transmits, so we can ignore this. */ + do { + kfree(ret); + ret = read_reply(&msg.type, len); + if (IS_ERR(ret)) + return ret; + } while (msg.type == XS_WATCH_EVENT); + + if (msg.type == XS_ERROR) { + err = get_error(ret); + kfree(ret); + return ERR_PTR(-err); + } + + BUG_ON(msg.type != type); + return ret; +} + +/* Simplified version of xs_talkv: single message. */ +static void *xs_single(enum xsd_sockmsg_type type, + const char *string, unsigned int *len) +{ + struct kvec iovec; + + iovec.iov_base = (void *)string; + iovec.iov_len = strlen(string) + 1; + return xs_talkv(type, &iovec, 1, len); +} + +/* Many commands only need an ack, don't care what it says. */ +static int xs_error(char *reply) +{ + if (IS_ERR(reply)) + return PTR_ERR(reply); + kfree(reply); + return 0; +} + +static unsigned int count_strings(const char *strings, unsigned int len) +{ + unsigned int num; + const char *p; + + for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1) + num++; + + return num; +} + +char **xs_directory(const char *path, unsigned int *num) +{ + char *strings, *p, **ret; + unsigned int len; + + strings = xs_single(XS_DIRECTORY, path, &len); + if (IS_ERR(strings)) + return (char **)strings; + + /* Count the strings. */ + *num = count_strings(strings, len); + + /* Transfer to one big alloc for easy freeing. */ + ret = kmalloc(*num * sizeof(char *) + len, GFP_ATOMIC); + if (!ret) { + kfree(strings); + return ERR_PTR(-ENOMEM); + } + memcpy(&ret[*num], strings, len); + kfree(strings); + + strings = (char *)&ret[*num]; + for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1) + ret[(*num)++] = p; + return ret; +} + +/* Check if a path exists. Return 1 if it does. */ +int xs_exists(const char *path) +{ + char **dir; + int dir_n; + + dir = xs_directory(path, &dir_n); + if(IS_ERR(dir)) + return 0; + kfree(dir); + return 1; +} + +/* Make a directory, creating dirs on the path to it if necessary. + * Return 0 on success, error code otherwise. + */ +int xs_mkdirs(const char *path) +{ + int err = 0; + char s[strlen(path) + 1], *p = s; + + if(xs_exists(path)) + goto out; + strcpy(p, path); + if(*p == '/') + p++; + for( ; ; ){ + p = strchr(p, '/'); + if(p) + *p = '\0'; + if(!xs_exists(s)){ + err = xs_mkdir(s); + if(err) + goto out; + + } + if(!p) + break; + *p++ = '/'; + } + out: + return err; +} + + +/* Get the value of a single file. + * Returns a kmalloced value: call free() on it after use. + * len indicates length in bytes. + */ +void *xs_read(const char *path, unsigned int *len) +{ + return xs_single(XS_READ, path, len); +} + +/* Write the value of a single file. + * Returns -err on failure. createflags can be 0, O_CREAT, or O_CREAT|O_EXCL. + */ +int xs_write(const char *path, + const void *data, unsigned int len, int createflags) +{ + const char *flags; + struct kvec iovec[3]; + + /* Format: Flags (as string), path, data. */ + if (createflags == 0) + flags = XS_WRITE_NONE; + else if (createflags == O_CREAT) + flags = XS_WRITE_CREATE; + else if (createflags == (O_CREAT|O_EXCL)) + flags = XS_WRITE_CREATE_EXCL; + else + return -EINVAL; + + iovec[0].iov_base = (void *)path; + iovec[0].iov_len = strlen(path) + 1; + iovec[1].iov_base = (void *)flags; + iovec[1].iov_len = strlen(flags) + 1; + iovec[2].iov_base = (void *)data; + iovec[2].iov_len = len; + + return xs_error(xs_talkv(XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL)); +} + +/* Create a new directory. */ +int xs_mkdir(const char *path) +{ + return xs_error(xs_single(XS_MKDIR, path, NULL)); +} + +/* Destroy a file or directory (directories must be empty). */ +int xs_rm(const char *path) +{ + return xs_error(xs_single(XS_RM, path, NULL)); +} + +/* Start a transaction: changes by others will not be seen during this + * transaction, and changes will not be visible to others until end. + * Transaction only applies to the given subtree. + * You can only have one transaction at any time. + */ +int xs_transaction_start(const char *subtree) +{ + return xs_error(xs_single(XS_TRANSACTION_START, subtree, NULL)); +} + +/* End a transaction. + * If abandon is true, transaction is discarded instead of committed. + */ +int xs_transaction_end(int abort) +{ + char abortstr[2]; + + if (abort) + strcpy(abortstr, "F"); + else + strcpy(abortstr, "T"); + return xs_error(xs_single(XS_TRANSACTION_END, abortstr, NULL)); +} + +char *xs_get_domain_path(domid_t domid) +{ + char domid_str[32]; + + sprintf(domid_str, "%u", domid); + return xs_single(XS_GETDOMAINPATH, domid_str, NULL); +} + +static int xs_watch(const char *path, const char *token, unsigned int priority) +{ + char prio[32]; + struct kvec iov[3]; + + sprintf(prio, "%u", priority); + iov[0].iov_base = (void *)path; + iov[0].iov_len = strlen(path) + 1; + iov[1].iov_base = (void *)token; + iov[1].iov_len = strlen(token) + 1; + iov[2].iov_base = prio; + iov[2].iov_len = strlen(prio) + 1; + + return xs_error(xs_talkv(XS_WATCH, iov, ARRAY_SIZE(iov), NULL)); +} + +static char *xs_read_watch(char **token) +{ + enum xsd_sockmsg_type type; + char *ret; + + ret = read_reply(&type, NULL); + if (IS_ERR(ret)) + return ret; + + BUG_ON(type != XS_WATCH_EVENT); + *token = ret + strlen(ret) + 1; + return ret; +} + +static int xs_acknowledge_watch(const char *token) +{ + return xs_error(xs_single(XS_WATCH_ACK, token, NULL)); +} + +static int xs_unwatch(const char *path, const char *token) +{ + struct kvec iov[2]; + + iov[0].iov_base = (char *)path; + iov[0].iov_len = strlen(path) + 1; + iov[1].iov_base = (char *)token; + iov[1].iov_len = strlen(token) + 1; + + return xs_error(xs_talkv(XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL)); +} + +/* A little paranoia: we don't just trust token. */ +static struct xenbus_watch *find_watch(const char *token) +{ + struct xenbus_watch *i, *cmp; + + cmp = (void *)simple_strtoul(token, NULL, 16); + + list_for_each_entry(i, &watches, list) + if (i == cmp) + return i; + return NULL; +} + +/* Register callback to watch this node. */ +int register_xenbus_watch(struct xenbus_watch *watch) +{ + /* Pointer in ascii is the token. */ + char token[sizeof(watch) * 2 + 1]; + int err; + + sprintf(token, "%lX", (long)watch); + down(&watches_lock); + BUG_ON(find_watch(token)); + + down(&xs_lock); + err = xs_watch(watch->node, token, watch->priority); + up(&xs_lock); + if (!err) + list_add(&watch->list, &watches); + up(&watches_lock); + return err; +} + +void unregister_xenbus_watch(struct xenbus_watch *watch) +{ + char token[sizeof(watch) * 2 + 1]; + int err; + + sprintf(token, "%lX", (long)watch); + down(&watches_lock); + BUG_ON(!find_watch(token)); + + down(&xs_lock); + err = xs_unwatch(watch->node, token); + up(&xs_lock); + list_del(&watch->list); + up(&watches_lock); + + if (err) + printk(KERN_WARNING "XENBUS Failed to release watch %s: %i\n", + watch->node, err); +} + +static int watch_thread(void *unused) +{ + int err; + unsigned long mtu; + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ*10); + printk("watch_thread, doing read\n"); + down(&xs_lock); + err = xenbus_read_long("", "mtu", &mtu); + up(&xs_lock); + printk("fake field read: %i (%lu)\n", err, mtu); + + for (;;) { + char *token; + char *node = NULL; + + wait_event(xb_waitq, xs_input_avail(xs_in)); + + /* If this is a spurious wakeup caused by someone + * doing an op, they'll hold the lock and the buffer + * will be empty by the time we get there. + */ + down(&xs_lock); + if (xs_input_avail(xs_in)) + node = xs_read_watch(&token); + /* Release lock before calling callback. */ + up(&xs_lock); + if (node && !IS_ERR(node)) { + struct xenbus_watch *w; + int err; + + down(&watches_lock); + w = find_watch(token); + BUG_ON(!w); + w->callback(w, node); + up(&watches_lock); + down(&xs_lock); + err = xs_acknowledge_watch(token); + if (err) + printk(KERN_WARNING + "XENBUS acknowledge %s failed %i\n", + node, err); + up(&xs_lock); + kfree(node); + } else + printk(KERN_WARNING "XENBUS xs_read_watch: %li\n", + PTR_ERR(node)); + } +} + +int xs_init(void) +{ + int err; + struct task_struct *watcher; + + err = xb_init_comms(&xs_in, &xs_out); + if (err) + return err; + + watcher = kthread_run(watch_thread, NULL, "kxbwatch"); + if (IS_ERR(watcher)) + return PTR_ERR(watcher); + return 0; +} diff --git a/linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h b/linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h new file mode 100644 index 0000000000..d97d64cba0 --- /dev/null +++ b/linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h @@ -0,0 +1,143 @@ +#ifndef _ASM_XEN_XENBUS_H +#define _ASM_XEN_XENBUS_H +/****************************************************************************** + * xenbus.h + * + * Talks to Xen Store to figure out what devices we have. + * + * Copyright (C) 2005 Rusty Russell, IBM Corporation + * + * This file may be distributed separately from the Linux kernel, or + * incorporated into other software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, modify, + * merge, publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include +#include + +/* A xenbus device. */ +struct xenbus_device { + char *devicetype; + char *subtype; + char *nodename; + int id; + struct device dev; +}; + +static inline struct xenbus_device *to_xenbus_device(struct device *dev) +{ + return container_of(dev, struct xenbus_device, dev); +} + +struct xenbus_device_id +{ + /* .../device// */ + char devicetype[32]; /* General class of device. */ + char subtype[32]; /* Contents of "subtype" for this device */ +}; + +/* A xenbus driver. */ +struct xenbus_driver { + char *name; + struct module *owner; + const struct xenbus_device_id *ids; + /* Called when xenstore is connected. */ + int (*connect) (struct xenbus_driver * drv); + + int (*probe) (struct xenbus_device * dev, const struct xenbus_device_id * id); + int (*remove) (struct xenbus_device * dev); + int (*configure)(struct xenbus_device * dev); + + struct device_driver driver; +}; + +struct xenbus_evtchn { + unsigned long dom1; + unsigned long port1; + unsigned long dom2; + unsigned long port2; +}; + +static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv) +{ + return container_of(drv, struct xenbus_driver, driver); +} + +int xenbus_register_driver(struct xenbus_driver *drv); +void xenbus_unregister_driver(struct xenbus_driver *drv); + +int xenbus_register_backend(struct xenbus_driver *drv); +void xenbus_unregister_backend(struct xenbus_driver *drv); + +/* Iterator over xenbus devices (frontend). */ +int xenbus_for_each_dev(struct xenbus_device * start, void * data, + int (*fn)(struct xenbus_device *, void *)); + +/* Iterator over xenbus drivers (frontend). */ +int xenbus_for_each_drv(struct xenbus_driver * start, void * data, + int (*fn)(struct xenbus_driver *, void *)); + +/* Iterator over xenbus drivers (backend). */ +int xenbus_for_each_backend(struct xenbus_driver * start, void * data, + int (*fn)(struct xenbus_driver *, void *)); + +/* Caller must hold this lock to call these functions. */ +extern struct semaphore xs_lock; + +char **xs_directory(const char *path, unsigned int *num); +void *xs_read(const char *path, unsigned int *len); +int xs_write(const char *path, + const void *data, unsigned int len, int createflags); +int xs_mkdir(const char *path); +int xs_exists(const char *path); +int xs_mkdirs(const char *path); +int xs_rm(const char *path); +int xs_transaction_start(const char *subtree); +int xs_transaction_end(int abort); +char *xs_get_domain_path(domid_t domid); + +/* Register callback to watch this node. */ +struct xenbus_watch +{ + struct list_head list; + char *node; + unsigned int priority; + void (*callback)(struct xenbus_watch *, const char *node); +}; + +int register_xenbus_watch(struct xenbus_watch *watch); +void unregister_xenbus_watch(struct xenbus_watch *watch); + +char *xenbus_path(const char *dir, const char *name); +char *xenbus_read(const char *dir, const char *name, unsigned int *data_n); +int xenbus_write(const char *dir, const char *name, + const char *data, int data_n); + +int xenbus_read_string(const char *dir, const char *name, char **val); +int xenbus_write_string(const char *dir, const char *name, const char *val); +int xenbus_read_ulong(const char *dir, const char *name, unsigned long *val); +int xenbus_write_ulong(const char *dir, const char *name, unsigned long val); +int xenbus_read_long(const char *dir, const char *name, long *val); +int xenbus_write_long(const char *dir, const char *name, long val); +int xenbus_read_mac(const char *dir, const char *name, unsigned char mac[6]); +int xenbus_write_mac(const char *dir, const char *name, const unsigned char mac[6]); +int xenbus_read_evtchn(const char *dir, const char *name, struct xenbus_evtchn *evtchn); +int xenbus_message(const char *dir, const char *val, ...); + +#endif /* _ASM_XEN_XENBUS_H */ diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index 4716f4958e..f8b36d44a9 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -565,10 +565,10 @@ class XendDomainInfo: self.create_channel() self.image.createImage() self.exportToDB() - #if self.store_channel: - # self.db.introduceDomain(self.id, - # self.store_mfn, - # self.store_channel) + if self.store_channel: + self.db.introduceDomain(self.id, + self.store_mfn, + self.store_channel) def delete(self): """Delete the vm's db. @@ -615,11 +615,11 @@ class XendDomainInfo: self.store_channel = None except: pass - #try: - # self.db.releaseDomain(self.id) - #except Exception, ex: - # log.warning("error in domain release on xenstore: %s", ex) - # pass + try: + self.db.releaseDomain(self.id) + except Exception, ex: + log.warning("error in domain release on xenstore: %s", ex) + pass if self.image: try: self.image.destroy() -- cgit v1.2.3