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
|