WARNING - OLD ARCHIVES

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

xen-changelog

[Xen-changelog] 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] Merged, Xen patchbot -unstable <=