[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] Merge in the newer Xenbus implementation from Linux to the Mini-OS. The new



# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 7557f0b4098c4c3c5ac9d6620672d62263c91366
# Parent  5f7398785e02a753d50c022b6dbe5a6983166f89
Merge in the newer Xenbus implementation from Linux to the Mini-OS. The new
version compiles and starts up, but I'm not really sure how to test the new
xenbus implementation.

* Added unbind_evtchn
* Copied parts of the Linux spinlock implementation to make the changes to
  xenbus compared to Linux smaller. Also added a dummy rwsem implementation.
* Updated the xenbus-files

Signed-off-by: Simon Kagstrom <simon.kagstrom@xxxxxx>

diff -r 5f7398785e02 -r 7557f0b4098c extras/mini-os/events.c
--- a/extras/mini-os/events.c   Thu Dec  8 14:21:36 2005
+++ b/extras/mini-os/events.c   Thu Dec  8 14:24:02 2005
@@ -56,7 +56,7 @@
 
 }
 
-void bind_evtchn( u32 port, void (*handler)(int, struct pt_regs *) )
+int bind_evtchn( u32 port, void (*handler)(int, struct pt_regs *) )
 {
        if(ev_actions[port].handler)
         printk("WARN: Handler for port %d already registered, replacing\n",
@@ -67,6 +67,16 @@
  
        /* Finally unmask the port */
        unmask_evtchn(port);
+
+       return port;
+}
+
+void unbind_evtchn( u32 port )
+{
+       if (!ev_actions[port].handler)
+               printk("WARN: No handler for port %d when unbinding\n", port);
+       ev_actions[port].handler = NULL;
+       ev_actions[port].status |= EVS_DISABLED;
 }
 
 int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *) )
@@ -90,6 +100,10 @@
        return ret;
 }
 
+void unbind_virq( u32 port )
+{
+       unbind_evtchn(port);
+}
 
 
 /*
diff -r 5f7398785e02 -r 7557f0b4098c extras/mini-os/include/events.h
--- a/extras/mini-os/include/events.h   Thu Dec  8 14:21:36 2005
+++ b/extras/mini-os/include/events.h   Thu Dec  8 14:24:02 2005
@@ -40,10 +40,12 @@
 /* prototypes */
 int do_event(u32 port, struct pt_regs *regs);
 int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *) );
-void bind_evtchn( u32 virq, void (*handler)(int, struct pt_regs *) );
+int bind_evtchn( u32 virq, void (*handler)(int, struct pt_regs *) );
+void unbind_evtchn( u32 port );
 void init_events(void);
+void unbind_virq( u32 port );
 
-static inline int notify_via_evtchn(int port)
+static inline int notify_remote_via_evtchn(int port)
 {
     evtchn_op_t op;
     op.cmd = EVTCHNOP_send;
diff -r 5f7398785e02 -r 7557f0b4098c extras/mini-os/include/os.h
--- a/extras/mini-os/include/os.h       Thu Dec  8 14:21:36 2005
+++ b/extras/mini-os/include/os.h       Thu Dec  8 14:24:02 2005
@@ -131,9 +131,11 @@
 #if defined(__i386__)
 #define mb()    __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
 #define rmb()   __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
+#define wmb()  __asm__ __volatile__ ("": : :"memory")
 #elif defined(__x86_64__)
 #define mb()    __asm__ __volatile__ ("mfence":::"memory")
 #define rmb()   __asm__ __volatile__ ("lfence":::"memory")
+#define wmb()  __asm__ __volatile__ ("sfence" ::: "memory") /* From 
CONFIG_UNORDERED_IO (linux) */
 #endif
 
 
diff -r 5f7398785e02 -r 7557f0b4098c extras/mini-os/include/semaphore.h
--- a/extras/mini-os/include/semaphore.h        Thu Dec  8 14:21:36 2005
+++ b/extras/mini-os/include/semaphore.h        Thu Dec  8 14:24:02 2005
@@ -2,6 +2,7 @@
 #define _SEMAPHORE_H_
 
 #include <wait.h>
+#include <spinlock.h>
 
 /*
  * Implementation of semaphore in Mini-os is simple, because 
@@ -14,6 +15,15 @@
        struct wait_queue_head wait;
 };
 
+/*
+ * the semaphore definition
+ */
+struct rw_semaphore {
+       signed long             count;
+       spinlock_t              wait_lock;
+       struct list_head        wait_list;
+       int                     debug;
+};
 
 #define __SEMAPHORE_INITIALIZER(name, n)                            \
 {                                                                   \
@@ -31,6 +41,12 @@
 
 #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
 
+static inline void init_MUTEX(struct semaphore *sem)
+{
+  sem->count = 1;
+  init_waitqueue_head(&sem->wait);
+}
+
 static void inline down(struct semaphore *sem)
 {
     wait_event(sem->wait, sem->count > 0);
@@ -43,4 +59,27 @@
     wake_up(&sem->wait);
 }
 
+/* FIXME! Thre read/write semaphores are unimplemented! */
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+  sem->count = 1;
+}
+
+static inline void down_read(struct rw_semaphore *sem)
+{
+}
+
+
+static inline void up_read(struct rw_semaphore *sem)
+{
+}
+
+static inline void up_write(struct rw_semaphore *sem)
+{
+}
+
+static inline void down_write(struct rw_semaphore *sem)
+{
+}
+
 #endif /* _SEMAPHORE_H */
diff -r 5f7398785e02 -r 7557f0b4098c extras/mini-os/include/wait.h
--- a/extras/mini-os/include/wait.h     Thu Dec  8 14:21:36 2005
+++ b/extras/mini-os/include/wait.h     Thu Dec  8 14:24:02 2005
@@ -33,6 +33,10 @@
 }
 
 
