WARNING - OLD ARCHIVES

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

xen-changelog

[Xen-changelog] [xen-unstable] blktap2: The tap-ctl userspace control ut

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] blktap2: The tap-ctl userspace control utility and library.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Wed, 09 Jun 2010 00:01:03 -0700
Delivery-date: Wed, 09 Jun 2010 00:02:24 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] blktap2: The tap-ctl userspace control utility and library., Xen patchbot-unstable <=