WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] Add xenbus driver.

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] Add xenbus driver.
From: BitKeeper Bot <riel@xxxxxxxxxxx>
Date: Tue, 28 Jun 2005 15:44:49 +0000
Cc: james@xxxxxxxxxxxxx
Delivery-date: Tue, 28 Jun 2005 18:01:05 +0000
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: Xen Development List <xen-devel@xxxxxxxxxxxxxxxxxxx>
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
ChangeSet 1.1766, 2005/06/28 16:44:49+01:00, cl349@xxxxxxxxxxxxxxxxxxxx

        Add xenbus driver.
        XendDomainInfo.py:
          Connect/Disconnect domains to/from store.
        Signed-off-by: Rusty Russel <rusty@xxxxxxxxxxxxxxx> (authored)
        Signed-off-by: Mike Wray <mike.wray@xxxxxx>
        Signed-off-by: Christian Limpach <Christian.Limpach@xxxxxxxxxxxx>



 linux-2.6.11-xen-sparse/drivers/xen/Makefile              |    1 
 linux-2.6.11-xen-sparse/drivers/xen/xenbus/Makefile       |   10 
 linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.c |  208 +++
 linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.h |   14 
 linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_probe.c |  870 ++++++++++++++
 linux-2.6.11-xen-sparse/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 
 8 files changed, 1743 insertions(+), 9 deletions(-)


diff -Nru a/linux-2.6.11-xen-sparse/drivers/xen/Makefile 
b/linux-2.6.11-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6.11-xen-sparse/drivers/xen/Makefile      2005-06-28 14:02:15 
-04:00
+++ b/linux-2.6.11-xen-sparse/drivers/xen/Makefile      2005-06-28 14:02:15 
-04:00
@@ -4,6 +4,7 @@
 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 -Nru a/linux-2.6.11-xen-sparse/drivers/xen/xenbus/Makefile 
b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/Makefile
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/Makefile       2005-06-28 
14:02:15 -04:00
@@ -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 -Nru 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
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.c 2005-06-28 
14:02:15 -04:00
@@ -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 <asm-xen/hypervisor.h>
+#include <asm-xen/evtchn.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#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 -Nru 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
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_comms.h 2005-06-28 
14:02:15 -04:00
@@ -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 -Nru 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
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_probe.c 2005-06-28 
14:02:15 -04:00
@@ -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 <asm-xen/hypervisor.h>
+#include <asm-xen/xenbus.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/fcntl.h>
+#include <stdarg.h>
+#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 -Nru 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
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/linux-2.6.11-xen-sparse/drivers/xen/xenbus/xenbus_xs.c    2005-06-28 
14:02:15 -04:00
@@ -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 <linux/errno.h>
+#include <linux/types.h>
+#include "xenstore/xenstored.h"
+#include <linux/uio.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/fcntl.h>
+#include <linux/kthread.h>
+#include <asm-xen/xenbus.h>
+#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 -Nru a/linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h 
b/linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/linux-2.6.11-xen-sparse/include/asm-xen/xenbus.h  2005-06-28 14:02:15 
-04:00
@@ -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 <linux/device.h>
+#include <asm/semaphore.h>
+
+/* 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/<device_type>/<identifier> */
+       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 -Nru a/tools/python/xen/xend/XendDomainInfo.py 
b/tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py   2005-06-28 14:02:15 -04:00
+++ b/tools/python/xen/xend/XendDomainInfo.py   2005-06-28 14:02:15 -04:00
@@ -565,10 +565,10 @@
         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 @@
                 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()

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] Add xenbus driver., BitKeeper Bot <=