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

[Xen-changelog] [xen-unstable] blktap2: The tap-ctl userspace control utility and library.



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1275980709 -3600
# Node ID 63d0f5348af242e6046e1e30d22841ba20f8e6d6
# Parent  54675b91b3c17093efd347bd88ea57fce7240f30
blktap2: The tap-ctl userspace control utility and library.

Tapdisk control in userspace, a replacement for the original blktap2
control stack, which had to pass a kernel space interface based on
sysfs nodes.

All tapdisk processes listen for commands on a unix stream socket. The
control library supports scanning the socket namespace for running
tapdisks, VBD minors allocated, associated images and state inquiry.

Control operations include allocating/releasing devices, spawning
tapdisks, opening/closing images, attaching disk images to
devices. disk pause/resume operations and runtime switching of disk
images.

Signed-off-by: Jake Wires <jake.wires@xxxxxxxxxx>
Signed-off-by: Daniel Stodden <daniel.stodden@xxxxxxxxxx>
---
 tools/blktap2/drivers/blktap2.h          |   66 --
 tools/blktap2/Makefile                   |    1 
 tools/blktap2/control/Makefile           |   57 ++
 tools/blktap2/control/tap-ctl-allocate.c |  242 ++++++++
 tools/blktap2/control/tap-ctl-attach.c   |   61 ++
 tools/blktap2/control/tap-ctl-check.c    |   79 ++
 tools/blktap2/control/tap-ctl-close.c    |   87 +++
 tools/blktap2/control/tap-ctl-create.c   |   65 ++
 tools/blktap2/control/tap-ctl-destroy.c  |   56 ++
 tools/blktap2/control/tap-ctl-detach.c   |   61 ++
 tools/blktap2/control/tap-ctl-free.c     |   54 ++
 tools/blktap2/control/tap-ctl-ipc.c      |  237 ++++++++
 tools/blktap2/control/tap-ctl-list.c     |  506 ++++++++++++++++++
 tools/blktap2/control/tap-ctl-major.c    |   69 ++
 tools/blktap2/control/tap-ctl-open.c     |   75 ++
 tools/blktap2/control/tap-ctl-pause.c    |   59 ++
 tools/blktap2/control/tap-ctl-spawn.c    |  174 ++++++
 tools/blktap2/control/tap-ctl-unpause.c  |   64 ++
 tools/blktap2/control/tap-ctl.c          |  815 ++++++++++++++++++++++++++++++
 tools/blktap2/control/tap-ctl.h          |  101 +++
 tools/blktap2/drivers/Makefile           |    4 
 tools/blktap2/drivers/tapdisk-control.c  |  836 +++++++++++++++++++++++++++++++
 tools/blktap2/drivers/tapdisk-control.h  |   35 +
 tools/blktap2/drivers/tapdisk-server.c   |   83 ++-
 tools/blktap2/drivers/tapdisk-server.h   |    5 
 tools/blktap2/drivers/tapdisk-vbd.c      |  105 ++-
 tools/blktap2/drivers/tapdisk-vbd.h      |   10 
 tools/blktap2/drivers/tapdisk2.c         |  441 ++--------------
 tools/blktap2/include/blktap2.h          |   67 ++
 tools/blktap2/include/tapdisk-message.h  |   64 ++
 30 files changed, 4071 insertions(+), 508 deletions(-)

diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/Makefile
--- a/tools/blktap2/Makefile    Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/Makefile    Tue Jun 08 08:05:09 2010 +0100
@@ -9,6 +9,7 @@ SUBDIRS-y += lvm
 SUBDIRS-y += lvm
 SUBDIRS-y += vhd
 SUBDIRS-y += drivers