+static inline void init_waitqueue_head(struct wait_queue_head *h)
+{
+  INIT_LIST_HEAD(&h->thread_list);
+}
 
 static inline void init_waitqueue_entry(struct wait_queue *q, struct thread 
*thread)
 {
diff -r 5f7398785e02 -r 7557f0b4098c extras/mini-os/include/xenbus.h
--- a/extras/mini-os/include/xenbus.h   Thu Dec  8 14:21:36 2005
+++ b/extras/mini-os/include/xenbus.h   Thu Dec  8 14:24:02 2005
@@ -4,6 +4,7 @@
  * Talks to Xen Store to figure out what devices we have.
  *
  * Copyright (C) 2005 Rusty Russell, IBM Corporation
+ * Copyright (C) 2005 XenSource Ltd.
  * 
  * This file may be distributed separately from the Linux kernel, or
  * incorporated into other software packages, subject to the following license:
@@ -30,45 +31,98 @@
 #ifndef _ASM_XEN_XENBUS_H
 #define _ASM_XEN_XENBUS_H
 
-
-/* Caller must hold this lock to call these functions: it's also held
- * across watch callbacks. */
-// TODO
-//extern struct semaphore xenbus_lock;
-
-char **xenbus_directory(const char *dir, const char *node, unsigned int *num);
-void *xenbus_read(const char *dir, const char *node, unsigned int *len);
-int xenbus_write(const char *dir, const char *node,
-                const char *string, int createflags);
-int xenbus_mkdir(const char *dir, const char *node);
-int xenbus_exists(const char *dir, const char *node);
-int xenbus_rm(const char *dir, const char *node);
-int xenbus_transaction_start(const char *subtree);
-int xenbus_transaction_end(int abort);
-
-/* Single read and scanf: returns -errno or num scanned if > 0. */
-int xenbus_scanf(const char *dir, const char *node, const char *fmt, ...)
-       __attribute__((format(scanf, 3, 4)));
-
-/* Single printf and write: returns -errno or 0. */
-int xenbus_printf(const char *dir, const char *node, const char *fmt, ...)
-       __attribute__((format(printf, 3, 4)));
-
-/* Generic read function: NULL-terminated triples of name,
- * sprintf-style type string, and pointer. Returns 0 or errno.*/
-int xenbus_gather(const char *dir, ...);
+#include <errno.h>
+#include <xen/io/xenbus.h>
+#include <xen/io/xs_wire.h>
 
 /* Register callback to watch this node. */
 struct xenbus_watch
 {
        struct list_head list;
-       char *node;
-       void (*callback)(struct xenbus_watch *, const char *node);
-};
+
+       /* Path being watched. */
+       const char *node;
+
+       /* Callback (executed in a process context with no locks held). */
+       void (*callback)(struct xenbus_watch *,
+                        const char **vec, unsigned int len);
+};
+
+
+/* A xenbus device. */
+struct xenbus_device {
+       const char *devicetype;
+       const char *nodename;
+       const char *otherend;
+       int otherend_id;
+       struct xenbus_watch otherend_watch;
+       int has_error;
+       void *data;
+};
+
+struct xenbus_device_id
+{
+       /* .../device/<device_type>/<identifier> */
+       char devicetype[32];    /* General class of device. */
+};
+
+/* A xenbus driver. */
+struct xenbus_driver {
+       char *name;
+       struct module *owner;
+       const struct xenbus_device_id *ids;
+       int (*probe)(struct xenbus_device *dev,
+                    const struct xenbus_device_id *id);
+       void (*otherend_changed)(struct xenbus_device *dev,
+                                XenbusState backend_state);
+       int (*remove)(struct xenbus_device *dev);
+       int (*suspend)(struct xenbus_device *dev);
+       int (*resume)(struct xenbus_device *dev);
+       int (*hotplug)(struct xenbus_device *, char **, int, char *, int);
+       int (*read_otherend_details)(struct xenbus_device *dev);
+};
+
+int xenbus_register_frontend(struct xenbus_driver *drv);
+int xenbus_register_backend(struct xenbus_driver *drv);
+void xenbus_unregister_driver(struct xenbus_driver *drv);
+
+struct xenbus_transaction;
+
+char **xenbus_directory(struct xenbus_transaction *t,
+                       const char *dir, const char *node, unsigned int *num);
+void *xenbus_read(struct xenbus_transaction *t,
+                 const char *dir, const char *node, unsigned int *len);
+int xenbus_write(struct xenbus_transaction *t,
+                const char *dir, const char *node, const char *string);
+int xenbus_mkdir(struct xenbus_transaction *t,
+                const char *dir, const char *node);
+int xenbus_exists(struct xenbus_transaction *t,
+                 const char *dir, const char *node);
+int xenbus_rm(struct xenbus_transaction *t, const char *dir, const char *node);
+struct xenbus_transaction *xenbus_transaction_start(void);
+int xenbus_transaction_end(struct xenbus_transaction *t, int abort);
+
+/* Single read and scanf: returns -errno or num scanned if > 0. */
+int xenbus_scanf(struct xenbus_transaction *t,
+                const char *dir, const char *node, const char *fmt, ...)
+       __attribute__((format(scanf, 4, 5)));
+
+/* Single printf and write: returns -errno or 0. */
+int xenbus_printf(struct xenbus_transaction *t,
+                 const char *dir, const char *node, const char *fmt, ...)
+       __attribute__((format(printf, 4, 5)));
+
+/* Generic read function: NULL-terminated triples of name,
+ * sprintf-style type string, and pointer. Returns 0 or errno.*/
+int xenbus_gather(struct xenbus_transaction *t, const char *dir, ...);
 
 int register_xenbus_watch(struct xenbus_watch *watch);
 void unregister_xenbus_watch(struct xenbus_watch *watch);
-void reregister_xenbus_watches(void);
+void xs_suspend(void);
+void xs_resume(void);
+
+/* Used by xenbus_dev to borrow kernel's store connection. */
+void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg);
 
 /* Called from xen core code. */
 void xenbus_suspend(void);
@@ -84,6 +138,87 @@
 
 #define XENBUS_EXIST_ERR(err) ((err) == -ENOENT || (err) == -ERANGE)
 
-int xs_init(void);
+
+/**
+ * Register a watch on the given path, using the given xenbus_watch structure
+ * for storage, and the given callback function as the callback.  Return 0 on
+ * success, or -errno on error.  On success, the given path will be saved as
+ * watch->node, and remains the caller's to free.  On error, watch->node will
+ * be NULL, the device will switch to XenbusStateClosing, and the error will
+ * be saved in the store.
+ */
+int xenbus_watch_path(struct xenbus_device *dev, const char *path,
+                     struct xenbus_watch *watch, 
+                     void (*callback)(struct xenbus_watch *,
+                                      const char **, unsigned int));
+
+
+/**
+ * Register a watch on the given path/path2, using the given xenbus_watch
+ * structure for storage, and the given callback function as the callback.
+ * Return 0 on success, or -errno on error.  On success, the watched path
+ * (path/path2) will be saved as watch->node, and becomes the caller's to
+ * kfree().  On error, watch->node will be NULL, so the caller has nothing to
+ * free, the device will switch to XenbusStateClosing, and the error will be
+ * saved in the store.
+ */
+int xenbus_watch_path2(struct xenbus_device *dev, const char *path,
+                      const char *path2, struct xenbus_watch *watch, 
+                      void (*callback)(struct xenbus_watch *,
+                                       const char **, unsigned int));
+
+
+/**
+ * Advertise in the store a change of the given driver to the given new_state.
+ * Perform the change inside the given transaction xbt.  xbt may be NULL, in
+ * which case this is performed inside its own transaction.  Return 0 on
+ * success, or -errno on error.  On error, the device will switch to
+ * XenbusStateClosing, and the error will be saved in the store.
+ */
+int xenbus_switch_state(struct xenbus_device *dev,
+                       struct xenbus_transaction *xbt,
+                       XenbusState new_state);
+
+
+/**
+ * Grant access to the given ring_mfn to the peer of the given device.  Return
+ * 0 on success, or -errno on error.  On error, the device will switch to
+ * XenbusStateClosing, and the error will be saved in the store.
+ */
+int xenbus_grant_ring(struct xenbus_device *dev, unsigned long ring_mfn);
+
+
+/**
+ * Allocate an event channel for the given xenbus_device, assigning the newly
+ * created local port to *port.  Return 0 on success, or -errno on error.  On
+ * error, the device will switch to XenbusStateClosing, and the error will be
+ * saved in the store.
+ */
+int xenbus_alloc_evtchn(struct xenbus_device *dev, int *port);
+
+
+/**
+ * Return the state of the driver rooted at the given store path, or
+ * XenbusStateClosed if no state can be read.
+ */
+XenbusState xenbus_read_driver_state(const char *path);
+
+
+/***
+ * Report the given negative errno into the store, along with the given
+ * formatted message.
+ */
+void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt,
+                     ...);
+
+
+/***
+ * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by
+ * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly
+ * closedown of this driver and its peer.
+ */
+void xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt,
+                     ...);
+
 
 #endif /* _ASM_XEN_XENBUS_H */
