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

[Xen-changelog] Merged



# HG changeset patch
# User djm@xxxxxxxxxxxxxxx
# Node ID 74d56b7ff46cb07fbf7dbb72cad4e14e9d22324f
# Parent  333f722ed6d05d80e341a72f19bad4143c94cd87
# Parent  4e335372ace84b605cebc36a42610caadb09a4d8
Merged

diff -r 333f722ed6d0 -r 74d56b7ff46c .hgignore
--- a/.hgignore Tue Oct 11 21:50:21 2005
+++ b/.hgignore Tue Oct 11 22:57:44 2005
@@ -161,6 +161,7 @@
 ^tools/xenstore/xs_tdb_dump$
 ^tools/xenstore/xs_test$
 ^tools/xenstore/xs_watch_stress$
+^tools/xenstore/xsls$
 ^tools/xentrace/xenctx$
 ^tools/xentrace/xentrace$
 ^xen/BLOG$
diff -r 333f722ed6d0 -r 74d56b7ff46c Makefile
--- a/Makefile  Tue Oct 11 21:50:21 2005
+++ b/Makefile  Tue Oct 11 22:57:44 2005
@@ -66,7 +66,7 @@
        $(MAKE) -C tools install
 
 install-kernels:
-       for i in $(XKERNELS) ; do $(MAKE) $$i-build || exit 1; done
+       for i in $(XKERNELS) ; do $(MAKE) $$i-install || exit 1; done
 
 install-docs:
        sh ./docs/check_pkgs && $(MAKE) -C docs install || true
@@ -179,7 +179,7 @@
        rm -rf $(D)/usr/$(LIBDIR)/libxenctrl* $(D)/usr/$(LIBDIR)/libxenguest*
        rm -rf $(D)/usr/$(LIBDIR)/libxenstore*
        rm -rf $(D)/usr/$(LIBDIR)/python/xen $(D)/usr/$(LIBDIR)/xen 
-       rm -rf $(D)/usr/libexec/xen
+       rm -rf $(D)/usr/$(LIBDIR)/xen/bin
        rm -rf $(D)/usr/sbin/xen* $(D)/usr/sbin/netfix $(D)/usr/sbin/xm
        rm -rf $(D)/usr/share/doc/xen
        rm -rf $(D)/usr/share/xen
diff -r 333f722ed6d0 -r 74d56b7ff46c buildconfigs/Rules.mk
--- a/buildconfigs/Rules.mk     Tue Oct 11 21:50:21 2005
+++ b/buildconfigs/Rules.mk     Tue Oct 11 22:57:44 2005
@@ -87,8 +87,16 @@
        touch $@ # update timestamp to avoid rebuild
 endif
 
-%-build:
+%-install:
        $(MAKE) -f buildconfigs/mk.$* build
+
+%-dist: DESTDIR=$(DISTDIR)/install
+%-dist: %-install
+       @: # do nothing
+
+# Legacy dist target
+%-build: %-dist
+       @: # do nothing
 
 %-delete:
        $(MAKE) -f buildconfigs/mk.$* delete
diff -r 333f722ed6d0 -r 74d56b7ff46c linux-2.6-xen-sparse/arch/xen/boot/Makefile
--- a/linux-2.6-xen-sparse/arch/xen/boot/Makefile       Tue Oct 11 21:50:21 2005
+++ b/linux-2.6-xen-sparse/arch/xen/boot/Makefile       Tue Oct 11 22:57:44 2005
@@ -8,4 +8,4 @@
        $(call if_changed,objcopy)
 
 bzImage: vmlinuz
-       $(Q)$(LN) -sf ../../../vmlinuz $(srctree)/arch/xen/boot/bzImage
+       $(Q)ln -sf ../../../vmlinuz $(srctree)/arch/xen/boot/bzImage
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c
--- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c       Tue Oct 11 
21:50:21 2005
+++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/smpboot.c       Tue Oct 11 
22:57:44 2005
@@ -1327,18 +1327,14 @@
        .callback = handle_vcpu_hotplug_event
 };
 
-/* NB: Assumes xenbus_lock is held! */
 static int setup_cpu_watcher(struct notifier_block *notifier,
                              unsigned long event, void *data)
 {
-       int err = 0;
-
-       BUG_ON(down_trylock(&xenbus_lock) == 0);
+       int err;
+
        err = register_xenbus_watch(&cpu_watch);
-
-       if (err) {
+       if (err)
                printk("Failed to register watch on /cpu\n");
-       }
 
        return NOTIFY_DONE;
 }
@@ -1368,7 +1364,7 @@
                        return;
 
                /* get the state value */