+SUBDIRS-y += control
 
 clean:
        rm -rf *.a *.so *.o *.rpm $(LIB) *~ $(DEPS) TAGS
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/Makefile    Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,57 @@
+XEN_ROOT := ../../../
+include $(XEN_ROOT)/tools/Rules.mk
+
+IBIN               = tap-ctl
+INST_DIR           = /usr/sbin
+
+CFLAGS            += -Werror
+CFLAGS            += -Wno-unused
+CFLAGS            += -I../include -I../drivers
+CFLAGS            += -I$(XEN_INCLUDE) -I$(XEN_LIBXC)
+CFLAGS            += -D_GNU_SOURCE
+CFLAGS            += -DTAPCTL
+
+# Get gcc to generate the dependencies for us.
+CFLAGS            += -Wp,-MD,.$(@F).d
+DEPS               = .*.d
+
+CTL_OBJS  := tap-ctl-ipc.o
+CTL_OBJS  += tap-ctl-list.o
+CTL_OBJS  += tap-ctl-allocate.o
+CTL_OBJS  += tap-ctl-free.o
+CTL_OBJS  += tap-ctl-create.o
+CTL_OBJS  += tap-ctl-destroy.o
+CTL_OBJS  += tap-ctl-spawn.o
+CTL_OBJS  += tap-ctl-attach.o
+CTL_OBJS  += tap-ctl-detach.o
+CTL_OBJS  += tap-ctl-open.o
+CTL_OBJS  += tap-ctl-close.o
+CTL_OBJS  += tap-ctl-pause.o
+CTL_OBJS  += tap-ctl-unpause.o
+CTL_OBJS  += tap-ctl-major.o
+CTL_OBJS  += tap-ctl-check.o
+
+OBJS = $(CTL_OBJS)
+LIBS = libblktapctl.a
+
+all: build
+
+build: $(IBIN)
+
+tap-ctl: tap-ctl.o libblktapctl.a
+       $(CC) $(CFLAGS) -o $@ $^
+
+libblktapctl.a: $(CTL_OBJS)
+       ar r $@ $^
+
+install: all
+       $(INSTALL_DIR) -p $(DESTDIR)$(INST_DIR)
+       $(INSTALL_PROG) $(IBIN) $(DESTDIR)$(INST_DIR)
+
+clean:
+       rm -f $(OBJS) $(DEPS) $(IBIN) $(LIBS)
+       rm -f *~
+
+.PHONY: all build clean install
+
+-include $(DEPS)
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-allocate.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-allocate.c  Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <linux/major.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+static int
+tap_ctl_prepare_directory(const char *dir)
+{
+       int err;
+       char *ptr, *name, *start;
+
+       err = access(dir, W_OK | R_OK);
+       if (!err)
+               return 0;
+
+       name = strdup(dir);
+       if (!name)
+               return ENOMEM;
+
+       start = name;
+
+       for (;;) {
+               ptr = strchr(start + 1, '/');
+               if (ptr)
+                       *ptr = '\0';
+
+               err = mkdir(name, 0755);
+               if (err && errno != EEXIST) {
+                       PERROR("mkdir %s", name);
+                       err = errno;
+                       break;
+               }
+
+               if (!ptr)
+                       break;
+               else {
+                       *ptr = '/';
+                       start = ptr + 1;
+               }
+       }
+
+       free(name);
+       return err;
+}
+
+static int
+tap_ctl_make_device(const char *devname, const int major,
+                   const int minor, const int perm)
+{
+       int err;
+       char *copy, *dir;
+
+       copy = strdup(devname);
+       if (!copy)
+               return ENOMEM;
+
+       dir = dirname(copy);
+
+       err = tap_ctl_prepare_directory(dir);
+       free(copy);
+
+       if (err)
+               return err;
+
+       if (!access(devname, F_OK))
+               if (unlink(devname)) {
+                       PERROR("unlink %s", devname);
+                       return errno;
+               }
+
+       err = mknod(devname, perm, makedev(major, minor));
+       if (err) {
+               PERROR("mknod %s", devname);
+               return errno;
+       }
+
+       return 0;
+}
+
+static int
+tap_ctl_check_environment(void)
+{
+       FILE *f;
+       int err, minor;
+       char name[256];
+
+       err = tap_ctl_prepare_directory(BLKTAP2_CONTROL_DIR);
+       if (err)
+               return err;
+
+       if (!access(BLKTAP2_CONTROL_DEVICE, R_OK | W_OK))
+               return 0;
+
+       memset(name, 0, sizeof(name));
+
+       f = fopen("/proc/misc", "r");
+       if (!f) {
+               EPRINTF("failed to open /proc/misc: %d\n", errno);
+               return errno;
+       }
+
+       while (fscanf(f, "%d %256s", &minor, name) == 2)
+               if (!strcmp(name, BLKTAP2_CONTROL_NAME)) {
+                       err = tap_ctl_make_device(BLKTAP2_CONTROL_DEVICE,
+                                                 MISC_MAJOR,
+                                                 minor, S_IFCHR | 0600);
+                       goto out;
+               }
+
+       err = ENOSYS;
+       EPRINTF("didn't find %s in /proc/misc\n", BLKTAP2_CONTROL_NAME);
+
+out:
+       fclose(f);
+       return err;
+}
+
+static int
+tap_ctl_allocate_device(int *minor, char **devname)
+{
+       char *name;
+       int fd, err;
+       struct blktap2_handle handle;
+
+       *minor = -1;
+       if (!devname)
+               return EINVAL;
+
+       fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY);
+       if (fd == -1) {
+               EPRINTF("failed to open control device: %d\n", errno);
+               return errno;
+       }
+
+       err = ioctl(fd, BLKTAP2_IOCTL_ALLOC_TAP, &handle);
+       close(fd);
+       if (err == -1) {
+               EPRINTF("failed to allocate new device: %d\n", errno);
+               return errno;
+       }
+
+       err = asprintf(&name, "%s%d", BLKTAP2_RING_DEVICE, handle.minor);
+       if (err == -1) {
+               err = ENOMEM;
+               goto fail;
+       }
+
+       err = tap_ctl_make_device(name, handle.ring,
+                                 handle.minor, S_IFCHR | 0600);
+       free(name);
+       if (err) {
+               EPRINTF("creating ring device for %d failed: %d\n",
+                       handle.minor, err);
+               goto fail;
+       }
+
+       if (*devname)
+               name = *devname;
+       else {
+               err = asprintf(&name, "%s%d",
+                              BLKTAP2_IO_DEVICE, handle.minor);
+               if (err == -1) {
+                       err = ENOMEM;
+                       goto fail;
+               }
+               *devname = name;
+       }
+
+       err = tap_ctl_make_device(name, handle.device,
+                                 handle.minor, S_IFBLK | 0600);
+       if (err) {
+               EPRINTF("creating IO device for %d failed: %d\n",
+                       handle.minor, err);
+               goto fail;
+       }
+
+       DBG("new interface: ring: %u, device: %u, minor: %u\n",
+           handle.ring, handle.device, handle.minor);
+
+       *minor = handle.minor;
+       return 0;
+
+fail:
+       tap_ctl_free(handle.minor);
+       return err;
+}
+
+int
+tap_ctl_allocate(int *minor, char **devname)
+{
+       int err;
+
+       *minor = -1;
+
+       err = tap_ctl_check_environment();
+       if (err)
+               return err;
+
+       err = tap_ctl_allocate_device(minor, devname);
+       if (err)
+               return err;
+
+       return 0;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-attach.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-attach.c    Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+
+int
+tap_ctl_attach(const int id, const int minor)
+{
+       int err;
+       tapdisk_message_t message;
+
+       memset(&message, 0, sizeof(message));
+       message.type = TAPDISK_MESSAGE_ATTACH;
+       message.cookie = minor;
+
+       err = tap_ctl_connect_send_and_receive(id, &message, 5);
+       if (err)
+               return err;
+
+       if (message.type == TAPDISK_MESSAGE_ATTACH_RSP) {
+               err = message.u.response.error;
+               if (err)
+                       EPRINTF("attach failed: %d\n", err);
+       } else {
+               EPRINTF("got unexpected result '%s' from %d\n",
+                       tapdisk_message_name(message.type), id);
+               err = EINVAL;
+       }
+
+       return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-check.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-check.c     Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+int
+tap_ctl_check_blktap(const char **msg)
+{
+       FILE *f;
+       int err = 0, minor;
+       char name[32];
+
+       memset(name, 0, sizeof(name));
+
+       f = fopen("/proc/misc", "r");
+       if (!f) {
+               *msg = "failed to open /proc/misc";
+               return -errno;
+       }
+
+       while (fscanf(f, "%d %32s", &minor, name) == 2) {
+               if (!strcmp(name, BLKTAP2_CONTROL_NAME))
+                       goto out;
+       }
+
+       err = -ENOSYS;
+       *msg = "blktap kernel module not installed";
+
+out:
+       fclose(f);
+       return err;
+}
+
+int
+tap_ctl_check(const char **msg)
+{
+       int err;
+       uid_t uid;
+
+       err = tap_ctl_check_blktap(msg);
+       if (err)
+               goto out;
+
+       err  = 0;
+       *msg = "ok";
+
+out:
+       return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-close.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-close.c     Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+
+static int
+__tap_ctl_close(const int id, const int minor, const int force)
+{
+       int err;
+       tapdisk_message_t message;
+
+       memset(&message, 0, sizeof(message));
+       message.type = TAPDISK_MESSAGE_CLOSE;
+       if (force)
+               message.type = TAPDISK_MESSAGE_FORCE_SHUTDOWN;
+       message.cookie = minor;
+
+       err = tap_ctl_connect_send_and_receive(id, &message, 5);
+       if (err)
+               return err;
+
+       if (message.type == TAPDISK_MESSAGE_CLOSE_RSP) {
+               err = message.u.response.error;
+               if (err)
+                       EPRINTF("close failed: %d\n", err);
+       } else {
+               EPRINTF("got unexpected result '%s' from %d\n",
+                       tapdisk_message_name(message.type), id);
+               err = EINVAL;
+       }
+
+       return err;
+}
+
+int
+tap_ctl_close(const int id, const int minor, const int force)
+{
+       int i, err;
+
+       for (i = 0; i < 20; i++) {
+               err = __tap_ctl_close(id, minor, force);
+               if (!err)
+                       return 0;
+
+               err = (err < 0 ? -err : err);
+               if (err != EAGAIN) {
+                       EPRINTF("close failed: %d\n", err);
+                       return err;
+               }
+
+               usleep(1000);
+       }
+
+       EPRINTF("close timed out\n");
+       return EIO;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-create.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-create.c    Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+int
+tap_ctl_create(const char *params, char **devname)
+{
+       int err, id, minor;
+
+       err = tap_ctl_allocate(&minor, devname);
+       if (err)
+               return err;
+
+       id = tap_ctl_spawn();
+       if (id < 0)
+               goto destroy;
+
+       err = tap_ctl_attach(id, minor);
+       if (err)
+               goto destroy;
+
+       err = tap_ctl_open(id, minor, params);
+       if (err)
+               goto detach;
+
+       return 0;
+
+detach:
+       tap_ctl_detach(id, minor);
+destroy:
+       tap_ctl_free(minor);
+       return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-destroy.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-destroy.c   Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+int
+tap_ctl_destroy(const int id, const int minor)
+{
+       int err;
+
+       err = tap_ctl_close(id, minor, 0);
+       if (err)
+               return err;
+
+       err = tap_ctl_detach(id, minor);
+       if (err)
+               return err;
+
+       err = tap_ctl_free(minor);
+       if (err)
+               return err;
+
+       return 0;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-detach.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-detach.c    Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+
+int
+tap_ctl_detach(const int id, const int minor)
+{
+       int err;
+       tapdisk_message_t message;
+
+       memset(&message, 0, sizeof(message));
+       message.type = TAPDISK_MESSAGE_DETACH;
+       message.cookie = minor;
+
+       err = tap_ctl_connect_send_and_receive(id, &message, 5);
+       if (err)
+               return err;
+
+       if (message.type == TAPDISK_MESSAGE_DETACH_RSP) {
+               err = message.u.response.error;
+               if (err < 0)
+                       printf("detach failed: %d\n", err);
+       } else {
+               printf("got unexpected result '%s' from %d\n",
+                      tapdisk_message_name(message.type), id);
+               err = EINVAL;
+       }
+
+       return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-free.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-free.c      Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+int
+tap_ctl_free(const int minor)
+{
+       int fd, err;
+
+       fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY);
+       if (fd == -1) {
+               EPRINTF("failed to open control device: %d\n", errno);
+               return errno;
+       }
+
+       err = ioctl(fd, BLKTAP2_IOCTL_FREE_TAP, minor);
+       close(fd);
+
+       return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-ipc.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-ipc.c       Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+int tap_ctl_debug = 0;
+
+int
+tap_ctl_read_message(int fd, tapdisk_message_t *message, int timeout)
+{
+       fd_set readfds;
+       int ret, len, offset;
+       struct timeval tv, *t;
+
+       t      = NULL;
+       offset = 0;
+       len    = sizeof(tapdisk_message_t);
+
+       if (timeout) {
+               tv.tv_sec  = timeout;
+               tv.tv_usec = 0;
+               t = &tv;
+       }
+
+       memset(message, 0, sizeof(tapdisk_message_t));
+
+       while (offset < len) {
+               FD_ZERO(&readfds);
+               FD_SET(fd, &readfds);
+
+               ret = select(fd + 1, &readfds, NULL, NULL, t);
+               if (ret == -1)
+                       break;
+               else if (FD_ISSET(fd, &readfds)) {
+                       ret = read(fd, message + offset, len - offset);
+                       if (ret <= 0)
+                               break;
+                       offset += ret;
+               } else
+                       break;
+       }
+
+       if (offset != len) {
+               EPRINTF("failure reading message\n");
+               return -EIO;
+       }
+
+       DBG("received '%s' message (uuid = %u)\n",
+           tapdisk_message_name(message->type), message->cookie);
+
+       return 0;
+}
+
+int
+tap_ctl_write_message(int fd, tapdisk_message_t *message, int timeout)
+{
+       fd_set writefds;
+       int ret, len, offset;
+       struct timeval tv, *t;
+
+       t      = NULL;
+       offset = 0;
+       len    = sizeof(tapdisk_message_t);
+
+       if (timeout) {
+               tv.tv_sec  = timeout;
+               tv.tv_usec = 0;
+               t = &tv;
+       }
+
+       DBG("sending '%s' message (uuid = %u)\n",
+           tapdisk_message_name(message->type), message->cookie);
+
+       while (offset < len) {
+               FD_ZERO(&writefds);
+               FD_SET(fd, &writefds);
+
+               /* we don't bother reinitializing tv. at worst, it will wait a
+                * bit more time than expected. */
+
+               ret = select(fd + 1, NULL, &writefds, NULL, t);
+               if (ret == -1)
+                       break;
+               else if (FD_ISSET(fd, &writefds)) {
+                       ret = write(fd, message + offset, len - offset);
+                       if (ret <= 0)
+                               break;
+                       offset += ret;
+               } else
+                       break;
+       }
+
+       if (offset != len) {
+               EPRINTF("failure writing message\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+int
+tap_ctl_send_and_receive(int sfd, tapdisk_message_t *message, int timeout)
+{
+       int err;
+
+       err = tap_ctl_write_message(sfd, message, timeout);
+       if (err) {
+               EPRINTF("failed to send '%s' message\n",
+                       tapdisk_message_name(message->type));
+               return err;
+       }
+
+       err = tap_ctl_read_message(sfd, message, timeout);
+       if (err) {
+               EPRINTF("failed to receive '%s' message\n",
+                       tapdisk_message_name(message->type));
+               return err;
+       }
+
+       return 0;
+}
+
+char *
+tap_ctl_socket_name(int id)
+{
+       char *name;
+
+       if (asprintf(&name, "%s/%s%d",
+                    BLKTAP2_CONTROL_DIR, BLKTAP2_CONTROL_SOCKET, id) == -1)
+               return NULL;
+
+       return name;
+}
+
+int
+tap_ctl_connect(const char *name, int *sfd)
+{
+       int fd, err;
+       struct sockaddr_un saddr;
+
+       *sfd = -1;
+
+       fd = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (fd == -1) {
+               EPRINTF("couldn't create socket for %s: %d\n", name, errno);
+               return -errno;
+       }
+
+       memset(&saddr, 0, sizeof(saddr));
+       saddr.sun_family = AF_UNIX;
+       strcpy(saddr.sun_path, name);
+
+       err = connect(fd, (const struct sockaddr *)&saddr, sizeof(saddr));
+       if (err) {
+               EPRINTF("couldn't connect to %s: %d\n", name, errno);
+               close(fd);
+               return -errno;
+       }
+
+       *sfd = fd;
+       return 0;
+}
+
+int
+tap_ctl_connect_id(int id, int *sfd)
+{
+       int err;
+       char *name;
+
+       *sfd = -1;
+
+       if (id < 0) {
+               EPRINTF("invalid id %d\n", id);
+               return -EINVAL;
+       }
+
+       name = tap_ctl_socket_name(id);
+       if (!name) {
+               EPRINTF("couldn't name socket for %d\n", id);
+               return -ENOMEM;
+       }
+
+       err = tap_ctl_connect(name, sfd);
+       free(name);
+
+       return err;
+}
+
+int
+tap_ctl_connect_send_and_receive(int id, tapdisk_message_t *message, int 
timeout)
+{
+       int err, sfd;
+
+       err = tap_ctl_connect_id(id, &sfd);
+       if (err)
+               return err;
+
+       err = tap_ctl_send_and_receive(sfd, message, timeout);
+
+       close(sfd);
+       return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-list.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-list.c      Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <glob.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+#include "list.h"
+
+static void
+free_list(tap_list_t *entry)
+{
+       if (entry->type) {
+               free(entry->type);
+               entry->type = NULL;
+       }
+
+       if (entry->path) {
+               free(entry->path);
+               entry->path = NULL;
+       }
+
+       free(entry);
+}
+
+int
+_parse_params(const char *params, char **type, char **path)
+{
+       char *ptr;
+       size_t len;
+
+       ptr = strchr(params, ':');
+       if (!ptr)
+               return -EINVAL;
+
+       len = ptr - params;
+
+       *type = strndup(params, len);
+       *path =  strdup(params + len + 1);
+
+       if (!*type || !*path) {
+               free(*type);
+               *type = NULL;
+
+               free(*path);
+               *path = NULL;
+
+               return -errno;
+       }
+
+       return 0;
+}
+
+static int
+init_list(tap_list_t *entry,
+         int tap_id, pid_t tap_pid, int vbd_minor, int vbd_state,
+         const char *params)
+{
+       int err = 0;
+
+       entry->id     = tap_id;
+       entry->pid    = tap_pid;
+       entry->minor  = vbd_minor;
+       entry->state  = vbd_state;
+
+       if (params)
+               err = _parse_params(params, &entry->type, &entry->path);
+
+       return err;
+}
+
+void
+tap_ctl_free_list(tap_list_t **list)
+{
+       tap_list_t **_entry;
+
+       for (_entry = list; *_entry != NULL; ++_entry)
+               free_list(*_entry);
+
+       free(list);
+}
+
+static tap_list_t**
+tap_ctl_alloc_list(int n)
+{
+       tap_list_t **list, *entry;
+       size_t size;
+       int i;
+
+       size = sizeof(tap_list_t*) * (n+1);
+       list = malloc(size);
+       if (!list)
+               goto fail;
+
+       memset(list, 0, size);
+
+       for (i = 0; i < n; ++i) {
+               tap_list_t *entry;
+
+               entry = malloc(sizeof(tap_list_t));
+               if (!entry)
+                       goto fail;
+
+               memset(entry, 0, sizeof(tap_list_t));
+
+               list[i] = entry;
+       }
+
+       return list;
+
+fail:
+       if (list)
+               tap_ctl_free_list(list);
+
+       return NULL;
+}
+
+static int
+tap_ctl_list_length(const tap_list_t **list)
+{
+       const tap_list_t **_entry;
+       int n;
+
+       n = 0;
+       for (_entry = list; *_entry != NULL; ++_entry)
+               n++;
+
+       return n;
+}
+
+static int
+_tap_minor_cmp(const void *a, const void *b)
+{
+       return *(int*)a - *(int*)b;
+}
+
+int
+_tap_ctl_find_minors(int **_minorv)
+{
+       glob_t glbuf = { 0 };
+       const char *pattern, *format;
+       int *minorv = NULL, n_minors = 0;
+       int err, i;
+
+       pattern = BLKTAP2_SYSFS_DIR"/blktap*";
+       format  = BLKTAP2_SYSFS_DIR"/blktap%d";
+
+       n_minors = 0;
+       minorv   = NULL;
+
+       err = glob(pattern, 0, NULL, &glbuf);
+       switch (err) {
+       case GLOB_NOMATCH:
+               goto done;
+
+       case GLOB_ABORTED:
+       case GLOB_NOSPACE:
+               err = -errno;
+               EPRINTF("%s: glob failed, err %d", pattern, err);
+               goto fail;
+       }
+
+       minorv = malloc(sizeof(int) * glbuf.gl_pathc);
+       if (!minorv) {
+               err = -errno;
+               goto fail;
+       }
+
+       for (i = 0; i < glbuf.gl_pathc; ++i) {
+               int n;
+
+               n = sscanf(glbuf.gl_pathv[i], format, &minorv[n_minors]);
+               if (n != 1)
+                       continue;
+
+               n_minors++;
+       }
+
+       qsort(minorv, n_minors, sizeof(int), _tap_minor_cmp);
+
+done:
+       *_minorv = minorv;
+       err = 0;
+
+out:
+       if (glbuf.gl_pathv)
+               globfree(&glbuf);
+
+       return err ? : n_minors;
+
+fail:
+       if (minorv)
+               free(minorv);
+
+       goto out;
+}
+
+struct tapdisk {
+       int    id;
+       pid_t  pid;
+       struct list_head list;
+};
+
+static int
+_tap_tapdisk_cmp(const void *a, const void *b)
+{
+       return ((struct tapdisk*)a)->id - ((struct tapdisk*)b)->id;
+}
+
+int
+_tap_ctl_find_tapdisks(struct tapdisk **_tapv)
+{
+       glob_t glbuf = { 0 };
+       const char *pattern, *format;
+       struct tapdisk *tapv = NULL;
+       int err, i, n_taps = 0;
+
+       pattern = BLKTAP2_CONTROL_DIR"/"BLKTAP2_CONTROL_SOCKET"*";
+       format  = BLKTAP2_CONTROL_DIR"/"BLKTAP2_CONTROL_SOCKET"%d";
+
+       n_taps = 0;
+       tapv   = NULL;
+
+       err = glob(pattern, 0, NULL, &glbuf);
+       switch (err) {
+       case GLOB_NOMATCH:
+               goto done;
+
+       case GLOB_ABORTED:
+       case GLOB_NOSPACE:
+               err = -errno;
+               EPRINTF("%s: glob failed, err %d", pattern, err);
+               goto fail;
+       }
+
+       tapv = malloc(sizeof(struct tapdisk) * glbuf.gl_pathc);
+       if (!tapv) {
+               err = -errno;
+               goto fail;
+       }
+
+       for (i = 0; i < glbuf.gl_pathc; ++i) {
+               struct tapdisk *tap;
+               int n;
+
+               tap = &tapv[n_taps];
+
+               err = sscanf(glbuf.gl_pathv[i], format, &tap->id);
+               if (err != 1)
+                       continue;
+
+               tap->pid = tap_ctl_get_pid(tap->id);
+               if (tap->pid < 0)
+                       continue;
+
+               n_taps++;
+       }
+
+       qsort(tapv, n_taps, sizeof(struct tapdisk), _tap_tapdisk_cmp);
+
+       for (i = 0; i < n_taps; ++i)
+               INIT_LIST_HEAD(&tapv[i].list);
+
+done:
+       *_tapv = tapv;
+       err = 0;
+
+out:
+       if (glbuf.gl_pathv)
+               globfree(&glbuf);
+
+       return err ? : n_taps;
+
+fail:
+       if (tapv)
+               free(tapv);
+
+       goto out;
+}
+
+struct tapdisk_list {
+       int  minor;
+       int  state;
+       char *params;
+       struct list_head entry;
+};
+
+int
+_tap_ctl_list_tapdisk(int id, struct list_head *_list)
+{
+       tapdisk_message_t message;
+       struct list_head list;
+       struct tapdisk_list *tl, *next;
+       int err, sfd;
+
+       err = tap_ctl_connect_id(id, &sfd);
+       if (err)
+               return err;
+
+       memset(&message, 0, sizeof(message));
+       message.type   = TAPDISK_MESSAGE_LIST;
+       message.cookie = -1;
+
+       err = tap_ctl_write_message(sfd, &message, 2);
+       if (err)
+               return err;
+
+       INIT_LIST_HEAD(&list);
+       do {
+               err = tap_ctl_read_message(sfd, &message, 2);
+               if (err) {
+                       err = -EPROTO;
+                       break;
+               }
+
+               if (message.u.list.count == 0)
+                       break;
+
+               tl = malloc(sizeof(struct tapdisk_list));
+               if (!tl) {
+                       err = -ENOMEM;
+                       break;
+               }
+
+               tl->minor  = message.u.list.minor;
+               tl->state  = message.u.list.state;
+               if (message.u.list.path[0] != 0) {
+                       tl->params = strndup(message.u.list.path,
+                                            sizeof(message.u.list.path));
+                       if (!tl->params) {
+                               err = -errno;
+                               break;
+                       }
+               } else
+                       tl->params = NULL;
+
+               list_add(&tl->entry, &list);
+       } while (1);
+
+       if (err)
+               list_for_each_entry_safe(tl, next, &list, entry) {
+                       list_del(&tl->entry);
+                       free(tl->params);
+                       free(tl);
+               }
+
+       close(sfd);
+       list_splice(&list, _list);
+       return err;
+}
+
+void
+_tap_ctl_free_tapdisks(struct tapdisk *tapv, int n_taps)
+{
+       struct tapdisk *tap;
+
+       for (tap = tapv; tap < &tapv[n_taps]; ++tap) {
+               struct tapdisk_list *tl;
+
+               list_for_each_entry(tl, &tap->list, entry) {
+                       free(tl->params);
+                       free(tl);
+               }
+       }
+
+       free(tapv);
+}
+
+int
+_tap_list_join3(int n_minors, int *minorv, int n_taps, struct tapdisk *tapv,
+               tap_list_t ***_list)
+{
+       tap_list_t **list, **_entry, *entry;
+       int i, _m, err;
+
+       list = tap_ctl_alloc_list(n_minors + n_taps);
+       if (!list) {
+               err = -ENOMEM;
+               goto fail;
+       }
+
+       _entry = list;
+
+       for (i = 0; i < n_taps; ++i) {
+               struct tapdisk *tap = &tapv[i];
+               struct tapdisk_list *tl;
+
+               /* orphaned tapdisk */
+               if (list_empty(&tap->list)) {
+                       err = init_list(*_entry++, tap->id, tap->pid, -1, -1, 
NULL);
+                       if (err)
+                               goto fail;
+                       continue;
+               }
+
+               list_for_each_entry(tl, &tap->list, entry) {
+
+                       err = init_list(*_entry++,
+                                       tap->id, tap->pid,
+                                       tl->minor, tl->state, tl->params);
+                       if (err)
+                               goto fail;
+
+                       if (tl->minor >= 0) {
+                               /* clear minor */
+                               for (_m = 0; _m < n_minors; ++_m) {
+                                       if (minorv[_m] == tl->minor) {
+                                               minorv[_m] = -1;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* orphaned minors */
+       for (_m = 0; _m < n_minors; ++_m) {
+               int minor = minorv[_m];
+               if (minor >= 0) {
+                       err = init_list(*_entry++, -1, -1, minor, -1, NULL);
+                       if (err)
+                               goto fail;
+               }
+       }
+
+       /* free extraneous list entries */
+       for (; *_entry != NULL; ++entry) {
+               free_list(*_entry);
+               *_entry = NULL;
+       }
+
+       *_list = list;
+
+       return 0;
+
+fail:
+       if (list)
+               tap_ctl_free_list(list);
+
+       return err;
+}
+
+int
+tap_ctl_list(tap_list_t ***list)
+{
+       int n_taps, n_minors, err, *minorv;
+       struct tapdisk *tapv, *tap;
+
+       n_taps   = -1;
+       n_minors = -1;
+
+       err = n_minors = _tap_ctl_find_minors(&minorv);
+       if (err < 0)
+               goto out;
+
+       err = n_taps = _tap_ctl_find_tapdisks(&tapv);
+       if (err < 0)
+               goto out;
+
+       for (tap = tapv; tap < &tapv[n_taps]; ++tap) {
+               err = _tap_ctl_list_tapdisk(tap->id, &tap->list);
+               if (err)
+                       goto out;
+       }
+
+       err = _tap_list_join3(n_minors, minorv, n_taps, tapv, list);
+
+out:
+       if (n_taps > 0)
+               _tap_ctl_free_tapdisks(tapv, n_taps);
+
+       if (n_minors > 0)
+               free(minorv);
+
+       return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-major.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-major.c     Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "tap-ctl.h"
+
+int
+tap_ctl_blk_major(void)
+{
+       FILE *devices;
+       int rv, major;
+
+       devices = fopen("/proc/devices", "r");
+       if (!devices) {
+               rv = -errno;
+               goto out;
+       }
+
+       do {
+               char buf[32], *s;
+               int n, offset;
+
+               s = fgets(buf, sizeof(buf), devices);
+               if (!s)
+                       break;
+
+               major  = -ENODEV;
+               offset = 0;
+
+               n = sscanf(buf, "%d tapdev%n", &major, &offset);
+               if (n == 1 && offset)
+                       break;
+       } while (1);
+
+       rv = major;
+
+out:
+       if (devices)
+               fclose(devices);
+
+       return rv;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-open.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-open.c      Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+#include "blktaplib.h"
+
+int
+tap_ctl_open(const int id, const int minor, const char *params)
+{
+       int err;
+       tapdisk_message_t message;
+
+       memset(&message, 0, sizeof(message));
+       message.type = TAPDISK_MESSAGE_OPEN;
+       message.cookie = minor;
+       message.u.params.storage = TAPDISK_STORAGE_TYPE_DEFAULT;
+       message.u.params.devnum = minor;
+
+       err = snprintf(message.u.params.path,
+                      sizeof(message.u.params.path) - 1, "%s", params);
+       if (err >= sizeof(message.u.params.path)) {
+               EPRINTF("name too long\n");
+               return ENAMETOOLONG;
+       }
+
+       err = tap_ctl_connect_send_and_receive(id, &message, 5);
+       if (err)
+               return err;
+
+       switch (message.type) {
+       case TAPDISK_MESSAGE_OPEN_RSP:
+               break;
+       case TAPDISK_MESSAGE_ERROR:
+               err = -message.u.response.error;
+               EPRINTF("open failed, err %d\n", err);
+               break;
+       default:
+               EPRINTF("got unexpected result '%s' from %d\n",
+                       tapdisk_message_name(message.type), id);
+               err = EINVAL;
+       }
+
+       return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-pause.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-pause.c     Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "tap-ctl.h"
+
+int
+tap_ctl_pause(const int id, const int minor)
+{
+       int err;
+       tapdisk_message_t message;
+
+       memset(&message, 0, sizeof(message));
+       message.type = TAPDISK_MESSAGE_PAUSE;
+       message.cookie = minor;
+
+       err = tap_ctl_connect_send_and_receive(id, &message, 5);
+       if (err)
+               return err;
+
+       if (message.type == TAPDISK_MESSAGE_PAUSE_RSP)
+               err = message.u.response.error;
+       else {
+               err = EINVAL;
+               EPRINTF("got unexpected result '%s' from %d\n",
+                       tapdisk_message_name(message.type), id);
+       }
+
+       return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-spawn.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-spawn.c     Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+
+#include "tap-ctl.h"
+#include "blktap2.h"
+
+static pid_t
+__tap_ctl_spawn(int *readfd)
+{
+       int err, child, channel[2];
+       char *tapdisk;
+
+       if (pipe(channel)) {
+               EPRINTF("pipe failed: %d\n", errno);
+               return -errno;
+       }
+
+       if ((child = fork()) == -1) {
+               EPRINTF("fork failed: %d\n", errno);
+               return -errno;
+       }
+
+       if (child) {
+               close(channel[1]);
+               *readfd = channel[0];
+               return child;
+       }
+
+       if (dup2(channel[1], STDOUT_FILENO) == -1) {
+               EPRINTF("dup2 failed: %d\n", errno);
+               exit(errno);
+       }
+
+       if (dup2(channel[1], STDERR_FILENO) == -1) {
+               EPRINTF("dup2 failed: %d\n", errno);
+               exit(errno);
+       }
+
+       close(channel[0]);
+       close(channel[1]);
+
+       tapdisk = getenv("TAPDISK2");
+       if (!tapdisk)
+               tapdisk = "tapdisk2";
+
+       execlp(tapdisk, tapdisk, NULL);
+
+       EPRINTF("exec failed\n");
+       exit(1);
+}
+
+pid_t
+tap_ctl_get_pid(const int id)
+{
+       int err;
+       tapdisk_message_t message;
+
+       memset(&message, 0, sizeof(message));
+       message.type = TAPDISK_MESSAGE_PID;
+
+       err = tap_ctl_connect_send_and_receive(id, &message, 2);
+       if (err)
+               return err;
+
+       return message.u.tapdisk_pid;
+}
+
+static int
+tap_ctl_wait(pid_t child)
+{
+       pid_t pid;
+       int status;
+
+       pid = waitpid(child, &status, 0);
+       if (pid < 0) {
+               EPRINTF("wait(%d) failed, err %d\n", child, errno);
+               return -errno;
+       }
+
+       if (WIFEXITED(status)) {
+               int code = WEXITSTATUS(status);
+               if (code)
+                       EPRINTF("tapdisk2[%d] failed, status %d\n", child, 
code);
+               return -code;
+       }
+
+       if (WIFSIGNALED(status)) {
+               int signo = WTERMSIG(status);
+               EPRINTF("tapdisk2[%d] killed by signal %d\n", child, signo);
+               return -EINTR;
+       }
+
+       EPRINTF("tapdisk2[%d]: unexpected status %#x\n", child, status);
+       return -EAGAIN;
+}
+
+static int
+tap_ctl_get_child_id(int readfd)
+{
+       int id;
+       FILE *f;
+
+       f = fdopen(readfd, "r");
+       if (!f) {
+               EPRINTF("fdopen failed: %d\n", errno);
+               return -1;
+       }
+
+       errno = 0;
+       if (fscanf(f, BLKTAP2_CONTROL_DIR"/"
+                  BLKTAP2_CONTROL_SOCKET"%d", &id) != 1) {
+               errno = (errno ? : EINVAL);
+               EPRINTF("parsing id failed: %d\n", errno);
+               id = -1;
+       }
+
+       fclose(f);
+       return id;
+}
+
+int
+tap_ctl_spawn(void)
+{
+       pid_t child;
+       int err, id, readfd;
+
+       readfd = -1;
+
+       child = __tap_ctl_spawn(&readfd);
+       if (child < 0)
+               return child;
+
+       err = tap_ctl_wait(child);
+       if (err)
+               return err;
+
+       id = tap_ctl_get_child_id(readfd);
+       if (id < 0)
+               EPRINTF("get_id failed, child %d err %d\n", child, errno);
+
+       return id;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl-unpause.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl-unpause.c   Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+
+int
+tap_ctl_unpause(const int id, const int minor, const char *params)
+{
+       int err;
+       tapdisk_message_t message;
+
+       memset(&message, 0, sizeof(message));
+       message.type = TAPDISK_MESSAGE_RESUME;
+       message.cookie = minor;
+
+       if (params)
+               strncpy(message.u.params.path, params,
+                       sizeof(message.u.params.path) - 1);
+
+       err = tap_ctl_connect_send_and_receive(id, &message, 15);
+       if (err)
+               return err;
+
+       if (message.type == TAPDISK_MESSAGE_RESUME_RSP)
+               err = message.u.response.error;
+       else {
+               err = EINVAL;
+               EPRINTF("got unexpected result '%s' from %d\n",
+                       tapdisk_message_name(message.type), id);
+       }
+
+       return err;
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl.c   Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,815 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "tap-ctl.h"
+
+typedef int (*tap_ctl_func_t) (int, char **);
+
+struct command {
+       char                     *name;
+       tap_ctl_func_t            func;
+};
+
+static void
+tap_cli_list_usage(FILE *stream)
+{
+       fprintf(stream,
+               "usage: list [-h] [-p pid] [-m minor] [-t type] [-f file]\n");
+}
+
+static void
+tap_ctl_list_row(tap_list_t *entry)
+{
+       char minor_str[10] = "-";
+       char state_str[10] = "-";
+       char pid_str[10]   = "-";
+
+       if (entry->pid != -1)
+               sprintf(pid_str, "%d", entry->pid);
+
+       if (entry->minor != -1)
+               sprintf(minor_str, "%d", entry->minor);
+
+       if (entry->state != -1)
+               sprintf(state_str, "%x", entry->state);
+
+       printf("%8s %2s %4s %10s %s\n",
+              pid_str, minor_str, state_str,
+              entry->type ? : "-", entry->path ? : "-");
+}
+
+static void
+tap_ctl_list_dict(tap_list_t *entry)
+{
+       int d = 0;
+
+       if (entry->pid != -1) {
+               if (d) putc(' ', stdout);
+               d = printf("pid=%d", entry->pid);
+       }
+
+       if (entry->minor != -1) {
+               if (d) putc(' ', stdout);
+               d = printf("minor=%d", entry->minor);
+       }
+
+       if (entry->state != -1) {
+               if (d) putc(' ', stdout);
+               d = printf("state=%d", entry->state);
+       }
+
+       if (entry->type && entry->path) {
+               if (d) putc(' ', stdout);
+               d = printf("args=%s:%s", entry->type, entry->path);
+       }
+
+       putc('\n', stdout);
+}
+
+int
+tap_cli_list(int argc, char **argv)
+{
+       tap_list_t **list, **_entry;
+       int c, minor, tty, err;
+       const char *type, *file;
+       pid_t pid;
+
+       err = tap_ctl_list(&list);
+       if (err)
+               return -err;
+
+       pid   = -1;
+       minor = -1;
+       type  = NULL;
+       file  = NULL;
+
+       while ((c = getopt(argc, argv, "m:p:t:f:h")) != -1) {
+               switch (c) {
+               case 'm':
+                       minor = atoi(optarg);
+                       break;
+               case 'p':
+                       pid = atoi(optarg);
+                       break;
+               case 't':
+                       type = optarg;
+                       break;
+               case 'f':
+                       file = optarg;
+                       break;
+               case '?':
+                       goto usage;
+               case 'h':
+                       tap_cli_list_usage(stdout);
+                       return 0;
+               }
+       }
+
+       tty = isatty(STDOUT_FILENO);
+
+       for (_entry = list; *_entry != NULL; ++_entry) {
+               tap_list_t *entry  = *_entry;
+
+               if (minor >= 0 && entry->minor != minor)
+                       continue;
+
+               if (pid >= 0 && entry->pid != pid)
+                       continue;
+
+               if (type && entry->type && strcmp(entry->type, type))
+                       continue;
+
+               if (file && entry->path && strcmp(entry->path, file))
+                       continue;
+
+               if (tty)
+                       tap_ctl_list_row(entry);
+               else
+                       tap_ctl_list_dict(entry);
+       }
+
+       tap_ctl_free_list(list);
+
+       return 0;
+
+usage:
+       tap_cli_list_usage(stderr);
+       return EINVAL;
+}
+
+static void
+tap_cli_allocate_usage(FILE *stream)
+{
+       fprintf(stream, "usage: allocate [-d device name]>\n");
+}
+
+static int
+tap_cli_allocate(int argc, char **argv)
+{
+       char *devname;
+       int c, minor, err;
+
+       devname = NULL;
+
+       optind = 0;
+       while ((c = getopt(argc, argv, "d:h")) != -1) {
+               switch (c) {
+               case 'd':
+                       devname = optarg;
+                       break;
+               case '?':
+                       goto usage;
+               case 'h':
+                       tap_cli_allocate_usage(stdout);
+                       return 0;
+               }
+       }
+
+       err = tap_ctl_allocate(&minor, &devname);
+       if (!err)
+               printf("%s\n", devname);
+
+       return err;
+
+usage:
+       tap_cli_allocate_usage(stderr);
+       return EINVAL;
+}
+
+static void
+tap_cli_free_usage(FILE *stream)
+{
+       fprintf(stream, "usage: free <-m minor>\n");
+}
+
+static int
+tap_cli_free(int argc, char **argv)
+{
+       int c, minor;
+
+       minor = -1;
+
+       optind = 0;
+       while ((c = getopt(argc, argv, "m:h")) != -1) {
+               switch (c) {
+               case 'm':
+                       minor = atoi(optarg);
+                       break;
+               case '?':
+                       goto usage;
+               case 'h':
+                       tap_cli_free_usage(stdout);
+                       return 0;
+               }
+       }
+
+       if (minor == -1)
+               goto usage;
+
+       return tap_ctl_free(minor);
+
+usage:
+       tap_cli_free_usage(stderr);
+       return EINVAL;
+}
+
+static void
+tap_cli_create_usage(FILE *stream)
+{
+       fprintf(stream, "usage: create <-a args> [-d device name]\n");
+}
+
+static int
+tap_cli_create(int argc, char **argv)
+{
+       int c, err;
+       char *args, *devname;
+
+       args    = NULL;
+       devname = NULL;
+
+       optind = 0;
+       while ((c = getopt(argc, argv, "a:d:h")) != -1) {
+               switch (c) {
+               case 'a':
+                       args = optarg;
+                       break;
+               case 'd':
+                       devname = optarg;
+                       break;
+               case '?':
+                       goto usage;
+               case 'h':
+                       tap_cli_create_usage(stdout);
+                       return 0;
+               }
+       }
+
+       if (!args)
+               goto usage;
+
+       err = tap_ctl_create(args, &devname);
+       if (!err)
+               printf("%s\n", devname);
+
+       return err;
+
+usage:
+       tap_cli_create_usage(stderr);
+       return EINVAL;
+}
+
+static void
+tap_cli_destroy_usage(FILE *stream)
+{
+       fprintf(stream, "usage: destroy <-p pid> <-m minor>\n");
+}
+
+static int
+tap_cli_destroy(int argc, char **argv)
+{
+       int c, pid, minor;
+
+       pid   = -1;
+       minor = -1;
+
+       optind = 0;
+       while ((c = getopt(argc, argv, "p:m:h")) != -1) {
+               switch (c) {
+               case 'p':
+                       pid = atoi(optarg);
+                       break;
+               case 'm':
+                       minor = atoi(optarg);
+                       break;
+               case '?':
+                       goto usage;
+               case 'h':
+                       tap_cli_destroy_usage(stdout);
+                       return 0;
+               }
+       }
+
+       if (pid == -1 || minor == -1)
+               goto usage;
+
+       return tap_ctl_destroy(pid, minor);
+
+usage:
+       tap_cli_destroy_usage(stderr);
+       return EINVAL;
+}
+
+static void
+tap_cli_spawn_usage(FILE *stream)
+{
+       fprintf(stream, "usage: spawn\n");
+}
+
+static int
+tap_cli_spawn(int argc, char **argv)
+{
+       int c;
+       pid_t task;
+
+       optind = 0;
+       while ((c = getopt(argc, argv, "h")) != -1) {
+               switch (c) {
+               case '?':
+                       goto usage;
+               case 'h':
+                       tap_cli_spawn_usage(stdout);
+                       return 0;
+               }
+       }
+
+       task = tap_ctl_spawn();
+       if (task < 0) {
+               printf("spawn failed: %d\n", errno);
+               return task;
+       }
+
+       printf("tapdisk spawned with pid %d\n", task);
+       return 0;
+
+usage:
+       tap_cli_spawn_usage(stderr);
+       return EINVAL;
+}
+
+static void
+tap_cli_attach_usage(FILE *stream)
+{
+       fprintf(stream, "usage: attach <-p pid> <-m minor>\n");
+}
+
+static int
+tap_cli_attach(int argc, char **argv)
+{
+       int c, pid, minor;
+
+       pid   = -1;
+       minor = -1;
+
+       optind = 0;
+       while ((c = getopt(argc, argv, "p:m:h")) != -1) {
+               switch (c) {
+               case 'p':
+                       pid = atoi(optarg);
+                       break;
+               case 'm':
+                       minor = atoi(optarg);
+                       break;
+               case '?':
+                       goto usage;
+               case 'h':
+                       tap_cli_attach_usage(stderr);
+                       return 0;
+               }
+       }
+
+       if (pid == -1 || minor == -1)
+               goto usage;
+
+       return tap_ctl_attach(pid, minor);
+
+usage:
+       tap_cli_attach_usage(stderr);
+       return EINVAL;
+}
+
+static void
+tap_cli_detach_usage(FILE *stream)
+{
+       fprintf(stream, "usage: detach <-p pid> <-m minor>\n");
+}
+
+static int
+tap_cli_detach(int argc, char **argv)
+{
+       int c, pid, minor;
+
+       pid   = -1;
+       minor = -1;
+
+       optind = 0;
+       while ((c = getopt(argc, argv, "p:m:h")) != -1) {
+               switch (c) {
+               case 'p':
+                       pid = atoi(optarg);
+                       break;
+               case 'm':
+                       minor = atoi(optarg);
+                       break;
+               case '?':
+                       goto usage;
+               case 'h':
+                       tap_cli_detach_usage(stdout);
+                       return 0;
+               }
+       }
+
+       if (pid == -1 || minor == -1)
+               goto usage;
+
+       return tap_ctl_detach(pid, minor);
+
+usage:
+       tap_cli_detach_usage(stderr);
+       return EINVAL;
+}
+
+static void
+tap_cli_close_usage(FILE *stream)
+{
+       fprintf(stream, "usage: close <-p pid> <-m minor> [-f force]\n");
+}
+
+static int
+tap_cli_close(int argc, char **argv)
+{
+       int c, pid, minor, force;
+
+       pid   = -1;
+       minor = -1;
+       force = 0;
+
+       optind = 0;
+       while ((c = getopt(argc, argv, "p:m:fh")) != -1) {
+               switch (c) {
+               case 'p':
+                       pid = atoi(optarg);
+                       break;
+               case 'm':
+                       minor = atoi(optarg);
+                       break;
+               case 'f':
+                       force = -1;
+                       break;
+               case '?':
+                       goto usage;
+               case 'h':
+                       tap_cli_close_usage(stdout);
+                       return 0;
+               }
+       }
+
+       if (pid == -1 || minor == -1)
+               goto usage;
+
+       return tap_ctl_close(pid, minor, force);
+
+usage:
+       tap_cli_close_usage(stderr);
+       return EINVAL;
+}
+
+static void
+tap_cli_pause_usage(FILE *stream)
+{
+       fprintf(stream, "usage: pause <-p pid> <-m minor>\n");
+}
+
+static int
+tap_cli_pause(int argc, char **argv)
+{
+       int c, pid, minor;
+
+       pid   = -1;
+       minor = -1;
+
+       optind = 0;
+       while ((c = getopt(argc, argv, "p:m:h")) != -1) {
+               switch (c) {
+               case 'p':
+                       pid = atoi(optarg);
+                       break;
+               case 'm':
+                       minor = atoi(optarg);
+                       break;
+               case '?':
+                       goto usage;
+               case 'h':
+                       tap_cli_pause_usage(stdout);
+                       return 0;
+               }
+       }
+
+       if (pid == -1 || minor == -1)
+               goto usage;
+
+       return tap_ctl_pause(pid, minor);
+
+usage:
+       tap_cli_pause_usage(stderr);
+       return EINVAL;
+}
+
+static void
+tap_cli_unpause_usage(FILE *stream)
+{
+       fprintf(stream, "usage: unpause <-p pid> <-m minor> [-a args]\n");
+}
+
+int
+tap_cli_unpause(int argc, char **argv)
+{
+       const char *args;
+       int c, pid, minor;
+
+       pid   = -1;
+       minor = -1;
+       args  = NULL;
+
+       optind = 0;
+       while ((c = getopt(argc, argv, "p:m:a:h")) != -1) {
+               switch (c) {
+               case 'p':
+                       pid = atoi(optarg);
+                       break;
+               case 'm':
+                       minor = atoi(optarg);
+                       break;
+               case 'a':
+                       args = optarg;
+                       break;
+               case '?':
+                       goto usage;
+               case 'h':
+                       tap_cli_unpause_usage(stdout);
+                       return 0;
+               }
+       }
+
+       if (pid == -1 || minor == -1)
+               goto usage;
+
+       return tap_ctl_unpause(pid, minor, args);
+
+usage:
+       tap_cli_unpause_usage(stderr);
+       return EINVAL;
+}
+
+static void
+tap_cli_major_usage(FILE *stream)
+{
+       fprintf(stream, "usage: major [-h]\n");
+}
+
+static int
+tap_cli_major(int argc, char **argv)
+{
+       int c, chr, major;
+
+       chr = 0;
+
+       while ((c = getopt(argc, argv, "bch")) != -1) {
+               switch (c) {
+               case 'b':
+                       chr = 0;
+                       break;
+               case 'c':
+                       chr = 1;
+                       break;
+               case '?':
+                       goto usage;
+               case 'h':
+                       tap_cli_major_usage(stdout);
+                       return 0;
+               default:
+                       goto usage;
+               }
+       }
+
+       if (chr)
+               major = -EINVAL;
+       else
+               major = tap_ctl_blk_major();
+
+       if (major < 0)
+               return -major;
+
+       printf("%d\n", major);
+
+       return 0;
+
+usage:
+       tap_cli_major_usage(stderr);
+       return EINVAL;
+}
+
+static void
+tap_cli_open_usage(FILE *stream)
+{
+       fprintf(stream, "usage: open <-p pid> <-m minor> <-a args>\n");
+}
+
+static int
+tap_cli_open(int argc, char **argv)
+{
+       const char *args;
+       int c, pid, minor;
+
+       pid   = -1;
+       minor = -1;
+       args  = NULL;
+
+       optind = 0;
+       while ((c = getopt(argc, argv, "a:m:p:h")) != -1) {
+               switch (c) {
+               case 'p':
+                       pid = atoi(optarg);
+                       break;
+               case 'm':
+                       minor = atoi(optarg);
+                       break;
+               case 'a':
+                       args = optarg;
+                       break;
+               case '?':
+                       goto usage;
+               case 'h':
+                       tap_cli_open_usage(stdout);
+                       return 0;
+               }
+       }
+
+       if (pid == -1 || minor == -1 || !args)
+               goto usage;
+
+       return tap_ctl_open(pid, minor, args);
+
+usage:
+       tap_cli_open_usage(stderr);
+       return EINVAL;
+}
+
+static void
+tap_cli_check_usage(FILE *stream)
+{
+       fprintf(stream, "usage: check\n"
+               "(checks whether environment is suitable for tapdisk2)\n");
+}
+
+static int
+tap_cli_check(int argc, char **argv)
+{
+       int err;
+       const char *msg;
+
+       if (argc != 1)
+               goto usage;
+
+       err = tap_ctl_check(&msg);
+       printf("%s\n", msg);
+
+       return err;
+
+usage:
+       tap_cli_check_usage(stderr);
+       return EINVAL;
+}
+
+struct command commands[] = {
+       { .name = "list",         .func = tap_cli_list          },
+       { .name = "allocate",     .func = tap_cli_allocate      },
+       { .name = "free",         .func = tap_cli_free          },
+       { .name = "create",       .func = tap_cli_create        },
+       { .name = "destroy",      .func = tap_cli_destroy       },
+       { .name = "spawn",        .func = tap_cli_spawn         },
+       { .name = "attach",       .func = tap_cli_attach        },
+       { .name = "detach",       .func = tap_cli_detach        },
+       { .name = "open",         .func = tap_cli_open          },
+       { .name = "close",        .func = tap_cli_close         },
+       { .name = "pause",        .func = tap_cli_pause         },
+       { .name = "unpause",      .func = tap_cli_unpause       },
+       { .name = "major",        .func = tap_cli_major         },
+       { .name = "check",        .func = tap_cli_check         },
+};
+
+#define print_commands()                                       \
+       do {                                                    \
+               int i, n;                                       \
+               n = sizeof(commands) / sizeof(struct command);  \
+               printf("COMMAND := { ");                        \
+               printf("%s", commands[0].name);                 \
+               for (i = 1; i < n; i++)                         \
+                       printf(" | %s", commands[i].name);      \
+               printf(" }\n");                                 \
+       } while (0)
+
+void
+help(void)
+{
+       printf("usage: tap-ctl COMMAND [OPTIONS]\n");
+       print_commands();
+       exit(0);
+}
+
+struct command *
+get_command(char *command)
+{
+       int i, n;
+
+       if (strnlen(command, 25) >= 25)
+               return NULL;
+
+       n = sizeof(commands) / sizeof (struct command);
+
+       for (i = 0; i < n; i++)
+               if (!strcmp(command, commands[i].name))
+                       return &commands[i];
+
+       return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+       char **cargv;
+       const char *msg;
+       struct command *cmd;
+       int cargc, i, cnt, ret;
+
+#ifdef CORE_DUMP
+       #include <sys/resource.h>
+       struct rlimit rlim;
+       rlim.rlim_cur = RLIM_INFINITY;
+       rlim.rlim_max = RLIM_INFINITY;
+       if (setrlimit(RLIMIT_CORE, &rlim) < 0)
+               PERROR("setrlimit failed");
+#endif
+
+       ret = 0;
+
+       if (argc < 2)
+               help();
+
+       cargc = argc - 1;
+       cmd   = get_command(argv[1]);
+       if (!cmd) {
+               EPRINTF("invalid COMMAND %s", argv[1]);
+               help();
+       }
+
+       ret = tap_ctl_check(&msg);
+       if (ret) {
+               printf("%s\n", msg);
+               return ret;
+       }
+
+       cargv = malloc(sizeof(char *) * cargc);
+       if (!cargv)
+               exit(ENOMEM);
+
+       cnt      = 1;
+       cargv[0] = cmd->name;
+       for (i = 1; i < cargc; i++) {
+               char *arg = argv[i + (argc - cargc)];
+
+               if (!strcmp(arg, "--debug")) {
+                       tap_ctl_debug = 1;
+                       continue;
+               }
+
+               cargv[cnt++] = arg;
+       }
+
+       ret = cmd->func(cnt, cargv);
+
+       free(cargv);
+
+       return (ret >= 0 ? ret : -ret);
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/control/tap-ctl.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/control/tap-ctl.h   Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __TAP_CTL_H__
+#define __TAP_CTL_H__
+
+#include <syslog.h>
+#include <errno.h>
+
+#include "tapdisk-message.h"
+
+extern int tap_ctl_debug;
+
+#ifdef TAPCTL
+#define DBG(_f, _a...)                         \
+       do {                                    \
+               if (tap_ctl_debug)              \
+                       printf(_f, ##_a);       \
+       } while (0)
+
+#define DPRINTF(_f, _a...) syslog(LOG_INFO, _f, ##_a)
+#define EPRINTF(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f, __func__, ##_a)
+#define  PERROR(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f ": %s", __func__, 
##_a, \
+                                 strerror(errno))
+#endif
+
+void tap_ctl_version(int *major, int *minor);
+int tap_ctl_kernel_version(int *major, int *minor);
+
+int tap_ctl_check_blktap(const char **message);
+int tap_ctl_check_version(const char **message);
+int tap_ctl_check(const char **message);
+
+int tap_ctl_connect(const char *path, int *socket);
+int tap_ctl_connect_id(int id, int *socket);
+int tap_ctl_read_message(int fd, tapdisk_message_t *message, int timeout);
+int tap_ctl_write_message(int fd, tapdisk_message_t *message, int timeout);
+int tap_ctl_send_and_receive(int fd, tapdisk_message_t *message, int timeout);
+int tap_ctl_connect_send_and_receive(int id,
+                                    tapdisk_message_t *message, int timeout);
+char *tap_ctl_socket_name(int id);
+
+typedef struct {
+       int         id;
+       pid_t       pid;
+       int         minor;
+       int         state;
+       char       *type;
+       char       *path;
+} tap_list_t;
+
+int tap_ctl_get_driver_id(const char *handle);
+
+int tap_ctl_list(tap_list_t ***list);
+void tap_ctl_free_list(tap_list_t **list);
+
+int tap_ctl_allocate(int *minor, char **devname);
+int tap_ctl_free(const int minor);
+
+int tap_ctl_create(const char *params, char **devname);
+int tap_ctl_destroy(const int id, const int minor);
+
+int tap_ctl_spawn(void);
+pid_t tap_ctl_get_pid(const int id);
+
+int tap_ctl_attach(const int id, const int minor);
+int tap_ctl_detach(const int id, const int minor);
+
+int tap_ctl_open(const int id, const int minor, const char *params);
+int tap_ctl_close(const int id, const int minor, const int force);
+
+int tap_ctl_pause(const int id, const int minor);
+int tap_ctl_unpause(const int id, const int minor, const char *params);
+
+int tap_ctl_blk_major(void);
+
+#endif
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/Makefile
--- a/tools/blktap2/drivers/Makefile    Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/drivers/Makefile    Tue Jun 08 08:05:09 2010 +0100
@@ -12,8 +12,7 @@ CFLAGS    += -Werror -g -O0
 CFLAGS    += -Werror -g -O0
 CFLAGS    += -Wno-unused
 CFLAGS    += -fno-strict-aliasing
-CFLAGS    += -I../lib -I../../libxc
-CFLAGS    += -I../include -I../../include
+CFLAGS    += -I$(BLKTAP_ROOT)/include -I$(BLKTAP_ROOT)/drivers
 CFLAGS    += $(CFLAGS_libxenctrl)
 CFLAGS    += -I $(LIBAIO_DIR)
 CFLAGS    += -I $(MEMSHR_DIR)
@@ -63,6 +62,7 @@ PORTABLE-OBJS-$(CONFIG_NetBSD) += blk_ne
 
 TAP-OBJS-y  := scheduler.o
 TAP-OBJS-y  += tapdisk-vbd.o
+TAP-OBJS-y  += tapdisk-control.o
 TAP-OBJS-y  += tapdisk-image.o
 TAP-OBJS-y  += tapdisk-driver.o
 TAP-OBJS-y  += tapdisk-disktype.o
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/blktap2.h
--- a/tools/blktap2/drivers/blktap2.h   Tue Jun 08 08:04:36 2010 +0100
+++ /dev/null   Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2008, XenSource Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * Neither the name of XenSource Inc. nor the names of its contributors
- *       may be used to endorse or promote products derived from this software
- *       without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef _BLKTAP_2_H_
-#define _BLKTAP_2_H_
-
-#define MISC_MAJOR_NUMBER              10
-
-#define BLKTAP2_MAX_MESSAGE_LEN        256
-
-#define BLKTAP2_RING_MESSAGE_PAUSE     1
-#define BLKTAP2_RING_MESSAGE_RESUME    2
-#define BLKTAP2_RING_MESSAGE_CLOSE     3
-
-#define BLKTAP2_IOCTL_KICK_FE          1
-#define BLKTAP2_IOCTL_ALLOC_TAP        200
-#define BLKTAP2_IOCTL_FREE_TAP         201
-#define BLKTAP2_IOCTL_CREATE_DEVICE    202
-#define BLKTAP2_IOCTL_SET_PARAMS       203
-#define BLKTAP2_IOCTL_PAUSE            204
-#define BLKTAP2_IOCTL_REOPEN           205
-#define BLKTAP2_IOCTL_RESUME           206
-
-#define BLKTAP2_CONTROL_NAME           "blktap-control"
-#define BLKTAP2_DIRECTORY              "/dev/xen/blktap-2"
-#define BLKTAP2_CONTROL_DEVICE         BLKTAP2_DIRECTORY"/control"
-#define BLKTAP2_RING_DEVICE            BLKTAP2_DIRECTORY"/blktap"
-#define BLKTAP2_IO_DEVICE              BLKTAP2_DIRECTORY"/tapdev"
-
-struct blktap2_handle {
-       unsigned int                   ring;
-       unsigned int                   device;
-       unsigned int                   minor;
-};
-
-struct blktap2_params {
-       char                           name[BLKTAP2_MAX_MESSAGE_LEN];
-       unsigned long long             capacity;
-       unsigned long                  sector_size;
-};
-
-#endif
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/tapdisk-control.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/drivers/tapdisk-control.c   Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,836 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include "list.h"
+#include "tapdisk.h"
+#include "blktap2.h"
+#include "blktaplib.h"
+#include "tapdisk-vbd.h"
+#include "tapdisk-utils.h"
+#include "tapdisk-server.h"
+#include "tapdisk-message.h"
+#include "tapdisk-disktype.h"
+
+struct tapdisk_control {
+       char              *path;
+       int                socket;
+       int                event_id;
+};
+
+struct tapdisk_control_connection {
+       int                socket;
+       event_id_t         event_id;
+};
+
+static struct tapdisk_control td_control;
+
+static void
+tapdisk_control_initialize(void)
+{
+       td_control.socket   = -1;
+       td_control.event_id = -1;
+
+       signal(SIGPIPE, SIG_IGN);
+}
+
+void
+tapdisk_control_close(void)
+{
+       if (td_control.path) {
+               unlink(td_control.path);
+               free(td_control.path);
+               td_control.path = NULL;
+       }
+
+       if (td_control.socket != -1) {
+               close(td_control.socket);
+               td_control.socket = -1;
+       }
+}
+
+static struct tapdisk_control_connection *
+tapdisk_control_allocate_connection(int fd)
+{
+       struct tapdisk_control_connection *connection;
+       size_t sz;
+
+       connection = calloc(1, sizeof(*connection));
+       if (!connection) {
+               EPRINTF("calloc");
+               return NULL;
+       }
+
+       connection->socket = fd;
+       return connection;
+}
+
+static void
+tapdisk_control_close_connection(struct tapdisk_control_connection *connection)
+{
+       tapdisk_server_unregister_event(connection->event_id);
+       close(connection->socket);
+       free(connection);
+}
+
+static int
+tapdisk_control_read_message(int fd, tapdisk_message_t *message, int timeout)
+{
+       fd_set readfds;
+       int ret, len, offset;
+       struct timeval tv, *t;
+
+       t      = NULL;
+       offset = 0;
+       len    = sizeof(tapdisk_message_t);
+
+       if (timeout) {
+               tv.tv_sec  = timeout;
+               tv.tv_usec = 0;
+               t = &tv;
+       }
+
+       memset(message, 0, sizeof(tapdisk_message_t));
+
+       while (offset < len) {
+               FD_ZERO(&readfds);
+               FD_SET(fd, &readfds);
+
+               ret = select(fd + 1, &readfds, NULL, NULL, t);
+               if (ret == -1)
+                       break;
+               else if (FD_ISSET(fd, &readfds)) {
+                       ret = read(fd, message + offset, len - offset);
+                       if (ret <= 0)
+                               break;
+                       offset += ret;
+               } else
+                       break;
+       }
+
+       if (offset != len) {
+               EPRINTF("failure reading message (wanted %d but got %d)\n",
+                       len, offset);
+               return -EIO;
+       }
+
+       DPRINTF("received '%s' message (uuid = %u)\n",
+               tapdisk_message_name(message->type), message->cookie);
+
+       return 0;
+}
+
+static int
+tapdisk_control_write_message(int fd, tapdisk_message_t *message, int timeout)
+{
+       fd_set writefds;
+       int ret, len, offset;
+       struct timeval tv, *t;
+
+       t      = NULL;
+       offset = 0;
+       len    = sizeof(tapdisk_message_t);
+
+       if (timeout) {
+               tv.tv_sec  = timeout;
+               tv.tv_usec = 0;
+               t = &tv;
+       }
+
+       DPRINTF("sending '%s' message (uuid = %u)\n",
+               tapdisk_message_name(message->type), message->cookie);
+
+       while (offset < len) {
+               FD_ZERO(&writefds);
+               FD_SET(fd, &writefds);
+
+               /* we don't bother reinitializing tv. at worst, it will wait a
+                * bit more time than expected. */
+
+               ret = select(fd + 1, NULL, &writefds, NULL, t);
+               if (ret == -1)
+                       break;
+               else if (FD_ISSET(fd, &writefds)) {
+                       ret = write(fd, message + offset, len - offset);
+                       if (ret <= 0)
+                               break;
+                       offset += ret;
+               } else
+                       break;
+       }
+
+       if (offset != len) {
+               EPRINTF("failure writing message\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int
+tapdisk_control_validate_request(tapdisk_message_t *request)
+{
+       if (strnlen(request->u.params.path,
+                   TAPDISK_MESSAGE_MAX_PATH_LENGTH) >=
+           TAPDISK_MESSAGE_MAX_PATH_LENGTH)
+               return EINVAL;
+
+       return 0;
+}
+
+static void
+tapdisk_control_list_minors(struct tapdisk_control_connection *connection,
+                           tapdisk_message_t *request)
+{
+       int i;
+       td_vbd_t *vbd;
+       struct list_head *head;
+       tapdisk_message_t response;
+
+       i = 0;
+       memset(&response, 0, sizeof(response));
+
+       response.type = TAPDISK_MESSAGE_LIST_MINORS_RSP;
+       response.cookie = request->cookie;
+
+       head = tapdisk_server_get_all_vbds();
+
+       list_for_each_entry(vbd, head, next) {
+               response.u.minors.list[i++] = vbd->minor;
+               if (i >= TAPDISK_MESSAGE_MAX_MINORS) {
+                       response.type = TAPDISK_MESSAGE_ERROR;
+                       response.u.response.error = ERANGE;
+                       break;
+               }
+       }
+
+       response.u.minors.count = i;
+       tapdisk_control_write_message(connection->socket, &response, 2);
+       tapdisk_control_close_connection(connection);
+}
+
+static void
+tapdisk_control_list(struct tapdisk_control_connection *connection,
+                    tapdisk_message_t *request)
+{
+       td_vbd_t *vbd;
+       struct list_head *head;
+       tapdisk_message_t response;
+       int count, i;
+
+       memset(&response, 0, sizeof(response));
+       response.type = TAPDISK_MESSAGE_LIST_RSP;
+       response.cookie = request->cookie;
+
+       head = tapdisk_server_get_all_vbds();
+
+       count = 0;
+       list_for_each_entry(vbd, head, next)
+               count++;
+
+       list_for_each_entry(vbd, head, next) {
+               response.u.list.count   = count--;
+               response.u.list.minor   = vbd->minor;
+               response.u.list.state   = vbd->state;
+               response.u.list.path[0] = 0;
+
+               if (!list_empty(&vbd->images)) {
+                       td_image_t *image = list_entry(vbd->images.next,
+                                                      td_image_t, next);
+                       snprintf(response.u.list.path,
+                                sizeof(response.u.list.path),
+                                "%s:%s",
+                                tapdisk_disk_types[image->type]->name,
+                                image->name);
+               }
+
+               tapdisk_control_write_message(connection->socket, &response, 2);
+       }
+
+       response.u.list.count   = count;
+       response.u.list.minor   = -1;
+       response.u.list.path[0] = 0;
+
+       tapdisk_control_write_message(connection->socket, &response, 2);
+       tapdisk_control_close_connection(connection);
+}
+
+static void
+tapdisk_control_get_pid(struct tapdisk_control_connection *connection,
+                       tapdisk_message_t *request)
+{
+       tapdisk_message_t response;
+
+       memset(&response, 0, sizeof(response));
+       response.type = TAPDISK_MESSAGE_PID_RSP;
+       response.cookie = request->cookie;
+       response.u.tapdisk_pid = getpid();
+
+       tapdisk_control_write_message(connection->socket, &response, 2);
+       tapdisk_control_close_connection(connection);
+}
+
+static void
+tapdisk_control_attach_vbd(struct tapdisk_control_connection *connection,
+                          tapdisk_message_t *request)
+{
+       tapdisk_message_t response;
+       char *devname;
+       td_vbd_t *vbd;
+       struct blktap2_params params;
+       image_t image;
+       int minor, err;
+
+       /*
+        * TODO: check for max vbds per process
+        */
+
+       vbd = tapdisk_server_get_vbd(request->cookie);
+       if (vbd) {
+               err = -EEXIST;
+               goto out;
+       }
+
+       minor = request->cookie;
+       if (minor < 0) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       vbd = tapdisk_vbd_create(minor);
+       if (!vbd) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = asprintf(&devname, BLKTAP2_RING_DEVICE"%d", minor);
+       if (err == -1) {
+               err = -ENOMEM;
+               goto fail_vbd;
+       }
+
+       err = tapdisk_vbd_attach(vbd, devname, minor);
+       free(devname);
+       if (err)
+               goto fail_vbd;
+
+       tapdisk_server_add_vbd(vbd);
+
+out:
+       memset(&response, 0, sizeof(response));
+       response.type = TAPDISK_MESSAGE_ATTACH_RSP;
+       response.cookie = request->cookie;
+       response.u.response.error = -err;
+
+       tapdisk_control_write_message(connection->socket, &response, 2);
+       tapdisk_control_close_connection(connection);
+
+       return;
+
+fail_vbd:
+       tapdisk_vbd_detach(vbd);
+       free(vbd);
+       goto out;
+}
+
+
+static void
+tapdisk_control_detach_vbd(struct tapdisk_control_connection *connection,
+                          tapdisk_message_t *request)
+{
+       tapdisk_message_t response;
+       td_vbd_t *vbd;
+       int err;
+
+       vbd = tapdisk_server_get_vbd(request->cookie);
+       if (!vbd) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       tapdisk_vbd_detach(vbd);
+
+       if (list_empty(&vbd->images)) {
+               tapdisk_server_remove_vbd(vbd);
+               free(vbd);
+       }
+
+       err = 0;
+out:
+       memset(&response, 0, sizeof(response));
+       response.type = TAPDISK_MESSAGE_DETACH_RSP;
+       response.cookie = request->cookie;
+       response.u.response.error = -err;
+
+       tapdisk_control_write_message(connection->socket, &response, 2);
+       tapdisk_control_close_connection(connection);
+}
+
+static void
+tapdisk_control_open_image(struct tapdisk_control_connection *connection,
+                          tapdisk_message_t *request)
+{
+       int err;
+       image_t image;
+       td_vbd_t *vbd;
+       td_flag_t flags;
+       tapdisk_message_t response;
+       struct blktap2_params params;
+
+       vbd = tapdisk_server_get_vbd(request->cookie);
+       if (!vbd) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (vbd->minor == -1) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (vbd->name) {
+               err = -EALREADY;
+               goto out;
+       }
+
+       flags = 0;
+       if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_RDONLY)
+               flags |= TD_OPEN_RDONLY;
+       if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_SHARED)
+               flags |= TD_OPEN_SHAREABLE;
+       if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_ADD_CACHE)
+               flags |= TD_OPEN_ADD_CACHE;
+       if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_VHD_INDEX)
+               flags |= TD_OPEN_VHD_INDEX;
+       if (request->u.params.flags & TAPDISK_MESSAGE_FLAG_LOG_DIRTY)
+               flags |= TD_OPEN_LOG_DIRTY;
+
+       vbd->name = strndup(request->u.params.path,
+                           sizeof(request->u.params.path));
+       if (!vbd->name) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       err = tapdisk_vbd_parse_stack(vbd, request->u.params.path);
+       if (err)
+               goto out;
+
+       err = tapdisk_vbd_open_stack(vbd, request->u.params.storage, flags);
+       if (err)
+               goto out;
+
+       err = tapdisk_vbd_get_image_info(vbd, &image);
+       if (err)
+               goto fail_close;
+
+       params.capacity = image.size;
+       params.sector_size = image.secsize;
+
+       err = ioctl(vbd->ring.fd, BLKTAP2_IOCTL_CREATE_DEVICE, &params);
+       if (err && errno != EEXIST) {
+               err = -errno;
+               EPRINTF("create device failed: %d\n", err);
+               goto fail_close;
+       }
+
+       err = 0;
+
+out:
+       memset(&response, 0, sizeof(response));
+       response.cookie = request->cookie;
+
+       if (err) {
+               response.type                = TAPDISK_MESSAGE_ERROR;
+               response.u.response.error    = -err;
+       } else {
+               response.u.image.sectors     = image.size;
+               response.u.image.sector_size = image.secsize;
+               response.u.image.info        = image.info;
+               response.type                = TAPDISK_MESSAGE_OPEN_RSP;
+       }
+
+       tapdisk_control_write_message(connection->socket, &response, 2);
+       tapdisk_control_close_connection(connection);
+
+       return;
+
+fail_close:
+       tapdisk_vbd_close_vdi(vbd);
+       free(vbd->name);
+       vbd->name = NULL;
+       goto out;
+}
+
+static void
+tapdisk_control_close_image(struct tapdisk_control_connection *connection,
+                           tapdisk_message_t *request)
+{
+       tapdisk_message_t response;
+       td_vbd_t *vbd;
+       int err;
+
+       vbd = tapdisk_server_get_vbd(request->cookie);
+       if (!vbd) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (!list_empty(&vbd->pending_requests)) {
+               err = -EAGAIN;
+               goto out;
+       }
+
+       tapdisk_vbd_close_vdi(vbd);
+
+       /* NB. vbd->name free should probably belong into close_vdi,
+          but the current blktap1 reopen-stuff likely depends on a
+          lifetime extended until shutdown. */
+       free(vbd->name);
+       vbd->name = NULL;
+
+       if (vbd->minor == -1) {
+               tapdisk_server_remove_vbd(vbd);
+               tapdisk_vbd_free(vbd);
+       }
+
+       err = 0;
+out:
+       memset(&response, 0, sizeof(response));
+       response.type = TAPDISK_MESSAGE_CLOSE_RSP;
+       response.cookie = request->cookie;
+       response.u.response.error = -err;
+
+       tapdisk_control_write_message(connection->socket, &response, 2);
+       tapdisk_control_close_connection(connection);
+}
+
+static void
+tapdisk_control_pause_vbd(struct tapdisk_control_connection *connection,
+                         tapdisk_message_t *request)
+{
+       int err;
+       td_vbd_t *vbd;
+       tapdisk_message_t response;
+
+       memset(&response, 0, sizeof(response));
+
+       response.type = TAPDISK_MESSAGE_PAUSE_RSP;
+
+       vbd = tapdisk_server_get_vbd(request->cookie);
+       if (!vbd) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       do {
+               err = tapdisk_vbd_pause(vbd);
+
+               if (!err || err != -EAGAIN)
+                       break;
+
+               tapdisk_server_iterate();
+       } while (1);
+
+out:
+       response.cookie = request->cookie;
+       response.u.response.error = -err;
+       tapdisk_control_write_message(connection->socket, &response, 2);
+       tapdisk_control_close_connection(connection);
+}
+
+static void
+tapdisk_control_resume_vbd(struct tapdisk_control_connection *connection,
+                          tapdisk_message_t *request)
+{
+       int err;
+       td_vbd_t *vbd;
+       tapdisk_message_t response;
+
+       memset(&response, 0, sizeof(response));
+
+       response.type = TAPDISK_MESSAGE_RESUME_RSP;
+
+       vbd = tapdisk_server_get_vbd(request->cookie);
+       if (!vbd) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (!td_flag_test(vbd->state, TD_VBD_PAUSED)) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       if (request->u.params.path[0]) {
+               free(vbd->name);
+               vbd->name = strndup(request->u.params.path,
+                                   sizeof(request->u.params.path));
+               if (!vbd->name) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+       } else if (!vbd->name) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       err = tapdisk_vbd_parse_stack(vbd, vbd->name);
+       if (err)
+               goto out;
+
+       err = tapdisk_vbd_resume(vbd, NULL, -1);
+       if (err)
+               goto out;
+
+out:
+       response.cookie = request->cookie;
+       response.u.response.error = -err;
+       tapdisk_control_write_message(connection->socket, &response, 2);
+       tapdisk_control_close_connection(connection);
+}
+
+static void
+tapdisk_control_handle_request(event_id_t id, char mode, void *private)
+{
+       int err;
+       tapdisk_message_t message;
+       struct tapdisk_control_connection *connection =
+               (struct tapdisk_control_connection *)private;
+
+       if (tapdisk_control_read_message(connection->socket, &message, 2)) {
+               EPRINTF("failed to read message from %d\n", connection->socket);
+               tapdisk_control_close_connection(connection);
+               return;
+       }
+
+       err = tapdisk_control_validate_request(&message);
+       if (err)
+               goto fail;
+
+       switch (message.type) {
+       case TAPDISK_MESSAGE_PID:
+               return tapdisk_control_get_pid(connection, &message);
+       case TAPDISK_MESSAGE_LIST_MINORS:
+               return tapdisk_control_list_minors(connection, &message);
+       case TAPDISK_MESSAGE_LIST:
+               return tapdisk_control_list(connection, &message);
+       case TAPDISK_MESSAGE_ATTACH:
+               return tapdisk_control_attach_vbd(connection, &message);
+       case TAPDISK_MESSAGE_DETACH:
+               return tapdisk_control_detach_vbd(connection, &message);
+       case TAPDISK_MESSAGE_OPEN:
+               return tapdisk_control_open_image(connection, &message);
+       case TAPDISK_MESSAGE_PAUSE:
+               return tapdisk_control_pause_vbd(connection, &message);
+       case TAPDISK_MESSAGE_RESUME:
+               return tapdisk_control_resume_vbd(connection, &message);
+       case TAPDISK_MESSAGE_CLOSE:
+               return tapdisk_control_close_image(connection, &message);
+       default: {
+               tapdisk_message_t response;
+       fail:
+
+               EPRINTF("received unsupported message '%s'\n",
+                       tapdisk_message_name(message.type));
+
+               memset(&response, 0, sizeof(response));
+
+               response.type = TAPDISK_MESSAGE_ERROR;
+               response.u.response.error = (err ? -err : EINVAL);
+               tapdisk_control_write_message(connection->socket, &response, 2);
+
+               tapdisk_control_close_connection(connection);
+               break;
+       }
+       }
+}
+
+static void
+tapdisk_control_accept(event_id_t id, char mode, void *private)
+{
+       int err, fd;
+       struct tapdisk_control_connection *connection;
+
+       fd = accept(td_control.socket, NULL, NULL);
+       if (fd == -1) {
+               EPRINTF("failed to accept new control connection: %d\n", errno);
+               return;
+       }
+
+       connection = tapdisk_control_allocate_connection(fd);
+       if (!connection) {
+               close(fd);
+               EPRINTF("failed to allocate new control connection\n");
+       }
+
+       err = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
+                                           connection->socket, 0,
+                                           tapdisk_control_handle_request,
+                                           connection);
+       if (err == -1) {
+               close(fd);
+               free(connection);
+               EPRINTF("failed to register new control event: %d\n", err);
+       }
+
+       connection->event_id = err;
+}
+
+static int
+tapdisk_control_mkdir(const char *dir)
+{
+       int err;
+       char *ptr, *name, *start;
+
+       err = access(dir, W_OK | R_OK);
+       if (!err)
+               return 0;
+
+       name = strdup(dir);
+       if (!name)
+               return -ENOMEM;
+
+       start = name;
+
+       for (;;) {
+               ptr = strchr(start + 1, '/');
+               if (ptr)
+                       *ptr = '\0';
+
+               err = mkdir(name, 0755);
+               if (err && errno != EEXIST) {
+                       err = -errno;
+                       EPRINTF("failed to create directory %s: %d\n",
+                                 name, err);
+                       break;
+               }
+
+               if (!ptr)
+                       break;
+               else {
+                       *ptr = '/';
+                       start = ptr + 1;
+               }
+       }
+
+       free(name);
+       return err;
+}
+
+static int
+tapdisk_control_create_socket(char **socket_path)
+{
+       int err, flags;
+       struct sockaddr_un saddr;
+
+       err = tapdisk_control_mkdir(BLKTAP2_CONTROL_DIR);
+       if (err) {
+               EPRINTF("failed to create directory %s: %d\n",
+                       BLKTAP2_CONTROL_DIR, err);
+               return err;
+       }
+
+       err = asprintf(&td_control.path, "%s/%s%d",
+                      BLKTAP2_CONTROL_DIR, BLKTAP2_CONTROL_SOCKET, getpid());
+       if (err == -1) {
+               td_control.path = NULL;
+               err = (errno ? : ENOMEM);
+               goto fail;
+       }
+
+       if (unlink(td_control.path) && errno != ENOENT) {
+               err = errno;
+               EPRINTF("failed to unlink %s: %d\n", td_control.path, errno);
+               goto fail;
+       }
+
+       td_control.socket = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (td_control.socket == -1) {
+               err = errno;
+               EPRINTF("failed to create control socket: %d\n", err);
+               goto fail;
+       }
+
+       memset(&saddr, 0, sizeof(saddr));
+       strncpy(saddr.sun_path, td_control.path, sizeof(saddr.sun_path));
+       saddr.sun_family = AF_UNIX;
+
+       err = bind(td_control.socket,
+                  (const struct sockaddr *)&saddr, sizeof(saddr));
+       if (err == -1) {
+               err = errno;
+               EPRINTF("failed to bind to %s: %d\n", saddr.sun_path, err);
+               goto fail;
+       }
+
+       err = listen(td_control.socket, 10);
+       if (err == -1) {
+               err = errno;
+               EPRINTF("failed to listen: %d\n", err);
+               goto fail;
+       }
+
+       err = tapdisk_server_register_event(SCHEDULER_POLL_READ_FD,
+                                           td_control.socket, 0,
+                                           tapdisk_control_accept, NULL);
+       if (err < 0) {
+               EPRINTF("failed to add watch: %d\n", err);
+               goto fail;
+       }
+
+       td_control.event_id = err;
+       *socket_path = td_control.path;
+
+       return 0;
+
+fail:
+       tapdisk_control_close();
+       return err;
+}
+
+int
+tapdisk_control_open(char **path)
+{
+       int err;
+
+       tapdisk_control_initialize();
+
+       return tapdisk_control_create_socket(path);
+}
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/tapdisk-control.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/drivers/tapdisk-control.h   Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __TAPDISK_CONTROL_H__
+#define __TAPDISK_CONTROL_H__
+
+int tapdisk_control_open(char **path);
+void tapdisk_control_close(void);
+
+#endif
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/tapdisk-server.c
--- a/tools/blktap2/drivers/tapdisk-server.c    Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/drivers/tapdisk-server.c    Tue Jun 08 08:05:09 2010 +0100
@@ -63,6 +63,12 @@ tapdisk_server_get_shared_image(td_image
        return NULL;
 }
 
+struct list_head *
+tapdisk_server_get_all_vbds(void)
+{
+       return &server.vbds;
+}
+
 td_vbd_t *
 tapdisk_server_get_vbd(uint16_t uuid)
 {
@@ -218,24 +224,29 @@ tapdisk_server_close(void)
        tapdisk_server_close_aio();
 }
 
+void
+tapdisk_server_iterate(void)
+{
+       int ret;
+
+       tapdisk_server_assert_locks();
+       tapdisk_server_set_retry_timeout();
+       tapdisk_server_check_progress();
+
+       ret = scheduler_wait_for_events(&server.scheduler);
+       if (ret < 0)
+               DBG(TLOG_WARN, "server wait returned %d\n", ret);
+
+       tapdisk_server_check_vbds();
+       tapdisk_server_submit_tiocbs();
+       tapdisk_server_kick_responses();
+}
+
 static void
 __tapdisk_server_run(void)
 {
-       int ret;
-
-       while (server.run) {
-               tapdisk_server_assert_locks();
-               tapdisk_server_set_retry_timeout();
-               tapdisk_server_check_progress();
-
-               ret = scheduler_wait_for_events(&server.scheduler);
-               if (ret < 0)
-                       DBG(TLOG_WARN, "server wait returned %d\n", ret);
-
-               tapdisk_server_check_vbds();
-               tapdisk_server_submit_tiocbs();
-               tapdisk_server_kick_responses();
-       }
+       while (server.run)
+               tapdisk_server_iterate();
 }
 
 static void
@@ -267,22 +278,50 @@ tapdisk_server_signal_handler(int signal
 }
 
 int
-tapdisk_server_initialize(void)
+tapdisk_server_init(void)
+{
+       memset(&server, 0, sizeof(server));
+       INIT_LIST_HEAD(&server.vbds);
+
+       scheduler_initialize(&server.scheduler);
+
+       return 0;
+}
+
+int
+tapdisk_server_complete(void)
 {
        int err;
-
-       memset(&server, 0, sizeof(tapdisk_server_t));
-       INIT_LIST_HEAD(&server.vbds);
-
-       scheduler_initialize(&server.scheduler);
 
        err = tapdisk_server_init_aio();
        if (err)
-               return err;
+               goto fail;
 
        server.run = 1;
 
        return 0;
+
+fail:
+       tapdisk_server_close_aio();
+       return err;
+}
+
+int
+tapdisk_server_initialize(void)
+{
+       int err;
+
+       tapdisk_server_init();
+
+       err = tapdisk_server_complete();
+       if (err)
+               goto fail;
+
+       return 0;
+
+fail:
+       tapdisk_server_close();
+       return err;
 }
 
 int
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/tapdisk-server.h
--- a/tools/blktap2/drivers/tapdisk-server.h    Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/drivers/tapdisk-server.h    Tue Jun 08 08:05:09 2010 +0100
@@ -28,6 +28,7 @@
 #ifndef _TAPDISK_SERVER_H_
 #define _TAPDISK_SERVER_H_
 
+#include "list.h"
 #include "tapdisk-vbd.h"
 #include "tapdisk-queue.h"
 
@@ -35,6 +36,7 @@ struct tap_disk *tapdisk_server_find_dri
 
 td_image_t *tapdisk_server_get_shared_image(td_image_t *);
 
+struct list_head *tapdisk_server_get_all_vbds(void);
 td_vbd_t *tapdisk_server_get_vbd(td_uuid_t);
 void tapdisk_server_add_vbd(td_vbd_t *);
 void tapdisk_server_remove_vbd(td_vbd_t *);
@@ -47,8 +49,11 @@ void tapdisk_server_unregister_event(eve
 void tapdisk_server_unregister_event(event_id_t);
 void tapdisk_server_set_max_timeout(int);
 
+int tapdisk_server_init(void);
 int tapdisk_server_initialize(void);
+int tapdisk_server_complete(void);
 int tapdisk_server_run(void);
+void tapdisk_server_iterate(void);
 
 #define TAPDISK_TIOCBS              (TAPDISK_DATA_REQUESTS + 50)
 
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/tapdisk-vbd.c
--- a/tools/blktap2/drivers/tapdisk-vbd.c       Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/drivers/tapdisk-vbd.c       Tue Jun 08 08:05:09 2010 +0100
@@ -38,7 +38,6 @@
 #include <memshr.h>
 #endif
 
-#include "libvhd.h"
 #include "tapdisk-image.h"
 #include "tapdisk-driver.h"
 #include "tapdisk-server.h"
@@ -93,25 +92,20 @@ tapdisk_vbd_free(td_vbd_t *vbd)
        }
 }
 
-int
-tapdisk_vbd_initialize(uint16_t uuid)
-{
+td_vbd_t*
+tapdisk_vbd_create(uint16_t uuid)
+{
+       td_vbd_t *vbd;
        int i;
-       td_vbd_t *vbd;
-
-       vbd = tapdisk_server_get_vbd(uuid);
-       if (vbd) {
-               EPRINTF("duplicate vbds! %u\n", uuid);
-               return -EEXIST;
-       }
 
        vbd = calloc(1, sizeof(td_vbd_t));
        if (!vbd) {
                EPRINTF("failed to allocate tapdisk state\n");
-               return -ENOMEM;
+               return NULL;
        }
 
        vbd->uuid     = uuid;
+       vbd->minor    = -1;
        vbd->ring.fd  = -1;
 
        /* default blktap ring completion */
@@ -134,6 +128,22 @@ tapdisk_vbd_initialize(uint16_t uuid)
        for (i = 0; i < MAX_REQUESTS; i++)
                tapdisk_vbd_initialize_vreq(vbd->request_list + i);
 
+       return vbd;
+}
+
+int
+tapdisk_vbd_initialize(uint16_t uuid)
+{
+       td_vbd_t *vbd;
+
+       vbd = tapdisk_server_get_vbd(uuid);
+       if (vbd) {
+               EPRINTF("duplicate vbds! %u\n", uuid);
+               return -EEXIST;
+       }
+
+       vbd = tapdisk_vbd_create(uuid);
+
        tapdisk_server_add_vbd(vbd);
 
        return 0;
@@ -181,6 +191,8 @@ tapdisk_vbd_close_vdi(td_vbd_t *vbd)
 
        INIT_LIST_HEAD(&vbd->images);
        td_flag_set(vbd->state, TD_VBD_CLOSED);
+
+       tapdisk_vbd_free_stack(vbd);
 }
 
 static int
@@ -646,9 +658,42 @@ tapdisk_vbd_unmap_device(td_vbd_t *vbd)
        return 0;
 }
 
+void
+tapdisk_vbd_detach(td_vbd_t *vbd)
+{
+       tapdisk_vbd_unregister_events(vbd);
+
+       tapdisk_vbd_unmap_device(vbd);
+       vbd->minor = -1;
+}
+
+
+int
+tapdisk_vbd_attach(td_vbd_t *vbd, const char *devname, int minor)
+{
+       int err;
+
+       err = tapdisk_vbd_map_device(vbd, devname);
+       if (err)
+               goto fail;
+
+       err = tapdisk_vbd_register_event_watches(vbd);
+       if (err)
+               goto fail;
+
+       vbd->minor = minor;
+
+       return 0;
+
+fail:
+       tapdisk_vbd_detach(vbd);
+
+       return err;
+}
+
 int
 tapdisk_vbd_open(td_vbd_t *vbd, const char *name, uint16_t type,
-                uint16_t storage, const char *ring, td_flag_t flags)
+                uint16_t storage, int minor, const char *ring, td_flag_t flags)
 {
        int err;
 
@@ -656,20 +701,15 @@ tapdisk_vbd_open(td_vbd_t *vbd, const ch
        if (err)
                goto out;
 
-       err = tapdisk_vbd_map_device(vbd, ring);
+       err = tapdisk_vbd_attach(vbd, ring, minor);
        if (err)
                goto out;
 
-       err = tapdisk_vbd_register_event_watches(vbd);
-       if (err)
-               goto out;
-
        return 0;
 
 out:
+       tapdisk_vbd_detach(vbd);
        tapdisk_vbd_close_vdi(vbd);
-       tapdisk_vbd_unmap_device(vbd);
-       tapdisk_vbd_unregister_events(vbd);
        free(vbd->name);
        vbd->name = NULL;
        return err;
@@ -727,11 +767,9 @@ tapdisk_vbd_shutdown(td_vbd_t *vbd)
                vbd->kicked);
 
        tapdisk_vbd_close_vdi(vbd);
-       tapdisk_vbd_unregister_events(vbd);
-       tapdisk_vbd_unmap_device(vbd);
+       tapdisk_vbd_detach(vbd);
        tapdisk_server_remove_vbd(vbd);
-       free(vbd->name);
-       free(vbd);
+       tapdisk_vbd_free(vbd);
 
        tlog_print_errors();
 
@@ -941,17 +979,18 @@ tapdisk_vbd_resume(td_vbd_t *vbd, const 
                return -EINVAL;
        }
 
-       free(vbd->name);
-       vbd->name = strdup(path);
-       if (!vbd->name) {
-               EPRINTF("copying new vbd %s name failed\n", path);
-               return -EINVAL;
-       }
-       vbd->type = drivertype;
+       if (path) {
+               free(vbd->name);
+               vbd->name = strdup(path);
+               if (!vbd->name) {
+                       EPRINTF("copying new vbd %s name failed\n", path);
+                       return -EINVAL;
+               }
+       }
 
        for (i = 0; i < TD_VBD_EIO_RETRIES; i++) {
                err = __tapdisk_vbd_open_vdi(vbd, TD_OPEN_STRICT);
-               if (!err)
+               if (err != -EIO)
                        break;
 
                sleep(TD_VBD_EIO_SLEEP);
@@ -963,6 +1002,7 @@ tapdisk_vbd_resume(td_vbd_t *vbd, const 
        tapdisk_vbd_start_queue(vbd);
        td_flag_clear(vbd->state, TD_VBD_PAUSED);
        td_flag_clear(vbd->state, TD_VBD_PAUSE_REQUESTED);
+       tapdisk_vbd_check_state(vbd);
 
        return 0;
 }
@@ -1607,7 +1647,6 @@ tapdisk_vbd_resume_ring(td_vbd_t *vbd)
                err = -ENOMEM;
                goto out;
        }
-       vbd->type = type;
 
        tapdisk_vbd_start_queue(vbd);
 
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/tapdisk-vbd.h
--- a/tools/blktap2/drivers/tapdisk-vbd.h       Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/drivers/tapdisk-vbd.h       Tue Jun 08 08:05:09 2010 +0100
@@ -89,7 +89,7 @@ struct td_vbd_handle {
        char                       *name;
 
        td_uuid_t                   uuid;
-       int                         type;
+       int                         minor;
 
        struct list_head            driver_stack;
 
@@ -168,17 +168,23 @@ tapdisk_vbd_next_image(td_image_t *image
        return list_entry(image->next.next, td_image_t, next);
 }
 
+td_vbd_t *tapdisk_vbd_create(td_uuid_t);
 int tapdisk_vbd_initialize(td_uuid_t);
 void tapdisk_vbd_set_callback(td_vbd_t *, td_vbd_cb_t, void *);
 int tapdisk_vbd_parse_stack(td_vbd_t *vbd, const char *path);
 int tapdisk_vbd_open(td_vbd_t *, const char *, uint16_t,
-                    uint16_t, const char *, td_flag_t);
+                    uint16_t, int, const char *, td_flag_t);
 int tapdisk_vbd_close(td_vbd_t *);
+void tapdisk_vbd_free(td_vbd_t *);
 void tapdisk_vbd_free_stack(td_vbd_t *);
 
+int tapdisk_vbd_open_stack(td_vbd_t *, uint16_t, td_flag_t);
 int tapdisk_vbd_open_vdi(td_vbd_t *, const char *,
                         uint16_t, uint16_t, td_flag_t);
 void tapdisk_vbd_close_vdi(td_vbd_t *);
+
+int tapdisk_vbd_attach(td_vbd_t *, const char *, int);
+void tapdisk_vbd_detach(td_vbd_t *);
 
 void tapdisk_vbd_forward_request(td_request_t);
 
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/drivers/tapdisk2.c
--- a/tools/blktap2/drivers/tapdisk2.c  Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/drivers/tapdisk2.c  Tue Jun 08 08:05:09 2010 +0100
@@ -28,397 +28,37 @@
 #include <stdio.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <stdlib.h>
 #include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
 #ifdef MEMSHR
 #include <memshr.h>
 #endif
 
 #include "tapdisk.h"
-#include "blktap2.h"
-#include "tapdisk-vbd.h"
 #include "tapdisk-utils.h"
 #include "tapdisk-server.h"
-#include "tapdisk-disktype.h"
-
-#define TAPDISK2_VBD 0
-
-#define cprintf(_err, _f, _a...)                                       \
-       do {                                                            \
-               if (child_out) {                                        \
-                       fprintf(child_out, "%d: " _f, _err, ##_a);      \
-                       fflush(child_out);                              \
-               }                                                       \
-       } while (0)
-
-#define CHILD_ERR(_err, _f, _a...)                                     \
-       do {                                                            \
-               EPRINTF(_f, ##_a);                                      \
-               cprintf(_err, _f, ##_a);                                \
-       } while (0)
-
-static int channel[2];
-static FILE *child_out;
-static struct blktap2_handle handle;
-
-static int
-tapdisk2_prepare_directory(void)
-{
-       int err;
-       char *ptr, *name, *start;
-
-       err = access(BLKTAP2_DIRECTORY, W_OK | R_OK);
-       if (!err)
-               return 0;
-
-       name = strdup(BLKTAP2_DIRECTORY);
-       if (!name)
-               return -ENOMEM;
-
-       start = name;
-
-       for (;;) {
-               ptr = strchr(start + 1, '/');
-               if (ptr)
-                       *ptr = '\0';
-
-               err = mkdir(name, 0755);
-               if (err && errno != EEXIST) {
-                       err = -errno;
-                       CHILD_ERR(err, "failed to create directory %s: %d\n",
-                                 name, err);
-                       break;
-               }
-
-               if (!ptr)
-                       break;
-               else {
-                       *ptr = '/';
-                       start = ptr + 1;
-               }
-       }
-
-       free(name);
-       return err;
-}
-
-static int
-tapdisk2_make_device(char *devname, int major, int minor, int perm)
-{
-       int err;
-       struct stat st;
-
-       err = tapdisk2_prepare_directory();
-       if (err)
-               return err;
-
-       if (!access(devname, F_OK))
-               if (unlink(devname)) {
-                       CHILD_ERR(errno, "error unlinking %s: %d\n",
-                                 devname, errno);
-                       return -errno;
-               }
-
-       err = mknod(devname, perm, makedev(major, minor));
-       if (err) {
-               CHILD_ERR(errno, "mknod %s failed: %d\n", devname, -errno);
-               return -errno;
-       }
-
-       DPRINTF("Created %s device\n", devname);
-       return 0;
-}
-
-static int
-tapdisk2_check_environment(void)
-{
-       FILE *f;
-       int err, minor;
-       char name[256];
-
-       if (!access(BLKTAP2_CONTROL_DEVICE, R_OK | W_OK))
-               return 0;
-
-       memset(name, 0, sizeof(name));
-
-       f = fopen("/proc/misc", "r");
-       if (!f) {
-               CHILD_ERR(errno, "failed to open /proc/misc: %d\n", errno);
-               return -errno;
-       }
-
-       while (fscanf(f, "%d %256s", &minor, name) == 2)
-               if (!strcmp(name, BLKTAP2_CONTROL_NAME)) {
-                       err = tapdisk2_make_device(BLKTAP2_CONTROL_DEVICE,
-                                                  MISC_MAJOR_NUMBER,
-                                                  minor, S_IFCHR | 0600);
-                       goto out;
-               }
-
-       err = -ENOSYS;
-       CHILD_ERR(err, "didn't find %s in /proc/misc\n", BLKTAP2_CONTROL_NAME);
-
-out:
-       fclose(f);
-       return err;
-}
-
-static void
-tapdisk2_free_device(void)
-{
-       int fd, err;
-
-       fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY);
-       if (fd == -1) {
-               CHILD_ERR(errno, "failed to open control device: %d\n", errno);
-               return;
-       }
-
-       err = ioctl(fd, BLKTAP2_IOCTL_FREE_TAP, handle.minor);
-       close(fd);
-}
-
-static int
-tapdisk2_prepare_device(void)
-{
-       char *name;
-       int fd, err;
-
-       fd = open(BLKTAP2_CONTROL_DEVICE, O_RDONLY);
-       if (fd == -1) {
-               CHILD_ERR(errno, "failed to open control device: %d\n", errno);
-               return -errno;
-       }
-
-       err = ioctl(fd, BLKTAP2_IOCTL_ALLOC_TAP, &handle);
-       close(fd);
-       if (err == -1) {
-               CHILD_ERR(errno, "failed to allocate new device: %d\n", errno);
-               return -errno;
-       }
-
-       err = asprintf(&name, "%s%d", BLKTAP2_RING_DEVICE, handle.minor);
-       if (err == -1) {
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       err = tapdisk2_make_device(name, handle.ring,
-                                  handle.minor, S_IFCHR | 0600);
-       free(name);
-       if (err) {
-               CHILD_ERR(err, "creating ring device for %d failed: %d\n",
-                         handle.minor, err);
-               goto fail;
-       }
-
-       err = asprintf(&name, "%s%d", BLKTAP2_IO_DEVICE, handle.minor);
-       if (err == -1) {
-               err = -ENOMEM;
-               goto fail;
-       }
-
-       err = tapdisk2_make_device(name, handle.device,
-                                  handle.minor, S_IFBLK | 0600);
-       free(name);
-       if (err) {
-               CHILD_ERR(err, "creating IO device for %d failed: %d\n",
-                         handle.minor, err);
-               goto fail;
-       }
-
-       DPRINTF("new interface: ring: %u, device: %u, minor: %u\n",
-               handle.ring, handle.device, handle.minor);
-
-       return 0;
-
-fail:
-       tapdisk2_free_device();
-       return err;
-}
-
-static int
-tapdisk2_open_device(int type, const char *path, const char *name)
-{
-       int err;
-       td_vbd_t *vbd;
-       image_t image;
-       char *devname;
-       struct blktap2_params params;
-
-       err = tapdisk_vbd_initialize(TAPDISK2_VBD);
-       if (err)
-               return err;
-
-       vbd = tapdisk_server_get_vbd(TAPDISK2_VBD);
-       if (!vbd) {
-               err = -ENODEV;
-               CHILD_ERR(err, "couldn't find vbd\n");
-               return err;
-       }
-
-       err = asprintf(&devname, "%s%d", BLKTAP2_RING_DEVICE, handle.minor);
-       if (err == -1) {
-               err = -ENOMEM;
-               CHILD_ERR(err, "couldn't allocate ring\n");
-               return err;
-       }
-
-       err = tapdisk_vbd_parse_stack(vbd, name);
-       if (err) {
-               CHILD_ERR(err, "vbd_parse_stack failed: %d\n", err);
-               return err;
-       }
-
-       /* TODO: clean this up */
-       err = tapdisk_vbd_open(vbd, path, type,
-                              TAPDISK_STORAGE_TYPE_DEFAULT,
-                              devname, 0);
-       free(devname);
-       if (err) {
-               CHILD_ERR(err, "vbd open failed: %d\n", err);
-               return err;
-       }
-
-       memset(&params, 0, sizeof(params));
-       tapdisk_vbd_get_image_info(vbd, &image);
-
-       params.capacity    = image.size;
-       params.sector_size = image.secsize;
-       snprintf(params.name, sizeof(params.name) - 1, "%s", name);
-
-       err = ioctl(vbd->ring.fd, BLKTAP2_IOCTL_CREATE_DEVICE, &params);
-       if (err) {
-               err = -errno;
-               CHILD_ERR(err, "create device failed: %d\n", err);
-               return err;
-       }
-
-       return 0;
-}
-
-static int
-tapdisk2_set_child_fds(void)
-{
-       int i, err;
-
-       err = dup2(channel[1], STDOUT_FILENO);
-       if (err == -1) {
-               CHILD_ERR(errno, "failed duping pipe: %d\n", errno);
-               return errno;
-       }
-
-       child_out = fdopen(STDOUT_FILENO, "w");
-       if (!child_out) {
-               CHILD_ERR(errno, "failed setting child_out: %d\n", errno);
-               return errno;
-       }
-
-       for (i = 0; i < sysconf(_SC_OPEN_MAX); i++)
-               if (i != STDOUT_FILENO)
-                       close(i);
-
-       return 0;
-}
-
-static int
-tapdisk2_create_device(const char *params)
-{
-       const char *path;
-       int err, type;
-
-       chdir("/");
-       tapdisk_start_logging("tapdisk2");
-
-       err = tapdisk2_set_child_fds();
-       if (err)
-               goto out;
-
-       err = tapdisk2_check_environment();
-       if (err)
-               goto out;
-
-       err = tapdisk_parse_disk_type(params, &path, &type);
-       if (err)
-               goto out;
-
-       err = tapdisk2_prepare_device();
-       if (err)
-               goto out;
-
-       err = tapdisk_server_initialize();
-       if (err)
-               goto fail;
-
-       err = tapdisk2_open_device(type, path, params);
-       if (err)
-               goto fail;
-
-       cprintf(0, "%s%d\n", BLKTAP2_IO_DEVICE, handle.minor);
-       close(STDOUT_FILENO);
-
-       err = tapdisk_server_run();
-       if (err)
-               goto fail;
-
-       err = 0;
-
-out:
-       tapdisk_stop_logging();
-       return err;
-
-fail:
-       tapdisk2_free_device();
-       goto out;
-}
-
-static int
-tapdisk2_wait_for_device(void)
-{
-       int err;
-       char msg[1024];
-       FILE *parent_in;
-
-       close(channel[1]);
-       parent_in = fdopen(channel[0], "r");
-       if (!parent_in) {
-               printf("failed to connect to child: %d\n", errno);
-               return errno;
-       }
-
-       memset(msg, 0, sizeof(msg));
-       if (fscanf(parent_in, "%d: %1023[^\n]", &err, msg) != 2) {
-               printf("unrecognized child response\n");
-               return EINVAL;
-       }
-
-       printf("%s\n", msg);
-       return (err >= 0 ? err : -err);
-}
+#include "tapdisk-control.h"
 
 static void
 usage(const char *app, int err)
 {
-       fprintf(stderr, "usage: %s <-n file>\n", app);
+       fprintf(stderr, "usage: %s <-u uuid> <-c control socket>\n", app);
        exit(err);
 }
 
 int
 main(int argc, char *argv[])
 {
-       int c;
-       char *params;
+       char *control;
+       int c, err, nodaemon;
 
-       params = NULL;
+       control  = NULL;
+       nodaemon = 0;
 
-       while ((c = getopt(argc, argv, "n:s:h")) != -1) {
+       while ((c = getopt(argc, argv, "s:Dh")) != -1) {
                switch (c) {
-               case 'n':
-                       params = optarg;
+               case 'D':
+                       nodaemon = 1;
                        break;
                case 'h':
                        usage(argv[0], 0);
@@ -436,21 +76,58 @@ main(int argc, char *argv[])
                }
        }
 
-       if (!params || optind != argc)
+       if (optind != argc)
                usage(argv[0], EINVAL);
 
-       if (pipe(channel) == -1) {
-               printf("pipe failed: %d\n", errno);
-               return errno;
+       chdir("/");
+       tapdisk_start_logging("tapdisk2");
+
+       err = tapdisk_server_init();
+       if (err) {
+               DPRINTF("failed to initialize server: %d\n", err);
+               goto out;
        }
 
-       switch (fork()) {
-       case -1:
-               printf("fork failed: %d\n", errno);
-               return errno;
-       case 0:
-               return tapdisk2_create_device(params);
-       default:
-               return tapdisk2_wait_for_device();
+       if (!nodaemon) {
+               err = daemon(0, 1);
+               if (err) {
+                       DPRINTF("failed to daemonize: %d\n", errno);
+                       goto out;
+               }
        }
+
+       err = tapdisk_control_open(&control);
+       if (err) {
+               DPRINTF("failed to open control socket: %d\n", err);
+               goto out;
+       }
+
+       fprintf(stdout, "%s\n", control);
+       fflush(stdout);
+
+       if (!nodaemon) {
+               int fd;
+
+               fd = open("/dev/null", O_RDWR);
+               if (fd != -1) {
+                       dup2(fd, STDIN_FILENO);
+                       dup2(fd, STDOUT_FILENO);
+                       dup2(fd, STDERR_FILENO);
+                       if (fd > 2)
+                               close(fd);
+               }
+       }
+
+       err = tapdisk_server_complete();
+       if (err) {
+               DPRINTF("failed to complete server: %d\n", err);
+               goto out;
+       }
+
+       err = tapdisk_server_run();
+
+out:
+       tapdisk_control_close();
+       tapdisk_stop_logging();
+       return err;
 }
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/include/blktap2.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap2/include/blktap2.h   Tue Jun 08 08:05:09 2010 +0100
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2008, XenSource Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of XenSource Inc. nor the names of its contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _BLKTAP_2_H_
+#define _BLKTAP_2_H_
+
+#define BLKTAP2_MAX_MESSAGE_LEN        256
+
+#define BLKTAP2_RING_MESSAGE_PAUSE     1
+#define BLKTAP2_RING_MESSAGE_RESUME    2
+#define BLKTAP2_RING_MESSAGE_CLOSE     3
+
+#define BLKTAP2_IOCTL_KICK_FE          1
+#define BLKTAP2_IOCTL_ALLOC_TAP        200
+#define BLKTAP2_IOCTL_FREE_TAP         201
+#define BLKTAP2_IOCTL_CREATE_DEVICE    202
+#define BLKTAP2_IOCTL_SET_PARAMS       203
+#define BLKTAP2_IOCTL_PAUSE            204
+#define BLKTAP2_IOCTL_REOPEN           205
+#define BLKTAP2_IOCTL_RESUME           206
+
+#define BLKTAP2_SYSFS_DIR              "/sys/class/blktap2"
+#define BLKTAP2_CONTROL_NAME           "blktap-control"
+#define BLKTAP2_CONTROL_DIR            "/var/run/"BLKTAP2_CONTROL_NAME
+#define BLKTAP2_CONTROL_SOCKET         "ctl"
+#define BLKTAP2_DIRECTORY              "/dev/xen/blktap-2"
+#define BLKTAP2_CONTROL_DEVICE         BLKTAP2_DIRECTORY"/control"
+#define BLKTAP2_RING_DEVICE            BLKTAP2_DIRECTORY"/blktap"
+#define BLKTAP2_IO_DEVICE              BLKTAP2_DIRECTORY"/tapdev"
+
+struct blktap2_handle {
+       unsigned int                   ring;
+       unsigned int                   device;
+       unsigned int                   minor;
+};
+
+struct blktap2_params {
+       char                           name[BLKTAP2_MAX_MESSAGE_LEN];
+       unsigned long long             capacity;
+       unsigned long                  sector_size;
+};
+
+#endif
diff -r 54675b91b3c1 -r 63d0f5348af2 tools/blktap2/include/tapdisk-message.h
--- a/tools/blktap2/include/tapdisk-message.h   Tue Jun 08 08:04:36 2010 +0100
+++ b/tools/blktap2/include/tapdisk-message.h   Tue Jun 08 08:05:09 2010 +0100
@@ -33,6 +33,9 @@
 #define TAPDISK_MESSAGE_MAX_PATH_LENGTH  256
 #define TAPDISK_MESSAGE_STRING_LENGTH    256
 
+#define TAPDISK_MESSAGE_MAX_MINORS \
+       ((TAPDISK_MESSAGE_MAX_PATH_LENGTH / sizeof(int)) - 1)
+
 #define TAPDISK_MESSAGE_FLAG_SHARED      0x01
 #define TAPDISK_MESSAGE_FLAG_RDONLY      0x02
 #define TAPDISK_MESSAGE_FLAG_ADD_CACHE   0x04
@@ -44,10 +47,13 @@ typedef struct tapdisk_message_image    
 typedef struct tapdisk_message_image     tapdisk_message_image_t;
 typedef struct tapdisk_message_params    tapdisk_message_params_t;
 typedef struct tapdisk_message_string    tapdisk_message_string_t;
+typedef struct tapdisk_message_response  tapdisk_message_response_t;
+typedef struct tapdisk_message_minors    tapdisk_message_minors_t;
+typedef struct tapdisk_message_list      tapdisk_message_list_t;
 
 struct tapdisk_message_params {
        tapdisk_message_flag_t           flags;
-       
+
        uint8_t                          storage;
        uint32_t                         devnum;
        uint32_t                         domid;
@@ -65,6 +71,23 @@ struct tapdisk_message_string {
        char                             text[TAPDISK_MESSAGE_STRING_LENGTH];
 };
 
+struct tapdisk_message_response {
+       int                              error;
+       char                             message[TAPDISK_MESSAGE_STRING_LENGTH];
+};
+
+struct tapdisk_message_minors {
+       int                              count;
+       int                              list[TAPDISK_MESSAGE_MAX_MINORS];
+};
+
+struct tapdisk_message_list {
+       int                              count;
+       int                              minor;
+       int                              state;
+       char                             path[TAPDISK_MESSAGE_MAX_PATH_LENGTH];
+};
+
 struct tapdisk_message {
        uint16_t                         type;
        uint16_t                         cookie;
@@ -74,6 +97,9 @@ struct tapdisk_message {
                tapdisk_message_image_t  image;
                tapdisk_message_params_t params;
                tapdisk_message_string_t string;
+               tapdisk_message_minors_t minors;
+               tapdisk_message_response_t response;
+               tapdisk_message_list_t   list;
        } u;
 };
 
@@ -82,6 +108,8 @@ enum tapdisk_message_id {
        TAPDISK_MESSAGE_RUNTIME_ERROR,
        TAPDISK_MESSAGE_PID,
        TAPDISK_MESSAGE_PID_RSP,
+       TAPDISK_MESSAGE_ATTACH,
+       TAPDISK_MESSAGE_ATTACH_RSP,
        TAPDISK_MESSAGE_OPEN,
        TAPDISK_MESSAGE_OPEN_RSP,
        TAPDISK_MESSAGE_PAUSE,
@@ -90,6 +118,13 @@ enum tapdisk_message_id {
        TAPDISK_MESSAGE_RESUME_RSP,
        TAPDISK_MESSAGE_CLOSE,
        TAPDISK_MESSAGE_CLOSE_RSP,
+       TAPDISK_MESSAGE_DETACH,
+       TAPDISK_MESSAGE_DETACH_RSP,
+       TAPDISK_MESSAGE_LIST_MINORS,
+       TAPDISK_MESSAGE_LIST_MINORS_RSP,
+       TAPDISK_MESSAGE_LIST,
+       TAPDISK_MESSAGE_LIST_RSP,
+       TAPDISK_MESSAGE_FORCE_SHUTDOWN,
        TAPDISK_MESSAGE_EXIT,
 };
 
@@ -127,8 +162,35 @@ tapdisk_message_name(enum tapdisk_messag
        case TAPDISK_MESSAGE_CLOSE:
                return "close";
 
+       case TAPDISK_MESSAGE_FORCE_SHUTDOWN:
+               return "force shutdown";
+
        case TAPDISK_MESSAGE_CLOSE_RSP:
                return "close response";
+
+       case TAPDISK_MESSAGE_ATTACH:
+               return "attach";
+
+       case TAPDISK_MESSAGE_ATTACH_RSP:
+               return "attach response";
+
+       case TAPDISK_MESSAGE_DETACH:
+               return "detach";
+
+       case TAPDISK_MESSAGE_DETACH_RSP:
+               return "detach response";
+
+       case TAPDISK_MESSAGE_LIST_MINORS:
+               return "list minors";
+
+       case TAPDISK_MESSAGE_LIST_MINORS_RSP:
+               return "list minors response";
+
+       case TAPDISK_MESSAGE_LIST:
+               return "list";
+
+       case TAPDISK_MESSAGE_LIST_RSP:
+               return "list response";
 
        case TAPDISK_MESSAGE_EXIT:
                return "exit";

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


 


Rackspace

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