diff -r 5f7398785e02 -r 7557f0b4098c extras/mini-os/include/xmalloc.h
--- a/extras/mini-os/include/xmalloc.h  Thu Dec  8 14:21:36 2005
+++ b/extras/mini-os/include/xmalloc.h  Thu Dec  8 14:24:02 2005
@@ -6,6 +6,9 @@
 
 /* Allocate space for array of typed objects. */
 #define xmalloc_array(_type, _num) ((_type *)_xmalloc_array(sizeof(_type), 
__alignof__(_type), _num))
+
+#define malloc(size) _xmalloc(size, 4)
+#define free(ptr) xfree(ptr)
 
 /* Free any of the above. */
 extern void xfree(const void *);
diff -r 5f7398785e02 -r 7557f0b4098c extras/mini-os/kernel.c
--- a/extras/mini-os/kernel.c   Thu Dec  8 14:21:36 2005
+++ b/extras/mini-os/kernel.c   Thu Dec  8 14:24:02 2005
@@ -35,6 +35,7 @@
 #include <lib.h>
 #include <sched.h>
 #include <xenbus.h>
+#include "xenbus/xenbus_comms.h"
 
 /*
  * Shared page for communicating with the hypervisor.
diff -r 5f7398785e02 -r 7557f0b4098c extras/mini-os/xenbus/xenbus_comms.c
--- a/extras/mini-os/xenbus/xenbus_comms.c      Thu Dec  8 14:21:36 2005
+++ b/extras/mini-os/xenbus/xenbus_comms.c      Thu Dec  8 14:24:02 2005
@@ -33,35 +33,19 @@
 #include <events.h>
 #include <os.h>
 #include <lib.h>
+#include <xenbus.h>
+#include "xenbus_comms.h"
 
+static int xenbus_irq;
 
-#ifdef XENBUS_COMMS_DEBUG
-#define DEBUG(_f, _a...) \
-    printk("MINI_OS(file=xenbus_comms.c, line=%d) " _f "\n", __LINE__, ## _a)
-#else
-#define DEBUG(_f, _a...)    ((void)0)
-#endif
-
-
-#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));
+extern void xenbus_probe(void *);
+extern int xenstored_ready;
 
 DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
 
-static inline struct ringbuf_head *outbuf(void)
+static inline struct xenstore_domain_interface *xenstore_domain_interface(void)
 {
        return mfn_to_virt(start_info.store_mfn);
-}
-
-static inline struct ringbuf_head *inbuf(void)
-{
-       return (struct ringbuf_head *)((char 
*)mfn_to_virt(start_info.store_mfn) + PAGE_SIZE/2);
 }
 
 static void wake_waiting(int port, struct pt_regs *regs)
@@ -69,138 +53,112 @@
        wake_up(&xb_waitq);
 }
 
-static int check_buffer(const struct ringbuf_head *h)
+static int check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
 {
-       return (h->write < RINGBUF_DATASIZE && h->read < RINGBUF_DATASIZE);
+       return ((prod - cons) <= XENSTORE_RING_SIZE);
 }
 
-/* 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)
+static void *get_output_chunk(XENSTORE_RING_IDX cons,
+                             XENSTORE_RING_IDX prod,
+                             char *buf, uint32_t *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 (void *)((char *)buf + h->write);
+       *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
+       if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
+               *len = XENSTORE_RING_SIZE - (prod - cons);
+       return buf + MASK_XENSTORE_IDX(prod);
 }
 
-static const void *get_input_chunk(const struct ringbuf_head *h,
-                                  const void *buf, u32 *len)
+static const void *get_input_chunk(XENSTORE_RING_IDX cons,
+                                  XENSTORE_RING_IDX prod,
+                                  const char *buf, uint32_t *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 (void *)((char *)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;
+       *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
+       if ((prod - cons) < *len)
+               *len = prod - cons;
+       return buf + MASK_XENSTORE_IDX(cons);
 }
 
 int xb_write(const void *data, unsigned len)
 {
-       struct ringbuf_head h;
-       struct ringbuf_head *out = outbuf();
+       struct xenstore_domain_interface *intf = xenstore_domain_interface();
+       XENSTORE_RING_IDX cons, prod;
 
-       do {
+       while (len != 0) {
                void *dst;
                unsigned int avail;
 
-               wait_event(xb_waitq, output_avail(out));
+               wait_event(xb_waitq, (intf->req_prod - intf->req_cons) !=
+                          XENSTORE_RING_SIZE);
 
-               /* 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;
+               /* Read indexes, then verify. */
+               cons = intf->req_cons;
+               prod = intf->req_prod;
                mb();
-               if (!check_buffer(&h)) {
-                       return -1; /* ETERRORIST! */
-               }
+               if (!check_indexes(cons, prod))
+                       return -EIO;
 
-               dst = get_output_chunk(&h, out->buf, &avail);
+               dst = get_output_chunk(cons, prod, intf->req, &avail);
+               if (avail == 0)
+                       continue;
                if (avail > len)
                        avail = len;
+
                memcpy(dst, data, avail);
-               data = (void *)((char *)data + avail);
+               data = (void*) ( (unsigned long)data + avail );
                len -= avail;
-               update_output_chunk(out, avail);
-               notify_via_evtchn(start_info.store_evtchn);
-       } while (len != 0);
+
+               /* Other side must not see new header until data is there. */
+               wmb();
+               intf->req_prod += avail;
+
+               /* This implies mb() before other side sees interrupt. */
+               notify_remote_via_evtchn(start_info.store_evtchn);
+       }
 
        return 0;
 }
 