-               err = xenbus_scanf(dir, "availability", "%s", state);
+               err = xenbus_scanf(NULL, dir, "availability", "%s", state);
 
                if (err != 1) {
                        printk(KERN_ERR
@@ -1578,7 +1574,7 @@
 void smp_resume(void)
 {
        smp_intr_init();
-       local_setup_timer_irq();
+       local_setup_timer();
 }
 
 void vcpu_prepare(int vcpu)
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c
--- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c  Tue Oct 11 21:50:21 2005
+++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c  Tue Oct 11 22:57:44 2005
@@ -122,7 +122,7 @@
 static u64 processed_system_time;   /* System time (ns) at last processing. */
 static DEFINE_PER_CPU(u64, processed_system_time);
 
-#define NS_PER_TICK (1000000000L/HZ)
+#define NS_PER_TICK (1000000000ULL/HZ)
 
 static inline void __normalize_time(time_t *sec, s64 *nsec)
 {
@@ -800,9 +800,9 @@
                delta = j - jiffies;
                /* NB. The next check can trigger in some wrap-around cases,
                 * but that's ok: we'll just end up with a shorter timeout. */
-               if (delta < 1)
+               if (delta < 1) 
                        delta = 1;
-               st = processed_system_time + (delta * NS_PER_TICK);
+               st = processed_system_time + ((u64)delta * NS_PER_TICK);
        } while (read_seqretry(&xtime_lock, seq));
 
        return st;
@@ -816,7 +816,7 @@
 {
        unsigned int cpu = smp_processor_id();
        unsigned long j;
-
+       
        /* s390 does this /before/ checking rcu_pending(). We copy them. */
        cpu_set(cpu, nohz_cpu_mask);
 
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/arch/xen/kernel/reboot.c
--- a/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c     Tue Oct 11 21:50:21 2005
+++ b/linux-2.6-xen-sparse/arch/xen/kernel/reboot.c     Tue Oct 11 22:57:44 2005
@@ -270,26 +270,28 @@
        }
 }
 
-static void shutdown_handler(struct xenbus_watch *watch, const char *node)
+static void shutdown_handler(struct xenbus_watch *watch,
+                            const char **vec, unsigned int len)
 {
        static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL);
        char *str;
+       struct xenbus_transaction *xbt;
        int err;
 
  again:
-       err = xenbus_transaction_start();
-       if (err)
+       xbt = xenbus_transaction_start();
+       if (IS_ERR(xbt))
                return;
-       str = (char *)xenbus_read("control", "shutdown", NULL);
+       str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
        /* Ignore read errors and empty reads. */
        if (XENBUS_IS_ERR_READ(str)) {
-               xenbus_transaction_end(1);
+               xenbus_transaction_end(xbt, 1);
                return;
        }
 
-       xenbus_write("control", "shutdown", "");
-
-       err = xenbus_transaction_end(0);
+       xenbus_write(xbt, "control", "shutdown", "");
+
+       err = xenbus_transaction_end(xbt, 0);
        if (err == -EAGAIN) {
                kfree(str);
                goto again;
@@ -315,26 +317,28 @@
 }
 
 #ifdef CONFIG_MAGIC_SYSRQ
-static void sysrq_handler(struct xenbus_watch *watch, const char *node)
+static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
+                         unsigned int len)
 {
        char sysrq_key = '\0';
+       struct xenbus_transaction *xbt;
        int err;
 
  again:
-       err = xenbus_transaction_start();
-       if (err)
+       xbt  = xenbus_transaction_start();
+       if (IS_ERR(xbt))
                return;
-       if (!xenbus_scanf("control", "sysrq", "%c", &sysrq_key)) {
+       if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
                printk(KERN_ERR "Unable to read sysrq code in "
                       "control/sysrq\n");
-               xenbus_transaction_end(1);
+               xenbus_transaction_end(xbt, 1);
                return;
        }
 
        if (sysrq_key != '\0')
-               xenbus_printf("control", "sysrq", "%c", '\0');
-
-       err = xenbus_transaction_end(0);
+               xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
+
+       err = xenbus_transaction_end(xbt, 0);
        if (err == -EAGAIN)
                goto again;
 
@@ -358,9 +362,6 @@
 
 static struct notifier_block xenstore_notifier;
 
-/* Setup our watcher
-   NB: Assumes xenbus_lock is held!
-*/
 static int setup_shutdown_watcher(struct notifier_block *notifier,
                                   unsigned long event,
                                   void *data)
@@ -369,8 +370,6 @@
 #ifdef CONFIG_MAGIC_SYSRQ
        int err2 = 0;
 #endif
-
-       BUG_ON(down_trylock(&xenbus_lock) == 0);
 
        err1 = register_xenbus_watch(&shutdown_watch);
 #ifdef CONFIG_MAGIC_SYSRQ
@@ -411,4 +410,3 @@
  *  tab-width: 8
  * End:
  */
-#
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c
--- a/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c        Tue Oct 11 
21:50:21 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/balloon/balloon.c        Tue Oct 11 
22:57:44 2005
@@ -357,7 +357,7 @@
        unsigned long long new_target;
        int err;
 
-       err = xenbus_scanf("memory", "target", "%llu", &new_target);
+       err = xenbus_scanf(NULL, "memory", "target", "%llu", &new_target);
        if (err != 1) {
                printk(KERN_ERR "Unable to read memory/target\n");
                return;
@@ -370,16 +370,11 @@
     
 }
 
-/* Setup our watcher
-   NB: Assumes xenbus_lock is held!
-*/
 int balloon_init_watcher(struct notifier_block *notifier,
                          unsigned long event,
                          void *data)
 {
        int err;
-
-       BUG_ON(down_trylock(&xenbus_lock) == 0);
 
        err = register_xenbus_watch(&target_watch);
        if (err)
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c
--- a/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c Tue Oct 11 21:50:21 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/blkback/xenbus.c Tue Oct 11 22:57:44 2005
@@ -61,18 +61,19 @@
        unsigned long ring_ref;
        unsigned int evtchn;
        int err;
+       struct xenbus_transaction *xbt;
        struct backend_info *be
                = container_of(watch, struct backend_info, watch);
 
        /* If other end is gone, delete ourself. */
-       if (vec && !xenbus_exists(be->frontpath, "")) {
+       if (vec && !xenbus_exists(NULL, be->frontpath, "")) {
                device_unregister(&be->dev->dev);
                return;
        }
        if (be->blkif == NULL || be->blkif->status == CONNECTED)
                return;
 
-       err = xenbus_gather(be->frontpath, "ring-ref", "%lu", &ring_ref,
+       err = xenbus_gather(NULL, be->frontpath, "ring-ref", "%lu", &ring_ref,
                            "event-channel", "%u", &evtchn, NULL);
        if (err) {
                xenbus_dev_error(be->dev, err,
@@ -84,7 +85,8 @@
        /* Map the shared frame, irq etc. */
        err = blkif_map(be->blkif, ring_ref, evtchn);
        if (err) {
-               xenbus_dev_error(be->dev, err, "mapping ring-ref %lu port %u",
+               xenbus_dev_error(be->dev, err,
+                                "mapping ring-ref %lu port %u",
                                 ring_ref, evtchn);
                return;
        }
@@ -92,13 +94,13 @@
 
 again:
        /* Supply the information about the device the frontend needs */
-       err = xenbus_transaction_start();
-       if (err) {
+       xbt = xenbus_transaction_start();
+       if (IS_ERR(xbt)) {
                xenbus_dev_error(be->dev, err, "starting transaction");
                return;
        }
 
-       err = xenbus_printf(be->dev->nodename, "sectors", "%lu",
+       err = xenbus_printf(xbt, be->dev->nodename, "sectors", "%lu",
                            vbd_size(&be->blkif->vbd));
        if (err) {
                xenbus_dev_error(be->dev, err, "writing %s/sectors",
@@ -107,14 +109,14 @@
        }
 
        /* FIXME: use a typename instead */
-       err = xenbus_printf(be->dev->nodename, "info", "%u",
+       err = xenbus_printf(xbt, be->dev->nodename, "info", "%u",
                            vbd_info(&be->blkif->vbd));
        if (err) {
                xenbus_dev_error(be->dev, err, "writing %s/info",
                                 be->dev->nodename);
                goto abort;
        }
-       err = xenbus_printf(be->dev->nodename, "sector-size", "%lu",
+       err = xenbus_printf(xbt, be->dev->nodename, "sector-size", "%lu",
                            vbd_secsize(&be->blkif->vbd));
        if (err) {
                xenbus_dev_error(be->dev, err, "writing %s/sector-size",
@@ -122,7 +124,7 @@
                goto abort;
        }
 
-       err = xenbus_transaction_end(0);
+       err = xenbus_transaction_end(xbt, 0);
        if (err == -EAGAIN)
                goto again;
        if (err) {
@@ -136,7 +138,7 @@
        return;
 
  abort:
-       xenbus_transaction_end(1);
+       xenbus_transaction_end(xbt, 1);
 }
 
 /* 
@@ -154,7 +156,8 @@
                = container_of(watch, struct backend_info, backend_watch);
        struct xenbus_device *dev = be->dev;
 
-       err = xenbus_scanf(dev->nodename, "physical-device", "%li", &pdev);
+       err = xenbus_scanf(NULL, dev->nodename,
+                          "physical-device", "%li", &pdev);
        if (XENBUS_EXIST_ERR(err))
                return;
        if (err < 0) {
@@ -169,7 +172,7 @@
        be->pdev = pdev;
 
        /* If there's a read-only node, we're read only. */
-       p = xenbus_read(dev->nodename, "read-only", NULL);
+       p = xenbus_read(NULL, dev->nodename, "read-only", NULL);
        if (!IS_ERR(p)) {
                be->readonly = 1;
                kfree(p);
@@ -184,7 +187,8 @@
                if (IS_ERR(be->blkif)) {
                        err = PTR_ERR(be->blkif);
                        be->blkif = NULL;
-                       xenbus_dev_error(dev, err, "creating block interface");
+                       xenbus_dev_error(dev, err,
+                                        "creating block interface");
                        return;
                }
 
@@ -192,7 +196,8 @@
                if (err) {
                        blkif_put(be->blkif);
                        be->blkif = NULL;
-                       xenbus_dev_error(dev, err, "creating vbd structure");
+                       xenbus_dev_error(dev, err,
+                                        "creating vbd structure");
                        return;
                }
 
@@ -210,13 +215,14 @@
 
        be = kmalloc(sizeof(*be), GFP_KERNEL);
        if (!be) {
-               xenbus_dev_error(dev, -ENOMEM, "allocating backend structure");
+               xenbus_dev_error(dev, -ENOMEM,
+                                "allocating backend structure");
                return -ENOMEM;
        }
        memset(be, 0, sizeof(*be));
 
        frontend = NULL;
-       err = xenbus_gather(dev->nodename,
+       err = xenbus_gather(NULL, dev->nodename,
                            "frontend-id", "%li", &be->frontend_id,
                            "frontend", NULL, &frontend,
                            NULL);
@@ -228,7 +234,7 @@
                                 dev->nodename);
                goto free_be;
        }
-       if (strlen(frontend) == 0 || !xenbus_exists(frontend, "")) {
+       if (strlen(frontend) == 0 || !xenbus_exists(NULL, frontend, "")) {
                /* If we can't get a frontend path and a frontend-id,
                 * then our bus-id is no longer valid and we need to
                 * destroy the backend device.
@@ -244,7 +250,8 @@
        err = register_xenbus_watch(&be->backend_watch);
        if (err) {
                be->backend_watch.node = NULL;
-               xenbus_dev_error(dev, err, "adding backend watch on %s",
+               xenbus_dev_error(dev, err,
+                                "adding backend watch on %s",
                                 dev->nodename);
                goto free_be;
        }
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c
--- a/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c      Tue Oct 11 
21:50:21 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/blkfront.c      Tue Oct 11 
22:57:44 2005
@@ -460,7 +460,7 @@
        if (info->connected == BLKIF_STATE_CONNECTED)
                return;
 
-       err = xenbus_gather(watch->node,
+       err = xenbus_gather(NULL, watch->node,
                            "sectors", "%lu", &sectors,
                            "info", "%u", &binfo,
                            "sector-size", "%lu", &sector_size,
@@ -532,10 +532,11 @@
 {
        char *backend;
        const char *message;
+       struct xenbus_transaction *xbt;
        int err;
 
        backend = NULL;
-       err = xenbus_gather(dev->nodename,
+       err = xenbus_gather(NULL, dev->nodename,
                            "backend-id", "%i", &info->backend_id,
                            "backend", NULL, &backend,
                            NULL);
@@ -559,25 +560,26 @@
        }
 
 again:
-       err = xenbus_transaction_start();
-       if (err) {
+       xbt = xenbus_transaction_start();
+       if (IS_ERR(xbt)) {
                xenbus_dev_error(dev, err, "starting transaction");
                goto destroy_blkring;
        }
 
-       err = xenbus_printf(dev->nodename, "ring-ref","%u", info->ring_ref);
+       err = xenbus_printf(xbt, dev->nodename,
+                           "ring-ref","%u", info->ring_ref);
        if (err) {
                message = "writing ring-ref";
                goto abort_transaction;
        }
-       err = xenbus_printf(dev->nodename,
+       err = xenbus_printf(xbt, dev->nodename,
                            "event-channel", "%u", info->evtchn);
        if (err) {
                message = "writing event-channel";
                goto abort_transaction;
        }
 
-       err = xenbus_transaction_end(0);
+       err = xenbus_transaction_end(xbt, 0);
        if (err) {
                if (err == -EAGAIN)
                        goto again;
@@ -598,8 +600,7 @@
        return 0;
 
  abort_transaction:
-       xenbus_transaction_end(1);
-       /* Have to do this *outside* transaction.  */
+       xenbus_transaction_end(xbt, 1);
        xenbus_dev_error(dev, err, "%s", message);
  destroy_blkring:
        blkif_free(info);
@@ -620,7 +621,8 @@
        struct blkfront_info *info;
 
        /* FIXME: Use dynamic device id if this is not set. */
-       err = xenbus_scanf(dev->nodename, "virtual-device", "%i", &vdevice);
+       err = xenbus_scanf(NULL, dev->nodename,
+                          "virtual-device", "%i", &vdevice);
        if (XENBUS_EXIST_ERR(err))
                return err;
        if (err < 0) {
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c
--- a/linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c   Tue Oct 11 21:50:21 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/blkfront/vbd.c   Tue Oct 11 22:57:44 2005
@@ -160,7 +160,8 @@
 
        mi = ((major_info[index] != NULL) ? major_info[index] :
              xlbd_alloc_major_info(major, minor, index));
-       mi->usage++;
+       if (mi)
+               mi->usage++;
        return mi;
 }
 
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/drivers/xen/console/xencons_ring.c
--- a/linux-2.6-xen-sparse/drivers/xen/console/xencons_ring.c   Tue Oct 11 
21:50:21 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/console/xencons_ring.c   Tue Oct 11 
22:57:44 2005
@@ -20,69 +20,48 @@
 #include <linux/sched.h>
 #include <linux/err.h>
 #include "xencons_ring.h"
-
-struct ring_head
-{
-       u32 cons;
-       u32 prod;
-       char buf[0];
-} __attribute__((packed));
+#include <asm-xen/xen-public/io/console.h>
 
 static int xencons_irq;
+static xencons_receiver_func *xencons_receiver;
 
-#define XENCONS_RING_SIZE (PAGE_SIZE/2 - sizeof (struct ring_head))
-#define XENCONS_IDX(cnt) ((cnt) % XENCONS_RING_SIZE)
-#define XENCONS_FULL(ring) (((ring)->prod - (ring)->cons) == XENCONS_RING_SIZE)
-
-static inline struct ring_head *outring(void)
+static inline struct xencons_interface *xencons_interface(void)
 {
        return mfn_to_virt(xen_start_info->console_mfn);
 }
 
-static inline struct ring_head *inring(void)
-{
-       return mfn_to_virt(xen_start_info->console_mfn) + PAGE_SIZE/2;
-}
-
-
-/* don't block -  write as much as possible and return */
-static int __xencons_ring_send(
-       struct ring_head *ring, const char *data, unsigned len)
-{
-       int copied = 0;
-
-       mb();
-       while (copied < len && !XENCONS_FULL(ring)) {
-               ring->buf[XENCONS_IDX(ring->prod)] = data[copied];
-               ring->prod++;
-               copied++;
-       }
-       mb();
-
-       return copied;
-}
-
 int xencons_ring_send(const char *data, unsigned len)
 {
-       int sent = __xencons_ring_send(outring(), data, len);
+       int sent = 0;
+       struct xencons_interface *intf = xencons_interface();
+
+       while ((sent < len) &&
+              (intf->out_prod - intf->out_cons) < sizeof(intf->out)) {
+               intf->out[MASK_XENCONS_IDX(intf->out_prod, intf->out)] =
+                       data[sent];
+               intf->out_prod++;
+               sent++;
+       }
+
        /* Use evtchn: this is called early, before irq is set up. */
        notify_remote_via_evtchn(xen_start_info->console_evtchn);
+
        return sent;
 }      
 
-
-static xencons_receiver_func *xencons_receiver;
-
 static irqreturn_t handle_input(int irq, void *unused, struct pt_regs *regs)
 {
-       struct ring_head *ring = inring();
-       while (ring->cons < ring->prod) {
-               if (xencons_receiver != NULL) {
-                       xencons_receiver(ring->buf + XENCONS_IDX(ring->cons),
-                                        1, regs);
-               }
-               ring->cons++;
+       struct xencons_interface *intf = xencons_interface();
+
+       while (intf->in_cons != intf->in_prod) {
+               if (xencons_receiver != NULL)
+                       xencons_receiver(
+                               intf->in + MASK_XENCONS_IDX(intf->in_cons,
+                                                           intf->in),
+                               1, regs);
+               intf->in_cons++;
        }
+
        return IRQ_HANDLED;
 }
 
@@ -96,7 +75,7 @@
        int err;
 
        if (xencons_irq)
-               unbind_evtchn_from_irqhandler(xencons_irq, inring());
+               unbind_evtchn_from_irqhandler(xencons_irq, NULL);
        xencons_irq = 0;
 
        if (!xen_start_info->console_evtchn)
@@ -104,7 +83,7 @@
 
        err = bind_evtchn_to_irqhandler(
                xen_start_info->console_evtchn,
-               handle_input, 0, "xencons", inring());
+               handle_input, 0, "xencons", NULL);
        if (err <= 0) {
                xprintk("XEN console request irq failed %i\n", err);
                return err;
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c
--- a/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c Tue Oct 11 21:50:21 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/netback/xenbus.c Tue Oct 11 22:57:44 2005
@@ -69,15 +69,15 @@
        int i;
 
        /* If other end is gone, delete ourself. */
-       if (vec && !xenbus_exists(be->frontpath, "")) {
-               xenbus_rm(be->dev->nodename, "");
+       if (vec && !xenbus_exists(NULL, be->frontpath, "")) {
+               xenbus_rm(NULL, be->dev->nodename, "");
                device_unregister(&be->dev->dev);
                return;
        }
        if (be->netif == NULL || be->netif->status == CONNECTED)
                return;
 
-       mac = xenbus_read(be->frontpath, "mac", NULL);
+       mac = xenbus_read(NULL, be->frontpath, "mac", NULL);
        if (IS_ERR(mac)) {
                err = PTR_ERR(mac);
                xenbus_dev_error(be->dev, err, "reading %s/mac",
@@ -98,7 +98,8 @@
        }
        kfree(mac);
 
-       err = xenbus_gather(be->frontpath, "tx-ring-ref", "%lu", &tx_ring_ref,
+       err = xenbus_gather(NULL, be->frontpath,
+                           "tx-ring-ref", "%lu", &tx_ring_ref,
                            "rx-ring-ref", "%lu", &rx_ring_ref,
                            "event-channel", "%u", &evtchn, NULL);
        if (err) {
@@ -137,7 +138,7 @@
        struct xenbus_device *dev = be->dev;
        u8 be_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
 
-       err = xenbus_scanf(dev->nodename, "handle", "%li", &handle);
+       err = xenbus_scanf(NULL, dev->nodename, "handle", "%li", &handle);
        if (XENBUS_EXIST_ERR(err))
                return;
        if (err < 0) {
@@ -188,7 +189,7 @@
 
        key = env_vars;
        while (*key != NULL) {
-               val = xenbus_read(xdev->nodename, *key, NULL);
+               val = xenbus_read(NULL, xdev->nodename, *key, NULL);
                if (!IS_ERR(val)) {
                        char buf[strlen(*key) + 4];
                        sprintf(buf, "%s=%%s", *key);
@@ -220,7 +221,7 @@
        memset(be, 0, sizeof(*be));
 
        frontend = NULL;
-       err = xenbus_gather(dev->nodename,
+       err = xenbus_gather(NULL, dev->nodename,
                            "frontend-id", "%li", &be->frontend_id,
                            "frontend", NULL, &frontend,
                            NULL);
@@ -232,7 +233,7 @@
                                 dev->nodename);
                goto free_be;
        }
-       if (strlen(frontend) == 0 || !xenbus_exists(frontend, "")) {
+       if (strlen(frontend) == 0 || !xenbus_exists(NULL, frontend, "")) {
                /* If we can't get a frontend path and a frontend-id,
                 * then our bus-id is no longer valid and we need to
                 * destroy the backend device.
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c
--- a/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c      Tue Oct 11 
21:50:21 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c      Tue Oct 11 
22:57:44 2005
@@ -1083,10 +1083,11 @@
 {
        char *backend, *mac, *e, *s;
        const char *message;
+       struct xenbus_transaction *xbt;
        int err, i;
 
        backend = NULL;
-       err = xenbus_gather(dev->nodename,
+       err = xenbus_gather(NULL, dev->nodename,
                            "backend-id", "%i", &info->backend_id,
                            "backend", NULL, &backend,
                            NULL);
@@ -1102,7 +1103,7 @@
                goto out;
        }
 
-       mac = xenbus_read(dev->nodename, "mac", NULL);
+       mac = xenbus_read(NULL, dev->nodename, "mac", NULL);
        if (IS_ERR(mac)) {
                err = PTR_ERR(mac);
                xenbus_dev_error(dev, err, "reading %s/mac",
@@ -1131,32 +1132,32 @@
        }
 
 again:
-       err = xenbus_transaction_start();
-       if (err) {
+       xbt = xenbus_transaction_start();
+       if (IS_ERR(xbt)) {
                xenbus_dev_error(dev, err, "starting transaction");
                goto destroy_ring;
        }
 
-       err = xenbus_printf(dev->nodename, "tx-ring-ref","%u",
+       err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref","%u",
                            info->tx_ring_ref);
        if (err) {
                message = "writing tx ring-ref";
                goto abort_transaction;
        }
-       err = xenbus_printf(dev->nodename, "rx-ring-ref","%u",
+       err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref","%u",
                            info->rx_ring_ref);
        if (err) {
                message = "writing rx ring-ref";
                goto abort_transaction;
        }
-       err = xenbus_printf(dev->nodename,
+       err = xenbus_printf(xbt, dev->nodename,
                            "event-channel", "%u", info->evtchn);
        if (err) {
                message = "writing event-channel";
                goto abort_transaction;
        }
 
-       err = xenbus_transaction_end(0);
+       err = xenbus_transaction_end(xbt, 0);
        if (err) {
                if (err == -EAGAIN)
                        goto again;
@@ -1177,8 +1178,7 @@
        return 0;
 
  abort_transaction:
-       xenbus_transaction_end(1);
-       /* Have to do this *outside* transaction.  */
+       xenbus_transaction_end(xbt, 1);
        xenbus_dev_error(dev, err, "%s", message);
  destroy_ring:
        shutdown_device(info);
@@ -1201,7 +1201,7 @@
        struct netfront_info *info;
        unsigned int handle;
 
-       err = xenbus_scanf(dev->nodename, "handle", "%u", &handle);
+       err = xenbus_scanf(NULL, dev->nodename, "handle", "%u", &handle);
        if (XENBUS_EXIST_ERR(err))
                return err;
        if (err < 0) {
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c
--- a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c        Tue Oct 11 
21:50:21 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c        Tue Oct 11 
22:57:44 2005
@@ -246,7 +246,10 @@
                                   PAGE_SHIFT);
                ret = xen_start_info->store_mfn;
 
-               /* We'll return then this will wait for daemon to answer */
+               /* 
+               ** Complete initialization of xenbus (viz. set up the 
+               ** connection to xenstored now that it has started). 
+               */
                kthread_run(do_xenbus_probe, NULL, "xenbus_probe");
        }
        break;
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c
--- a/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c Tue Oct 11 21:50:21 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/xenbus.c Tue Oct 11 22:57:44 2005
@@ -66,12 +66,13 @@
        unsigned int evtchn;
        unsigned long ready = 1;
        int err;
+       struct xenbus_transaction *xbt;
        struct backend_info *be
                = container_of(watch, struct backend_info, watch);
 
        /* If other end is gone, delete ourself. */
-       if (vec && !xenbus_exists(be->frontpath, "")) {
-               xenbus_rm(be->dev->nodename, "");
+       if (vec && !xenbus_exists(NULL, be->frontpath, "")) {
+               xenbus_rm(NULL, be->dev->nodename, "");
                device_unregister(&be->dev->dev);
                return;
        }
@@ -79,7 +80,7 @@
        if (be->tpmif == NULL || be->tpmif->status == CONNECTED)
                return;
 
-       err = xenbus_gather(be->frontpath,
+       err = xenbus_gather(NULL, be->frontpath,
                            "ring-ref", "%lu", &ringref,
                            "event-channel", "%u", &evtchn, NULL);
        if (err) {
@@ -115,20 +116,20 @@
         * unless something bad happens
         */
 again:
-       err = xenbus_transaction_start();
-       if (err) {
+       xbt = xenbus_transaction_start();
+       if (IS_ERR(xbt)) {
                xenbus_dev_error(be->dev, err, "starting transaction");
                return;
        }
 
-       err = xenbus_printf(be->dev->nodename,
+       err = xenbus_printf(xbt, be->dev->nodename,
                            "ready", "%lu", ready);
        if (err) {
                xenbus_dev_error(be->dev, err, "writing 'ready'");
                goto abort;
        }
 
-       err = xenbus_transaction_end(0);
+       err = xenbus_transaction_end(xbt, 0);
        if (err == -EAGAIN)
                goto again;
        if (err) {
@@ -139,7 +140,7 @@
        xenbus_dev_ok(be->dev);
        return;
 abort:
-       xenbus_transaction_end(1);
+       xenbus_transaction_end(xbt, 1);
 }
 
 
@@ -152,7 +153,7 @@
                = container_of(watch, struct backend_info, backend_watch);
        struct xenbus_device *dev = be->dev;
 
-       err = xenbus_scanf(dev->nodename, "instance", "%li", &instance);
+       err = xenbus_scanf(NULL, dev->nodename, "instance", "%li", &instance);
        if (XENBUS_EXIST_ERR(err))
                return;
        if (err < 0) {
@@ -205,7 +206,7 @@
        memset(be, 0, sizeof(*be));
 
        frontend = NULL;
-       err = xenbus_gather(dev->nodename,
+       err = xenbus_gather(NULL, dev->nodename,
                            "frontend-id", "%li", &be->frontend_id,
                            "frontend", NULL, &frontend,
                            NULL);
@@ -217,7 +218,7 @@
                                 dev->nodename);
                goto free_be;
        }
-       if (strlen(frontend) == 0 || !xenbus_exists(frontend, "")) {
+       if (strlen(frontend) == 0 || !xenbus_exists(NULL, frontend, "")) {
                /* If we can't get a frontend path and a frontend-id,
                 * then our bus-id is no longer valid and we need to
                 * destroy the backend device.
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c
--- a/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c      Tue Oct 11 
21:50:21 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/tpmfront/tpmfront.c      Tue Oct 11 
22:57:44 2005
@@ -226,7 +226,7 @@
        if (tp->connected)
                return;
 
-       err = xenbus_gather(watch->node,
+       err = xenbus_gather(NULL, watch->node,
                            "ready", "%lu", &ready,
                            NULL);
        if (err) {
@@ -311,9 +311,10 @@
        const char *message;
        int err;
        int backend_id;
+       struct xenbus_transaction *xbt;
 
        backend = NULL;
-       err = xenbus_gather(dev->nodename,
+       err = xenbus_gather(NULL, dev->nodename,
                            "backend-id", "%i", &backend_id,
                            "backend", NULL, &backend,
                            NULL);
@@ -339,27 +340,27 @@
        }
 
 again:
-       err = xenbus_transaction_start();
-       if (err) {
+       xbt = xenbus_transaction_start();
+       if (IS_ERR(xbt)) {
                xenbus_dev_error(dev, err, "starting transaction");
                goto destroy_tpmring;
        }
 
-       err = xenbus_printf(dev->nodename,
+       err = xenbus_printf(xbt, dev->nodename,
                            "ring-ref","%u", info->ring_ref);
        if (err) {
                message = "writing ring-ref";
                goto abort_transaction;
        }
 
-       err = xenbus_printf(dev->nodename,
+       err = xenbus_printf(xbt, dev->nodename,
                            "event-channel", "%u", my_private.evtchn);
        if (err) {
                message = "writing event-channel";
                goto abort_transaction;
        }
 
-       err = xenbus_transaction_end(0);
+       err = xenbus_transaction_end(xbt, 0);
        if (err == -EAGAIN)
                goto again;
        if (err) {
@@ -380,8 +381,7 @@
        return 0;
 
 abort_transaction:
-       xenbus_transaction_end(1);
-       /* Have to do this *outside* transaction.  */
+       xenbus_transaction_end(xbt, 1);
        xenbus_dev_error(dev, err, "%s", message);
 destroy_tpmring:
        destroy_tpmring(info, &my_private);
@@ -399,7 +399,7 @@
        struct tpmfront_info *info;
        int handle;
 
-       err = xenbus_scanf(dev->nodename,
+       err = xenbus_scanf(NULL, dev->nodename,
                           "handle", "%i", &handle);
        if (XENBUS_EXIST_ERR(err))
                return err;
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c    Tue Oct 11 
21:50:21 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_comms.c    Tue Oct 11 
22:57:44 2005
@@ -128,19 +128,16 @@
                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... */
+               wait_event_interruptible(xb_waitq, output_avail(out));
+
+               mb();
                h = *out;
-               mb();
-               if (!check_buffer(&h)) {
-                       set_current_state(TASK_RUNNING);
-                       return -EIO; /* ETERRORIST! */
-               }
+               if (!check_buffer(&h))
+                       return -EIO;
 
                dst = get_output_chunk(&h, out->buf, &avail);
+               if (avail == 0)
+                       continue;
                if (avail > len)
                        avail = len;
                memcpy(dst, data, avail);
@@ -172,15 +169,16 @@
                unsigned int avail;
                const char *src;
 
-               wait_event(xb_waitq, xs_input_avail());
+               wait_event_interruptible(xb_waitq, xs_input_avail());
+
+               mb();
                h = *in;
-               mb();
-               if (!check_buffer(&h)) {
-                       set_current_state(TASK_RUNNING);
+               if (!check_buffer(&h))
                        return -EIO;
-               }
 
                src = get_input_chunk(&h, in->buf, &avail);
+               if (avail == 0)
+                       continue;
                if (avail > len)
                        avail = len;
                was_full = !output_avail(&h);
@@ -195,10 +193,6 @@
                        notify_remote_via_evtchn(xen_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;
 }
 
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c      Tue Oct 11 
21:50:21 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_dev.c      Tue Oct 11 
22:57:44 2005
@@ -45,86 +45,132 @@
 #include <asm-xen/xen_proc.h>
 #include <asm/hypervisor.h>
 
+struct xenbus_dev_transaction {
+       struct list_head list;
+       struct xenbus_transaction *handle;
+};
+
 struct xenbus_dev_data {
-       /* Are there bytes left to be read in this message? */
-       int bytes_left;
-       /* Are we still waiting for the reply to a message we wrote? */
-       int awaiting_reply;
-       /* Buffer for outgoing messages. */
+       /* In-progress transaction. */
+       struct list_head transactions;
+
+       /* Partial request. */
        unsigned int len;
        union {
                struct xsd_sockmsg msg;
                char buffer[PAGE_SIZE];
        } u;
+
+       /* Response queue. */
+#define MASK_READ_IDX(idx) ((idx)&(PAGE_SIZE-1))
+       char read_buffer[PAGE_SIZE];
+       unsigned int read_cons, read_prod;
+       wait_queue_head_t read_waitq;
 };
 
 static struct proc_dir_entry *xenbus_dev_intf;
 
-/* Reply can be long (dir, getperm): don't buffer, just examine
- * headers so we can discard rest if they die. */
 static ssize_t xenbus_dev_read(struct file *filp,
                               char __user *ubuf,
                               size_t len, loff_t *ppos)
 {
-       struct xenbus_dev_data *data = filp->private_data;
-       struct xsd_sockmsg msg;
-       int err;
-
-       /* Refill empty buffer? */
-       if (data->bytes_left == 0) {
-               if (len < sizeof(msg))
-                       return -EINVAL;
-
-               err = xb_read(&msg, sizeof(msg));
-               if (err)
-                       return err;
-               data->bytes_left = msg.len;
-               if (ubuf && copy_to_user(ubuf, &msg, sizeof(msg)) != 0)
-                       return -EFAULT;
-               /* We can receive spurious XS_WATCH_EVENT messages. */
-               if (msg.type != XS_WATCH_EVENT)
-                       data->awaiting_reply = 0;
-               return sizeof(msg);
-       }
-
-       /* Don't read over next header, or over temporary buffer. */
-       if (len > sizeof(data->u.buffer))
-               len = sizeof(data->u.buffer);
-       if (len > data->bytes_left)
-               len = data->bytes_left;
-
-       err = xb_read(data->u.buffer, len);
-       if (err)
-               return err;
-
-       data->bytes_left -= len;
-       if (ubuf && copy_to_user(ubuf, data->u.buffer, len) != 0)
-               return -EFAULT;
-       return len;
-}
-
-/* We do v. basic sanity checking so they don't screw up kernel later. */
+       struct xenbus_dev_data *u = filp->private_data;
+       int i;
+
+       if (wait_event_interruptible(u->read_waitq,
+                                    u->read_prod != u->read_cons))
+               return -EINTR;
+
+       for (i = 0; i < len; i++) {
+               if (u->read_cons == u->read_prod)
+                       break;
+               put_user(u->read_buffer[MASK_READ_IDX(u->read_cons)], ubuf+i);
+               u->read_cons++;
+       }
+
+       return i;
+}
+
+static void queue_reply(struct xenbus_dev_data *u,
+                       char *data, unsigned int len)
+{
+       int i;
+
+       for (i = 0; i < len; i++, u->read_prod++)
+               u->read_buffer[MASK_READ_IDX(u->read_prod)] = data[i];
+
+       BUG_ON((u->read_prod - u->read_cons) > sizeof(u->read_buffer));
+
+       wake_up(&u->read_waitq);
+}
+
 static ssize_t xenbus_dev_write(struct file *filp,
                                const char __user *ubuf,
                                size_t len, loff_t *ppos)
 {
-       struct xenbus_dev_data *data = filp->private_data;
-       int err;
-
-       /* We gather data in buffer until we're ready to send it. */
-       if (len > data->len + sizeof(data->u))
+       struct xenbus_dev_data *u = filp->private_data;
+       struct xenbus_dev_transaction *trans;
+       void *reply;
+       int err = 0;
+
+       if ((len + u->len) > sizeof(u->u.buffer))
                return -EINVAL;
-       if (copy_from_user(data->u.buffer + data->len, ubuf, len) != 0)
+
+       if (copy_from_user(u->u.buffer + u->len, ubuf, len) != 0)
                return -EFAULT;
-       data->len += len;
-       if (data->len >= sizeof(data->u.msg) + data->u.msg.len) {
-               err = xb_write(data->u.buffer, data->len);
-               if (err)
-                       return err;
-               data->len = 0;
-               data->awaiting_reply = 1;
-       }
-       return len;
+
+       u->len += len;
+       if (u->len < (sizeof(u->u.msg) + u->u.msg.len))
+               return len;
+
+       switch (u->u.msg.type) {
+       case XS_TRANSACTION_START:
+       case XS_TRANSACTION_END:
+       case XS_DIRECTORY:
+       case XS_READ:
+       case XS_GET_PERMS:
+       case XS_RELEASE:
+       case XS_GET_DOMAIN_PATH:
+       case XS_WRITE:
+       case XS_MKDIR:
+       case XS_RM:
+       case XS_SET_PERMS:
+               reply = xenbus_dev_request_and_reply(&u->u.msg);
+               if (IS_ERR(reply)) {
+                       err = PTR_ERR(reply);
+               } else {
+                       if (u->u.msg.type == XS_TRANSACTION_START) {
+                               trans = kmalloc(sizeof(*trans), GFP_KERNEL);
+                               trans->handle = (struct xenbus_transaction *)
+                                       simple_strtoul(reply, NULL, 0);
+                               list_add(&trans->list, &u->transactions);
+                       } else if (u->u.msg.type == XS_TRANSACTION_END) {
+                               list_for_each_entry(trans, &u->transactions,
+                                                   list)
+                                       if ((unsigned long)trans->handle ==
+                                           (unsigned long)u->u.msg.tx_id)
+                                               break;
+                               BUG_ON(&trans->list == &u->transactions);
+                               list_del(&trans->list);
+                               kfree(trans);
+                       }
+                       queue_reply(u, (char *)&u->u.msg, sizeof(u->u.msg));
+                       queue_reply(u, (char *)reply, u->u.msg.len);
+                       kfree(reply);
+               }
+               break;
+
+       default:
+               err = -EINVAL;
+               break;
+       }
+
+       if (err == 0) {
+               u->len = 0;
+               err = len;
+       }
+
+       return err;
 }
 
 static int xenbus_dev_open(struct inode *inode, struct file *filp)
@@ -134,7 +180,6 @@
        if (xen_start_info->store_evtchn == 0)
                return -ENOENT;
 
-       /* Don't try seeking. */
        nonseekable_open(inode, filp);
 
        u = kmalloc(sizeof(*u), GFP_KERNEL);
@@ -142,28 +187,26 @@
                return -ENOMEM;
 
        memset(u, 0, sizeof(*u));
+       INIT_LIST_HEAD(&u->transactions);
+       init_waitqueue_head(&u->read_waitq);
 
        filp->private_data = u;
 
-       down(&xenbus_lock);
-
        return 0;
 }
 
 static int xenbus_dev_release(struct inode *inode, struct file *filp)
 {
-       struct xenbus_dev_data *data = filp->private_data;
-
-       /* Discard any unread replies. */
-       while (data->bytes_left || data->awaiting_reply)
-               xenbus_dev_read(filp, NULL, sizeof(data->u.buffer), NULL);
-
-       /* Harmless if no transaction in progress. */
-       xenbus_transaction_end(1);
-
-       up(&xenbus_lock);
-
-       kfree(data);
+       struct xenbus_dev_data *u = filp->private_data;
+       struct xenbus_dev_transaction *trans, *tmp;
+
+       list_for_each_entry_safe(trans, tmp, &u->transactions, list) {
+               xenbus_transaction_end(trans->handle, 1);
+               list_del(&trans->list);
+               kfree(trans);
+       }
+
+       kfree(u);
 
        return 0;
 }
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c    Tue Oct 11 
21:50:21 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c    Tue Oct 11 
22:57:44 2005
@@ -125,7 +125,7 @@
 
        devid = strrchr(nodename, '/') + 1;
 
-       err = xenbus_gather(nodename, "frontend-id", "%i", &domid,
+       err = xenbus_gather(NULL, nodename, "frontend-id", "%i", &domid,
                            "frontend", NULL, &frontend,
                            NULL);
        if (err)
@@ -133,7 +133,7 @@
        if (strlen(frontend) == 0)
                err = -ERANGE;
 
-       if (!err && !xenbus_exists(frontend, ""))
+       if (!err && !xenbus_exists(NULL, frontend, ""))
                err = -ENOENT;
 
        if (err) {
@@ -229,18 +229,13 @@
 static int xenbus_register_driver_common(struct xenbus_driver *drv,
                                         struct xen_bus_type *bus)
 {
-       int err;
-
        drv->driver.name = drv->name;
        drv->driver.bus = &bus->bus;
        drv->driver.owner = drv->owner;
        drv->driver.probe = xenbus_dev_probe;
        drv->driver.remove = xenbus_dev_remove;
 
-       down(&xenbus_lock);
-       err = driver_register(&drv->driver);
-       up(&xenbus_lock);
-       return err;
+       return driver_register(&drv->driver);
 }
 
 int xenbus_register_driver(struct xenbus_driver *drv)
@@ -256,9 +251,7 @@
 
 void xenbus_unregister_driver(struct xenbus_driver *drv)
 {
-       down(&xenbus_lock);
        driver_unregister(&drv->driver);
-       up(&xenbus_lock);
 }
 EXPORT_SYMBOL(xenbus_unregister_driver);
 
@@ -447,7 +440,7 @@
        if (!nodename)
                return -ENOMEM;
 
-       dir = xenbus_directory(nodename, "", &dir_n);
+       dir = xenbus_directory(NULL, nodename, "", &dir_n);
        if (IS_ERR(dir)) {
                kfree(nodename);
                return PTR_ERR(dir);
@@ -470,7 +463,7 @@
        unsigned int dir_n = 0;
        int i;
 
-       dir = xenbus_directory(bus->root, type, &dir_n);
+       dir = xenbus_directory(NULL, bus->root, type, &dir_n);
        if (IS_ERR(dir))
                return PTR_ERR(dir);
 
@@ -489,7 +482,7 @@
        char **dir;
        unsigned int i, dir_n;
 
-       dir = xenbus_directory(bus->root, "", &dir_n);
+       dir = xenbus_directory(NULL, bus->root, "", &dir_n);
        if (IS_ERR(dir))
                return PTR_ERR(dir);
 
@@ -535,7 +528,7 @@
        if (char_count(node, '/') < 2)
                return;
 
-       exists = xenbus_exists(node, "");
+       exists = xenbus_exists(NULL, node, "");
        if (!exists) {
                xenbus_cleanup_devices(node, &bus->bus);
                return;
@@ -621,26 +614,22 @@
 
 void xenbus_suspend(void)
 {
-       /* We keep lock, so no comms can happen as page moves. */
-       down(&xenbus_lock);
        bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
        bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev);
+       xs_suspend();
 }
 
 void xenbus_resume(void)
 {
        xb_init_comms();
-       reregister_xenbus_watches();
+       xs_resume();
        bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
        bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev);
-       up(&xenbus_lock);
 }
 
 int register_xenstore_notifier(struct notifier_block *nb)
 {
        int ret = 0;
-
-       down(&xenbus_lock);
 
        if (xen_start_info->store_evtchn) {
                ret = nb->notifier_call(nb, 0, NULL);
@@ -648,26 +637,26 @@
                notifier_chain_register(&xenstore_chain, nb);
        }
 
-       up(&xenbus_lock);
-
        return ret;
 }
 EXPORT_SYMBOL(register_xenstore_notifier);
 
 void unregister_xenstore_notifier(struct notifier_block *nb)
 {
-       down(&xenbus_lock);
        notifier_chain_unregister(&xenstore_chain, nb);
-       up(&xenbus_lock);
 }
 EXPORT_SYMBOL(unregister_xenstore_notifier);
 
-/* called from a thread in privcmd/privcmd.c */
+/* 
+** Called either from below xenbus_probe_init() initcall (for domUs) 
+** or, for dom0, from a thread created in privcmd/privcmd.c (after 
+** the user-space tools have invoked initDomainStore()) 
+*/
 int do_xenbus_probe(void *unused)
 {
        int err = 0;
 
-       /* Initialize xenstore comms unless already done. */
+       /* Initialize the interface to xenstore. */
        err = xs_init();
        if (err) {
                printk("XENBUS: Error initializing xenstore comms:"
@@ -675,16 +664,17 @@
                return err;
        }
 
-       down(&xenbus_lock);
        /* Enumerate devices in xenstore. */
        xenbus_probe_devices(&xenbus_frontend);
        xenbus_probe_devices(&xenbus_backend);
+
        /* Watch for changes. */
        register_xenbus_watch(&fe_watch);
        register_xenbus_watch(&be_watch);
+
        /* Notify others that xenstore is up */
        notifier_call_chain(&xenstore_chain, 0, 0);
-       up(&xenbus_lock);
+
        return 0;
 }
 
@@ -698,6 +688,10 @@
        device_register(&xenbus_frontend.dev);
        device_register(&xenbus_backend.dev);
 
+       /* 
+       ** Domain0 doesn't have a store_evtchn yet - this will
+       ** be set up later by xend invoking initDomainStore() 
+       */
        if (!xen_start_info->store_evtchn)
                return 0;
 
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c
--- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c       Tue Oct 11 
21:50:21 2005
+++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_xs.c       Tue Oct 11 
22:57:44 2005
@@ -42,11 +42,58 @@
 
 #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;
+       wait_queue_head_t 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);
-
-DECLARE_MUTEX(xenbus_lock);
-EXPORT_SYMBOL(xenbus_lock);
+static DEFINE_SPINLOCK(watches_lock);
+
+/* List of pending watch calbback 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 pid_t xenwatch_pid;
+static DECLARE_MUTEX(xenwatch_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(watch_events_waitq);
 
 static int get_error(const char *errorstring)
 {
@@ -65,47 +112,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 = kmalloc(msg.len + 1, GFP_KERNEL);
-       if (!ret)
-               return ERR_PTR(-ENOMEM);
-
-       err = xb_read(ret, msg.len);
-       if (err) {
-               kfree(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_interruptible(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;
+
+       kfree(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,31 +197,34 @@
        unsigned int i;
        int err;
 
-       WARN_ON(down_trylock(&xenbus_lock) == 0);
-
+       msg.tx_id = (u32)(unsigned long)t;
        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)
+               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 {
-               kfree(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);
@@ -152,14 +237,16 @@
 }
 
 /* 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. */
@@ -182,20 +269,22 @@
        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 = kmalloc(strlen(dir) + strlen("/") + strlen(name) + 1,
+                        GFP_KERNEL);
+       if (buffer == NULL)
+               return ERR_PTR(-ENOMEM);
 
        strcpy(buffer, dir);
        if (!streq(name, "")) {
                strcat(buffer, "/");
                strcat(buffer, name);
        }
+
        return buffer;
 }
 
@@ -207,7 +296,7 @@
        *num = count_strings(strings, len);
 
        /* Transfer to one big alloc for easy freeing. */
-       ret = kmalloc(*num * sizeof(char *) + len, GFP_ATOMIC);
+       ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL);
        if (!ret) {
                kfree(strings);
                return ERR_PTR(-ENOMEM);
@@ -222,12 +311,18 @@
        return ret;
 }
 
-char **xenbus_directory(const char *dir, const char *node, unsigned int *num)
-{
-       char *strings;
+char **xenbus_directory(struct xenbus_transaction *t,
+                       const char *dir, const char *node, unsigned int *num)
+{
+       char *strings, *path;
        unsigned int len;
 
-       strings = xs_single(XS_DIRECTORY, join(dir, node), &len);
+       path = join(dir, node);
+       if (IS_ERR(path))
+               return (char **)path;
+
+       strings = xs_single(t, XS_DIRECTORY, path, &len);
+       kfree(path);
        if (IS_ERR(strings))
                return (char **)strings;
 
@@ -236,12 +331,13 @@
 EXPORT_SYMBOL(xenbus_directory);
 
 /* 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;
        kfree(d);
@@ -253,78 +349,133 @@
  * 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);
+       kfree(path);
+       return ret;
 }
 EXPORT_SYMBOL(xenbus_read);
 
 /* Write the value of a single file.
  * Returns -err on failure.
  */
-int xenbus_write(const char *dir, const char *node, const char *string)
+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);
+       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 *)string;
        iovec[1].iov_len = strlen(string);
 
-       return xs_error(xs_talkv(XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
+       ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
+       kfree(path);
+       return ret;
 }
 EXPORT_SYMBOL(xenbus_write);
 
 /* 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));
+       kfree(path);
+       return ret;
 }
 EXPORT_SYMBOL(xenbus_mkdir);
 
 /* 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));
+       kfree(path);
+       return ret;
 }
 EXPORT_SYMBOL(xenbus_rm);
 
 /* Start a transaction: changes by others will not be seen during this
  * transaction, and changes will not be visible to others until end.
- * You can only have one transaction at any time.
  */
-int xenbus_transaction_start(void)
-{
-       return xs_error(xs_single(XS_TRANSACTION_START, "", 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);
+       kfree(id_str);
+
+       return (struct xenbus_transaction *)id;
 }
 EXPORT_SYMBOL(xenbus_transaction_start);
 
 /* 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;
 }
 EXPORT_SYMBOL(xenbus_transaction_end);
 
 /* 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);
 
@@ -340,18 +491,28 @@
 EXPORT_SYMBOL(xenbus_scanf);
 
 /* 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 = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
+       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);
+       BUG_ON(ret > PRINTF_BUFFER_SIZE-1);
+       ret = xenbus_write(t, dir, node, printf_buffer);
+
+       kfree(printf_buffer);
+
+       return ret;
 }
 EXPORT_SYMBOL(xenbus_printf);
 
@@ -361,19 +522,28 @@
        va_list ap;
        int ret;
        unsigned int len;
-
-       BUG_ON(down_trylock(&xenbus_lock) == 0);
+       char *printf_buffer;
+
+       printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
+       if (printf_buffer == NULL)
+               goto fail;
 
        len = sprintf(printf_buffer, "%i ", -err);
        va_start(ap, fmt);
-       ret = vsnprintf(printf_buffer+len, sizeof(printf_buffer)-len, fmt, ap);
+       ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
        va_end(ap);
 
-       BUG_ON(len + ret > sizeof(printf_buffer)-1);
+       BUG_ON(len + ret > PRINTF_BUFFER_SIZE-1);
        dev->has_error = 1;
-       if (xenbus_write(dev->nodename, "error", printf_buffer) != 0)
-               printk("xenbus: failed to write error node for %s (%s)\n",
-                      dev->nodename, printf_buffer);
+       if (xenbus_write(NULL, dev->nodename, "error", printf_buffer) != 0)
+               goto fail;
+
+       kfree(printf_buffer);
+       return;
+
+ fail:
+       printk("xenbus: failed to write error node for %s (%s)\n",
+              dev->nodename, printf_buffer);
 }
 EXPORT_SYMBOL(xenbus_dev_error);
 
@@ -381,7 +551,7 @@
 void xenbus_dev_ok(struct xenbus_device *dev)
 {
        if (dev->has_error) {
-               if (xenbus_rm(dev->nodename, "error") != 0)
+               if (xenbus_rm(NULL, dev->nodename, "error") != 0)
                        printk("xenbus: failed to clear error node for %s\n",
                               dev->nodename);
                else
@@ -391,7 +561,7 @@
 EXPORT_SYMBOL(xenbus_dev_ok);
        
 /* 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;
@@ -403,7 +573,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;
@@ -429,27 +599,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(unsigned int *num)
-{
-       enum xsd_sockmsg_type type;
-       char *strings;
-       unsigned int len;
-
-       strings = read_reply(&type, &len);
-       if (IS_ERR(strings))
-               return (char **)strings;
-
-       BUG_ON(type != XS_WATCH_EVENT);
-
-       return split(strings, len, num);
-}
-
-static int xs_acknowledge_watch(const char *token)
-{
-       return xs_error(xs_single(XS_WATCH_ACK, token, NULL));
+       return xs_error(xs_talkv(NULL, XS_WATCH, iov,
+                                ARRAY_SIZE(iov), NULL));
 }
 
 static int xs_unwatch(const char *path, const char *token)
@@ -461,10 +612,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;
@@ -474,6 +625,7 @@
        list_for_each_entry(i, &watches, list)
                if (i == cmp)
                        return i;
+
        return NULL;
 }
 
@@ -485,92 +637,223 @@
        int err;
 
        sprintf(token, "%lX", (long)watch);
+
+       down_read(&xs_state.suspend_mutex);
+
+       spin_lock(&watches_lock);
        BUG_ON(find_watch(token));
+       spin_unlock(&watches_lock);
 
        err = xs_watch(watch->node, token);
-       if (!err)
+
+       /* Ignore errors due to multiple registration. */
+       if ((err == 0) || (err == -EEXIST)) {
+               spin_lock(&watches_lock);
                list_add(&watch->list, &watches);
+               spin_unlock(&watches_lock);
+       }
+
+       up_read(&xs_state.suspend_mutex);
+
        return err;
 }
 EXPORT_SYMBOL(register_xenbus_watch);
 
 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);
+
+       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(KERN_WARNING
                       "XENBUS Failed to release watch %s: %i\n",
                       watch->node, err);
+
+       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);
+               kfree(msg->u.watch.vec);
+               kfree(msg);
+       }
+       spin_unlock(&watch_events_lock);
+
+       /* Flush any currently-executing callback, unless we are it. :-) */
+       if (current->pid != xenwatch_pid) {
+               down(&xenwatch_mutex);
+               up(&xenwatch_mutex);
+       }
 }
 EXPORT_SYMBOL(unregister_xenbus_watch);
 
-/* Re-register callbacks to all watches. */
-void reregister_xenbus_watches(void)
+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);
        }
-}
-
-static int watch_thread(void *unused)
-{
+
+       up_write(&xs_state.suspend_mutex);
+}
+
+static int xenwatch_thread(void *unused)
+{
+       struct list_head *ent;
+       struct xs_stored_msg *msg;
+
        for (;;) {
-               char **vec = NULL;
-               unsigned int num;
-
-               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())
-                       vec = xs_read_watch(&num);
-
-               if (vec && !IS_ERR(vec)) {
-                       struct xenbus_watch *w;
-                       int err;
-
-                       err = xs_acknowledge_watch(vec[XS_WATCH_TOKEN]);
-                       if (err)
-                               printk(KERN_WARNING "XENBUS ack %s fail %i\n",
-                                      vec[XS_WATCH_TOKEN], err);
-                       w = find_watch(vec[XS_WATCH_TOKEN]);
-                       BUG_ON(!w);
-                       w->callback(w, (const char **)vec, num);
-                       kfree(vec);
-               } else if (vec)
-                       printk(KERN_WARNING "XENBUS xs_read_watch: %li\n",
-                              PTR_ERR(vec));
-               up(&xenbus_lock);
+               wait_event_interruptible(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);
+                       kfree(msg->u.watch.vec);
+                       kfree(msg);
+               }
+
+               up(&xenwatch_mutex);
+       }
+}
+
+static int process_msg(void)
+{
+       struct xs_stored_msg *msg;
+       char *body;
+       int err;
+
+       msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+       if (msg == NULL)
+               return -ENOMEM;
+
+       err = xb_read(&msg->hdr, sizeof(msg->hdr));
+       if (err) {
+               kfree(msg);
+               return err;
+       }
+
+       body = kmalloc(msg->hdr.len + 1, GFP_KERNEL);
+       if (body == NULL) {
+               kfree(msg);
+               return -ENOMEM;
+       }
+
+       err = xb_read(body, msg->hdr.len);
+       if (err) {
+               kfree(body);
+               kfree(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)) {
+                       kfree(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 {
+                       kfree(msg->u.watch.vec);
+                       kfree(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 int xenbus_thread(void *unused)
+{
+       int err;
+
+       for (;;) {
+               err = process_msg();
+               if (err)
+                       printk(KERN_WARNING "XENBUS error %d while reading "
+                              "message\n", err);
        }
 }
 
 int xs_init(void)
 {
        int err;
-       struct task_struct *watcher;
-
+       struct task_struct *task;
+
+       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 = kthread_run(watch_thread, NULL, "kxbwatch");
-       if (IS_ERR(watcher))
-               return PTR_ERR(watcher);
+
+       task = kthread_run(xenwatch_thread, NULL, "xenwatch");
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+       xenwatch_pid = task->pid;
+
+       task = kthread_run(xenbus_thread, NULL, "xenbus");
+       if (IS_ERR(task))
+               return PTR_ERR(task);
+
        return 0;
 }
 
diff -r 333f722ed6d0 -r 74d56b7ff46c 
linux-2.6-xen-sparse/include/asm-xen/xenbus.h
--- a/linux-2.6-xen-sparse/include/asm-xen/xenbus.h     Tue Oct 11 21:50:21 2005
+++ b/linux-2.6-xen-sparse/include/asm-xen/xenbus.h     Tue Oct 11 22:57:44 2005
@@ -78,30 +78,35 @@
 int xenbus_register_backend(struct xenbus_driver *drv);
 void xenbus_unregister_driver(struct xenbus_driver *drv);
 
-/* Caller must hold this lock to call these functions: it's also held
- * across watch callbacks. */
-extern struct semaphore xenbus_lock;
+struct xenbus_transaction;
 
-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 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(void);
-int xenbus_transaction_end(int abort);
+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(const char *dir, const char *node, const char *fmt, ...)
-       __attribute__((format(scanf, 3, 4)));
+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(const char *dir, const char *node, const char *fmt, ...)
-       __attribute__((format(printf, 3, 4)));
+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(const char *dir, ...);
+int xenbus_gather(struct xenbus_transaction *t, const char *dir, ...);
 
 /* Report a (negative) errno into the store, with explanation. */
 void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt,...);
@@ -113,7 +118,11 @@
 struct xenbus_watch
 {
        struct list_head list;
+
+       /* Path being watched. */
        char *node;
+
+       /* Callback (executed in a process context with no locks held). */
        void (*callback)(struct xenbus_watch *,
                         const char **vec, unsigned int len);
 };
@@ -124,7 +133,11 @@
 
 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);
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/blktap/xenbus.c
--- a/tools/blktap/xenbus.c     Tue Oct 11 21:50:21 2005
+++ b/tools/blktap/xenbus.c     Tue Oct 11 22:57:44 2005
@@ -260,10 +260,6 @@
     node  = res[XS_WATCH_PATH];
     token = res[XS_WATCH_TOKEN];
 
-    er = xs_acknowledge_watch(h, token);
-    if (er == 0)
-        warn("Couldn't acknowledge watch (%s)", token);
-
     w = find_watch(token);
     if (!w)
     {
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/console/Makefile
--- a/tools/console/Makefile    Tue Oct 11 21:50:21 2005
+++ b/tools/console/Makefile    Tue Oct 11 22:57:44 2005
@@ -3,7 +3,7 @@
 include $(XEN_ROOT)/tools/Rules.mk
 
 DAEMON_INSTALL_DIR = /usr/sbin
-CLIENT_INSTALL_DIR = /usr/libexec/xen
+CLIENT_INSTALL_DIR = /usr/$(LIBDIR)/xen/bin
 
 INSTALL         = install
 INSTALL_PROG    = $(INSTALL) -m0755
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/console/client/main.c
--- a/tools/console/client/main.c       Tue Oct 11 21:50:21 2005
+++ b/tools/console/client/main.c       Tue Oct 11 22:57:44 2005
@@ -220,7 +220,7 @@
        if (path == NULL)
                err(ENOMEM, "realloc");
        strcat(path, "/console/tty");
-       str_pty = xs_read(xs, path, &len);
+       str_pty = xs_read(xs, NULL, path, &len);
 
        /* FIXME consoled currently does not assume domain-0 doesn't have a
           console which is good when we break domain-0 up.  To keep us
@@ -245,7 +245,7 @@
                struct timeval tv = { 0, 500 };
                select(0, NULL, NULL, NULL, &tv); /* pause briefly */
 
-               str_pty = xs_read(xs, path, &len);
+               str_pty = xs_read(xs, NULL, path, &len);
        }
 
        if (str_pty == NULL) {
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/console/daemon/io.c
--- a/tools/console/daemon/io.c Tue Oct 11 21:50:21 2005
+++ b/tools/console/daemon/io.c Tue Oct 11 22:57:44 2005
@@ -25,6 +25,7 @@
 #include <xenctrl.h>
 #include <xs.h>
 #include <xen/linux/evtchn.h>
+#include <xen/io/console.h>
 
 #include <malloc.h>
 #include <stdlib.h>
@@ -62,24 +63,11 @@
        char *conspath;
        int ring_ref;
        int local_port;
-       char *page;
        int evtchn_fd;
+       struct xencons_interface *interface;
 };
 
 static struct domain *dom_head;
-
-struct ring_head
-{
-       u32 cons;
-       u32 prod;
-       char buf[0];
-} __attribute__((packed));
-
-#define PAGE_SIZE (getpagesize())
-#define XENCONS_RING_SIZE (PAGE_SIZE/2 - sizeof (struct ring_head))
-#define XENCONS_IDX(cnt) ((cnt) % XENCONS_RING_SIZE)
-#define XENCONS_FULL(ring) (((ring)->prod - (ring)->cons) == XENCONS_RING_SIZE)
-#define XENCONS_SPACE(ring) (XENCONS_RING_SIZE - ((ring)->prod - (ring)->cons))
 
 static void evtchn_notify(struct domain *dom)
 {
@@ -91,12 +79,12 @@
 static void buffer_append(struct domain *dom)
 {
        struct buffer *buffer = &dom->buffer;
-       struct ring_head *ring = (struct ring_head *)dom->page;
        size_t size;
-       u32 oldcons;
+       XENCONS_RING_IDX oldcons;
        int notify = 0;
-
-       while ((size = ring->prod - ring->cons) != 0) {
+       struct xencons_interface *intf = dom->interface;
+
+       while ((size = (intf->out_prod - intf->out_cons)) != 0) {
                notify = 1;
 
                if ((buffer->capacity - buffer->size) < size) {
@@ -108,12 +96,12 @@
                        }
                }
 
-               oldcons = ring->cons;
-               while (ring->cons < (oldcons + size)) {
-                       buffer->data[buffer->size] =
-                               ring->buf[XENCONS_IDX(ring->cons)];
+               oldcons = intf->out_cons;
+               while ((intf->out_cons - oldcons) < size) {
+                       buffer->data[buffer->size] = intf->out[
+                               MASK_XENCONS_IDX(intf->out_cons, intf->out)];
                        buffer->size++;
-                       ring->cons++;
+                       intf->out_cons++;
                }
 
                if (buffer->max_capacity &&
@@ -179,7 +167,7 @@
                success = asprintf(&path, "%s/tty", dom->conspath) != -1;
                if (!success)
                        goto out;
-               success = xs_write(xs, path, slave, strlen(slave));
+               success = xs_write(xs, NULL, path, slave, strlen(slave));
                free(path);
                if (!success)
                        goto out;
@@ -187,7 +175,7 @@
                success = asprintf(&path, "%s/limit", dom->conspath) != -1;
                if (!success)
                        goto out;
-               data = xs_read(xs, path, &len);
+               data = xs_read(xs, NULL, path, &len);
                if (data) {
                        dom->buffer.max_capacity = strtoul(data, 0, 0);
                        free(data);
@@ -216,7 +204,7 @@
                char *p;
 
                asprintf(&path, "%s/%s", dir, name);
-               p = xs_read(xs, path, NULL);
+               p = xs_read(xs, NULL, path, NULL);
                free(path);
                if (p == NULL) {
                        ret = ENOENT;
@@ -246,12 +234,13 @@
                goto out;
 
        if (ring_ref != dom->ring_ref) {
-               if (dom->page)
-                       munmap(dom->page, getpagesize());
-               dom->page = xc_map_foreign_range(xc, dom->domid, getpagesize(),
-                                                PROT_READ|PROT_WRITE,
-                                                (unsigned long)ring_ref);
-               if (dom->page == NULL) {
+               if (dom->interface != NULL)
+                       munmap(dom->interface, getpagesize());
+               dom->interface = xc_map_foreign_range(
+                       xc, dom->domid, getpagesize(),
+                       PROT_READ|PROT_WRITE,
+                       (unsigned long)ring_ref);
+               if (dom->interface == NULL) {
                        err = EINVAL;
                        goto out;
                }
@@ -334,7 +323,7 @@
 
        dom->ring_ref = -1;
        dom->local_port = -1;
-       dom->page = NULL;
+       dom->interface = NULL;
        dom->evtchn_fd = -1;
 
        if (!watch_domain(dom, true))
@@ -396,9 +385,9 @@
 {
        d->is_dead = true;
        watch_domain(d, false);
-       if (d->page)
-               munmap(d->page, getpagesize());
-       d->page = NULL;
+       if (d->interface != NULL)
+               munmap(d->interface, getpagesize());
+       d->interface = NULL;
        if (d->evtchn_fd != -1)
                close(d->evtchn_fd);
        d->evtchn_fd = -1;
@@ -426,13 +415,21 @@
 
 static void handle_tty_read(struct domain *dom)
 {
-       ssize_t len;
+       ssize_t len = 0;
        char msg[80];
-       struct ring_head *inring =
-               (struct ring_head *)(dom->page + PAGE_SIZE/2);
        int i;
-
-       len = read(dom->tty_fd, msg, MIN(XENCONS_SPACE(inring), sizeof(msg)));
+       struct xencons_interface *intf = dom->interface;
+       XENCONS_RING_IDX filled = intf->in_prod - intf->in_cons;
+
+       if (sizeof(intf->in) > filled)
+               len = sizeof(intf->in) - filled;
+       if (len > sizeof(msg))
+               len = sizeof(msg);
+
+       if (len == 0)
+               return;
+
+       len = read(dom->tty_fd, msg, len);
        if (len < 1) {
                close(dom->tty_fd);
                dom->tty_fd = -1;
@@ -444,8 +441,9 @@
                }
        } else if (domain_is_valid(dom->domid)) {
                for (i = 0; i < len; i++) {
-                       inring->buf[XENCONS_IDX(inring->prod)] = msg[i];
-                       inring->prod++;
+                       intf->in[MASK_XENCONS_IDX(intf->in_prod, intf->in)] =
+                               msg[i];
+                       intf->in_prod++;
                }
                evtchn_notify(dom);
        } else {
@@ -505,7 +503,6 @@
                        domain_create_ring(dom);
        }
 
-       xs_acknowledge_watch(xs, vec[1]);
        free(vec);
 }
 
@@ -565,3 +562,13 @@
                }
        } while (ret > -1);
 }
+
+/*
+ * Local variables:
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/examples/Makefile
--- a/tools/examples/Makefile   Tue Oct 11 21:50:21 2005
+++ b/tools/examples/Makefile   Tue Oct 11 22:57:44 2005
@@ -24,6 +24,7 @@
 XEN_SCRIPTS += network-nat vif-nat
 XEN_SCRIPTS += block
 XEN_SCRIPTS += block-enbd
+XEN_SCRIPTS += xen-hotplug-common.sh
 
 XEN_HOTPLUG_DIR = /etc/hotplug
 XEN_HOTPLUG_SCRIPTS = xen-backend.agent
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/examples/block
--- a/tools/examples/block      Tue Oct 11 21:50:21 2005
+++ b/tools/examples/block      Tue Oct 11 22:57:44 2005
@@ -1,8 +1,7 @@
 #!/bin/sh
 
-set -e
-
-export PATH=/sbin:/bin:/usr/bin:/usr/sbin:$PATH
+dir=$(dirname "$0")
+. "$dir/xen-hotplug-common.sh"
 
 expand_dev() {
   local dev
@@ -25,15 +24,15 @@
   major=$(stat -L -c %t "$1")
   minor=$(stat -L -c %T "$1")
   pdev=$(printf "0x%02x%02x" 0x$major 0x$minor)
-  xenstore-write "$XENBUS_PATH"/physical-device $pdev \
+  xenstore_write "$XENBUS_PATH"/physical-device $pdev \
       "$XENBUS_PATH"/node $1
 }
 
-t=$(xenstore-read "$XENBUS_PATH"/type)
+t=$(xenstore_read "$XENBUS_PATH"/type || true)
 
 case $1 in 
   bind)
-    p=$(xenstore-read "$XENBUS_PATH"/params)
+    p=$(xenstore_read "$XENBUS_PATH"/params)
     case $t in 
       phy)
         dev=$(expand_dev $p)
@@ -60,7 +59,7 @@
     ;;
 
   unbind)
-    node=$(xenstore-read "$XENBUS_PATH"/node)
+    node=$(xenstore_read "$XENBUS_PATH"/node)
     case $t in 
       phy)
        exit 0
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/libxc/xc_linux_save.c
--- a/tools/libxc/xc_linux_save.c       Tue Oct 11 21:50:21 2005
+++ b/tools/libxc/xc_linux_save.c       Tue Oct 11 22:57:44 2005
@@ -35,7 +35,7 @@
 #define DEBUG 0
 
 #if 1
-#define ERR(_f, _a...) do { fprintf(stderr, _f , ## _a); fflush(stderr); } 
while (0)
+#define ERR(_f, _a...) do { fprintf(stderr, _f "\n" , ## _a); fflush(stderr); 
} while (0)
 #else
 #define ERR(_f, _a...) ((void)0)
 #endif
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/misc/xend
--- a/tools/misc/xend   Tue Oct 11 21:50:21 2005
+++ b/tools/misc/xend   Tue Oct 11 22:57:44 2005
@@ -2,9 +2,10 @@
 #  -*- mode: python; -*-
 #============================================================================
 # Copyright (C) 2004 Mike Wray <mike.wray@xxxxxx>
+# Copyright (C) 2005 XenSource Ltd
 #============================================================================
 
-"""Xen management daemon. Lives in /usr/sbin.
+"""Xen management daemon.
    Provides console server and HTTP management api.
 
    Run:
@@ -67,14 +68,14 @@
 
 def start_xenstored():
     XENSTORED_TRACE = os.getenv("XENSTORED_TRACE")
-    cmd = "/usr/sbin/xenstored --pid-file=/var/run/xenstore.pid"
+    cmd = "xenstored --pid-file=/var/run/xenstore.pid"
     if XENSTORED_TRACE:
         cmd += " -T /var/log/xenstored-trace.log"
     s,o = commands.getstatusoutput(cmd)
 
 def start_consoled():
     if os.fork() == 0:
-        os.execvp('/usr/sbin/xenconsoled', ['/usr/sbin/xenconsoled'])
+        os.execvp('xenconsoled', ['xenconsoled'])
             
 def main():
     try:
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/pygrub/src/fsys/reiser/reisermodule.c
--- a/tools/pygrub/src/fsys/reiser/reisermodule.c       Tue Oct 11 21:50:21 2005
+++ b/tools/pygrub/src/fsys/reiser/reisermodule.c       Tue Oct 11 22:57:44 2005
@@ -46,7 +46,7 @@
 
        if (!dal) return;
 
-       close((int)dal->dev);
+       close((size_t)dal->dev);
        dal_free(dal);
 }
 
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/lowlevel/xs/xs.c
--- a/tools/python/xen/lowlevel/xs/xs.c Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/lowlevel/xs/xs.c Tue Oct 11 22:57:44 2005
@@ -80,8 +80,8 @@
 
 static PyObject *xspy_read(PyObject *self, PyObject *args, PyObject *kwds)
 {
-    static char *kwd_spec[] = { "path", NULL };
-    static char *arg_spec = "s|";
+    static char *kwd_spec[] = { "transaction", "path", NULL };
+    static char *arg_spec = "ss";
     char *path = NULL;
 
     struct xs_handle *xh = xshandle(self);
@@ -89,13 +89,19 @@
     unsigned int xsval_n = 0;
     PyObject *val = NULL;
 
-    if (!xh)
-        goto exit;
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
-                                     &path))
-        goto exit;
-    Py_BEGIN_ALLOW_THREADS
-    xsval = xs_read(xh, path, &xsval_n);
+    struct xs_transaction_handle *th;
+    char *thstr;
+
+    if (!xh)
+        goto exit;
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
+                                     &thstr, &path))
+        goto exit;
+
+    th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16);
+
+    Py_BEGIN_ALLOW_THREADS
+    xsval = xs_read(xh, th, path, &xsval_n);
     Py_END_ALLOW_THREADS
     if (!xsval) {
         if (errno == ENOENT) {
@@ -123,8 +129,8 @@
 
 static PyObject *xspy_write(PyObject *self, PyObject *args, PyObject *kwds)
 {
-    static char *kwd_spec[] = { "path", "data", NULL };
-    static char *arg_spec = "ss#";
+    static char *kwd_spec[] = { "transaction", "path", "data", NULL };
+    static char *arg_spec = "sss#";
     char *path = NULL;
     char *data = NULL;
     int data_n = 0;
@@ -133,13 +139,19 @@
     PyObject *val = NULL;
     int xsval = 0;
 
-    if (!xh)
-        goto exit;
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
-                                     &path, &data, &data_n))
-        goto exit;
-    Py_BEGIN_ALLOW_THREADS
-    xsval = xs_write(xh, path, data, data_n);
+    struct xs_transaction_handle *th;
+    char *thstr;
+
+    if (!xh)
+        goto exit;
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
+                                     &thstr, &path, &data, &data_n))
+        goto exit;
+
+    th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16);
+
+    Py_BEGIN_ALLOW_THREADS
+    xsval = xs_write(xh, th, path, data, data_n);
     Py_END_ALLOW_THREADS
     if (!xsval) {
         PyErr_SetFromErrno(PyExc_RuntimeError);
@@ -162,8 +174,8 @@
 
 static PyObject *xspy_ls(PyObject *self, PyObject *args, PyObject *kwds)
 {
-    static char *kwd_spec[] = { "path", NULL };
-    static char *arg_spec = "s|";
+    static char *kwd_spec[] = { "transaction", "path", NULL };
+    static char *arg_spec = "ss";
     char *path = NULL;
 
     struct xs_handle *xh = xshandle(self);
@@ -172,12 +184,20 @@
     unsigned int xsval_n = 0;
     int i;
 
-    if (!xh)
-        goto exit;
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
-        goto exit;
-    Py_BEGIN_ALLOW_THREADS
-    xsval = xs_directory(xh, path, &xsval_n);
+    struct xs_transaction_handle *th;
+    char *thstr;
+
+    if (!xh)
+        goto exit;
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
+                                     &thstr, &path))
+        goto exit;
+
+
+    th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16);
+
+    Py_BEGIN_ALLOW_THREADS
+    xsval = xs_directory(xh, th, path, &xsval_n);
     Py_END_ALLOW_THREADS
     if (!xsval) {
         if (errno == ENOENT) {
@@ -205,20 +225,27 @@
 
 static PyObject *xspy_mkdir(PyObject *self, PyObject *args, PyObject *kwds)
 {
-    static char *kwd_spec[] = { "path", NULL };
-    static char *arg_spec = "s|";
+    static char *kwd_spec[] = { "transaction", "path", NULL };
+    static char *arg_spec = "ss";
     char *path = NULL;
 
     struct xs_handle *xh = xshandle(self);
     PyObject *val = NULL;
     int xsval = 0;
 
-    if (!xh)
-        goto exit;
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
-        goto exit;
-    Py_BEGIN_ALLOW_THREADS
-    xsval = xs_mkdir(xh, path);
+    struct xs_transaction_handle *th;
+    char *thstr;
+
+    if (!xh)
+        goto exit;
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
+                                     &thstr, &path))
+        goto exit;
+
+    th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16);
+
+    Py_BEGIN_ALLOW_THREADS
+    xsval = xs_mkdir(xh, th, path);
     Py_END_ALLOW_THREADS
     if (!xsval) {
         PyErr_SetFromErrno(PyExc_RuntimeError);
@@ -240,20 +267,27 @@
 
 static PyObject *xspy_rm(PyObject *self, PyObject *args, PyObject *kwds)
 {
-    static char *kwd_spec[] = { "path", NULL };
-    static char *arg_spec = "s|";
+    static char *kwd_spec[] = { "transaction", "path", NULL };
+    static char *arg_spec = "ss";
     char *path = NULL;
 
     struct xs_handle *xh = xshandle(self);
     PyObject *val = NULL;
     int xsval = 0;
 
-    if (!xh)
-        goto exit;
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
-        goto exit;
-    Py_BEGIN_ALLOW_THREADS
-    xsval = xs_rm(xh, path);
+    struct xs_transaction_handle *th;
+    char *thstr;
+
+    if (!xh)
+        goto exit;
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
+                                     &thstr, &path))
+        goto exit;
+
+    th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16);
+
+    Py_BEGIN_ALLOW_THREADS
+    xsval = xs_rm(xh, th, path);
     Py_END_ALLOW_THREADS
     if (!xsval && errno != ENOENT) {
         PyErr_SetFromErrno(PyExc_RuntimeError);
@@ -276,8 +310,8 @@
 static PyObject *xspy_get_permissions(PyObject *self, PyObject *args,
                                       PyObject *kwds)
 {
-    static char *kwd_spec[] = { "path", NULL };
-    static char *arg_spec = "s|";
+    static char *kwd_spec[] = { "transaction", "path", NULL };
+    static char *arg_spec = "ss";
     char *path = NULL;
 
     struct xs_handle *xh = xshandle(self);
@@ -286,12 +320,19 @@
     unsigned int perms_n = 0;
     int i;
 
-    if (!xh)
-        goto exit;
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
-        goto exit;
-    Py_BEGIN_ALLOW_THREADS
-    perms = xs_get_permissions(xh, path, &perms_n);
+    struct xs_transaction_handle *th;
+    char *thstr;
+
+    if (!xh)
+        goto exit;
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
+                                     &thstr, &path))
+        goto exit;
+
+    th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16);
+
+    Py_BEGIN_ALLOW_THREADS
+    perms = xs_get_permissions(xh, th, path, &perms_n);
     Py_END_ALLOW_THREADS
     if (!perms) {
         PyErr_SetFromErrno(PyExc_RuntimeError);
@@ -321,8 +362,8 @@
 static PyObject *xspy_set_permissions(PyObject *self, PyObject *args,
                                       PyObject *kwds)
 {
-    static char *kwd_spec[] = { "path", "perms", NULL };
-    static char *arg_spec = "sO";
+    static char *kwd_spec[] = { "transaction", "path", "perms", NULL };
+    static char *arg_spec = "ssO";
     char *path = NULL;
     PyObject *perms = NULL;
     static char *perm_names[] = { "dom", "read", "write", NULL };
@@ -335,11 +376,17 @@
     PyObject *tuple0 = NULL;
     PyObject *val = NULL;
 
-    if (!xh)
-        goto exit;
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
-                                     &path, &perms))
-        goto exit;
+    struct xs_transaction_handle *th;
+    char *thstr;
+
+    if (!xh)
+        goto exit;
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
+                                     &thstr, &path, &perms))
+        goto exit;
+
+    th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16);
+
     if (!PyList_Check(perms)) {
         PyErr_SetString(PyExc_RuntimeError, "perms must be a list");
         goto exit;
@@ -369,7 +416,7 @@
             xsperms[i].perms |= XS_PERM_WRITE;
     }
     Py_BEGIN_ALLOW_THREADS
-    xsval = xs_set_permissions(xh, path, xsperms, xsperms_n);
+    xsval = xs_set_permissions(xh, th, path, xsperms, xsperms_n);
     Py_END_ALLOW_THREADS
     if (!xsval) {
         PyErr_SetFromErrno(PyExc_RuntimeError);
@@ -442,9 +489,6 @@
 
 #define xspy_read_watch_doc "\n"                               \
        "Read a watch notification.\n"                          \
-       "The notification must be acknowledged by passing\n"    \
-       "the token to acknowledge_watch().\n"                   \
-       " path [string]: xenstore path.\n"                      \
        "\n"                                                    \
        "Returns: [tuple] (path, token).\n"                     \
        "Raises RuntimeError on error.\n"                       \
@@ -492,44 +536,6 @@
  exit:
     if (xsval)
         free(xsval);
-    return val;
-}
-
-#define xspy_acknowledge_watch_doc "\n"                                        
\
-       "Acknowledge a watch notification that has been read.\n"        \
-       " token [string] : from the watch notification\n"               \
-       "\n"                                                            \
-       "Returns None on success.\n"                                    \
-       "Raises RuntimeError on error.\n"                               \
-       "\n"
-
-static PyObject *xspy_acknowledge_watch(PyObject *self, PyObject *args,
-                                        PyObject *kwds)
-{
-    static char *kwd_spec[] = { "token", NULL };
-    static char *arg_spec = "O";
-    PyObject *token;
-    char token_str[MAX_STRLEN(unsigned long) + 1];
-
-    struct xs_handle *xh = xshandle(self);
-    PyObject *val = NULL;
-    int xsval = 0;
-
-    if (!xh)
-        goto exit;
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &token))
-        goto exit;
-    sprintf(token_str, "%li", (unsigned long)token);
-    Py_BEGIN_ALLOW_THREADS
-    xsval = xs_acknowledge_watch(xh, token_str);
-    Py_END_ALLOW_THREADS
-    if (!xsval) {
-        PyErr_SetFromErrno(PyExc_RuntimeError);
-        goto exit;
-    }
-    Py_INCREF(Py_None);
-    val = Py_None;
- exit:
     return val;
 }
 
@@ -584,9 +590,8 @@
 
 #define xspy_transaction_start_doc "\n"                                \
        "Start a transaction.\n"                                \
-       "Only one transaction can be active at a time.\n"       \
        "\n"                                                    \
-       "Returns None on success.\n"                            \
+       "Returns transaction handle on success.\n"              \
        "Raises RuntimeError on error.\n"                       \
        "\n"
 
@@ -599,21 +604,23 @@
 
     struct xs_handle *xh = xshandle(self);
     PyObject *val = NULL;
-    int xsval = 0;
+    struct xs_transaction_handle *th;
+    char thstr[20];
 
     if (!xh)
         goto exit;
     if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
         goto exit;
     Py_BEGIN_ALLOW_THREADS
-    xsval = xs_transaction_start(xh);
-    Py_END_ALLOW_THREADS
-    if (!xsval) {
-        PyErr_SetFromErrno(PyExc_RuntimeError);
-        goto exit;
-    }
-    Py_INCREF(Py_None);
-    val = Py_None;
+    th = xs_transaction_start(xh);
+    Py_END_ALLOW_THREADS
+    if (th == NULL) {
+        PyErr_SetFromErrno(PyExc_RuntimeError);
+        goto exit;
+    }
+
+    sprintf(thstr, "%lX", (unsigned long)th);
+    val = PyString_FromString(thstr);
  exit:
     return val;
 }
@@ -630,20 +637,27 @@
 static PyObject *xspy_transaction_end(PyObject *self, PyObject *args,
                                       PyObject *kwds)
 {
-    static char *kwd_spec[] = { "abort", NULL };
-    static char *arg_spec = "|i";
+    static char *kwd_spec[] = { "transaction", "abort", NULL };
+    static char *arg_spec = "s|i";
     int abort = 0;
 
     struct xs_handle *xh = xshandle(self);
     PyObject *val = NULL;
     int xsval = 0;
 
-    if (!xh)
-        goto exit;
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &abort))
-        goto exit;
-    Py_BEGIN_ALLOW_THREADS
-    xsval = xs_transaction_end(xh, abort);
+    struct xs_transaction_handle *th;
+    char *thstr;
+
+    if (!xh)
+        goto exit;
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
+                                     &thstr, &abort))
+        goto exit;
+
+    th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16);
+
+    Py_BEGIN_ALLOW_THREADS
+    xsval = xs_transaction_end(xh, th, abort);
     Py_END_ALLOW_THREADS
     if (!xsval) {
        if (errno == EAGAIN) {
@@ -833,7 +847,6 @@
      XSPY_METH(set_permissions),
      XSPY_METH(watch),
      XSPY_METH(read_watch),
-     XSPY_METH(acknowledge_watch),
      XSPY_METH(unwatch),
      XSPY_METH(transaction_start),
      XSPY_METH(transaction_end),
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/util/Brctl.py
--- a/tools/python/xen/util/Brctl.py    Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/util/Brctl.py    Tue Oct 11 22:57:44 2005
@@ -5,7 +5,6 @@
 import re
 import sys
 
-os.defpath = os.defpath + ':/sbin:/usr/sbin:/usr/local/sbin'
 CMD_IFCONFIG = 'ifconfig'
 CMD_ROUTE    = 'route'
 CMD_BRCTL    = 'brctl'
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xend/XendCheckpoint.py
--- a/tools/python/xen/xend/XendCheckpoint.py   Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/XendCheckpoint.py   Tue Oct 11 22:57:44 2005
@@ -14,6 +14,8 @@
 
 from xen.util.xpopen import xPopen3
 
+import xen.util.auxbin
+
 import xen.lowlevel.xc
 
 from xen.xend.xenstore.xsutil import IntroduceDomain
@@ -21,9 +23,11 @@
 from XendError import XendError
 from XendLogging import log
 
+
 SIGNATURE = "LinuxGuestRecord"
-PATH_XC_SAVE = "/usr/libexec/xen/xc_save"
-PATH_XC_RESTORE = "/usr/libexec/xen/xc_restore"
+XC_SAVE = "xc_save"
+XC_RESTORE = "xc_restore"
+
 
 sizeof_int = calcsize("i")
 sizeof_unsigned_long = calcsize("L")
@@ -64,7 +68,7 @@
         # enabled. Passing "0" simply uses the defaults compiled into
         # libxenguest; see the comments and/or code in xc_linux_save() for
         # more information.
-        cmd = [PATH_XC_SAVE, str(xc.handle()), str(fd),
+        cmd = [xen.util.auxbin.pathTo(XC_SAVE), str(xc.handle()), str(fd),
                str(dominfo.getDomid()), "0", "0", str(int(live)) ]
         log.debug("[xc_save]: %s", string.join(cmd))
 
@@ -129,7 +133,7 @@
         store_evtchn = dominfo.store_channel
         console_evtchn = dominfo.console_channel
 
-        cmd = [PATH_XC_RESTORE, str(xc.handle()), str(fd),
+        cmd = [xen.util.auxbin.pathTo(XC_RESTORE), str(xc.handle()), str(fd),
                str(dominfo.getDomid()), str(nr_pfns),
                str(store_evtchn), str(console_evtchn)]
         log.debug("[xc_restore]: %s", string.join(cmd))
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xend/XendClient.py
--- a/tools/python/xen/xend/XendClient.py       Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/XendClient.py       Tue Oct 11 22:57:44 2005
@@ -195,6 +195,9 @@
 
     def xend_domains(self):
         return self.xendGet(self.domainurl())
+
+    def xend_list_domains(self):
+        return self.xendGet(self.domainurl(), {'detail': '1'})
 
     def xend_domain_create(self, conf):
         return self.xendPost(self.domainurl(),
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xend/XendDomain.py
--- a/tools/python/xen/xend/XendDomain.py       Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/XendDomain.py       Tue Oct 11 22:57:44 2005
@@ -359,20 +359,6 @@
             raise XendError(str(ex))
 
 
-    def domain_shutdown(self, domid, reason = 'poweroff'):
-        """Shutdown domain (nicely).
-
-        @param reason: shutdown reason: poweroff, reboot, suspend, halt
-        """
-        self.callInfo(domid, XendDomainInfo.XendDomainInfo.shutdown, reason)
-
-
-    def domain_sysrq(self, domid, key):
-        """Send a SysRq to the specified domain."""
-        return self.callInfo(domid, XendDomainInfo.XendDomainInfo.send_sysrq,
-                             key)
-
-
     def domain_destroy(self, domid):
         """Terminate domain immediately."""
 
@@ -475,37 +461,6 @@
             raise XendError(str(ex))
 
 
-    def domain_device_create(self, domid, devconfig):
-        """Create a new device for the specified domain.
-        """
-        return self.callInfo(domid,
-                             XendDomainInfo.XendDomainInfo.device_create,
-                             devconfig)
-
-
-    def domain_device_configure(self, domid, devconfig, devid):
-        """Configure an existing device in the specified domain.
-        @return: updated device configuration
-        """
-        return self.callInfo(domid,
-                             XendDomainInfo.XendDomainInfo.device_configure,
-                             devconfig, devid)
-
-    
-    def domain_device_destroy(self, domid, devtype, devid):
-        """Destroy a device."""
-        return self.callInfo(domid,
-                             XendDomainInfo.XendDomainInfo.destroyDevice,
-                             devtype, devid)
-
-
-    def domain_devtype_ls(self, domid, devtype):
-        """Get list of device sxprs for the specified domain."""
-        return self.callInfo(domid,
-                             XendDomainInfo.XendDomainInfo.getDeviceSxprs,
-                             devtype)
-
-
     def domain_vif_limit_set(self, domid, vif, credit, period):
         """Limit the vif's transmission rate
         """
@@ -536,44 +491,6 @@
                                        maxmem_kb = maxmem)
         except Exception, ex:
             raise XendError(str(ex))
-
-    def domain_mem_target_set(self, domid, mem):
-        """Set the memory target for a domain.
-
-        @param mem: memory target (in MiB)
-        """
-        self.callInfo(domid, XendDomainInfo.XendDomainInfo.setMemoryTarget,
-                      mem << 10)
-
-
-    def domain_vcpu_hotplug(self, domid, vcpu, state):
-        """Enable or disable specified VCPU in specified domain
-
-        @param vcpu: target VCPU in domain
-        @param state: which state VCPU will become
-        """
-        self.callInfo(domid, XendDomainInfo.XendDomainInfo.vcpu_hotplug, vcpu,
-                      state)
-
-
-    def domain_dumpcore(self, domid):
-        """Save a core dump for a crashed domain."""
-        self.callInfo(domid, XendDomainInfo.XendDomainInfo.dumpCore)
-
-
-    ## private:
-
-    def callInfo(self, domid, fn, *args, **kwargs):
-        try:
-            self.refresh()
-            dominfo = self.domains.get(domid)
-            if dominfo:
-                return fn(dominfo, *args, **kwargs)
-        except XendError:
-            raise
-        except Exception, exn:
-            log.exception("")
-            raise XendError(str(exn))
 
 
 def instance():
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py   Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/XendDomainInfo.py   Tue Oct 11 22:57:44 2005
@@ -30,6 +30,7 @@
 import errno
 
 import xen.lowlevel.xc
+from xen.util import asserts
 from xen.util.blkif import blkdev_uname_to_file
 
 from xen.xend import image
@@ -41,7 +42,8 @@
 from xen.xend.XendError import XendError, VmError
 from xen.xend.XendRoot import get_component
 
-from xen.xend.uuid import getUuid
+from uuid import getUuid
+
 from xen.xend.xenstore.xstransact import xstransact
 from xen.xend.xenstore.xsutil import GetDomainPath, IntroduceDomain
 
@@ -217,17 +219,12 @@
 def restore(config):
     """Create a domain and a VM object to do a restore.
 
-    @param config:    domain configuration
+    @param config: domain configuration
     """
 
     log.debug("XendDomainInfo.restore(%s)", config)
 
-    try:
-        uuid    =     sxp.child_value(config, 'uuid')
-        ssidref = int(sxp.child_value(config, 'ssidref'))
-    except TypeError, exn:
-        raise VmError('Invalid ssidref in config: %s' % exn)
-
+    uuid = sxp.child_value(config, 'uuid')
     vm = XendDomainInfo(uuid, parseConfig(config))
     try:
         vm.construct()
@@ -257,7 +254,7 @@
             return val
 
 
-    log.debug("parseConfig: config is %s" % str(config))
+    log.debug("parseConfig: config is %s", config)
 
     result = {}
 
@@ -315,7 +312,7 @@
             log.warn("Ignoring malformed and deprecated config option "
                      "restart = %s", restart)
 
-    log.debug("parseConfig: result is %s" % str(result))
+    log.debug("parseConfig: result is %s", result)
     return result
 
 
@@ -529,7 +526,7 @@
 
         except KeyError, exn:
             log.exception(exn)
-            raise VmError('Unspecified domain detail: %s' % str(exn))
+            raise VmError('Unspecified domain detail: %s' % exn)
 
 
     def readVm(self, *args):
@@ -579,7 +576,7 @@
             if self.infoIsSet(k):
                 to_store[k] = str(self.info[k])
 
-        log.debug("Storing VM details: %s" % str(to_store))
+        log.debug("Storing VM details: %s", to_store)
 
         self.writeVm(to_store)
 
@@ -605,7 +602,7 @@
         for v in range(0, self.info['vcpus']):
             to_store["cpu/%d/availability" % v] = availability(v)
 
-        log.debug("Storing domain details: %s" % str(to_store))
+        log.debug("Storing domain details: %s", to_store)
 
         self.writeDom(to_store)
 
@@ -746,7 +743,7 @@
 
     def shutdown(self, reason):
         if not reason in shutdown_reasons.values():
-            raise XendError('invalid reason:' + reason)
+            raise XendError('Invalid reason: %s' % reason)
         self.storeDom("control/shutdown", reason)
         if reason != 'suspend':
             self.storeDom('xend/shutdown_start_time', time.time())
@@ -793,10 +790,12 @@
 
     def setMemoryTarget(self, target):
         """Set the memory target of this domain.
-        @param target In KiB.
-        """
-        self.info['memory_KiB'] = target
-        self.storeDom("memory/target", target)
+        @param target In MiB.
+        """
+        # Internally we use KiB, but the command interface uses MiB.
+        t = target << 10
+        self.info['memory_KiB'] = t
+        self.storeDom("memory/target", t)
 
 
     def update(self, info = None):
@@ -986,8 +985,8 @@
         """
 
         log.debug('XendDomainInfo.construct: %s %s',
-                  str(self.domid),
-                  str(self.info['ssidref']))
+                  self.domid,
+                  self.info['ssidref'])
 
         self.domid = xc.domain_create(dom = 0, ssidref = self.info['ssidref'])
 
@@ -1004,9 +1003,9 @@
 
     def initDomain(self):
         log.debug('XendDomainInfo.initDomain: %s %s %s',
-                  str(self.domid),
-                  str(self.info['memory_KiB']),
-                  str(self.info['cpu_weight']))
+                  self.domid,
+                  self.info['memory_KiB'],
+                  self.info['cpu_weight'])
 
         if not self.infoIsSet('image'):
             raise VmError('Missing image in configuration')
@@ -1085,14 +1084,15 @@
     def destroy(self):
         """Cleanup VM and destroy domain.  Nothrow guarantee."""
 
-        log.debug("XendDomainInfo.destroy: domid=%s", str(self.domid))
+        log.debug("XendDomainInfo.destroy: domid=%s", self.domid)
 
         self.cleanupVm()
-        self.destroyDomain()
+        if self.dompath is not None:
+                self.destroyDomain()
 
 
     def destroyDomain(self):
-        log.debug("XendDomainInfo.destroyDomain(%s)", str(self.domid))
+        log.debug("XendDomainInfo.destroyDomain(%s)", self.domid)
 
         try:
             if self.domid is not None:
@@ -1366,7 +1366,10 @@
         self.storeVm('vcpu_avail', self.info['vcpu_avail'])
         self.storeDom("cpu/%d/availability" % vcpu, availability)
 
-    def send_sysrq(self, key=0):
+
+    def send_sysrq(self, key):
+        asserts.isCharConvertible(key)
+
         self.storeDom("control/sysrq", '%c' % key)
 
 
@@ -1388,18 +1391,18 @@
         dom = 0
         # get max number of vcpus to use for dom0 from config
         target = int(xroot.get_dom0_vcpus())
-        log.debug("number of vcpus to use is %d" % (target))
+        log.debug("number of vcpus to use is %d", target)
    
         # target = 0 means use all processors
         if target > 0:
             # count the number of online vcpus (cpu values in v2c map >= 0)
             vcpu_to_cpu = dom_get(dom)['vcpu_to_cpu']
             vcpus_online = len(filter(lambda x: x >= 0, vcpu_to_cpu))
-            log.debug("found %d vcpus online" % (vcpus_online))
+            log.debug("found %d vcpus online", vcpus_online)
 
             # disable any extra vcpus that are online over the requested target
             for vcpu in range(target, vcpus_online):
-                log.info("enforcement is disabling DOM%d VCPU%d" % (dom, vcpu))
+                log.info("enforcement is disabling DOM%d VCPU%d", dom, vcpu)
                 self.vcpu_hotplug(vcpu, 0)
 
 
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xend/XendLogging.py
--- a/tools/python/xen/xend/XendLogging.py      Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/XendLogging.py      Tue Oct 11 22:57:44 2005
@@ -13,79 +13,84 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #============================================================================
 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@xxxxxx>
+# Copyright (C) 2005 XenSource Ltd
 #============================================================================
 
+
+import tempfile
 import types
 import logging
-from logging import Formatter, StreamHandler
-from logging.handlers import RotatingFileHandler
+import logging.handlers
 
-class XendLogging:
 
-    KB = 1024
-    MB = 1024 * KB
-    
-    maxBytes = 1 * MB
-    backupCount = 5
+__all__ = [ 'log', 'init', 'getLogFilename', 'addLogStderr',
+            'removeLogStderr' ]
 
-    logStderrFormat = "[%(name)s] %(levelname)s (%(module)s:%(lineno)d) 
%(message)s"
-    logFileFormat   = "[%(asctime)s %(name)s] %(levelname)s 
(%(module)s:%(lineno)d) %(message)s"
-    dateFormat = "%Y-%m-%d %H:%M:%S"
-
-    def __init__(self, filename, level=logging.INFO, maxBytes=None, 
backupCount=None):
-        """Initialise logging. Logs to 'filename' by default, but does not log 
to
-        stderr unless addLogStderr() is called.
-        """
-        self.setLevel(level)
-        if maxBytes:
-            self.maxBytes = maxBytes
-        if backupCount:
-            self.backupCount = backupCount
-        self.initLogFile(filename)
-        self.initLogStderr()
-
-    def setLevel(self, level):
-        if isinstance(level, types.StringType):
-            level = logging._levelNames[level]
-        self.getLogger().setLevel(level)
-        self.level = level
-
-    def getLogger(self):
-        return logging.getLogger("xend")
-
-    def initLogFile(self, filename):
-        """Create the file logger and add it.
-        """
-        self.logfile = RotatingFileHandler(filename,
-                                           mode='a',
-                                           maxBytes=self.maxBytes,
-                                           backupCount=self.backupCount)
-        self.logfilename = filename
-        self.logfile.setFormatter(Formatter(self.logFileFormat, 
self.dateFormat))
-        self.getLogger().addHandler(self.logfile)
-
-    def getLogFile(self):
-        return self.logfile
-
-    def getLogFilename(self):
-        return self.logfilename
-
-    def initLogStderr(self):
-        """Create the stderr logger, but don't add it.
-        """
-        self.logstderr = StreamHandler()
-        self.logstderr.setFormatter(Formatter(self.logStderrFormat, 
self.dateFormat))
-
-    def addLogStderr(self):
-        """Add logging to stderr."""
-        self.getLogger().addHandler(self.logstderr)
-
-    def removeLogStderr(self):
-        """Remove logging to stderr."""
-        self.getLogger().removeHandler(self.logstderr)
-        
-    def getLogStderr(self):
-        return self.logstderr
 
 log = logging.getLogger("xend")
-    
+
+
+DEFAULT_MAX_BYTES = 1 << 20  # 1MB
+DEFAULT_BACKUP_COUNT = 5
+
+STDERR_FORMAT = "[%(name)s] %(levelname)s (%(module)s:%(lineno)d) %(message)s"
+LOGFILE_FORMAT = "[%(asctime)s %(name)s] %(levelname)s (%(module)s:%(lineno)d) 
%(message)s"
+DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
+
+
+stderrHandler = logging.StreamHandler()
+stderrHandler.setFormatter(logging.Formatter(STDERR_FORMAT, DATE_FORMAT))
+
+logfilename = None
+
+
+def init(filename, level=logging.INFO, maxBytes=None, backupCount=None):
+    """Initialise logging. Logs to 'filename' by default, but does not log to
+    stderr unless addLogStderr() is called.
+    """
+
+    global logfilename
+
+    def openFileHandler(fname):
+        return logging.handlers.RotatingFileHandler(fname,
+                                                    mode='a',
+                                                    maxBytes=maxBytes,
+                                                    backupCount=backupCount)
+
+    if not maxBytes:
+        maxBytes = DEFAULT_MAX_BYTES
+    if not backupCount:
+        backupCount = DEFAULT_BACKUP_COUNT
+
+    # Rather unintuitively, getLevelName will get the number corresponding to
+    # a level name, as well as getting the name corresponding to a level
+    # number.  setLevel seems to take the number only though, so convert if we
+    # are given a string.
+    if isinstance(level, types.StringType):
+        level = logging.getLevelName(level)
+
+    log.setLevel(level)
+
+    try:
+        fileHandler = openFileHandler(filename)
+        logfilename = filename
+    except IOError:
+        logfilename = tempfile.mkstemp("-xend.log")[1]
+        fileHandler = openFileHandler(logfilename)
+
+    fileHandler.setFormatter(logging.Formatter(LOGFILE_FORMAT, DATE_FORMAT))
+    log.addHandler(fileHandler)
+
+
+def getLogFilename():
+    return logfilename
+
+
+def addLogStderr():
+    """Add logging to stderr."""
+    log.addHandler(stderrHandler)
+
+
+def removeLogStderr():
+    """Remove logging to stderr."""
+    log.removeHandler(stderrHandler)
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xend/XendRoot.py
--- a/tools/python/xen/xend/XendRoot.py Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/XendRoot.py Tue Oct 11 22:57:44 2005
@@ -13,6 +13,7 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #============================================================================
 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@xxxxxx>
+# Copyright (C) 2005 XenSource Ltd
 #============================================================================
 
 """Xend root class.
@@ -29,7 +30,7 @@
 import string
 import sys
 
-from XendLogging import XendLogging
+import XendLogging
 from XendError import XendError
 
 import sxp
@@ -92,7 +93,6 @@
     def __init__(self):
         self.config_path = None
         self.config = None
-        self.logging = None
         self.configure()
 
 
@@ -114,84 +114,22 @@
         """
         return self.components.get(name)
 
-    def _format(self, msg, args):
-        if args:
-            return str(msg) % args
-        else:
-            return str(msg)
-
-    def _log(self, mode, fmt, args):
-        """Logging function that uses the logger if it exists, otherwise
-        logs to stderr. We use this for XendRoot log messages because
-        they may be logged before the logger has been configured.
-        Other components can safely use the logger.
-        """
-        log = self.get_logger()
-        if mode not in ['warning', 'info', 'debug', 'error']:
-            mode = 'info'
-        level = mode.upper()
-        if log:
-            getattr(log, mode)(fmt, *args)
-        else:
-            print >>sys.stderr, "xend", "[%s]" % level, self._format(fmt, args)
-
-    def logDebug(self, fmt, *args):
-        """Log a debug message.
-
-        @param fmt: message format
-        @param args: arguments
-        """
-        self._log('debug', fmt, args)
-        
-    def logInfo(self, fmt, *args):
-        """Log an info message.
-
-        @param fmt: message format
-        @param args: arguments
-        """
-        self._log('info', fmt, args)
-
-    def logWarning(self, fmt, *args):
-        """Log a warning message.
-
-        @param fmt: message format
-        @param args: arguments
-        """
-        self._log('warning', fmt, args)
-        
-    def logError(self, fmt, *args):
-        """Log an error message.
-
-        @param fmt: message format
-        @param args: arguments
-        """
-        self._log('error', fmt, args)
-        
-    def event_handler(self, event, val):
-        self.logInfo("EVENT> %s %s", str(event), str(val))
+    def _logError(self, fmt, args):
+        """Logging function to log to stderr. We use this for XendRoot log
+        messages because they may be logged before the logger has been
+        configured.  Other components can safely use the logger.
+        """
+        print >>sys.stderr, "xend [ERROR]", fmt % args
 
     def configure(self):
         self.set_config()
-        self.configure_logger()
-
-    def configure_logger(self):
         logfile = self.get_config_value("logfile", self.logfile_default)
         loglevel = self.get_config_value("loglevel", self.loglevel_default)
-        self.logging = XendLogging(logfile, level=loglevel)
+        XendLogging.init(logfile, level = loglevel)
 
         from xen.xend.server import params
         if params.XEND_DEBUG:
-            self.logging.addLogStderr()
-
-    def get_logging(self):
-        """Get the XendLogging instance.
-        """
-        return self.logging
-
-    def get_logger(self):
-        """Get the logger.
-        """
-        return self.logging and self.logging.getLogger()
+            XendLogging.addLogStderr()
 
     def set_config(self):
         """If the config file exists, read it. If not, ignore it.
@@ -200,7 +138,6 @@
         """
         self.config_path = os.getenv(self.config_var, self.config_default)
         if os.path.exists(self.config_path):
-            #self.logInfo('Reading config file %s', self.config_path)
             try:
                 fin = file(self.config_path, 'rb')
                 try:
@@ -210,10 +147,12 @@
                 config.insert(0, 'xend-config')
                 self.config = config
             except Exception, ex:
-                self.logError('Reading config file %s: %s', self.config_path, 
str(ex))
+                self._logError('Reading config file %s: %s',
+                               self.config_path, str(ex))
                 raise
         else:
-            self.logError('Config file does not exist: %s', self.config_path)
+            self._logError('Config file does not exist: %s',
+                           self.config_path)
             self.config = ['xend-config']
 
     def get_config(self, name=None):
@@ -339,11 +278,6 @@
         inst = XendRoot()
     return inst
 
-def logger():
-    """Get the logger.
-    """
-    return instance().get_logger()
-
 def add_component(name, val):
     """Register a component with XendRoot.
     This is used to work-round import cycles.
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xend/server/SrvDaemon.py
--- a/tools/python/xen/xend/server/SrvDaemon.py Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/server/SrvDaemon.py Tue Oct 11 22:57:44 2005
@@ -38,7 +38,7 @@
         pythonex = '(?P<python>\S*python\S*)'
         cmdex = '(?P<cmd>.*)'
         procre = re.compile('^\s*' + pidex + '\s*' + pythonex + '\s*' + cmdex 
+ '$')
-        xendre = re.compile('^/usr/sbin/xend\s*(start|restart)\s*.*$')
+        xendre = re.compile('^\S+/xend\s*(start|restart)\s*.*$')
         procs = os.popen('ps -e -o pid,args 2>/dev/null')
         for proc in procs:
             pm = procre.match(proc)
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xend/server/SrvDomain.py
--- a/tools/python/xen/xend/server/SrvDomain.py Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/server/SrvDomain.py Tue Oct 11 22:57:44 2005
@@ -51,40 +51,28 @@
         val = self.xd.domain_pause(self.dom.domid)
         return val
 
-    def op_shutdown(self, op, req):
-        fn = FormFn(self.xd.domain_shutdown,
-                    [['dom',    'int'],
-                     ['reason', 'str']])
-        val = fn(req.args, {'dom': self.dom.domid})
+    def acceptCommand(self, req):
         req.setResponseCode(http.ACCEPTED)
         req.setHeader("Location", "%s/.." % req.prePathURL())
-        return val
+
+    def op_shutdown(self, op, req):
+        self.acceptCommand(req)
+        return self.dom.shutdown(req.args['reason'][0])
 
     def op_sysrq(self, op, req):
-        fn = FormFn(self.xd.domain_sysrq,
-                    [['dom',    'int'],
-                     ['key',    'int']])
-        val = fn(req.args, {'dom' : self.dom.domid})
-        req.setResponseCode(http.ACCEPTED)
-        req.setHeader("Location", "%s/.." % req.prePathURL())
-        return val
+        self.acceptCommand(req)
+        return self.dom.send_sysrq(int(req.args['key'][0]))
 
     def op_destroy(self, op, req):
-        fn = FormFn(self.xd.domain_destroy,
-                    [['dom',    'int']])
-        val = fn(req.args, {'dom': self.dom.domid})
-        req.setHeader("Location", "%s/.." % req.prePathURL())
-        return val
+        self.acceptCommand(req)
+        return self.xd.domain_destroy(self.dom.domid)
 
     def op_save(self, op, req):
+        self.acceptCommand(req)
         return req.threadRequest(self.do_save, op, req)
 
     def do_save(self, op, req):
-        fn = FormFn(self.xd.domain_save,
-                    [['dom',  'int'],
-                     ['file', 'str']])
-        val = fn(req.args, {'dom': self.dom.domid})
-        return 0
+        return self.xd.domain_save(self.dom.domid, req.args['file'][0])
 
     def op_migrate(self, op, req):
         return req.threadRequest(self.do_migrate, op, req)
@@ -134,43 +122,39 @@
                      ['memory', 'int']])
         val = fn(req.args, {'dom': self.dom.domid})
         return val
-    
+
+    
+    def call(self, fn, args, req):
+        return FormFn(fn, args)(req.args)
+
+
     def op_mem_target_set(self, op, req):
-        fn = FormFn(self.xd.domain_mem_target_set,
-                    [['dom',    'int'],
-                     ['target', 'int']])
-        val = fn(req.args, {'dom': self.dom.domid})
-        return val
+        return self.call(self.dom.setMemoryTarget,
+                         [['target', 'int']],
+                         req)
 
     def op_devices(self, op, req):
-        fn = FormFn(self.xd.domain_devtype_ls,
-                    [['dom',    'int'],
-                     ['type',   'str']])
-        val = fn(req.args, {'dom': self.dom.domid})
-        return val
+        return self.call(self.dom.getDeviceSxprs,
+                         [['type', 'str']],
+                         req)
 
     def op_device_create(self, op, req):
-        fn = FormFn(self.xd.domain_device_create,
-                    [['dom',    'int'],
-                     ['config', 'sxpr']])
-        val = fn(req.args, {'dom': self.dom.domid})
-        return val
+        return self.call(self.dom.device_create,
+                         [['config', 'sxpr']],
+                         req)
 
     def op_device_destroy(self, op, req):
-        fn = FormFn(self.xd.domain_device_destroy,
-                    [['dom',  'int'],
-                     ['type', 'str'],
-                     ['dev',  'str']])
-        val = fn(req.args, {'dom': self.dom.domid})
-        return val
+        return self.call(self.dom.destroyDevice,
+                         [['type', 'str'],
+                          ['dev',  'int']],
+                         req)
                 
     def op_device_configure(self, op, req):
-        fn = FormFn(self.xd.domain_device_configure,
-                    [['dom',    'int'],
-                     ['config', 'sxpr'],
-                     ['dev',    'str']])
-        val = fn(req.args, {'dom': self.dom.domid})
-        return val
+        return self.call(self.dom.device_configure,
+                         [['config', 'sxpr'],
+                          ['dev',    'int']],
+                         req)
+
 
     def op_vif_limit_set(self, op, req):
         fn = FormFn(self.xd.domain_vif_limit_set,
@@ -182,12 +166,10 @@
         return val
 
     def op_vcpu_hotplug(self, op, req):
-        fn = FormFn(self.xd.domain_vcpu_hotplug,
-                    [['dom', 'int'],
-                     ['vcpu', 'int'],
-                     ['state', 'int']])
-        val = fn(req.args, {'dom': self.dom.domid})
-        return val
+        return self.call(self.dom.vcpu_hotplug,
+                         [['vcpu', 'int'],
+                          ['state', 'int']],
+                         req)
 
     def render_POST(self, req):
         return self.perform(req)
@@ -201,7 +183,6 @@
         #
         # if op and op[0] in ['vifs', 'vif', 'vbds', 'vbd', 'mem_target_set']:
         #    return self.perform(req)
-        self.dom.update()
         if self.use_sxp(req):
             req.setHeader("Content-Type", sxp.mime_type)
             sxp.show(self.dom.sxpr(), out=req)
diff -r 333f722ed6d0 -r 74d56b7ff46c 
tools/python/xen/xend/server/SrvDomainDir.py
--- a/tools/python/xen/xend/server/SrvDomainDir.py      Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/server/SrvDomainDir.py      Tue Oct 11 22:57:44 2005
@@ -22,12 +22,14 @@
 
 from xen.xend import sxp
 from xen.xend import XendDomain
+from xen.xend.XendDomainInfo import XendDomainInfo
 from xen.xend.Args import FormFn
 from xen.xend.XendError import XendError
 from xen.xend.XendLogging import log
 
 from xen.web.SrvDir import SrvDir
 from SrvDomain import SrvDomain
+
 
 class SrvDomainDir(SrvDir):
     """Service that manages the domain directory.
@@ -124,28 +126,41 @@
             out.close()
             return val
 
+
+    def op_list(self, _, req):
+        """List the details for this domain."""
+        self._list(req, True)
+
+
     def render_POST(self, req):
         return self.perform(req)
 
     def render_GET(self, req):
+        self._list(req, 'detail' in req.args and req.args['detail'] == ['1'])
+
+
+    def _list(self, req, detail):
         if self.use_sxp(req):
             req.setHeader("Content-Type", sxp.mime_type)
-            self.ls_domain(req, 1)
+            self.ls_domain(req, detail, True)
         else:
             req.write("<html><head></head><body>")
             self.print_path(req)
             self.ls(req)
-            self.ls_domain(req)
+            self.ls_domain(req, detail, False)
             self.form(req)
             req.write("</body></html>")
 
-    def ls_domain(self, req, use_sxp=0):
+
+    def ls_domain(self, req, detail, use_sxp):
         url = req.prePathURL()
         if not url.endswith('/'):
             url += '/'
         if use_sxp:
-            domains = self.xd.list_names()
-            sxp.show(domains, out=req)
+            if detail:
+                sxp.show(map(XendDomainInfo.sxpr, self.xd.list()), out=req)
+            else:
+                sxp.show(self.xd.list_names(), out=req)
         else:
             domains = self.xd.list_sorted()
             req.write('<ul>')
@@ -157,6 +172,7 @@
                        d.getMemoryTarget(), d.getSsidref()))
                 req.write('</li>')
             req.write('</ul>')
+
 
     def form(self, req):
         """Generate the form(s) for domain dir operations.
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xend/server/SrvServer.py
--- a/tools/python/xen/xend/server/SrvServer.py Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/server/SrvServer.py Tue Oct 11 22:57:44 2005
@@ -1,4 +1,3 @@
-#!/usr/bin/python
 #============================================================================
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of version 2.1 of the GNU Lesser General Public
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xend/server/SrvXendLog.py
--- a/tools/python/xen/xend/server/SrvXendLog.py        Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/server/SrvXendLog.py        Tue Oct 11 22:57:44 2005
@@ -13,11 +13,12 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #============================================================================
 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@xxxxxx>
+# Copyright (C) 2005 XenSource Ltd
 #============================================================================
 
 from xen.web import static
 
-from xen.xend import XendRoot
+from xen.xend import XendLogging
 
 from xen.web.SrvDir import SrvDir
 
@@ -27,8 +28,8 @@
 
     def __init__(self):
         SrvDir.__init__(self)
-        logging = XendRoot.instance().get_logging()
-        self.logfile = static.File(logging.getLogFilename(), 
defaultType="text/plain")
+        self.logfile = static.File(XendLogging.getLogFilename(),
+                                   defaultType="text/plain")
         self.logfile.type = "text/plain"
         self.logfile.encoding = None
 
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xend/server/event.py
--- a/tools/python/xen/xend/server/event.py     Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/server/event.py     Tue Oct 11 22:57:44 2005
@@ -25,6 +25,7 @@
 from xen.xend import sxp
 from xen.xend import PrettyPrint
 from xen.xend.XendError import XendError
+from xen.xend import XendLogging
 from xen.xend import XendRoot
 
 
@@ -146,11 +147,10 @@
 
     def op_log_stderr(self, _, v):
         mode = v[1]
-        logging = xroot.get_logging()
         if mode == 'on':
-            logging.addLogStderr()
+            XendLogging.addLogStderr()
         else:
-            logging.removeLogStderr()
+            XendLogging.removeLogStderr()
 
     def op_domain_ls(self, _1, _2):
         xd = xroot.get_component("xen.xend.XendDomain")
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xend/sxp.py
--- a/tools/python/xen/xend/sxp.py      Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/sxp.py      Tue Oct 11 22:57:44 2005
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 #============================================================================
 # This library is free software; you can redistribute it and/or
 # modify it under the terms of version 2.1 of the GNU Lesser General Public
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xend/uuid.py
--- a/tools/python/xen/xend/uuid.py     Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/uuid.py     Tue Oct 11 22:57:44 2005
@@ -13,14 +13,19 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #============================================================================
 # Copyright (C) 2005 Mike Wray <mike.wray@xxxxxx>
+# Copyright (C) 2005 XenSource Ltd
 #============================================================================
+
 
 """Universal(ly) Unique Identifiers (UUIDs).
 """
+
+
 import commands
 import random
 
-def uuidgen(random=True):
+
+def getUuidUuidgen(random = True):
     """Generate a UUID using the command uuidgen.
 
     If random is true (default) generates a random uuid.
@@ -33,50 +38,21 @@
         cmd += " -t"
     return commands.getoutput(cmd)
 
-class UuidFactoryUuidgen:
 
-    """A uuid factory using uuidgen."""
+def getUuidRandom():
+    """Generate a random UUID."""
+    
+    bytes = [ random.randint(0, 255) for i in range(0, 16) ]
+    # Encode the variant.
+    bytes[6] = (bytes[6] & 0x0f) | 0x40
+    bytes[8] = (bytes[8] & 0x3f) | 0x80
+    f = "%02x"
+    return ( "-".join([f*4, f*2, f*2, f*2, f*6]) % tuple(bytes) )
 
-    def __init__(self):
-        pass
 
-    def getUuid(self):
-        return uuidgen()
+#uuidFactory = getUuidUuidgen
+uuidFactory = getUuidRandom
 
-class UuidFactoryRandom:
-
-    """A random uuid factory."""
-
-    def __init__(self):
-        f = file("/dev/urandom", "r")
-        seed = f.read(16)
-        f.close()
-        self.rand = random.Random(seed)
-
-    def randBytes(self, n):
-        return [ self.rand.randint(0, 255) for i in range(0, n) ]
-
-    def getUuid(self):
-        bytes = self.randBytes(16)
-        # Encode the variant.
-        bytes[6] = (bytes[6] & 0x0f) | 0x40
-        bytes[8] = (bytes[8] & 0x3f) | 0x80
-        f = "%02x"
-        return ( "-".join([f*4, f*2, f*2, f*2, f*6]) % tuple(bytes) )
-
-def getFactory():
-    """Get the factory to use for creating uuids.
-    This is so it's easy to change the uuid factory.
-    For example, for testing we might want repeatable uuids
-    rather than the random ones we normally use.
-    """
-    global uuidFactory
-    try:
-        uuidFactory
-    except:
-        #uuidFactory = UuidFactoryUuidgen()
-        uuidFactory = UuidFactoryRandom()
-    return uuidFactory
 
 def getUuid():
-    return getFactory().getUuid()
+    return uuidFactory()
diff -r 333f722ed6d0 -r 74d56b7ff46c 
tools/python/xen/xend/xenstore/xstransact.py
--- a/tools/python/xen/xend/xenstore/xstransact.py      Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/xenstore/xstransact.py      Tue Oct 11 22:57:44 2005
@@ -14,29 +14,34 @@
 class xstransact:
 
     def __init__(self, path):
-        self.in_transaction = False
         self.path = path.rstrip("/")
-        xshandle().transaction_start()
+        self.transaction = xshandle().transaction_start()
         self.in_transaction = True
 
     def __del__(self):
         if self.in_transaction:
-            xshandle().transaction_end(True)
+            xshandle().transaction_end(self.transaction, True)
 
     def commit(self):
         if not self.in_transaction:
             raise RuntimeError
         self.in_transaction = False
-        return xshandle().transaction_end(False)
+        rc = xshandle().transaction_end(self.transaction, False)
+        self.transaction = "0"
+        return rc
 
     def abort(self):
+        if not self.in_transaction:
+            return True
         self.in_transaction = False
-        return xshandle().transaction_end(True)
+        rc = xshandle().transaction_end(self.transaction, True)
+        self.transaction = "0"
+        return rc
 
     def _read(self, key):
         path = "%s/%s" % (self.path, key)
         try:
-            return xshandle().read(path)
+            return xshandle().read(self.transaction, path)
         except RuntimeError, ex:
             raise RuntimeError(ex.args[0],
                                '%s, while reading %s' % (ex.args[1], path))
@@ -50,7 +55,7 @@
         instead.
         """
         if len(args) == 0:
-            return xshandle().read(self.path)
+            return xshandle().read(self.transaction, self.path)
         if len(args) == 1:
             return self._read(args[0])
         ret = []
@@ -61,7 +66,7 @@
     def _write(self, key, data):
         path = "%s/%s" % (self.path, key)
         try:
-            xshandle().write(path, data)
+            xshandle().write(self.transaction, path, data)
         except RuntimeError, ex:
             raise RuntimeError(ex.args[0],
                                ('%s, while writing %s : %s' %
@@ -93,7 +98,7 @@
 
     def _remove(self, key):
         path = "%s/%s" % (self.path, key)
-        return xshandle().rm(path)
+        return xshandle().rm(self.transaction, path)
 
     def remove(self, *args):
         """If no arguments are given, remove this transaction's path.
@@ -101,14 +106,14 @@
         path, and remove each of those instead.
         """
         if len(args) == 0:
-            xshandle().rm(self.path)
+            xshandle().rm(self.transaction, self.path)
         else:
             for key in args:
                 self._remove(key)
 
     def _list(self, key):
         path = "%s/%s" % (self.path, key)
-        l = xshandle().ls(path)
+        l = xshandle().ls(self.transaction, path)
         if l:
             return map(lambda x: key + "/" + x, l)
         return []
@@ -120,7 +125,7 @@
         path, and return the cumulative listing of each of those instead.
         """
         if len(args) == 0:
-            ret = xshandle().ls(self.path)
+            ret = xshandle().ls(self.transaction, self.path)
             if ret is None:
                 return []
             else:
@@ -136,11 +141,11 @@
         ret = []
         for key in keys:
             new_subdir = subdir + "/" + key
-            l = xshandle().ls(new_subdir)
+            l = xshandle().ls(self.transaction, new_subdir)
             if l:
                 ret.append([key, self.list_recursive_(new_subdir, l)])
             else:
-                ret.append([key, xshandle().read(new_subdir)])
+                ret.append([key, xshandle().read(self.transaction, 
new_subdir)])
         return ret
 
 
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xend/xenstore/xswatch.py
--- a/tools/python/xen/xend/xenstore/xswatch.py Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xend/xenstore/xswatch.py Tue Oct 11 22:57:44 2005
@@ -8,6 +8,7 @@
 import select
 import threading
 from xen.lowlevel import xs
+from xen.xend.xenstore.xsutil import xshandle
 
 class xswatch:
 
@@ -27,10 +28,7 @@
         if cls.watchThread:
             cls.xslock.release()
             return
-        # XXX: When we fix xenstored to have better watch semantics,
-        # this can change to shared xshandle(). Currently that would result
-        # in duplicate watch firings, thus failed extra xs.acknowledge_watch.
-        cls.xs = xs.open()
+        cls.xs = xshandle()
         cls.watchThread = threading.Thread(name="Watcher",
                                            target=cls.watchMain)
         cls.watchThread.setDaemon(True)
@@ -43,11 +41,10 @@
         while True:
             try:
                 we = cls.xs.read_watch()
-                watch = we[1]
-                cls.xs.acknowledge_watch(watch)
             except RuntimeError, ex:
                 print ex
                 raise
+            watch = we[1]
             watch.fn(*watch.args, **watch.kwargs)
 
     watchMain = classmethod(watchMain)
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py     Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xm/create.py     Tue Oct 11 22:57:44 2005
@@ -14,11 +14,14 @@
 #============================================================================
 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@xxxxxx>
 # Copyright (C) 2005 Nguyen Anh Quynh <aquynh@xxxxxxxxx>
+# Copyright (C) 2005 XenSource Ltd
 #============================================================================
 
 """Domain creation.
 """
 import random
+import os
+import os.path
 import string
 import sys
 import socket
@@ -35,6 +38,9 @@
 from xen.util import blkif
 
 from xen.xm.opts import *
+
+import console
+
 
 gopts = Opts(use="""[options] [vars]
 
@@ -879,8 +885,7 @@
 
         dom = make_domain(opts, config)
         if opts.vals.console_autoconnect:
-            cmd = "/usr/libexec/xen/xenconsole %d" % dom
-            os.execvp('/usr/libexec/xen/xenconsole', cmd.split())
+            console.execConsole(dom)
         
 if __name__ == '__main__':
     main(sys.argv)
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xm/main.py
--- a/tools/python/xen/xm/main.py       Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xm/main.py       Tue Oct 11 22:57:44 2005
@@ -37,6 +37,8 @@
 from xen.xend import PrettyPrint
 from xen.xend import sxp
 from xen.xm.opts import *
+
+import console
 
 
 shorthelp = """Usage: xm <subcommand> [args]
@@ -225,25 +227,22 @@
         if k in ['-v', '--vcpus']:
             show_vcpus = 1
 
-    domsinfo = []
     from xen.xend.XendClient import server
     if n == 0:
-        doms = server.xend_domains()
-        doms.sort()
-    else:
-        doms = params
-    for dom in doms:
-        info = server.xend_domain(dom)
-        domsinfo.append(parse_doms_info(info))
+        doms = server.xend_list_domains()
+    else:
+        doms = map(server.xend_domain, params)
                
     if use_long:
         for dom in doms:
-            info = server.xend_domain(dom)
-            PrettyPrint.prettyprint(info)
-    elif show_vcpus:
-        xm_show_vcpus(domsinfo)
-    else:
-        xm_brief_list(domsinfo)
+            PrettyPrint.prettyprint(doms)
+    else:
+        domsinfo = map(parse_doms_info, doms)
+
+        if show_vcpus:
+            xm_show_vcpus(domsinfo)
+        else:
+            xm_brief_list(domsinfo)
 
 def parse_doms_info(info):
     dominfo = {}
@@ -279,12 +278,12 @@
     return dominfo
         
 def xm_brief_list(domsinfo):
-    print 'Name              Id  Mem(MB)  CPU VCPU(s)  State  Time(s)'
+    print 'Name              ID  Mem(MiB)  CPU  VCPUs  State   Time(s)'
     for dominfo in domsinfo:
         if dominfo.has_key("ssidref1"):
-            print ("%(name)-16s %(dom)3d  %(mem)7d  %(cpu)3s  %(vcpus)5d   
%(state)5s  %(cpu_time)7.1f     s:%(ssidref2)02x/p:%(ssidref1)02x" % dominfo)
+            print ("%(name)-16s %(dom)3d  %(mem)8d  %(cpu)3s  %(vcpus)5d  
%(state)5s  %(cpu_time)7.1f     s:%(ssidref2)02x/p:%(ssidref1)02x" % dominfo)
         else:
-            print ("%(name)-16s %(dom)3d  %(mem)7d  %(cpu)3s  %(vcpus)5d   
%(state)5s  %(cpu_time)7.1f" % dominfo)
+            print ("%(name)-16s %(dom)3d  %(mem)8d  %(cpu)3s  %(vcpus)5d  
%(state)5s  %(cpu_time)7.1f" % dominfo)
 
 def xm_show_vcpus(domsinfo):
     print 'Name              Id  VCPU  CPU  CPUMAP'
@@ -445,12 +444,11 @@
     from xen.xend.XendClient import server
     info = server.xend_domain(dom)
     domid = int(sxp.child_value(info, 'domid', '-1'))
-    cmd = "/usr/libexec/xen/xenconsole %d" % domid
-    os.execvp('/usr/libexec/xen/xenconsole', cmd.split())
-    console = sxp.child(info, "console")
+    console.execConsole(domid)
+
 
 def xm_top(args):
-    os.execv('/usr/sbin/xentop', ['/usr/sbin/xentop'])
+    os.execvp('xentop', ['xentop'])
 
 def xm_dmesg(args):
     
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xm/sysrq.py
--- a/tools/python/xen/xm/sysrq.py      Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xm/sysrq.py      Tue Oct 11 22:57:44 2005
@@ -1,16 +1,11 @@
 # (C) Matthew Bloch <matthew@xxxxxxxxxxxxxx> 2004
+# Copyright (C) 2005 XenSource Ltd
 
-"""Domain shutdown.
+"""Domain sysrq.
 """
-import string
-import sys
-import time
 
 from xen.xend.XendClient import server
 from xen.xm.opts import *
-
-DOM0_NAME = 'Domain-0'
-DOM0_ID = '0'
 
 gopts = Opts(use="""[DOM] [letter]
 
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xcutils/Makefile
--- a/tools/xcutils/Makefile    Tue Oct 11 21:50:21 2005
+++ b/tools/xcutils/Makefile    Tue Oct 11 22:57:44 2005
@@ -15,7 +15,7 @@
 XEN_ROOT       = ../..
 include $(XEN_ROOT)/tools/Rules.mk
 
-PROGRAMS_INSTALL_DIR   = /usr/libexec/xen
+PROGRAMS_INSTALL_DIR = /usr/$(LIBDIR)/xen/bin
 
 INCLUDES += -I $(XEN_LIBXC)
 
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/Makefile
--- a/tools/xenstore/Makefile   Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/Makefile   Tue Oct 11 22:57:44 2005
@@ -8,7 +8,7 @@
 INSTALL_DIR     = $(INSTALL) -d -m0755
 
 PROFILE=#-pg
-BASECFLAGS=-Wall -W -g -Werror
+BASECFLAGS=-Wall -g -Werror
 # Make gcc generate dependencies.
 BASECFLAGS += -Wp,-MD,.$(@F).d
 PROG_DEP = .*.d
@@ -27,7 +27,7 @@
 CLIENTS += xenstore-write
 CLIENTS_OBJS := $(patsubst xenstore-%,xenstore_%.o,$(CLIENTS))
 
-all: libxenstore.so xenstored $(CLIENTS) xs_tdb_dump
+all: libxenstore.so xenstored $(CLIENTS) xs_tdb_dump xsls
 
 testcode: xs_test xenstored_test xs_random
 
@@ -39,6 +39,9 @@
 
 $(CLIENTS_OBJS): xenstore_%.o: xenstore_client.c
        $(COMPILE.c) -DCLIENT_$(*F) -o $@ $<
+
+xsls: xsls.o
+       $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -lxenctrl -L. -lxenstore -o $@
 
 xenstored_test: xenstored_core_test.o xenstored_watch_test.o 
xenstored_domain_test.o xenstored_transaction_test.o xs_lib.o talloc_test.o 
fake_libxc.o utils.o tdb.o
        $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@
@@ -126,7 +129,7 @@
 tarball: clean
        cd .. && tar -c -j -v -h -f xenstore.tar.bz2 xenstore/
 
-install: libxenstore.so xenstored $(CLIENTS)
+install: libxenstore.so xenstored xsls $(CLIENTS)
        $(INSTALL_DIR) -p $(DESTDIR)/var/run/xenstored
        $(INSTALL_DIR) -p $(DESTDIR)/var/lib/xenstored
        $(INSTALL_DIR) -p $(DESTDIR)/usr/bin
@@ -134,6 +137,7 @@
        $(INSTALL_DIR) -p $(DESTDIR)/usr/include
        $(INSTALL_PROG) xenstored $(DESTDIR)/usr/sbin
        $(INSTALL_PROG) $(CLIENTS) $(DESTDIR)/usr/bin
+       $(INSTALL_PROG) xsls $(DESTDIR)/usr/bin
        $(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR)
        $(INSTALL_DATA) libxenstore.so $(DESTDIR)/usr/$(LIBDIR)
        $(INSTALL_DATA) xs.h $(DESTDIR)/usr/include
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/testsuite/07watch.test
--- a/tools/xenstore/testsuite/07watch.test     Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/testsuite/07watch.test     Tue Oct 11 22:57:44 2005
@@ -5,7 +5,6 @@
 2 write /test contents2
 expect 1:/test:token
 1 waitwatch
-1 ackwatch token
 1 close
 
 # Check that reads don't set it off.
@@ -22,15 +21,12 @@
 2 mkdir /dir/newdir
 expect 1:/dir/newdir:token
 1 waitwatch
-1 ackwatch token
 2 setperm /dir/newdir 0 READ
 expect 1:/dir/newdir:token
 1 waitwatch
-1 ackwatch token
 2 rm /dir/newdir
 expect 1:/dir/newdir:token
 1 waitwatch
-1 ackwatch token
 1 close
 2 close
 
@@ -49,7 +45,6 @@
 read /dir/test
 expect /dir/test:token
 waitwatch
-ackwatch token
 close
 
 # watch priority test: all simultaneous
@@ -59,13 +54,10 @@
 write /dir/test contents
 expect 3:/dir/test:token3
 3 waitwatch
-3 ackwatch token3
 expect 2:/dir/test:token2
 2 waitwatch
-2 ackwatch token2
 expect 1:/dir/test:token1
 1 waitwatch
-1 ackwatch token1
 1 close
 2 close
 3 close
@@ -79,7 +71,6 @@
 2 close
 expect 1:/dir/test:token1
 1 waitwatch
-1 ackwatch token1
 1 close
 
 # If one dies (without reading at all), the other should still get ack.
@@ -89,7 +80,6 @@
 2 close
 expect 1:/dir/test:token1
 1 waitwatch
-1 ackwatch token1
 1 close
 2 close
 
@@ -111,7 +101,6 @@
 2 unwatch /dir token2
 expect 1:/dir/test:token1
 1 waitwatch
-1 ackwatch token1
 1 close
 2 close
 
@@ -123,14 +112,12 @@
 write /dir/test contents2
 expect 1:/dir/test:token2
 1 waitwatch
-1 ackwatch token2
 
 # check we only get notified once.
 1 watch /test token
 2 write /test contents2
 expect 1:/test:token
 1 waitwatch
-1 ackwatch token
 expect 1: waitwatch failed: Connection timed out
 1 waitwatch
 1 close
@@ -142,13 +129,10 @@
 2 write /test3 contents
 expect 1:/test1:token
 1 waitwatch
-1 ackwatch token
 expect 1:/test2:token
 1 waitwatch
-1 ackwatch token
 expect 1:/test3:token
 1 waitwatch
-1 ackwatch token
 1 close
 
 # Creation of subpaths should be covered correctly.
@@ -157,10 +141,8 @@
 2 write /test/subnode/subnode contents2
 expect 1:/test/subnode:token
 1 waitwatch
-1 ackwatch token
 expect 1:/test/subnode/subnode:token
 1 waitwatch
-1 ackwatch token
 expect 1: waitwatch failed: Connection timed out
 1 waitwatch
 1 close
@@ -171,7 +153,6 @@
 1 watchnoack / token2 0
 expect 1:/test/subnode:token
 1 waitwatch
-1 ackwatch token
 expect 1:/:token2
 1 waitwatch
 expect 1: waitwatch failed: Connection timed out
@@ -183,7 +164,6 @@
 2 rm /test
 expect 1:/test/subnode:token
 1 waitwatch
-1 ackwatch token
 
 # Watch should not double-send after we ack, even if we did something in 
between.
 1 watch /test2 token
@@ -192,6 +172,5 @@
 1 waitwatch
 expect 1:contents2
 1 read /test2/foo
-1 ackwatch token
 expect 1: waitwatch failed: Connection timed out
 1 waitwatch
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/testsuite/08transaction.test
--- a/tools/xenstore/testsuite/08transaction.test       Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/testsuite/08transaction.test       Tue Oct 11 22:57:44 2005
@@ -68,7 +68,6 @@
 2 commit
 expect 1:/test/dir/sub:token
 1 waitwatch
-1 ackwatch token
 1 close
 
 # Rm inside transaction works like rm outside: children get notified.
@@ -78,7 +77,6 @@
 2 commit
 expect 1:/test/dir/sub:token
 1 waitwatch
-1 ackwatch token
 1 close
 
 # Multiple events from single transaction don't trigger assert
@@ -89,8 +87,6 @@
 2 commit
 expect 1:/test/1:token
 1 waitwatch
-1 ackwatch token
 expect 1:/test/2:token
 1 waitwatch
-1 ackwatch token
 1 close
diff -r 333f722ed6d0 -r 74d56b7ff46c 
tools/xenstore/testsuite/10domain-homedir.test
--- a/tools/xenstore/testsuite/10domain-homedir.test    Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/testsuite/10domain-homedir.test    Tue Oct 11 22:57:44 2005
@@ -16,4 +16,3 @@
 write /home/foo/bar contents
 expect 1:foo/bar:token
 1 waitwatch
-1 ackwatch token
diff -r 333f722ed6d0 -r 74d56b7ff46c 
tools/xenstore/testsuite/11domain-watch.test
--- a/tools/xenstore/testsuite/11domain-watch.test      Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/testsuite/11domain-watch.test      Tue Oct 11 22:57:44 2005
@@ -10,7 +10,6 @@
 write /test contents2
 expect 1:/test:token
 1 waitwatch
-1 ackwatch token
 1 unwatch /test token
 release 1
 1 close
@@ -25,7 +24,6 @@
 1 write /dir/test4 contents4
 expect 1:/dir/test:token
 1 waitwatch
-1 ackwatch token
 release 1
 1 close
 
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/testsuite/12readonly.test
--- a/tools/xenstore/testsuite/12readonly.test  Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/testsuite/12readonly.test  Tue Oct 11 22:57:44 2005
@@ -36,4 +36,3 @@
 1 write /test contents
 expect /test:token
 waitwatch
-ackwatch token
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/testsuite/13watch-ack.test
--- a/tools/xenstore/testsuite/13watch-ack.test Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/testsuite/13watch-ack.test Tue Oct 11 22:57:44 2005
@@ -18,5 +18,4 @@
 1 waitwatch
 3 write /test/1 contents1
 4 write /test/3 contents3
-1 ackwatch token2
 1 close
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/utils.h
--- a/tools/xenstore/utils.h    Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/utils.h    Tue Oct 11 22:57:44 2005
@@ -55,4 +55,34 @@
 #define dprintf(_fmt, _args...) ((void)0)
 #endif
 
+/*
+ * Mux errno values onto returned pointers.
+ */
+
+static inline void *ERR_PTR(long error)
+{
+       return (void *)error;
+}
+
+static inline long PTR_ERR(const void *ptr)
+{
+       return (long)ptr;
+}
+
+static inline long IS_ERR(const void *ptr)
+{
+       return ((unsigned long)ptr > (unsigned long)-1000L);
+}
+
+
 #endif /* _UTILS_H */
+
+/*
+ * Local variables:
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/xenstore_client.c
--- a/tools/xenstore/xenstore_client.c  Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/xenstore_client.c  Tue Oct 11 22:57:44 2005
@@ -20,11 +20,11 @@
 usage(const char *progname)
 {
 #if defined(CLIENT_read)
-    errx(1, "Usage: %s [-h] [-p] key [...]", progname);
+    errx(1, "Usage: %s [-h] [-p] [-s] key [...]", progname);
 #elif defined(CLIENT_write)
-    errx(1, "Usage: %s [-h] key value [...]", progname);
+    errx(1, "Usage: %s [-h] [-s] key value [...]", progname);
 #elif defined(CLIENT_rm) || defined(CLIENT_exists) || defined(CLIENT_list)
-    errx(1, "Usage: %s [-h] key [...]", progname);
+    errx(1, "Usage: %s [-h] [-s] key [...]", progname);
 #endif
 }
 
@@ -32,15 +32,12 @@
 main(int argc, char **argv)
 {
     struct xs_handle *xsh;
+    struct xs_transaction_handle *xth;
     bool success;
-    int ret = 0;
+    int ret = 0, socket = 0;
 #if defined(CLIENT_read) || defined(CLIENT_list)
     int prefix = 0;
 #endif
-
-    xsh = xs_domain_open();
-    if (xsh == NULL)
-       err(1, "xs_domain_open");
 
     while (1) {
        int c, index = 0;
@@ -49,10 +46,11 @@
 #if defined(CLIENT_read) || defined(CLIENT_list)
            {"prefix", 0, 0, 'p'},
 #endif
+            {"socket", 0, 0, 's'},
            {0, 0, 0, 0}
        };
 
-       c = getopt_long(argc, argv, "h"
+       c = getopt_long(argc, argv, "hs"
 #if defined(CLIENT_read) || defined(CLIENT_list)
                        "p"
 #endif
@@ -64,6 +62,9 @@
        case 'h':
            usage(argv[0]);
            /* NOTREACHED */
+        case 's':
+            socket = 1;
+            break;
 #if defined(CLIENT_read) || defined(CLIENT_list)
        case 'p':
            prefix = 1;
@@ -83,14 +84,18 @@
     }
 #endif
 
+    xsh = socket ? xs_daemon_open() : xs_domain_open();
+    if (xsh == NULL)
+       err(1, socket ? "xs_daemon_open" : "xs_domain_open");
+
   again:
-    success = xs_transaction_start(xsh);
-    if (!success)
+    xth = xs_transaction_start(xsh);
+    if (xth == NULL)
        errx(1, "couldn't start transaction");
 
     while (optind < argc) {
 #if defined(CLIENT_read)
-       char *val = xs_read(xsh, argv[optind], NULL);
+       char *val = xs_read(xsh, xth, argv[optind], NULL);
        if (val == NULL) {
            warnx("couldn't read path %s", argv[optind]);
            ret = 1;
@@ -102,7 +107,7 @@
        free(val);
        optind++;
 #elif defined(CLIENT_write)
-       success = xs_write(xsh, argv[optind], argv[optind + 1],
+       success = xs_write(xsh, xth, argv[optind], argv[optind + 1],
                           strlen(argv[optind + 1]));
        if (!success) {
            warnx("could not write path %s", argv[optind]);
@@ -111,7 +116,7 @@
        }
        optind += 2;
 #elif defined(CLIENT_rm)
-       success = xs_rm(xsh, argv[optind]);
+       success = xs_rm(xsh, xth, argv[optind]);
        if (!success) {
            warnx("could not remove path %s", argv[optind]);
            ret = 1;
@@ -119,7 +124,7 @@
        }
        optind++;
 #elif defined(CLIENT_exists)
-       char *val = xs_read(xsh, argv[optind], NULL);
+       char *val = xs_read(xsh, xth, argv[optind], NULL);
        if (val == NULL) {
            ret = 1;
            goto out;
@@ -128,7 +133,7 @@
        optind++;
 #elif defined(CLIENT_list)
        unsigned int i, num;
-       char **list = xs_directory(xsh, argv[optind], &num);
+       char **list = xs_directory(xsh, xth, argv[optind], &num);
        if (list == NULL) {
            warnx("could not list path %s", argv[optind]);
            ret = 1;
@@ -145,7 +150,7 @@
     }
 
  out:
-    success = xs_transaction_end(xsh, ret ? true : false);
+    success = xs_transaction_end(xsh, xth, ret ? true : false);
     if (!success) {
        if (ret == 0 && errno == EAGAIN)
            goto again;
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/xenstored_core.c
--- a/tools/xenstore/xenstored_core.c   Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/xenstored_core.c   Tue Oct 11 22:57:44 2005
@@ -154,7 +154,6 @@
        case XS_READ: return "READ";
        case XS_GET_PERMS: return "GET_PERMS";
        case XS_WATCH: return "WATCH";
-       case XS_WATCH_ACK: return "WATCH_ACK";
        case XS_UNWATCH: return "UNWATCH";
        case XS_TRANSACTION_START: return "TRANSACTION_START";
        case XS_TRANSACTION_END: return "TRANSACTION_END";
@@ -236,10 +235,14 @@
        talloc_free(str);
 }
 
-static bool write_message(struct connection *conn)
+static bool write_messages(struct connection *conn)
 {
        int ret;
-       struct buffered_data *out = conn->out;
+       struct buffered_data *out;
+
+       out = list_top(&conn->out_list, struct buffered_data, list);
+       if (out == NULL)
+               return true;
 
        if (out->inhdr) {
                if (verbose)
@@ -265,7 +268,6 @@
 
        ret = conn->write(conn, out->buffer + out->used,
                          out->hdr.msg.len - out->used);
-
        if (ret < 0)
                return false;
 
@@ -274,14 +276,10 @@
                return true;
 
        trace_io(conn, "OUT", out);
-       conn->out = NULL;
+
+       list_del(&out->list);
        talloc_free(out);
 
-       queue_next_event(conn);
-
-       /* No longer busy? */
-       if (!conn->out)
-               conn->state = OK;
        return true;
 }
 
@@ -298,9 +296,9 @@
                FD_SET(conn->fd, &set);
                none.tv_sec = none.tv_usec = 0;
 
-               while (conn->out
+               while (!list_empty(&conn->out_list)
                       && select(conn->fd+1, NULL, &set, NULL, &none) == 1)
-                       if (!write_message(conn))
+                       if (!write_messages(conn))
                                break;
                close(conn->fd);
        }
@@ -327,9 +325,8 @@
        list_for_each_entry(i, &connections, list) {
                if (i->domain)
                        continue;
-               if (i->state == OK)
-                       FD_SET(i->fd, inset);
-               if (i->out)
+               FD_SET(i->fd, inset);
+               if (!list_empty(&i->out_list))
                        FD_SET(i->fd, outset);
                if (i->fd > max)
                        max = i->fd;
@@ -542,6 +539,9 @@
        struct buffered_data *data;
 
        data = talloc(ctx, struct buffered_data);
+       if (data == NULL)
+               return NULL;
+       
        data->inhdr = true;
        data->used = 0;
        data->buffer = NULL;
@@ -586,23 +586,25 @@
 {
        struct buffered_data *bdata;
 
-       /* When data gets freed, we want list entry is destroyed (so
-        * list entry is a child). */
+       /* Message is a child of the connection context for auto-cleanup. */
        bdata = new_buffer(conn);
        bdata->buffer = talloc_array(bdata, char, len);
 
+       /* Echo request header in reply unless this is an async watch event. */
+       if (type != XS_WATCH_EVENT) {
+               memcpy(&bdata->hdr.msg, &conn->in->hdr.msg,
+                      sizeof(struct xsd_sockmsg));
+       } else {
+               memset(&bdata->hdr.msg, 0, sizeof(struct xsd_sockmsg));
+       }
+
+       /* Update relevant header fields and fill in the message body. */
        bdata->hdr.msg.type = type;
        bdata->hdr.msg.len = len;
        memcpy(bdata->buffer, data, len);
 
-       /* There might be an event going out now.  Queue behind it. */
-       if (conn->out) {
-               assert(conn->out->hdr.msg.type == XS_WATCH_EVENT);
-               assert(!conn->waiting_reply);
-               conn->waiting_reply = bdata;
-       } else
-               conn->out = bdata;
-       conn->state = BUSY;
+       /* Queue for later transmission. */
+       list_add_tail(&bdata->list, &conn->out_list);
 }
 
 /* Some routines (write, mkdir, etc) just need a non-error return */
@@ -1053,6 +1055,17 @@
  */
 static void process_message(struct connection *conn, struct buffered_data *in)
 {
+       struct transaction *trans;
+
+       trans = transaction_lookup(conn, in->hdr.msg.tx_id);
+       if (IS_ERR(trans)) {
+               send_error(conn, -PTR_ERR(trans));
+               return;
+       }
+
+       assert(conn->transaction == NULL);
+       conn->transaction = trans;
+
        switch (in->hdr.msg.type) {
        case XS_DIRECTORY:
                send_directory(conn, onearg(in));
@@ -1103,10 +1116,6 @@
                do_watch(conn, in);
                break;
 
-       case XS_WATCH_ACK:
-               do_watch_ack(conn, onearg(in));
-               break;
-
        case XS_UNWATCH:
                do_unwatch(conn, in);
                break;
@@ -1131,11 +1140,13 @@
                do_get_domain_path(conn, onearg(in));
                break;
 
-       case XS_WATCH_EVENT:
        default:
                eprintf("Client unknown operation %i", in->hdr.msg.type);
                send_error(conn, ENOSYS);
-       }
+               break;
+       }
+
+       conn->transaction = NULL;
 }
 
 static int out_of_mem(void *data)
@@ -1145,43 +1156,25 @@
 
 static void consider_message(struct connection *conn)
 {
-       /*
-        * 'volatile' qualifier prevents register allocation which fixes:
-        *   warning: variable 'xxx' might be clobbered by 'longjmp' or 'vfork'
-        */
-       struct buffered_data *volatile in = NULL;
-       enum xsd_sockmsg_type volatile type = conn->in->hdr.msg.type;
        jmp_buf talloc_fail;
 
-       assert(conn->state == OK);
+       if (verbose)
+               xprintf("Got message %s len %i from %p\n",
+                       sockmsg_string(conn->in->hdr.msg.type),
+                       conn->in->hdr.msg.len, conn);
 
        /* For simplicity, we kill the connection on OOM. */
        talloc_set_fail_handler(out_of_mem, &talloc_fail);
        if (setjmp(talloc_fail)) {
-               /* Free in before conn, in case it needs something. */
-               talloc_free(in);
                talloc_free(conn);
                goto end;
        }
 
-       if (verbose)
-               xprintf("Got message %s len %i from %p\n",
-                       sockmsg_string(type), conn->in->hdr.msg.len, conn);
-
-       /* We might get a command while waiting for an ack: this means
-        * the other end discarded it: we will re-transmit. */
-       if (type != XS_WATCH_ACK)
-               conn->waiting_for_ack = NULL;
-
-       /* Careful: process_message may free connection.  We detach
-        * "in" beforehand and allocate the new buffer to avoid
-        * touching conn after process_message.
-        */
-       in = talloc_steal(talloc_autofree_context(), conn->in);
+       process_message(conn, conn->in);
+
+       talloc_free(conn->in);
        conn->in = new_buffer(conn);
-       process_message(conn, in);
-
-       talloc_free(in);
+
 end:
        talloc_set_fail_handler(NULL, NULL);
        if (talloc_total_blocks(NULL)
@@ -1196,10 +1189,7 @@
 static void handle_input(struct connection *conn)
 {
        int bytes;
-       struct buffered_data *in;
-
-       assert(conn->state == OK);
-       in = conn->in;
+       struct buffered_data *in = conn->in;
 
        /* Not finished header yet? */
        if (in->inhdr) {
@@ -1247,42 +1237,32 @@
 
 static void handle_output(struct connection *conn)
 {
-       if (!write_message(conn))
+       if (!write_messages(conn))
                talloc_free(conn);
 }
 
 struct connection *new_connection(connwritefn_t *write, connreadfn_t *read)
 {
-       /*
-        * 'volatile' qualifier prevents register allocation which fixes:
-        *   warning: variable 'xxx' might be clobbered by 'longjmp' or 'vfork'
-        */
-       struct connection *volatile new;
-       jmp_buf talloc_fail;
+       struct connection *new;
 
        new = talloc(talloc_autofree_context(), struct connection);
        if (!new)
                return NULL;
 
-       new->state = OK;
-       new->out = new->waiting_reply = NULL;
-       new->waiting_for_ack = NULL;
+       memset(new, 0, sizeof(*new));
        new->fd = -1;
-       new->id = 0;
-       new->domain = NULL;
-       new->transaction = NULL;
        new->write = write;
        new->read = read;
        new->can_write = true;
+       INIT_LIST_HEAD(&new->out_list);
        INIT_LIST_HEAD(&new->watches);
-
-       talloc_set_fail_handler(out_of_mem, &talloc_fail);
-       if (setjmp(talloc_fail)) {
+       INIT_LIST_HEAD(&new->transaction_list);
+
+       new->in = new_buffer(new);
+       if (new->in == NULL) {
                talloc_free(new);
                return NULL;
        }
-       new->in = new_buffer(new);
-       talloc_set_fail_handler(NULL, NULL);
 
        list_add_tail(&new->list, &connections);
        talloc_set_destructor(new, destroy_conn);
@@ -1328,23 +1308,17 @@
        list_for_each_entry(i, &connections, list) {
                printf("Connection %p:\n", i);
                printf("    state = %s\n",
-                      i->state == OK ? "OK"
-                      : i->state == BUSY ? "BUSY"
-                      : "INVALID");
+                      list_empty(&i->out_list) ? "OK" : "BUSY");
                if (i->id)
                        printf("    id = %i\n", i->id);
                if (!i->in->inhdr || i->in->used)
                        printf("    got %i bytes of %s\n",
                               i->in->used, i->in->inhdr ? "header" : "data");
+#if 0
                if (i->out)
                        printf("    sending message %s (%s) out\n",
                               sockmsg_string(i->out->hdr.msg.type),
                               i->out->buffer);
-               if (i->waiting_reply)
-                       printf("    ... and behind is queued %s (%s)\n",
-                              sockmsg_string(i->waiting_reply->hdr.msg.type),
-                              i->waiting_reply->buffer);
-#if 0
                if (i->transaction)
                        dump_transaction(i);
                if (i->domain)
@@ -1443,6 +1417,7 @@
 
 
 static struct option options[] = {
+       { "no-domain-init", 0, NULL, 'D' },
        { "pid-file", 1, NULL, 'F' },
        { "no-fork", 0, NULL, 'N' },
        { "output-pid", 0, NULL, 'P' },
@@ -1457,11 +1432,15 @@
        fd_set inset, outset;
        bool dofork = true;
        bool outputpid = false;
+       bool no_domain_init = false;
        const char *pidfile = NULL;
 
-       while ((opt = getopt_long(argc, argv, "F:NPT:V", options,
+       while ((opt = getopt_long(argc, argv, "DF:NPT:V", options,
                                  NULL)) != -1) {
                switch (opt) {
+               case 'D':
+                       no_domain_init = true;
+                       break;
                case 'F':
                        pidfile = optarg;
                        break;
@@ -1534,7 +1513,8 @@
        setup_structure();
 
        /* Listen to hypervisor. */
-       event_fd = domain_init();
+       if (!no_domain_init)
+               event_fd = domain_init();
 
        /* Restore existing connections. */
        restore_existing_connections();
@@ -1615,3 +1595,13 @@
                max = initialize_set(&inset, &outset, *sock, *ro_sock);
        }
 }
+
+/*
+ * Local variables:
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/xenstored_core.h
--- a/tools/xenstore/xenstored_core.h   Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/xenstored_core.h   Tue Oct 11 22:57:44 2005
@@ -31,14 +31,19 @@
 
 struct buffered_data
 {
+       struct list_head list;
+
        /* Are we still doing the header? */
        bool inhdr;
+
        /* How far are we? */
        unsigned int used;
+
        union {
                struct xsd_sockmsg msg;
                char raw[sizeof(struct xsd_sockmsg)];
        } hdr;
+
        /* The actual data. */
        char *buffer;
 };
@@ -47,14 +52,6 @@
 typedef int connwritefn_t(struct connection *, const void *, unsigned int);
 typedef int connreadfn_t(struct connection *, void *, unsigned int);
 
-enum state
-{
-       /* Doing action, not listening */
-       BUSY,
-       /* Completed */
-       OK,
-};
-
 struct connection
 {
        struct list_head list;
@@ -62,29 +59,24 @@
        /* The file descriptor we came in on. */
        int fd;
 
-       /* Who am I?  0 for socket connections. */
+       /* Who am I? 0 for socket connections. */
        domid_t id;
-
-       /* Blocked on transaction?  Busy? */
-       enum state state;
 
        /* Is this a read-only connection? */
        bool can_write;
-
-       /* Are we waiting for a watch event ack? */
-       struct watch *waiting_for_ack;
 
        /* Buffered incoming data. */
        struct buffered_data *in;
 
        /* Buffered output data */
-       struct buffered_data *out;
+       struct list_head out_list;
 
-       /* If we had a watch fire outgoing when we needed to reply... */
-       struct buffered_data *waiting_reply;
+       /* Transaction context for current request (NULL if none). */
+       struct transaction *transaction;
 
-       /* My transaction, if any. */
-       struct transaction *transaction;
+       /* List of in-progress transactions. */
+       struct list_head transaction_list;
+       u32 next_transaction_id;
 
        /* The domain I'm associated with, if any. */
        struct domain *domain;
@@ -175,3 +167,13 @@
 extern int event_fd;
 
 #endif /* _XENSTORED_CORE_H */
+
+/*
+ * Local variables:
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/xenstored_domain.c
--- a/tools/xenstore/xenstored_domain.c Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/xenstored_domain.c Tue Oct 11 22:57:44 2005
@@ -52,6 +52,14 @@
 
        /* Event channel port */
        u16 port;
+
+       /* The remote end of the event channel, used only to validate
+          repeated domain introductions. */
+       u16 remote_port;
+
+       /* The mfn associated with the event channel, used only to validate
+          repeated domain introductions. */
+       unsigned long mfn;
 
        /* Domain path in store. */
        char *path;
@@ -276,12 +284,13 @@
 
 bool domain_can_read(struct connection *conn)
 {
-       return conn->state == OK && buffer_has_input(conn->domain->input);
+       return buffer_has_input(conn->domain->input);
 }
 
 bool domain_can_write(struct connection *conn)
 {
-       return conn->out && buffer_has_output_room(conn->domain->output);
+       return (!list_empty(&conn->out_list) &&
+                buffer_has_output_room(conn->domain->output));
 }
 
 static struct domain *new_domain(void *context, domid_t domid,
@@ -321,45 +330,13 @@
        domain->port = rc;
        domain->conn = new_connection(writechn, readchn);
        domain->conn->domain = domain;
+
+       domain->remote_port = port;
+       domain->mfn = mfn;
+
        return domain;
 }
 
-/* domid, mfn, evtchn, path */
-void do_introduce(struct connection *conn, struct buffered_data *in)
-{
-       struct domain *domain;
-       char *vec[4];
-
-       if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) {
-               send_error(conn, EINVAL);
-               return;
-       }
-
-       if (conn->id != 0 || !conn->can_write) {
-               send_error(conn, EACCES);
-               return;
-       }
-
-       /* Sanity check args. */
-       if ((atoi(vec[2]) <= 0) || !is_valid_nodename(vec[3])) {
-               send_error(conn, EINVAL);
-               return;
-       }
-       /* Hang domain off "in" until we're finished. */
-       domain = new_domain(in, atoi(vec[0]), atol(vec[1]), atol(vec[2]),
-                           vec[3]);
-       if (!domain) {
-               send_error(conn, errno);
-               return;
-       }
-
-       /* Now domain belongs to its connection. */
-       talloc_steal(domain->conn, domain);
-
-       fire_watches(conn, "@introduceDomain", false);
-
-       send_ack(conn, XS_INTRODUCE);
-}
 
 static struct domain *find_domain_by_domid(domid_t domid)
 {
@@ -370,6 +347,67 @@
                        return i;
        }
        return NULL;
+}
+
+
+/* domid, mfn, evtchn, path */
+void do_introduce(struct connection *conn, struct buffered_data *in)
+{
+       struct domain *domain;
+       char *vec[4];
+       domid_t domid;
+       unsigned long mfn;
+       u16 port;
+       const char *path;
+
+       if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) {
+               send_error(conn, EINVAL);
+               return;
+       }
+
+       if (conn->id != 0 || !conn->can_write) {
+               send_error(conn, EACCES);
+               return;
+       }
+
+       domid = atoi(vec[0]);
+       mfn = atol(vec[1]);
+       port = atoi(vec[2]);
+       path = vec[3];
+
+       /* Sanity check args. */
+       if ((port <= 0) || !is_valid_nodename(path)) {
+               send_error(conn, EINVAL);
+               return;
+       }
+
+       domain = find_domain_by_domid(domid);
+
+       if (domain == NULL) {
+               /* Hang domain off "in" until we're finished. */
+               domain = new_domain(in, domid, mfn, port, path);
+               if (!domain) {
+                       send_error(conn, errno);
+                       return;
+               }
+
+               /* Now domain belongs to its connection. */
+               talloc_steal(domain->conn, domain);
+
+               fire_watches(conn, "@introduceDomain", false);
+       }
+       else {
+               /* Check that the given details match the ones we have
+                  previously recorded. */
+               if (port != domain->remote_port ||
+                   mfn != domain->mfn ||
+                   strcmp(path, domain->path) != 0) {
+                       send_error(conn, EINVAL);
+                       return;
+               }
+       }
+
+       send_ack(conn, XS_INTRODUCE);
 }
 
 /* domid */
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/xenstored_transaction.c
--- a/tools/xenstore/xenstored_transaction.c    Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/xenstored_transaction.c    Tue Oct 11 22:57:44 2005
@@ -37,7 +37,7 @@
 
 struct changed_node
 {
-       /* The list within this transaction. */
+       /* List of all changed nodes in the context of this transaction. */
        struct list_head list;
 
        /* The name of the node. */
@@ -49,14 +49,14 @@
 
 struct transaction
 {
-       /* Global list of transactions. */
+       /* List of all transactions active on this connection. */
        struct list_head list;
+
+       /* Connection-local identifier for this transaction. */
+       u32 id;
 
        /* Generation when transaction started. */
        unsigned int generation;
-
-       /* My owner (conn->transaction == me). */
-       struct connection *conn;
 
        /* TDB to work on, and filename */
        TDB_CONTEXT *tdb;
@@ -65,7 +65,7 @@
        /* List of changed nodes. */
        struct list_head changes;
 };
-static LIST_HEAD(transactions);
+
 static unsigned int generation;
 
 /* Return tdb context to use for this connection. */
@@ -100,7 +100,6 @@
 {
        struct transaction *trans = _transaction;
 
-       list_del(&trans->list);
        trace_destroy(trans, "transaction");
        if (trans->tdb)
                tdb_close(trans->tdb);
@@ -108,10 +107,26 @@
        return 0;
 }
 
+struct transaction *transaction_lookup(struct connection *conn, u32 id)
+{
+       struct transaction *trans;
+
+       if (id == 0)
+               return NULL;
+
+       list_for_each_entry(trans, &conn->transaction_list, list)
+               if (trans->id == id)
+                       return trans;
+
+       return ERR_PTR(-ENOENT);
+}
+
 void do_transaction_start(struct connection *conn, struct buffered_data *in)
 {
-       struct transaction *trans;
-
+       struct transaction *trans, *exists;
+       char id_str[20];
+
+       /* We don't support nested transactions. */
        if (conn->transaction) {
                send_error(conn, EBUSY);
                return;
@@ -120,7 +135,6 @@
        /* Attach transaction to input for autofree until it's complete */
        trans = talloc(in, struct transaction);
        INIT_LIST_HEAD(&trans->changes);
-       trans->conn = conn;
        trans->generation = generation;
        trans->tdb_name = talloc_asprintf(trans, "%s.%p",
                                          xs_daemon_tdb(), trans);
@@ -132,11 +146,19 @@
        /* Make it close if we go away. */
        talloc_steal(trans, trans->tdb);
 
+       /* Pick an unused transaction identifier. */
+       do {
+               trans->id = conn->next_transaction_id;
+               exists = transaction_lookup(conn, conn->next_transaction_id++);
+       } while (!IS_ERR(exists));
+
        /* Now we own it. */
-       conn->transaction = talloc_steal(conn, trans);
-       list_add_tail(&trans->list, &transactions);
+       list_add_tail(&trans->list, &conn->transaction_list);
+       talloc_steal(conn, trans);
        talloc_set_destructor(trans, destroy_transaction);
-       send_ack(conn, XS_TRANSACTION_START);
+
+       sprintf(id_str, "%u", trans->id);
+       send_reply(conn, XS_TRANSACTION_START, id_str, strlen(id_str)+1);
 }
 
 void do_transaction_end(struct connection *conn, const char *arg)
@@ -149,14 +171,14 @@
                return;
        }
 
-       if (!conn->transaction) {
+       if ((trans = conn->transaction) == NULL) {
                send_error(conn, ENOENT);
                return;
        }
 
-       /* Set to NULL so fire_watches sends events, tdb_context works. */
-       trans = conn->transaction;
        conn->transaction = NULL;
+       list_del(&trans->list);
+
        /* Attach transaction to arg for auto-cleanup */
        talloc_steal(arg, trans);
 
@@ -181,3 +203,12 @@
        send_ack(conn, XS_TRANSACTION_END);
 }
 
+/*
+ * Local variables:
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/xenstored_transaction.h
--- a/tools/xenstore/xenstored_transaction.h    Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/xenstored_transaction.h    Tue Oct 11 22:57:44 2005
@@ -25,10 +25,11 @@
 void do_transaction_start(struct connection *conn, struct buffered_data *node);
 void do_transaction_end(struct connection *conn, const char *arg);
 
-bool transaction_block(struct connection *conn);
+struct transaction *transaction_lookup(struct connection *conn, u32 id);
 
 /* This node was changed: can fail and longjmp. */
-void add_change_node(struct transaction *trans, const char *node, bool 
recurse);
+void add_change_node(struct transaction *trans, const char *node,
+                     bool recurse);
 
 /* Return tdb context to use for this connection. */
 TDB_CONTEXT *tdb_transaction_context(struct transaction *trans);
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/xenstored_watch.c
--- a/tools/xenstore/xenstored_watch.c  Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/xenstored_watch.c  Tue Oct 11 22:57:44 2005
@@ -32,17 +32,6 @@
 #include "xenstored_test.h"
 #include "xenstored_domain.h"
 
-/* FIXME: time out unacked watches. */
-struct watch_event
-{
-       /* The events on this watch. */
-       struct list_head list;
-
-       /* Data to send (node\0token\0). */
-       unsigned int len;
-       char *data;
-};
-
 struct watch
 {
        /* Watches on this connection */
@@ -58,54 +47,17 @@
        char *node;
 };
 
-/* Look through our watches: if any of them have an event, queue it. */
-void queue_next_event(struct connection *conn)
-{
-       struct watch_event *event;
-       struct watch *watch;
-
-       /* We had a reply queued already?  Send it: other end will
-        * discard watch. */
-       if (conn->waiting_reply) {
-               conn->out = conn->waiting_reply;
-               conn->waiting_reply = NULL;
-               conn->waiting_for_ack = NULL;
-               return;
-       }
-
-       /* If we're already waiting for ack, don't queue more. */
-       if (conn->waiting_for_ack)
-               return;
-
-       list_for_each_entry(watch, &conn->watches, list) {
-               event = list_top(&watch->events, struct watch_event, list);
-               if (event) {
-                       conn->waiting_for_ack = watch;
-                       send_reply(conn,XS_WATCH_EVENT,event->data,event->len);
-                       break;
-               }
-       }
-}
-
-static int destroy_watch_event(void *_event)
-{
-       struct watch_event *event = _event;
-
-       trace_destroy(event, "watch_event");
-       return 0;
-}
-
 static void add_event(struct connection *conn,
                      struct watch *watch,
                      const char *name)
 {
-       struct watch_event *event;
+       /* Data to send (node\0token\0). */
+       unsigned int len;
+       char *data;
 
        if (!check_event_node(name)) {
                /* Can this conn load node, or see that it doesn't exist? */
-               struct node *node;
-
-               node = get_node(conn, name, XS_PERM_READ);
+               struct node *node = get_node(conn, name, XS_PERM_READ);
                if (!node && errno != ENOENT)
                        return;
        }
@@ -116,14 +68,12 @@
                        name++;
        }
 
-       event = talloc(watch, struct watch_event);
-       event->len = strlen(name) + 1 + strlen(watch->token) + 1;
-       event->data = talloc_array(event, char, event->len);
-       strcpy(event->data, name);
-       strcpy(event->data + strlen(name) + 1, watch->token);
-       talloc_set_destructor(event, destroy_watch_event);
-       list_add_tail(&event->list, &watch->events);
-       trace_create(event, "watch_event");
+       len = strlen(name) + 1 + strlen(watch->token) + 1;
+       data = talloc_array(watch, char, len);
+       strcpy(data, name);
+       strcpy(data + strlen(name) + 1, watch->token);
+        send_reply(conn, XS_WATCH_EVENT, data, len);
+       talloc_free(data);
 }
 
 /* FIXME: we fail to fire on out of memory.  Should drop connections. */
@@ -143,11 +93,6 @@
                                add_event(i, watch, name);
                        else if (recurse && is_child(watch->node, name))
                                add_event(i, watch, watch->node);
-                       else
-                               continue;
-                       /* If connection not doing anything, queue this. */
-                       if (i->state == OK)
-                               queue_next_event(i);
                }
        }
 }
@@ -181,6 +126,15 @@
                }
        }
 
+       /* Check for duplicates. */
+       list_for_each_entry(watch, &conn->watches, list) {
+               if (streq(watch->node, vec[0]) &&
+                    streq(watch->token, vec[1])) {
+                       send_error(conn, EEXIST);
+                       return;
+               }
+       }
+
        watch = talloc(conn, struct watch);
        watch->node = talloc_strdup(watch, vec[0]);
        watch->token = talloc_strdup(watch, vec[1]);
@@ -200,37 +154,6 @@
        add_event(conn, watch, watch->node);
 }
 
-void do_watch_ack(struct connection *conn, const char *token)
-{
-       struct watch_event *event;
-
-       if (!token) {
-               send_error(conn, EINVAL);
-               return;
-       }
-
-       if (!conn->waiting_for_ack) {
-               send_error(conn, ENOENT);
-               return;
-       }
-
-       if (!streq(conn->waiting_for_ack->token, token)) {
-               /* They're confused: this will cause us to send event again */
-               conn->waiting_for_ack = NULL;
-               send_error(conn, EINVAL);
-               return;
-       }
-
-       /* Remove event: after ack sent, core will call queue_next_event */
-       event = list_top(&conn->waiting_for_ack->events, struct watch_event,
-                        list);
-       list_del(&event->list);
-       talloc_free(event);
-
-       conn->waiting_for_ack = NULL;
-       send_ack(conn, XS_WATCH_ACK);
-}
-
 void do_unwatch(struct connection *conn, struct buffered_data *in)
 {
        struct watch *watch;
@@ -241,9 +164,6 @@
                return;
        }
 
-       /* We don't need to worry if we're waiting for an ack for the
-        * watch we're deleting: conn->waiting_for_ack was reset by
-        * this command in consider_message anyway. */
        node = canonicalize(conn, vec[0]);
        list_for_each_entry(watch, &conn->watches, list) {
                if (streq(watch->node, node) && streq(watch->token, vec[1])) {
@@ -260,18 +180,19 @@
 void dump_watches(struct connection *conn)
 {
        struct watch *watch;
-       struct watch_event *event;
 
-       if (conn->waiting_for_ack)
-               printf("    waiting_for_ack for watch on %s token %s\n",
-                      conn->waiting_for_ack->node,
-                      conn->waiting_for_ack->token);
-
-       list_for_each_entry(watch, &conn->watches, list) {
+       list_for_each_entry(watch, &conn->watches, list)
                printf("    watch on %s token %s\n",
                       watch->node, watch->token);
-               list_for_each_entry(event, &watch->events, list)
-                       printf("        event: %s\n", event->data);
-       }
 }
 #endif
+
+/*
+ * Local variables:
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/xenstored_watch.h
--- a/tools/xenstore/xenstored_watch.h  Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/xenstored_watch.h  Tue Oct 11 22:57:44 2005
@@ -23,17 +23,9 @@
 #include "xenstored_core.h"
 
 void do_watch(struct connection *conn, struct buffered_data *in);
-void do_watch_ack(struct connection *conn, const char *token);
 void do_unwatch(struct connection *conn, struct buffered_data *in);
 
-/* Is this a watch event message for this connection? */
-bool is_watch_event(struct connection *conn, struct buffered_data *out);
-
-/* Look through our watches: if any of them have an event, queue it. */
-void queue_next_event(struct connection *conn);
-
-/* Fire all watches: recurse means all the children are affected (ie. rm).
- */
+/* Fire all watches: recurse means all the children are affected (ie. rm). */
 void fire_watches(struct connection *conn, const char *name, bool recurse);
 
 void dump_watches(struct connection *conn);
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/xs.c
--- a/tools/xenstore/xs.c       Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/xs.c       Tue Oct 11 22:57:44 2005
@@ -52,6 +52,7 @@
          * signals waiters.
          */
        pthread_t read_thr;
+       int read_thr_exists;
 
        /*
          * A list of fired watch messages, protected by a mutex. Users can
@@ -75,11 +76,9 @@
 
        /* One request at a time. */
        pthread_mutex_t request_mutex;
-
-       /* One transaction at a time. */
-       pthread_mutex_t transaction_mutex;
 };
 
+static int read_message(struct xs_handle *h);
 static void *read_thread(void *arg);
 
 int xs_fileno(struct xs_handle *h)
@@ -134,7 +133,7 @@
        int fd = -1, saved_errno;
 
        if (stat(connect_to, &buf) != 0)
-               goto error;
+               return NULL;
 
        if (S_ISSOCK(buf.st_mode))
                fd = get_socket(connect_to);
@@ -142,11 +141,17 @@
                fd = get_dev(connect_to);
 
        if (fd == -1)
-               goto error;
+               return NULL;
 
        h = malloc(sizeof(*h));
-       if (h == NULL)
-               goto error;
+       if (h == NULL) {
+               saved_errno = errno;
+               close(fd);
+               errno = saved_errno;
+               return NULL;
+       }
+
+       memset(h, 0, sizeof(*h));
 
        h->fd = fd;
 
@@ -162,21 +167,8 @@
        pthread_cond_init(&h->reply_condvar, NULL);
 
        pthread_mutex_init(&h->request_mutex, NULL);
-       pthread_mutex_init(&h->transaction_mutex, NULL);
-
-       if (pthread_create(&h->read_thr, NULL, read_thread, h) != 0)
-               goto error;
 
        return h;
-
- error:
-       saved_errno = errno;
-       if (h != NULL)
-               free(h);
-       if (fd != -1)
-               close(fd);
-       errno = saved_errno;
-       return NULL;
 }
 
 struct xs_handle *xs_daemon_open(void)
@@ -198,14 +190,15 @@
 {
        struct xs_stored_msg *msg, *tmsg;
 
-       pthread_mutex_lock(&h->transaction_mutex);
        pthread_mutex_lock(&h->request_mutex);
        pthread_mutex_lock(&h->reply_mutex);
        pthread_mutex_lock(&h->watch_mutex);
 
-       /* XXX FIXME: May leak an unpublished message buffer. */
-       pthread_cancel(h->read_thr);
-       pthread_join(h->read_thr, NULL);
+       if (h->read_thr_exists) {
+               /* XXX FIXME: May leak an unpublished message buffer. */
+               pthread_cancel(h->read_thr);
+               pthread_join(h->read_thr, NULL);
+       }
 
        list_for_each_entry_safe(msg, tmsg, &h->reply_list, list) {
                free(msg->body);
@@ -217,7 +210,6 @@
                free(msg);
        }
 
-       pthread_mutex_unlock(&h->transaction_mutex);
        pthread_mutex_unlock(&h->request_mutex);
        pthread_mutex_unlock(&h->reply_mutex);
        pthread_mutex_unlock(&h->watch_mutex);
@@ -277,6 +269,10 @@
        struct xs_stored_msg *msg;
        char *body;
 
+       /* Read from comms channel ourselves if there is no reader thread. */
+       if (!h->read_thr_exists && (read_message(h) == -1))
+               return NULL;
+
        pthread_mutex_lock(&h->reply_mutex);
        while (list_empty(&h->reply_list))
                pthread_cond_wait(&h->reply_condvar, &h->reply_mutex);
@@ -296,8 +292,10 @@
 }
 
 /* Send message to xs, get malloc'ed reply.  NULL and set errno on error. */
-static void *xs_talkv(struct xs_handle *h, enum xsd_sockmsg_type type,
-                     const struct iovec *iovec, unsigned int num_vecs,
+static void *xs_talkv(struct xs_handle *h, struct xs_transaction_handle *t,
+                     enum xsd_sockmsg_type type,
+                     const struct iovec *iovec,
+                     unsigned int num_vecs,
                      unsigned int *len)
 {
        struct xsd_sockmsg msg;
@@ -306,6 +304,7 @@
        unsigned int i;
        struct sigaction ignorepipe, oldact;
 
+       msg.tx_id = (u32)(unsigned long)t;
        msg.type = type;
        msg.len = 0;
        for (i = 0; i < num_vecs; i++)
@@ -368,14 +367,16 @@
 }
 
 /* Simplified version of xs_talkv: single message. */
-static void *xs_single(struct xs_handle *h, enum xsd_sockmsg_type type,
-                      const char *string, unsigned int *len)
+static void *xs_single(struct xs_handle *h, struct xs_transaction_handle *t,
+                      enum xsd_sockmsg_type type,
+                      const char *string,
+                      unsigned int *len)
 {
        struct iovec iovec;
 
        iovec.iov_base = (void *)string;
        iovec.iov_len = strlen(string) + 1;
-       return xs_talkv(h, type, &iovec, 1, len);
+       return xs_talkv(h, t, type, &iovec, 1, len);
 }
 
 static bool xs_bool(char *reply)
@@ -386,12 +387,13 @@
        return true;
 }
 
-char **xs_directory(struct xs_handle *h, const char *path, unsigned int *num)
+char **xs_directory(struct xs_handle *h, struct xs_transaction_handle *t,
+                   const char *path, unsigned int *num)
 {
        char *strings, *p, **ret;
        unsigned int len;
 
-       strings = xs_single(h, XS_DIRECTORY, path, &len);
+       strings = xs_single(h, t, XS_DIRECTORY, path, &len);
        if (!strings)
                return NULL;
 
@@ -417,16 +419,17 @@
  * Returns a malloced value: call free() on it after use.
  * len indicates length in bytes, not including the nul.
  */
-void *xs_read(struct xs_handle *h, const char *path, unsigned int *len)
-{
-       return xs_single(h, XS_READ, path, len);
+void *xs_read(struct xs_handle *h, struct xs_transaction_handle *t,
+             const char *path, unsigned int *len)
+{
+       return xs_single(h, t, XS_READ, path, len);
 }
 
 /* Write the value of a single file.
  * Returns false on failure.
  */
-bool xs_write(struct xs_handle *h, const char *path,
-             const void *data, unsigned int len)
+bool xs_write(struct xs_handle *h, struct xs_transaction_handle *t,
+             const char *path, const void *data, unsigned int len)
 {
        struct iovec iovec[2];
 
@@ -435,36 +438,40 @@
        iovec[1].iov_base = (void *)data;
        iovec[1].iov_len = len;
 
-       return xs_bool(xs_talkv(h, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
+       return xs_bool(xs_talkv(h, t, XS_WRITE, iovec,
+                               ARRAY_SIZE(iovec), NULL));
 }
 
 /* Create a new directory.
  * Returns false on failure, or success if it already exists.
  */
-bool xs_mkdir(struct xs_handle *h, const char *path)
-{
-       return xs_bool(xs_single(h, XS_MKDIR, path, NULL));
+bool xs_mkdir(struct xs_handle *h, struct xs_transaction_handle *t,
+             const char *path)
+{
+       return xs_bool(xs_single(h, t, XS_MKDIR, path, NULL));
 }
 
 /* Destroy a file or directory (directories must be empty).
  * Returns false on failure, or success if it doesn't exist.
  */
-bool xs_rm(struct xs_handle *h, const char *path)
-{
-       return xs_bool(xs_single(h, XS_RM, path, NULL));
+bool xs_rm(struct xs_handle *h, struct xs_transaction_handle *t,
+          const char *path)
+{
+       return xs_bool(xs_single(h, t, XS_RM, path, NULL));
 }
 
 /* Get permissions of node (first element is owner).
  * Returns malloced array, or NULL: call free() after use.
  */
 struct xs_permissions *xs_get_permissions(struct xs_handle *h,
+                                         struct xs_transaction_handle *t,
                                          const char *path, unsigned int *num)
 {
        char *strings;
        unsigned int len;
        struct xs_permissions *ret;
 
-       strings = xs_single(h, XS_GET_PERMS, path, &len);
+       strings = xs_single(h, t, XS_GET_PERMS, path, &len);
        if (!strings)
                return NULL;
 
@@ -490,7 +497,9 @@
 /* Set permissions of node (must be owner).
  * Returns false on failure.
  */
-bool xs_set_permissions(struct xs_handle *h, const char *path,
+bool xs_set_permissions(struct xs_handle *h,
+                       struct xs_transaction_handle *t,
+                       const char *path,
                        struct xs_permissions *perms,
                        unsigned int num_perms)
 {
@@ -512,7 +521,7 @@
                        goto unwind;
        }
 
-       if (!xs_bool(xs_talkv(h, XS_SET_PERMS, iov, 1+num_perms, NULL)))
+       if (!xs_bool(xs_talkv(h, t, XS_SET_PERMS, iov, 1+num_perms, NULL)))
                goto unwind;
        for (i = 0; i < num_perms; i++)
                free(iov[i+1].iov_base);
@@ -534,12 +543,24 @@
 {
        struct iovec iov[2];
 
+       /* We dynamically create a reader thread on demand. */
+       pthread_mutex_lock(&h->request_mutex);
+       if (!h->read_thr_exists) {
+               if (pthread_create(&h->read_thr, NULL, read_thread, h) != 0) {
+                       pthread_mutex_unlock(&h->request_mutex);
+                       return false;
+               }
+               h->read_thr_exists = 1;
+       }
+       pthread_mutex_unlock(&h->request_mutex);
+
        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;
 
-       return xs_bool(xs_talkv(h, XS_WATCH, iov, ARRAY_SIZE(iov), NULL));
+       return xs_bool(xs_talkv(h, NULL, XS_WATCH, iov,
+                               ARRAY_SIZE(iov), NULL));
 }
 
 /* Find out what node change was on (will block if nothing pending).
@@ -593,15 +614,6 @@
        return ret;
 }
 
-/* Acknowledge watch on node.  Watches must be acknowledged before
- * any other watches can be read.
- * Returns false on failure.
- */
-bool xs_acknowledge_watch(struct xs_handle *h, const char *token)
-{
-       return xs_bool(xs_single(h, XS_WATCH_ACK, token, NULL));
-}
-
 /* Remove a watch on a node.
  * Returns false on failure (no watch on that node).
  */
@@ -614,18 +626,28 @@
        iov[1].iov_base = (char *)token;
        iov[1].iov_len = strlen(token) + 1;
 
-       return xs_bool(xs_talkv(h, XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL));
+       return xs_bool(xs_talkv(h, NULL, XS_UNWATCH, iov,
+                               ARRAY_SIZE(iov), NULL));
 }
 
 /* Start a transaction: changes by others will not be seen during this
  * transaction, and changes will not be visible to others until end.
  * You can only have one transaction at any time.
- * Returns false on failure.
- */
-bool xs_transaction_start(struct xs_handle *h)
-{
-       pthread_mutex_lock(&h->transaction_mutex);
-       return xs_bool(xs_single(h, XS_TRANSACTION_START, "", NULL));
+ * Returns NULL on failure.
+ */
+struct xs_transaction_handle *xs_transaction_start(struct xs_handle *h)
+{
+       char *id_str;
+       unsigned long id;
+
+       id_str = xs_single(h, NULL, XS_TRANSACTION_START, "", NULL);
+       if (id_str == NULL)
+               return NULL;
+
+       id = strtoul(id_str, NULL, 0);
+       free(id_str);
+
+       return (struct xs_transaction_handle *)id;
 }
 
 /* End a transaction.
@@ -633,21 +655,17 @@
  * Returns false on failure, which indicates an error: transactions will
  * not fail spuriously.
  */
-bool xs_transaction_end(struct xs_handle *h, bool abort)
+bool xs_transaction_end(struct xs_handle *h, struct xs_transaction_handle *t,
+                       bool abort)
 {
        char abortstr[2];
-       bool rc;
 
        if (abort)
                strcpy(abortstr, "F");
        else
                strcpy(abortstr, "T");
        
-       rc = xs_bool(xs_single(h, XS_TRANSACTION_END, abortstr, NULL));
-
-       pthread_mutex_unlock(&h->transaction_mutex);
-
-       return rc;
+       return xs_bool(xs_single(h, t, XS_TRANSACTION_END, abortstr, NULL));
 }
 
 /* Introduce a new domain.
@@ -675,7 +693,8 @@
        iov[3].iov_base = (char *)path;
        iov[3].iov_len = strlen(path) + 1;
 
-       return xs_bool(xs_talkv(h, XS_INTRODUCE, iov, ARRAY_SIZE(iov), NULL));
+       return xs_bool(xs_talkv(h, NULL, XS_INTRODUCE, iov,
+                               ARRAY_SIZE(iov), NULL));
 }
 
 bool xs_release_domain(struct xs_handle *h, domid_t domid)
@@ -684,7 +703,7 @@
 
        sprintf(domid_str, "%u", domid);
 
-       return xs_bool(xs_single(h, XS_RELEASE, domid_str, NULL));
+       return xs_bool(xs_single(h, NULL, XS_RELEASE, domid_str, NULL));
 }
 
 char *xs_get_domain_path(struct xs_handle *h, domid_t domid)
@@ -693,7 +712,7 @@
 
        sprintf(domid_str, "%u", domid);
 
-       return xs_single(h, XS_GET_DOMAIN_PATH, domid_str, NULL);
+       return xs_single(h, NULL, XS_GET_DOMAIN_PATH, domid_str, NULL);
 }
 
 /* Only useful for DEBUG versions */
@@ -707,68 +726,76 @@
        iov[1].iov_base = data;
        iov[1].iov_len = len;
 
-       return xs_talkv(h, XS_DEBUG, iov, ARRAY_SIZE(iov), NULL);
-}
-
-static void *read_thread(void *arg)
-{
-       struct xs_handle *h = arg;
+       return xs_talkv(h, NULL, XS_DEBUG, iov,
+                       ARRAY_SIZE(iov), NULL);
+}
+
+static int read_message(struct xs_handle *h)
+{
        struct xs_stored_msg *msg = NULL;
        char *body = NULL;
-
-       for (;;) {
-               msg = NULL;
-               body = NULL;
-
-               /* Allocate message structure and read the message header. */
-               msg = malloc(sizeof(*msg));
-               if (msg == NULL)
+       int saved_errno;
+
+       /* Allocate message structure and read the message header. */
+       msg = malloc(sizeof(*msg));
+       if (msg == NULL)
+               goto error;
+       if (!read_all(h->fd, &msg->hdr, sizeof(msg->hdr)))
+               goto error;
+
+       /* Allocate and read the message body. */
+       body = msg->body = malloc(msg->hdr.len + 1);
+       if (body == NULL)
+               goto error;
+       if (!read_all(h->fd, body, msg->hdr.len))
+               goto error;
+       body[msg->hdr.len] = '\0';
+
+       if (msg->hdr.type == XS_WATCH_EVENT) {
+               pthread_mutex_lock(&h->watch_mutex);
+
+               /* Kick users out of their select() loop. */
+               if (list_empty(&h->watch_list) &&
+                   (h->watch_pipe[1] != -1))
+                       while (write(h->watch_pipe[1], body, 1) != 1)
+                               continue;
+
+               list_add_tail(&msg->list, &h->watch_list);
+               pthread_cond_signal(&h->watch_condvar);
+
+               pthread_mutex_unlock(&h->watch_mutex);
+       } else {
+               pthread_mutex_lock(&h->reply_mutex);
+
+               /* There should only ever be one response pending! */
+               if (!list_empty(&h->reply_list)) {
+                       pthread_mutex_unlock(&h->reply_mutex);
                        goto error;
-               if (!read_all(h->fd, &msg->hdr, sizeof(msg->hdr)))
-                       goto error;
-
-               /* Allocate and read the message body. */
-               body = msg->body = malloc(msg->hdr.len + 1);
-               if (body == NULL)
-                       goto error;
-               if (!read_all(h->fd, body, msg->hdr.len))
-                       goto error;
-               body[msg->hdr.len] = '\0';
-
-               if (msg->hdr.type == XS_WATCH_EVENT) {
-                       pthread_mutex_lock(&h->watch_mutex);
-
-                       /* Kick users out of their select() loop. */
-                       if (list_empty(&h->watch_list) &&
-                           (h->watch_pipe[1] != -1))
-                               while (write(h->watch_pipe[1], body, 1) != 1)
-                                       continue;
-
-                       list_add_tail(&msg->list, &h->watch_list);
-                       pthread_cond_signal(&h->watch_condvar);
-
-                       pthread_mutex_unlock(&h->watch_mutex);
-               } else {
-                       pthread_mutex_lock(&h->reply_mutex);
-
-                       /* There should only ever be one response pending! */
-                       if (!list_empty(&h->reply_list)) {
-                               pthread_mutex_unlock(&h->reply_mutex);
-                               goto error;
-                       }
-
-                       list_add_tail(&msg->list, &h->reply_list);
-                       pthread_cond_signal(&h->reply_condvar);
-
-                       pthread_mutex_unlock(&h->reply_mutex);
                }
-       }
+
+               list_add_tail(&msg->list, &h->reply_list);
+               pthread_cond_signal(&h->reply_condvar);
+
+               pthread_mutex_unlock(&h->reply_mutex);
+       }
+
+       return 0;
 
  error:
-       if (body != NULL)
-               free(body);
-       if (msg != NULL)
-               free(msg);
+       saved_errno = errno;
+       free(msg);
+       free(body);
+       errno = saved_errno;
+       return -1;
+}
+
+static void *read_thread(void *arg)
+{
+       struct xs_handle *h = arg;
+
+       while (read_message(h) != -1)
+               continue;
+
        return NULL;
 }
 
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/xs.h
--- a/tools/xenstore/xs.h       Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/xs.h       Tue Oct 11 22:57:44 2005
@@ -23,6 +23,7 @@
 #include <xs_lib.h>
 
 struct xs_handle;
+struct xs_transaction_handle;
 
 /* On failure, these routines set errno. */
 
@@ -44,41 +45,47 @@
  * Returns a malloced array: call free() on it after use.
  * Num indicates size.
  */
-char **xs_directory(struct xs_handle *h, const char *path, unsigned int *num);
+char **xs_directory(struct xs_handle *h, struct xs_transaction_handle *t,
+                   const char *path, unsigned int *num);
 
 /* Get the value of a single file, nul terminated.
  * Returns a malloced value: call free() on it after use.
  * len indicates length in bytes, not including terminator.
  */
-void *xs_read(struct xs_handle *h, const char *path, unsigned int *len);
+void *xs_read(struct xs_handle *h, struct xs_transaction_handle *t,
+             const char *path, unsigned int *len);
 
 /* Write the value of a single file.
  * Returns false on failure.
  */
-bool xs_write(struct xs_handle *h, const char *path, const void *data,
-             unsigned int len);
+bool xs_write(struct xs_handle *h, struct xs_transaction_handle *t,
+             const char *path, const void *data, unsigned int len);
 
 /* Create a new directory.
  * Returns false on failure, or success if it already exists.
  */
-bool xs_mkdir(struct xs_handle *h, const char *path);
+bool xs_mkdir(struct xs_handle *h, struct xs_transaction_handle *t,
+             const char *path);
 
 /* Destroy a file or directory (and children).
  * Returns false on failure, or success if it doesn't exist.
  */
-bool xs_rm(struct xs_handle *h, const char *path);
+bool xs_rm(struct xs_handle *h, struct xs_transaction_handle *t,
+          const char *path);
 
 /* Get permissions of node (first element is owner, first perms is "other").
  * Returns malloced array, or NULL: call free() after use.
  */
 struct xs_permissions *xs_get_permissions(struct xs_handle *h,
+                                         struct xs_transaction_handle *t,
                                          const char *path, unsigned int *num);
 
 /* Set permissions of node (must be owner).
  * Returns false on failure.
  */
-bool xs_set_permissions(struct xs_handle *h, const char *path,
-                       struct xs_permissions *perms, unsigned int num_perms);
+bool xs_set_permissions(struct xs_handle *h, struct xs_transaction_handle *t,
+                       const char *path, struct xs_permissions *perms,
+                       unsigned int num_perms);
 
 /* Watch a node for changes (poll on fd to detect, or call read_watch()).
  * When the node (or any child) changes, fd will become readable.
@@ -96,12 +103,6 @@
  */
 char **xs_read_watch(struct xs_handle *h, unsigned int *num);
 
-/* Acknowledge watch on node.  Watches must be acknowledged before
- * any other watches can be read.
- * Returns false on failure.
- */
-bool xs_acknowledge_watch(struct xs_handle *h, const char *token);
-
 /* Remove a watch on a node: implicitly acks any outstanding watch.
  * Returns false on failure (no watch on that node).
  */
@@ -110,16 +111,17 @@
 /* Start a transaction: changes by others will not be seen during this
  * transaction, and changes will not be visible to others until end.
  * You can only have one transaction at any time.
- * Returns false on failure.
+ * Returns NULL on failure.
  */
-bool xs_transaction_start(struct xs_handle *h);
+struct xs_transaction_handle *xs_transaction_start(struct xs_handle *h);
 
 /* End a transaction.
  * If abandon is true, transaction is discarded instead of committed.
  * Returns false on failure: if errno == EAGAIN, you have to restart
  * transaction.
  */
-bool xs_transaction_end(struct xs_handle *h, bool abort);
+bool xs_transaction_end(struct xs_handle *h, struct xs_transaction_handle *t,
+                       bool abort);
 
 /* Introduce a new domain.
  * This tells the store daemon about a shared memory page, event channel
@@ -142,3 +144,13 @@
                       void *data, unsigned int len);
 
 #endif /* _XS_H */
+
+/*
+ * Local variables:
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/xs_test.c
--- a/tools/xenstore/xs_test.c  Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/xs_test.c  Tue Oct 11 22:57:44 2005
@@ -42,6 +42,7 @@
 #define XSTEST
 
 static struct xs_handle *handles[10] = { NULL };
+static struct xs_transaction_handle *txh[10] = { NULL };
 
 static unsigned int timeout_ms = 500;
 static bool timeout_suppressed = true;
@@ -201,7 +202,6 @@
             "  watch <path> <token>\n"
             "  watchnoack <path> <token>\n"
             "  waitwatch\n"
-            "  ackwatch <token>\n"
             "  unwatch <path> <token>\n"
             "  close\n"
             "  start <node>\n"
@@ -313,7 +313,7 @@
        char **entries;
        unsigned int i, num;
 
-       entries = xs_directory(handles[handle], path, &num);
+       entries = xs_directory(handles[handle], txh[handle], path, &num);
        if (!entries) {
                failed(handle);
                return;
@@ -332,7 +332,7 @@
        char *value;
        unsigned int len;
 
-       value = xs_read(handles[handle], path, &len);
+       value = xs_read(handles[handle], txh[handle], path, &len);
        if (!value) {
                failed(handle);
                return;
@@ -348,7 +348,7 @@
 
 static void do_write(unsigned int handle, char *path, char *data)
 {
-       if (!xs_write(handles[handle], path, data, strlen(data)))
+       if (!xs_write(handles[handle], txh[handle], path, data, strlen(data)))
                failed(handle);
 }
 
@@ -361,13 +361,13 @@
 
 static void do_mkdir(unsigned int handle, char *path)
 {
-       if (!xs_mkdir(handles[handle], path))
+       if (!xs_mkdir(handles[handle], txh[handle], path))
                failed(handle);
 }
 
 static void do_rm(unsigned int handle, char *path)
 {
-       if (!xs_rm(handles[handle], path))
+       if (!xs_rm(handles[handle], txh[handle], path))
                failed(handle);
 }
 
@@ -376,7 +376,7 @@
        unsigned int i, num;
        struct xs_permissions *perms;
 
-       perms = xs_get_permissions(handles[handle], path, &num);
+       perms = xs_get_permissions(handles[handle], txh[handle], path, &num);
        if (!perms) {
                failed(handle);
                return;
@@ -437,7 +437,7 @@
                        barf("bad flags %s\n", arg);
        }
 
-       if (!xs_set_permissions(handles[handle], path, perms, i))
+       if (!xs_set_permissions(handles[handle], txh[handle], path, perms, i))
                failed(handle);
 }
 
@@ -454,8 +454,6 @@
                if (!vec ||
                    !streq(vec[XS_WATCH_PATH], node) ||
                    !streq(vec[XS_WATCH_TOKEN], token))
-                       failed(handle);
-               if (!xs_acknowledge_watch(handles[handle], token))
                        failed(handle);
        }
 }
@@ -515,12 +513,6 @@
        free(vec);
 }
 
-static void do_ackwatch(unsigned int handle, const char *token)
-{
-       if (!xs_acknowledge_watch(handles[handle], token))
-               failed(handle);
-}
-
 static void do_unwatch(unsigned int handle, const char *node, const char 
*token)
 {
        if (!xs_unwatch(handles[handle], node, token))
@@ -529,14 +521,16 @@
 
 static void do_start(unsigned int handle)
 {
-       if (!xs_transaction_start(handles[handle]))
+       txh[handle] = xs_transaction_start(handles[handle]);
+       if (txh[handle] == NULL)
                failed(handle);
 }
 
 static void do_end(unsigned int handle, bool abort)
 {
-       if (!xs_transaction_end(handles[handle], abort))
-               failed(handle);
+       if (!xs_transaction_end(handles[handle], txh[handle], abort))
+               failed(handle);
+       txh[handle] = NULL;
 }
 
 static void do_introduce(unsigned int handle,
@@ -626,7 +620,8 @@
 
                sprintf(subnode, "%s/%s", node, dir[i]);
 
-               perms = xs_get_permissions(handles[handle], subnode,&numperms);
+               perms = xs_get_permissions(handles[handle], txh[handle],
+                                          subnode,&numperms);
                if (!perms) {
                        failed(handle);
                        return;
@@ -643,7 +638,8 @@
                output("\n");
 
                /* Even directories can have contents. */
-               contents = xs_read(handles[handle], subnode, &len);
+               contents = xs_read(handles[handle], txh[handle], 
+                                  subnode, &len);
                if (!contents) {
                        if (errno != EISDIR)
                                failed(handle);
@@ -653,7 +649,8 @@
                }                       
 
                /* Every node is a directory. */
-               subdirs = xs_directory(handles[handle], subnode, &subnum);
+               subdirs = xs_directory(handles[handle], txh[handle], 
+                                      subnode, &subnum);
                if (!subdirs) {
                        failed(handle);
                        return;
@@ -668,7 +665,7 @@
        char **subdirs;
        unsigned int subnum;
 
-       subdirs = xs_directory(handles[handle], "/", &subnum);
+       subdirs = xs_directory(handles[handle], txh[handle], "/", &subnum);
        if (!subdirs) {
                failed(handle);
                return;
@@ -746,13 +743,12 @@
                do_watch(handle, arg(line, 1), arg(line, 2), false);
        else if (streq(command, "waitwatch"))
                do_waitwatch(handle);
-       else if (streq(command, "ackwatch"))
-               do_ackwatch(handle, arg(line, 1));
        else if (streq(command, "unwatch"))
                do_unwatch(handle, arg(line, 1), arg(line, 2));
        else if (streq(command, "close")) {
                xs_daemon_close(handles[handle]);
                handles[handle] = NULL;
+               txh[handle] = NULL;
        } else if (streq(command, "start"))
                do_start(handle);
        else if (streq(command, "commit"))
@@ -836,3 +832,13 @@
 
        return 0;
 }
+
+/*
+ * Local variables:
+ *  c-file-style: "linux"
+ *  indent-tabs-mode: t
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff -r 333f722ed6d0 -r 74d56b7ff46c xen/Makefile
--- a/xen/Makefile      Tue Oct 11 21:50:21 2005
+++ b/xen/Makefile      Tue Oct 11 22:57:44 2005
@@ -95,7 +95,7 @@
            -e 's/@@version@@/$(XEN_VERSION)/g' \
            -e 's/@@subversion@@/$(XEN_SUBVERSION)/g' \
            -e 's/@@extraversion@@/$(XEN_EXTRAVERSION)/g' \
-           -e 's!@@changeset@@!$(shell (hg parents | awk -F: 
'/^changeset/{CS=$$3};{FS="date:[ ]+"}/^date/{D=$$2}; END {print D, CS}') 
2>/dev/null || (head -n 6 ChangeLog | awk -F: '/^changeset/{CS=$$3};{FS="date:[ 
]+"}/^date/{D=$$2}; END {print D, CS}') 2>/dev/null || echo information 
unavailable)!g' \
+           -e 's!@@changeset@@!$(shell ((hg parents || head -n 7 ../ChangeLog 
|| echo date: unavailable) | awk '{FS="changeset:[ 
]+"}/^changeset/{CS=$$2};{FS="date:[ ]+"}/^date/{D=$$2}; END {print D, CS}') 
2>/dev/null)!g' \
            < include/xen/compile.h.in > $@.new
        @cat include/xen/banner.h >> $@.new
        @mv -f $@.new $@
diff -r 333f722ed6d0 -r 74d56b7ff46c xen/include/public/io/xs_wire.h
--- a/xen/include/public/io/xs_wire.h   Tue Oct 11 21:50:21 2005
+++ b/xen/include/public/io/xs_wire.h   Tue Oct 11 22:57:44 2005
@@ -30,25 +30,23 @@
 
 enum xsd_sockmsg_type
 {
-       XS_DEBUG,
-       XS_DIRECTORY,
-       XS_READ,
-       XS_GET_PERMS,
-       XS_WATCH,
-       XS_WATCH_ACK,
-       XS_UNWATCH,
-       XS_TRANSACTION_START,
-       XS_TRANSACTION_END,
-       XS_OP_READ_ONLY = XS_TRANSACTION_END,
-       XS_INTRODUCE,
-       XS_RELEASE,
-       XS_GET_DOMAIN_PATH,
-       XS_WRITE,
-       XS_MKDIR,
-       XS_RM,
-       XS_SET_PERMS,
-       XS_WATCH_EVENT,
-       XS_ERROR,
+    XS_DEBUG,
+    XS_DIRECTORY,
+    XS_READ,
+    XS_GET_PERMS,
+    XS_WATCH,
+    XS_UNWATCH,
+    XS_TRANSACTION_START,
+    XS_TRANSACTION_END,
+    XS_INTRODUCE,
+    XS_RELEASE,
+    XS_GET_DOMAIN_PATH,
+    XS_WRITE,
+    XS_MKDIR,
+    XS_RM,
+    XS_SET_PERMS,
+    XS_WATCH_EVENT,
+    XS_ERROR,
 };
 
 #define XS_WRITE_NONE "NONE"
@@ -58,38 +56,40 @@
 /* We hand errors as strings, for portability. */
 struct xsd_errors
 {
-       int errnum;
-       const char *errstring;
+    int errnum;
+    const char *errstring;
 };
 #define XSD_ERROR(x) { x, #x }
 static struct xsd_errors xsd_errors[] __attribute__((unused)) = {
-       XSD_ERROR(EINVAL),
-       XSD_ERROR(EACCES),
-       XSD_ERROR(EEXIST),
-       XSD_ERROR(EISDIR),
-       XSD_ERROR(ENOENT),
-       XSD_ERROR(ENOMEM),
-       XSD_ERROR(ENOSPC),
-       XSD_ERROR(EIO),
-       XSD_ERROR(ENOTEMPTY),
-       XSD_ERROR(ENOSYS),
-       XSD_ERROR(EROFS),
-       XSD_ERROR(EBUSY),
-       XSD_ERROR(EAGAIN),
-       XSD_ERROR(EISCONN),
+    XSD_ERROR(EINVAL),
+    XSD_ERROR(EACCES),
+    XSD_ERROR(EEXIST),
+    XSD_ERROR(EISDIR),
+    XSD_ERROR(ENOENT),
+    XSD_ERROR(ENOMEM),
+    XSD_ERROR(ENOSPC),
+    XSD_ERROR(EIO),
+    XSD_ERROR(ENOTEMPTY),
+    XSD_ERROR(ENOSYS),
+    XSD_ERROR(EROFS),
+    XSD_ERROR(EBUSY),
+    XSD_ERROR(EAGAIN),
+    XSD_ERROR(EISCONN),
 };
 struct xsd_sockmsg
 {
-       u32 type;
-       u32 len;                /* Length of data following this. */
+    u32 type;  /* XS_??? */
+    u32 req_id;/* Request identifier, echoed in daemon's response.  */
+    u32 tx_id; /* Transaction id (0 if not related to a transaction). */
+    u32 len;   /* Length of data following this. */
 
-       /* Generally followed by nul-terminated string(s). */
+    /* Generally followed by nul-terminated string(s). */
 };
 
 enum xs_watch_type
 {
-       XS_WATCH_PATH = 0,
-       XS_WATCH_TOKEN,
+    XS_WATCH_PATH = 0,
+    XS_WATCH_TOKEN,
 };
 
 #endif /* _XS_WIRE_H */
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/examples/xen-hotplug-common.sh
--- /dev/null   Tue Oct 11 21:50:21 2005
+++ b/tools/examples/xen-hotplug-common.sh      Tue Oct 11 22:57:44 2005
@@ -0,0 +1,26 @@
+set -e
+
+export PATH=/sbin:/bin:/usr/bin:/usr/sbin:$PATH
+
+log() {
+  local level="$1"
+  shift
+  logger -p "daemon.$level" -- "$0:" "$@" || echo "$0 $@" >&2
+}
+
+xenstore_read() {
+  local v=$(xenstore-read "$@" || true)
+  if [ "$v" == "" ]
+  then
+    log error "xenstore-read $@ failed."
+    exit 1
+  fi
+  echo "$v"
+}
+
+xenstore_write() {
+  log debug "Writing $@ to xenstore."
+  xenstore-write "$@" || log error "Writing $@ to xenstore failed."
+}
+
+log debug "$@" "XENBUS_PATH=$XENBUS_PATH"
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/util/asserts.py
--- /dev/null   Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/util/asserts.py  Tue Oct 11 22:57:44 2005
@@ -0,0 +1,27 @@
+#===========================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2005 XenSource Ltd
+#============================================================================
+
+
+def isCharConvertible(c):
+    """Assert that the given value is convertible to a character using the %c
+    conversion.  This implies that c is either an integer, or a character
+    (i.e. a string of length 1).
+    """
+    
+    assert (isinstance(c, int) or
+            (isinstance(c, str) and
+             len(c) == 1)), "%s is not convertible to a character" % c
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/util/auxbin.py
--- /dev/null   Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/util/auxbin.py   Tue Oct 11 22:57:44 2005
@@ -0,0 +1,44 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2005 XenSource Ltd
+#============================================================================
+
+
+LIB_BIN_32 = "/usr/lib/xen/bin"
+LIB_BIN_64 = "/usr/lib64/xen/bin"
+
+
+import os
+import os.path
+
+
+def execute(exe, args = None):
+    exepath = pathTo(exe)
+    a = [ exepath ]
+    if args:
+        a.extend(args)
+    os.execv(exepath, a)
+
+
+def pathTo(exe):
+    return os.path.join(path(), exe)
+
+
+def path():
+    machine = os.uname()[4]
+    if machine.find('64') != -1 and os.path.exists(LIB_BIN_64):
+        return LIB_BIN_64
+    else:
+        return LIB_BIN_32
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/python/xen/xm/console.py
--- /dev/null   Tue Oct 11 21:50:21 2005
+++ b/tools/python/xen/xm/console.py    Tue Oct 11 22:57:44 2005
@@ -0,0 +1,26 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2005 XenSource Ltd
+#============================================================================
+
+
+XENCONSOLE = "xenconsole"
+
+
+import xen.util.auxbin
+
+
+def execConsole(domid):
+    xen.util.auxbin.execute(XENCONSOLE, [str(domid)])
diff -r 333f722ed6d0 -r 74d56b7ff46c tools/xenstore/xsls.c
--- /dev/null   Tue Oct 11 21:50:21 2005
+++ b/tools/xenstore/xsls.c     Tue Oct 11 22:57:44 2005
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <xs.h>
+
+void print_dir(struct xs_handle *h, char *path, int cur_depth)
+{
+    char **e;
+    char newpath[512], *val;
+    int num, i, len;
+
+    e = xs_directory(h, NULL, path, &num);
+    if (e == NULL)
+        err(1, "xs_directory (%s)", path);
+
+    for (i = 0; i<num; i++) {
+        int j;
+        for (j=0; j<cur_depth; j++) printf(" ");
+        printf("%s", e[i]);
+        sprintf(newpath, "%s%s%s", path, 
+                path[strlen(path)-1] == '/' ? "" : "/", 
+                e[i]);
+        val = xs_read(h, NULL, newpath, &len);
+        if (val == NULL)
+            printf(":\n");
+        else if ((unsigned)len > (151 - strlen(e[i])))
+            printf(" = \"%.*s...\"\n", 148 - strlen(e[i]), val);
+        else
+            printf(" = \"%s\"\n", val);
+        free(val);
+        print_dir(h, newpath, cur_depth+1); 
+    }
+    free(e);
+}
+
+int main(int argc, char *argv[])
+{
+    struct xs_handle *xsh = xs_daemon_open();
+
+    if (xsh == NULL)
+        err(1, "xs_daemon_open");
+
+    print_dir(xsh, argc == 1 ? "/" : argv[1], 0);
+
+    return 0;
+}
diff -r 333f722ed6d0 -r 74d56b7ff46c xen/include/public/io/console.h
--- /dev/null   Tue Oct 11 21:50:21 2005
+++ b/xen/include/public/io/console.h   Tue Oct 11 22:57:44 2005
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * console.h
+ * 
+ * Console I/O interface for Xen guest OSes.
+ * 
+ * Copyright (c) 2005, Keir Fraser
+ */
+
+#ifndef __XEN_PUBLIC_IO_CONSOLE_H__
+#define __XEN_PUBLIC_IO_CONSOLE_H__
+
+typedef u32 XENCONS_RING_IDX;
+
+#define MASK_XENCONS_IDX(idx, ring) ((idx) & (sizeof(ring)-1))
+
+struct xencons_interface {
+    char in[1024];
+    char out[2048];
+    XENCONS_RING_IDX in_cons, in_prod;
+    XENCONS_RING_IDX out_cons, out_prod;
+};
+
+#endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */

_______________________________________________
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®.