-int xs_input_avail(void)
-{
-       unsigned int avail;
-       struct ringbuf_head *in = inbuf();
-
-       get_input_chunk(in, in->buf, &avail);
-       return avail != 0;
-}
-
 int xb_read(void *data, unsigned len)
 {
-       struct ringbuf_head h;
-       struct ringbuf_head *in = inbuf();
-       int was_full;
+       struct xenstore_domain_interface *intf = xenstore_domain_interface();
+       XENSTORE_RING_IDX cons, prod;
 
        while (len != 0) {
                unsigned int avail;
                const char *src;
 
-               wait_event(xb_waitq, xs_input_avail());
-               h = *in;
+               wait_event(xb_waitq,
+                          intf->rsp_cons != intf->rsp_prod);
+
+               /* Read indexes, then verify. */
+               cons = intf->rsp_cons;
+               prod = intf->rsp_prod;
                mb();
-               if (!check_buffer(&h)) {
-                       return -1;
-               }
+               if (!check_indexes(cons, prod))
+                       return -EIO;
 
-               src = get_input_chunk(&h, in->buf, &avail);
+               src = get_input_chunk(cons, prod, intf->rsp, &avail);
+               if (avail == 0)
+                       continue;
                if (avail > len)
                        avail = len;
-               was_full = !output_avail(&h);
+
+               /* We must read header before we read data. */
+               rmb();
 
                memcpy(data, src, avail);
-               data = (void *)((char *)data + avail);
+               data = (void*) ( (unsigned long)data + avail );
                len -= avail;
-               update_input_chunk(in, avail);
-               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(start_info.store_evtchn);
+
+               /* Other side must not see free space until we've copied out */
+               mb();
+               intf->rsp_cons += avail;
+
+               printk("Finished read of %i bytes (%i to go)\n", avail, len);
+
+               /* Implies mb(): they will see new header. */
+               notify_remote_via_evtchn(start_info.store_evtchn);
        }
-
-       /* If we left something, wake watch thread to deal with it. */
-       if (xs_input_avail())
-               wake_up(&xb_waitq);
 
        return 0;
 }
@@ -208,24 +166,19 @@
 /* Set up interrupt handler off store event channel. */
 int xb_init_comms(void)
 {
-    printk("Init xenbus comms, store event channel %d\n", 
start_info.store_evtchn);
-       if (!start_info.store_evtchn)
-               return 0;
-    printk("Binding virq\n");
-       bind_evtchn(start_info.store_evtchn, &wake_waiting);
+       int err;
 
-       /* FIXME zero out page -- domain builder should probably do this*/
-       memset(mfn_to_virt(start_info.store_mfn), 0, PAGE_SIZE);
-    notify_via_evtchn(start_info.store_evtchn);
+       if (xenbus_irq)
+               unbind_evtchn(xenbus_irq);
+
+       err = bind_evtchn(
+               start_info.store_evtchn, wake_waiting);
+       if (err <= 0) {
+               printk("XENBUS request irq failed %i\n", err);
+               return err;
+       }
+
+       xenbus_irq = err;
+
        return 0;
 }
-
-void xb_suspend_comms(void)
-{
-
-       if (!start_info.store_evtchn)
-               return;
-
-    // TODO
-       //unbind_evtchn_from_irqhandler(xen_start_info.store_evtchn, &xb_waitq);
-}
diff -r 5f7398785e02 -r 7557f0b4098c extras/mini-os/xenbus/xenbus_comms.h
--- a/extras/mini-os/xenbus/xenbus_comms.h      Thu Dec  8 14:21:36 2005
+++ b/extras/mini-os/xenbus/xenbus_comms.h      Thu Dec  8 14:24:02 2005
@@ -28,8 +28,8 @@
 #ifndef _XENBUS_COMMS_H
 #define _XENBUS_COMMS_H
 
+int xs_init(void);
 int xb_init_comms(void);
-void xb_suspend_comms(void);
 
 /* Low level routines. */
 int xb_write(const void *data, unsigned len);
diff -r 5f7398785e02 -r 7557f0b4098c extras/mini-os/xenbus/xenbus_xs.c
--- a/extras/mini-os/xenbus/xenbus_xs.c Thu Dec  8 14:21:36 2005
+++ b/extras/mini-os/xenbus/xenbus_xs.c Thu Dec  8 14:24:02 2005
@@ -39,15 +39,63 @@
 #include <wait.h>
 #include <sched.h>
 #include <semaphore.h>
+#include <spinlock.h>
 #include <xen/io/xs_wire.h>
 #include "xenbus_comms.h"
 
 #define streq(a, b) (strcmp((a), (b)) == 0)
 
-static char printf_buffer[4096];
+struct xs_stored_msg {
+       struct list_head list;
+
+       struct xsd_sockmsg hdr;
+
+       union {
+               /* Queued replies. */
+               struct {
+                       char *body;
+               } reply;
+
+               /* Queued watch events. */
+               struct {
+                       struct xenbus_watch *handle;
+                       char **vec;
+                       unsigned int vec_size;
+               } watch;
+       } u;
+};
+
+struct xs_handle {
+       /* A list of replies. Currently only one will ever be outstanding. */
+       struct list_head reply_list;
+       spinlock_t reply_lock;
+       struct wait_queue_head reply_waitq;
+
+       /* One request at a time. */
+       struct semaphore request_mutex;
+
+       /* Protect transactions against save/restore. */
+       struct rw_semaphore suspend_mutex;
+};
+
+static struct xs_handle xs_state;
+
+/* List of registered watches, and a lock to protect it. */
 static LIST_HEAD(watches);
-//TODO
-DECLARE_MUTEX(xenbus_lock);
+static DEFINE_SPINLOCK(watches_lock);
+
+/* List of pending watch callback events, and a lock to protect it. */
+static LIST_HEAD(watch_events);
+static DEFINE_SPINLOCK(watch_events_lock);
+
+/*
+ * Details of the xenwatch callback kernel thread. The thread waits on the
+ * watch_events_waitq for work to do (queued on watch_events list). When it
+ * wakes up it acquires the xenwatch_mutex before reading the list and
+ * carrying out work.
+ */
+/* static */ DECLARE_MUTEX(xenwatch_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq);
 
 static int get_error(const char *errorstring)
 {
@@ -65,47 +113,82 @@
 
 static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
 {
-       struct xsd_sockmsg msg;
-       void *ret;
-       int err;
-
-       err = xb_read(&msg, sizeof(msg));
-       if (err)
-               return ERR_PTR(err);
-
-       ret = xmalloc_array(char, msg.len + 1);
-       if (!ret)
-               return ERR_PTR(-ENOMEM);
-
-       err = xb_read(ret, msg.len);
-       if (err) {
-               xfree(ret);
-               return ERR_PTR(err);
-       }
-       ((char*)ret)[msg.len] = '\0';
-
-       *type = msg.type;
+       struct xs_stored_msg *msg;
+       char *body;
+
+       spin_lock(&xs_state.reply_lock);
+
+       while (list_empty(&xs_state.reply_list)) {
+               spin_unlock(&xs_state.reply_lock);
+               wait_event(xs_state.reply_waitq,
+                          !list_empty(&xs_state.reply_list));
+               spin_lock(&xs_state.reply_lock);
+       }
+
+       msg = list_entry(xs_state.reply_list.next,
+                        struct xs_stored_msg, list);
+       list_del(&msg->list);
+
+       spin_unlock(&xs_state.reply_lock);
+
+       *type = msg->hdr.type;
        if (len)
-               *len = msg.len;
-       return ret;
+               *len = msg->hdr.len;
+       body = msg->u.reply.body;
+
+       free(msg);
+
+       return body;
 }
 
 /* Emergency write. */
 void xenbus_debug_write(const char *str, unsigned int count)
 {
-       struct xsd_sockmsg msg;
+       struct xsd_sockmsg msg = { 0 };
 
        msg.type = XS_DEBUG;
        msg.len = sizeof("print") + count + 1;
 
+       down(&xs_state.request_mutex);
        xb_write(&msg, sizeof(msg));
        xb_write("print", sizeof("print"));
        xb_write(str, count);
        xb_write("", 1);
+       up(&xs_state.request_mutex);
+}
+
+void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg)
+{
+       void *ret;
+       struct xsd_sockmsg req_msg = *msg;
+       int err;
+
+       if (req_msg.type == XS_TRANSACTION_START)
+               down_read(&xs_state.suspend_mutex);
+
+       down(&xs_state.request_mutex);
+
+       err = xb_write(msg, sizeof(*msg) + msg->len);
+       if (err) {
+               msg->type = XS_ERROR;
+               ret = ERR_PTR(err);
+       } else {
+               ret = read_reply(&msg->type, &msg->len);
+       }
+
+       up(&xs_state.request_mutex);
+
+       if ((msg->type == XS_TRANSACTION_END) ||
+           ((req_msg.type == XS_TRANSACTION_START) &&
+            (msg->type == XS_ERROR)))
+               up_read(&xs_state.suspend_mutex);
+
+       return ret;
 }
 
 /* Send message to xs, get kmalloc'ed reply.  ERR_PTR() on error. */
-static void *xs_talkv(enum xsd_sockmsg_type type,
+static void *xs_talkv(struct xenbus_transaction *t,
+                     enum xsd_sockmsg_type type,
                      const struct kvec *iovec,
                      unsigned int num_vecs,
                      unsigned int *len)
@@ -115,51 +198,57 @@
        unsigned int i;
        int err;
 
-       //WARN_ON(down_trylock(&xenbus_lock) == 0);
-
+       msg.tx_id = (u32)(unsigned long)t;
+       msg.req_id = 0;
        msg.type = type;
        msg.len = 0;
        for (i = 0; i < num_vecs; i++)
                msg.len += iovec[i].iov_len;
 
+       down(&xs_state.request_mutex);
+
        err = xb_write(&msg, sizeof(msg));
-       if (err)
+       if (err) {
+               up(&xs_state.request_mutex);
                return ERR_PTR(err);
+       }
 
        for (i = 0; i < num_vecs; i++) {
-               err = xb_write(iovec[i].iov_base, iovec[i].iov_len);
-               if (err)
+               err = xb_write(iovec[i].iov_base, iovec[i].iov_len);;
+               if (err) {
+                       up(&xs_state.request_mutex);
                        return ERR_PTR(err);
-       }
-
-       /* Watches can have fired before reply comes: daemon detects
-        * and re-transmits, so we can ignore this. */
-       do {
-               xfree(ret);
-               ret = read_reply(&msg.type, len);
-               if (IS_ERR(ret))
-                       return ret;
-       } while (msg.type == XS_WATCH_EVENT);
+               }
+       }
+
+       ret = read_reply(&msg.type, len);
+
+       up(&xs_state.request_mutex);
+
+       if (IS_ERR(ret))
+               return ret;
 
        if (msg.type == XS_ERROR) {
                err = get_error(ret);
-               xfree(ret);
+               free(ret);
                return ERR_PTR(-err);
        }
 
-       //BUG_ON(msg.type != type);
+       //      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)
+static void *xs_single(struct xenbus_transaction *t,
+                      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);
+       return xs_talkv(t, type, &iovec, 1, len);
 }
 
 /* Many commands only need an ack, don't care what it says. */
@@ -167,7 +256,7 @@
 {
        if (IS_ERR(reply))
                return PTR_ERR(reply);
-       xfree(reply);
+       free(reply);
        return 0;
 }
 
@@ -182,60 +271,76 @@
        return num;
 }
 
-/* Return the path to dir with /name appended. */ 
+/* Return the path to dir with /name appended. Buffer must be kfree()'ed. */ 
 static char *join(const char *dir, const char *name)
 {
-       static char buffer[4096];
-
-       //BUG_ON(down_trylock(&xenbus_lock) == 0);
-       /* XXX FIXME: might not be correct if name == "" */
-       //BUG_ON(strlen(dir) + strlen("/") + strlen(name) + 1 > sizeof(buffer));
+       char *buffer;
+
+       buffer = malloc(strlen(dir) + strlen("/") + strlen(name) + 1);
+       if (buffer == NULL)
+               return ERR_PTR(-ENOMEM);
 
        strcpy(buffer, dir);
        if (!streq(name, "")) {
                strcat(buffer, "/");
                strcat(buffer, name);
        }
+
        return buffer;
 }
 
-char **xenbus_directory(const char *dir, const char *node, unsigned int *num)
-{
-       char *strings, *p, **ret;
-       unsigned int len;
-
-       strings = xs_single(XS_DIRECTORY, join(dir, node), &len);
-       if (IS_ERR(strings))
-               return (char **)strings;
+static char **split(char *strings, unsigned int len, unsigned int *num)
+{
+       char *p, **ret;
 
        /* Count the strings. */
        *num = count_strings(strings, len);
 
        /* Transfer to one big alloc for easy freeing. */
-       ret = (char **)xmalloc_array(char, *num * sizeof(char *) + len);
+       ret = malloc(*num * sizeof(char *) + len);
        if (!ret) {
-               xfree(strings);
+               free(strings);
                return ERR_PTR(-ENOMEM);
        }
        memcpy(&ret[*num], strings, len);
-       xfree(strings);
+       free(strings);
 
        strings = (char *)&ret[*num];
        for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
                ret[(*num)++] = p;
-       return ret;
+
+       return ret;
+}
+
+char **xenbus_directory(struct xenbus_transaction *t,
+                       const char *dir, const char *node, unsigned int *num)
+{
+       char *strings, *path;
+       unsigned int len;
+
+       path = join(dir, node);
+       if (IS_ERR(path))
+               return (char **)path;
+
+       strings = xs_single(t, XS_DIRECTORY, path, &len);
+       free(path);
+       if (IS_ERR(strings))
+               return (char **)strings;
+
+       return split(strings, len, num);
 }
 
 /* Check if a path exists. Return 1 if it does. */
-int xenbus_exists(const char *dir, const char *node)
+int xenbus_exists(struct xenbus_transaction *t,
+                 const char *dir, const char *node)
 {
        char **d;
        int dir_n;
 
-       d = xenbus_directory(dir, node, &dir_n);
+       d = xenbus_directory(t, dir, node, &dir_n);
        if (IS_ERR(d))
                return 0;
-       xfree(d);
+       free(d);
        return 1;
 }
 
@@ -243,92 +348,134 @@
  * Returns a kmalloced value: call free() on it after use.
  * len indicates length in bytes.
  */
-void *xenbus_read(const char *dir, const char *node, unsigned int *len)
-{
-       return xs_single(XS_READ, join(dir, node), len);
+void *xenbus_read(struct xenbus_transaction *t,
+                 const char *dir, const char *node, unsigned int *len)
+{
+       char *path;
+       void *ret;
+
+       path = join(dir, node);
+       if (IS_ERR(path))
+               return (void *)path;
+
+       ret = xs_single(t, XS_READ, path, len);
+       free(path);
+       return ret;
 }
 
 /* Write the value of a single file.
- * Returns -err on failure.  createflags can be 0, O_CREAT, or O_CREAT|O_EXCL.
+ * Returns -err on failure.
  */
-int xenbus_write(const char *dir, const char *node,
-                const char *string, int createflags)
-{
-       const char *flags, *path;
-       struct kvec iovec[3];
+int xenbus_write(struct xenbus_transaction *t,
+                const char *dir, const char *node, const char *string)
+{
+       const char *path;
+       struct kvec iovec[2];
+       int ret;
 
        path = join(dir, node);
-       /* 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;
+       if (IS_ERR(path))
+               return PTR_ERR(path);
 
        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 *)string;
-       iovec[2].iov_len = strlen(string);
-
-       return xs_error(xs_talkv(XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
+       iovec[1].iov_base = (void *)string;
+       iovec[1].iov_len = strlen(string);
+
+       ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
+       free(path);
+       return ret;
 }
 
 /* Create a new directory. */
-int xenbus_mkdir(const char *dir, const char *node)
-{
-       return xs_error(xs_single(XS_MKDIR, join(dir, node), NULL));
+int xenbus_mkdir(struct xenbus_transaction *t,
+                const char *dir, const char *node)
+{
+       char *path;
+       int ret;
+
+       path = join(dir, node);
+       if (IS_ERR(path))
+               return PTR_ERR(path);
+
+       ret = xs_error(xs_single(t, XS_MKDIR, path, NULL));
+       free(path);
+       return ret;
 }
 
 /* Destroy a file or directory (directories must be empty). */
-int xenbus_rm(const char *dir, const char *node)
-{
-       return xs_error(xs_single(XS_RM, join(dir, node), NULL));
+int xenbus_rm(struct xenbus_transaction *t, const char *dir, const char *node)
+{
+       char *path;
+       int ret;
+
+       path = join(dir, node);
+       if (IS_ERR(path))
+               return PTR_ERR(path);
+
+       ret = xs_error(xs_single(t, XS_RM, path, NULL));
+       free(path);
+       return ret;
 }
 
 /* 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 xenbus_transaction_start(const char *subtree)
-{
-       return xs_error(xs_single(XS_TRANSACTION_START, subtree, NULL));
+struct xenbus_transaction *xenbus_transaction_start(void)
+{
+       char *id_str;
+       unsigned long id;
+
+       down_read(&xs_state.suspend_mutex);
+
+       id_str = xs_single(NULL, XS_TRANSACTION_START, "", NULL);
+       if (IS_ERR(id_str)) {
+               up_read(&xs_state.suspend_mutex);
+               return (struct xenbus_transaction *)id_str;
+       }
+
+       id = simple_strtoul(id_str, NULL, 0);
+       free(id_str);
+
+       return (struct xenbus_transaction *)id;
 }
 
 /* End a transaction.
  * If abandon is true, transaction is discarded instead of committed.
  */
-int xenbus_transaction_end(int abort)
+int xenbus_transaction_end(struct xenbus_transaction *t, int abort)
 {
        char abortstr[2];
+       int err;
 
        if (abort)
                strcpy(abortstr, "F");
        else
                strcpy(abortstr, "T");
-       return xs_error(xs_single(XS_TRANSACTION_END, abortstr, NULL));
+
+       err = xs_error(xs_single(t, XS_TRANSACTION_END, abortstr, NULL));
+
+       up_read(&xs_state.suspend_mutex);
+
+       return err;
 }
 
 /* Single read and scanf: returns -errno or num scanned. */
-int xenbus_scanf(const char *dir, const char *node, const char *fmt, ...)
+int xenbus_scanf(struct xenbus_transaction *t,
+                const char *dir, const char *node, const char *fmt, ...)
 {
        va_list ap;
        int ret;
        char *val;
 
-       val = xenbus_read(dir, node, NULL);
+       val = xenbus_read(t, dir, node, NULL);
        if (IS_ERR(val))
                return PTR_ERR(val);
 
        va_start(ap, fmt);
        ret = vsscanf(val, fmt, ap);
        va_end(ap);
-       xfree(val);
+       free(val);
        /* Distinctive errno. */
        if (ret == 0)
                return -ERANGE;
@@ -336,23 +483,32 @@
 }
 
 /* Single printf and write: returns -errno or 0. */
-int xenbus_printf(const char *dir, const char *node, const char *fmt, ...)
+int xenbus_printf(struct xenbus_transaction *t,
+                 const char *dir, const char *node, const char *fmt, ...)
 {
        va_list ap;
        int ret;
-
-       //BUG_ON(down_trylock(&xenbus_lock) == 0);
+#define PRINTF_BUFFER_SIZE 4096
+       char *printf_buffer;
+
+       printf_buffer = malloc(PRINTF_BUFFER_SIZE);
+       if (printf_buffer == NULL)
+               return -ENOMEM;
+
        va_start(ap, fmt);
-       ret = vsnprintf(printf_buffer, sizeof(printf_buffer), fmt, ap);
+       ret = vsnprintf(printf_buffer, PRINTF_BUFFER_SIZE, fmt, ap);
        va_end(ap);
 
-       //BUG_ON(ret > sizeof(printf_buffer)-1);
-       return xenbus_write(dir, node, printf_buffer, O_CREAT);
-}
-
-       
+       //      BUG_ON(ret > PRINTF_BUFFER_SIZE-1);
+       ret = xenbus_write(t, dir, node, printf_buffer);
+
+       free(printf_buffer);
+
+       return ret;
+}
+
 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
-int xenbus_gather(const char *dir, ...)
+int xenbus_gather(struct xenbus_transaction *t, const char *dir, ...)
 {
        va_list ap;
        const char *name;
@@ -364,7 +520,7 @@
                void *result = va_arg(ap, void *);
                char *p;
 
-               p = xenbus_read(dir, name, NULL);
+               p = xenbus_read(t, dir, name, NULL);
                if (IS_ERR(p)) {
                        ret = PTR_ERR(p);
                        break;
@@ -372,7 +528,7 @@
                if (fmt) {
                        if (sscanf(p, fmt, result) == 0)
                                ret = -EINVAL;
-                       xfree(p);
+                       free(p);
                } else
                        *(char **)result = p;
        }
@@ -389,31 +545,8 @@
        iov[1].iov_base = (void *)token;
        iov[1].iov_len = strlen(token) + 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)
-{
-#if 0
-       return xs_error(xs_single(XS_WATCH_ACK, token, NULL));
-#else
-       /* XS_WATCH_ACK is no longer available */
-       return 0;
-#endif
+       return xs_error(xs_talkv(NULL, XS_WATCH, iov,
+                                ARRAY_SIZE(iov), NULL));
 }
 
 static int xs_unwatch(const char *path, const char *token)
@@ -425,10 +558,10 @@
        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. */
+       return xs_error(xs_talkv(NULL, XS_UNWATCH, iov,
+                                ARRAY_SIZE(iov), NULL));
+}
+
 static struct xenbus_watch *find_watch(const char *token)
 {
        struct xenbus_watch *i, *cmp;
@@ -438,6 +571,7 @@
        list_for_each_entry(i, &watches, list)
                if (i == cmp)
                        return i;
+
        return NULL;
 }
 
@@ -449,111 +583,214 @@
        int err;
 
        sprintf(token, "%lX", (long)watch);
-       //BUG_ON(find_watch(token));
-printk("Registered watch for: %s\n", token);
+
+       down_read(&xs_state.suspend_mutex);
+
+       spin_lock(&watches_lock);
+       //      BUG_ON(find_watch(token));
+       list_add(&watch->list, &watches);
+       spin_unlock(&watches_lock);
+
        err = xs_watch(watch->node, token);
-       if (!err)
-               list_add(&watch->list, &watches);
+
+       /* Ignore errors due to multiple registration. */
+       if ((err != 0) && (err != -EEXIST)) {
+               spin_lock(&watches_lock);
+               list_del(&watch->list);
+               spin_unlock(&watches_lock);
+       }
+
+       up_read(&xs_state.suspend_mutex);
+
        return err;
 }
 
 void unregister_xenbus_watch(struct xenbus_watch *watch)
 {
+       struct xs_stored_msg *msg, *tmp;
        char token[sizeof(watch) * 2 + 1];
        int err;
 
        sprintf(token, "%lX", (long)watch);
-       //BUG_ON(!find_watch(token));
+
+       down_read(&xs_state.suspend_mutex);
+
+       spin_lock(&watches_lock);
+       //      BUG_ON(!find_watch(token));
+       list_del(&watch->list);
+       spin_unlock(&watches_lock);
 
        err = xs_unwatch(watch->node, token);
-       list_del(&watch->list);
-
        if (err)
                printk("XENBUS Failed to release watch %s: %i\n",
                       watch->node, err);
-}
-
-/* Re-register callbacks to all watches. */
-void reregister_xenbus_watches(void)
+
+       up_read(&xs_state.suspend_mutex);
+
+       /* Cancel pending watch events. */
+       spin_lock(&watch_events_lock);
+       list_for_each_entry_safe(msg, tmp, &watch_events, list) {
+               if (msg->u.watch.handle != watch)
+                       continue;
+               list_del(&msg->list);
+               free(msg->u.watch.vec);
+               free(msg);
+       }
+       spin_unlock(&watch_events_lock);
+}
+
+void xs_suspend(void)
+{
+       down_write(&xs_state.suspend_mutex);
+       down(&xs_state.request_mutex);
+}
+
+void xs_resume(void)
 {
        struct xenbus_watch *watch;
        char token[sizeof(watch) * 2 + 1];
 
+       up(&xs_state.request_mutex);
+
+       /* No need for watches_lock: the suspend_mutex is sufficient. */
        list_for_each_entry(watch, &watches, list) {
                sprintf(token, "%lX", (long)watch);
                xs_watch(watch->node, token);
        }
-}
-
-void watch_thread(void *unused)
-{
+
+       up_write(&xs_state.suspend_mutex);
+}
+
+static void xenwatch_thread(void *unused)
+{
+       struct list_head *ent;
+       struct xs_stored_msg *msg;
+
        for (;;) {
-               char *token;
-               char *node = NULL;
-
-               wait_event(xb_waitq, xs_input_avail());
-
-               /* 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(&xenbus_lock);
-               if (xs_input_avail())
-                       node = xs_read_watch(&token);
-
-               if (node && !IS_ERR(node)) {
-                       struct xenbus_watch *w;
-                       int err;
-
-                       err = xs_acknowledge_watch(token);
-                       if (err)
-                               printk("XENBUS ack %s fail %i\n", node, err);
-                       w = find_watch(token);
-                       //BUG_ON(!w);
-                       w->callback(w, node);
-                       xfree(node);
-               } else
-                       printk("XENBUS xs_read_watch: %li\n", PTR_ERR(node));
-               up(&xenbus_lock);
-       }
-}
-
-
-static void ballon_changed(struct xenbus_watch *watch, const char *node)
-{
-    unsigned long new_target;
-    int err;
-    err = xenbus_scanf("memory", "target", "%lu", &new_target);
-
-    if(err != 1)
-    {
-        printk("Unable to read memory/target\n");
-        return;
-    }
-
-    printk("Memory target changed to: %ld bytes, ignoring.\n", new_target);
-}
-
-
-static struct xenbus_watch ballon_watch = {
-    .node = "memory/target",
-    .callback = ballon_changed,
-};
-
-
+               wait_event(watch_events_waitq,
+                          !list_empty(&watch_events));
+
+               down(&xenwatch_mutex);
+
+               spin_lock(&watch_events_lock);
+               ent = watch_events.next;
+               if (ent != &watch_events)
+                       list_del(ent);
+               spin_unlock(&watch_events_lock);
+
+               if (ent != &watch_events) {
+                       msg = list_entry(ent, struct xs_stored_msg, list);
+                       msg->u.watch.handle->callback(
+                               msg->u.watch.handle,
+                               (const char **)msg->u.watch.vec,
+                               msg->u.watch.vec_size);
+                       free(msg->u.watch.vec);
+                       free(msg);
+               }
+
+               up(&xenwatch_mutex);
+       }
+}
+
+static int process_msg(void)
+{
+       struct xs_stored_msg *msg;
+       char *body;
+       int err;
+
+       msg = malloc(sizeof(*msg));
+       if (msg == NULL)
+               return -ENOMEM;
+
+       err = xb_read(&msg->hdr, sizeof(msg->hdr));
+       if (err) {
+               free(msg);
+               return err;
+       }
+
+       body = malloc(msg->hdr.len + 1);
+       if (body == NULL) {
+               free(msg);
+               return -ENOMEM;
+       }
+
+       err = xb_read(body, msg->hdr.len);
+       if (err) {
+               free(body);
+               free(msg);
+               return err;
+       }
+       body[msg->hdr.len] = '\0';
+
+       if (msg->hdr.type == XS_WATCH_EVENT) {
+               msg->u.watch.vec = split(body, msg->hdr.len,
+                                        &msg->u.watch.vec_size);
+               if (IS_ERR(msg->u.watch.vec)) {
+                       free(msg);
+                       return PTR_ERR(msg->u.watch.vec);
+               }
+
+               spin_lock(&watches_lock);
+               msg->u.watch.handle = find_watch(
+                       msg->u.watch.vec[XS_WATCH_TOKEN]);
+               if (msg->u.watch.handle != NULL) {
+                       spin_lock(&watch_events_lock);
+                       list_add_tail(&msg->list, &watch_events);
+                       wake_up(&watch_events_waitq);
+                       spin_unlock(&watch_events_lock);
+               } else {
+                       free(msg->u.watch.vec);
+                       free(msg);
+               }
+               spin_unlock(&watches_lock);
+       } else {
+               msg->u.reply.body = body;
+               spin_lock(&xs_state.reply_lock);
+               list_add_tail(&msg->list, &xs_state.reply_list);
+               spin_unlock(&xs_state.reply_lock);
+               wake_up(&xs_state.reply_waitq);
+       }
+
+       return 0;
+}
+
+static void xenbus_thread(void *unused)
+{
+       int err;
+
+       for (;;) {
+               err = process_msg();
+               if (err)
+                       printk("XENBUS error %d while reading "
+                              "message\n", err);
+       }
+}
 
 int xs_init(void)
 {
        int err;
-       struct thread *watcher;
-    printk("xb_init_comms\n");
+       struct thread *kxwatcher_thread;
+       struct thread *kxenbus_thread;
+
+       INIT_LIST_HEAD(&xs_state.reply_list);
+       spin_lock_init(&xs_state.reply_lock);
+       init_waitqueue_head(&xs_state.reply_waitq);
+
+       init_MUTEX(&xs_state.request_mutex);
+       init_rwsem(&xs_state.suspend_mutex);
+
+       /* Initialize the shared memory rings to talk to xenstored */
        err = xb_init_comms();
        if (err)
                return err;
-       
-       watcher = create_thread("kxwatch", watch_thread, NULL);
-    down(&xenbus_lock);
-    register_xenbus_watch(&ballon_watch);
-    up(&xenbus_lock);
+
+       kxwatcher_thread = create_thread("kxwatch", xenwatch_thread, NULL);
+       if (IS_ERR(kxwatcher_thread))
+               return PTR_ERR(kxwatcher_thread);
+
+       kxenbus_thread = create_thread("kxenbus", xenbus_thread, NULL);
+       if (IS_ERR(kxenbus_thread))
+               return PTR_ERR(kxenbus_thread);
+
        return 0;
 }
diff -r 5f7398785e02 -r 7557f0b4098c extras/mini-os/include/spinlock.h
--- /dev/null   Thu Dec  8 14:21:36 2005
+++ b/extras/mini-os/include/spinlock.h Thu Dec  8 14:24:02 2005
@@ -0,0 +1,121 @@
+#ifndef __ASM_SPINLOCK_H
+#define __ASM_SPINLOCK_H
+
+#include <lib.h>
+
+/*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+ */
+
+typedef struct {
+       volatile unsigned int slock;
+} spinlock_t;
+
+#define SPINLOCK_MAGIC 0xdead4ead
+
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 }
+
+#define spin_lock_init(x)      do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
+
+/*
+ * Simple spin lock operations.  There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ */
+
+#define spin_is_locked(x)      (*(volatile signed char *)(&(x)->slock) <= 0)
+#define spin_unlock_wait(x)    do { barrier(); } while(spin_is_locked(x))
+
+#define spin_lock_string \
+        "1:\n" \
+       LOCK \
+       "decb %0\n\t" \
+       "jns 3f\n" \
+       "2:\t" \
+       "rep;nop\n\t" \
+       "cmpb $0,%0\n\t" \
+       "jle 2b\n\t" \
+       "jmp 1b\n" \
+       "3:\n\t"
+
+#define spin_lock_string_flags \
+        "1:\n" \
+       LOCK \
+       "decb %0\n\t" \
+       "jns 4f\n\t" \
+       "2:\t" \
+       "testl $0x200, %1\n\t" \
+       "jz 3f\n\t" \
+       "#sti\n\t" \
+       "3:\t" \
+       "rep;nop\n\t" \
+       "cmpb $0, %0\n\t" \
+       "jle 3b\n\t" \
+       "#cli\n\t" \
+       "jmp 1b\n" \
+       "4:\n\t"
+
+/*
+ * This works. Despite all the confusion.
+ * (except on PPro SMP or if we are using OOSTORE)
+ * (PPro errata 66, 92)
+ */
+
+#define spin_unlock_string \
+       "xchgb %b0, %1" \
+               :"=q" (oldval), "=m" (lock->slock) \
+               :"0" (oldval) : "memory"
+
+static inline void _raw_spin_unlock(spinlock_t *lock)
+{
+       char oldval = 1;
+       __asm__ __volatile__(
+               spin_unlock_string
+       );
+}
+
+static inline int _raw_spin_trylock(spinlock_t *lock)
+{
+       char oldval;
+       __asm__ __volatile__(
+               "xchgb %b0,%1\n"
+               :"=q" (oldval), "=m" (lock->slock)
+               :"0" (0) : "memory");
+       return oldval > 0;
+}
+
+static inline void _raw_spin_lock(spinlock_t *lock)
+{
+       __asm__ __volatile__(
+               spin_lock_string
+               :"=m" (lock->slock) : : "memory");
+}
+
+static inline void _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags)
+{
+       __asm__ __volatile__(
+               spin_lock_string_flags
+               :"=m" (lock->slock) : "r" (flags) : "memory");
+}
+
+#define _spin_trylock(lock)     ({_raw_spin_trylock(lock) ? \
+                                1 : ({ 0;});})
+
+#define _spin_lock(lock)        \
+do {                            \
+        _raw_spin_lock(lock);   \
+} while(0)
+
+#define _spin_unlock(lock)      \
+do {                            \
+        _raw_spin_unlock(lock); \
+} while (0)
+
+
+#define spin_lock(lock)       _spin_lock(lock)
+#define spin_unlock(lock)       _spin_unlock(lock)
+
+#define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED
+
+#endif

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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.