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

[Xen-changelog] [xen master] Revert "tools: remove blktap2 source code"



commit d383c07e8bc6df81afb5fb250cc55c507d75ac75
Author:     Wei Liu <wei.liu2@xxxxxxxxxx>
AuthorDate: Thu Sep 8 16:15:47 2016 +0100
Commit:     Wei Liu <wei.liu2@xxxxxxxxxx>
CommitDate: Thu Sep 8 16:15:47 2016 +0100

    Revert "tools: remove blktap2 source code"
    
    This reverts commit 44b2829a8b97a8b04e063a93303dbe3a468642e3.
---
 tools/blktap2/Makefile                     |   20 +
 tools/blktap2/README                       |  321 +++
 tools/blktap2/control/Makefile             |   80 +
 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     |   67 +
 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        |  249 +++
 tools/blktap2/control/tap-ctl-list.c       |  536 +++++
 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             |  113 +
 tools/blktap2/drivers/aes.c                | 1319 +++++++++++
 tools/blktap2/drivers/aes.h                |   28 +
 tools/blktap2/drivers/atomicio.c           |   61 +
 tools/blktap2/drivers/blk.h                |   36 +
 tools/blktap2/drivers/blk_linux.c          |   43 +
 tools/blktap2/drivers/blk_netbsd.c         |   41 +
 tools/blktap2/drivers/block-aio.c          |  258 +++
 tools/blktap2/drivers/block-cache.c        |  787 +++++++
 tools/blktap2/drivers/block-log.c          |  665 ++++++
 tools/blktap2/drivers/block-qcow.c         | 1501 +++++++++++++
 tools/blktap2/drivers/block-ram.c          |  256 +++
 tools/blktap2/drivers/block-remus.c        | 1733 ++++++++++++++
 tools/blktap2/drivers/block-vhd.c          | 2322 +++++++++++++++++++
 tools/blktap2/drivers/bswap.h              |  179 ++
 tools/blktap2/drivers/check_gcrypt         |   18 +
 tools/blktap2/drivers/hashtable.c          |  279 +++
 tools/blktap2/drivers/hashtable.h          |  204 ++
 tools/blktap2/drivers/hashtable_itr.c      |  195 ++
 tools/blktap2/drivers/hashtable_itr.h      |   96 +
 tools/blktap2/drivers/hashtable_private.h  |   90 +
 tools/blktap2/drivers/hashtable_utility.c  |   71 +
 tools/blktap2/drivers/hashtable_utility.h  |   55 +
 tools/blktap2/drivers/img2qcow.c           |  316 +++
 tools/blktap2/drivers/io-optimize.c        |  671 ++++++
 tools/blktap2/drivers/io-optimize.h        |   68 +
 tools/blktap2/drivers/libaio-compat.h      |  102 +
 tools/blktap2/drivers/lock.c               | 1000 +++++++++
 tools/blktap2/drivers/lock.h               |   51 +
 tools/blktap2/drivers/log.h                |  123 +
 tools/blktap2/drivers/md5.c                |  278 +++
 tools/blktap2/drivers/md5.h                |   15 +
 tools/blktap2/drivers/profile.h            |  191 ++
 tools/blktap2/drivers/qcow-create.c        |  121 +
 tools/blktap2/drivers/qcow.h               |  131 ++
 tools/blktap2/drivers/qcow2raw.c           |  443 ++++
 tools/blktap2/drivers/scheduler.c          |  265 +++
 tools/blktap2/drivers/scheduler.h          |   65 +
 tools/blktap2/drivers/tapdisk-client.c     |  496 +++++
 tools/blktap2/drivers/tapdisk-control.c    |  837 +++++++
 tools/blktap2/drivers/tapdisk-control.h    |   35 +
 tools/blktap2/drivers/tapdisk-diff.c       |  802 +++++++
 tools/blktap2/drivers/tapdisk-disktype.c   |  200 ++
 tools/blktap2/drivers/tapdisk-disktype.h   |   62 +
 tools/blktap2/drivers/tapdisk-driver.c     |  101 +
 tools/blktap2/drivers/tapdisk-driver.h     |   62 +
 tools/blktap2/drivers/tapdisk-filter.c     |  272 +++
 tools/blktap2/drivers/tapdisk-filter.h     |   67 +
 tools/blktap2/drivers/tapdisk-image.c      |  169 ++
 tools/blktap2/drivers/tapdisk-image.h      |   56 +
 tools/blktap2/drivers/tapdisk-interface.c  |  259 +++
 tools/blktap2/drivers/tapdisk-interface.h  |   54 +
 tools/blktap2/drivers/tapdisk-log.c        |  257 +++
 tools/blktap2/drivers/tapdisk-log.h        |   51 +
 tools/blktap2/drivers/tapdisk-queue.c      |  743 ++++++
 tools/blktap2/drivers/tapdisk-queue.h      |  125 ++
 tools/blktap2/drivers/tapdisk-ring.c       |  439 ++++
 tools/blktap2/drivers/tapdisk-ring.h       |   87 +
 tools/blktap2/drivers/tapdisk-server.c     |  345 +++
 tools/blktap2/drivers/tapdisk-server.h     |   67 +
 tools/blktap2/drivers/tapdisk-stream.c     |  605 +++++
 tools/blktap2/drivers/tapdisk-utils.c      |  214 ++
 tools/blktap2/drivers/tapdisk-utils.h      |   45 +
 tools/blktap2/drivers/tapdisk-vbd.c        | 1723 ++++++++++++++
 tools/blktap2/drivers/tapdisk-vbd.h        |  207 ++
 tools/blktap2/drivers/tapdisk.h            |  169 ++
 tools/blktap2/drivers/tapdisk2.c           |  138 ++
 tools/blktap2/drivers/td.c                 |  691 ++++++
 tools/blktap2/drivers/xmsnap               |   78 +
 tools/blktap2/include/Makefile             |   17 +
 tools/blktap2/include/atomicio.h           |   33 +
 tools/blktap2/include/blktap2.h            |   67 +
 tools/blktap2/include/blktaplib.h          |  242 ++
 tools/blktap2/include/libvhd-journal.h     |   68 +
 tools/blktap2/include/libvhd.h             |  326 +++
 tools/blktap2/include/list.h               |  125 ++
 tools/blktap2/include/lvm-util.h           |   71 +
 tools/blktap2/include/relative-path.h      |   43 +
 tools/blktap2/include/tapdisk-message.h    |  203 ++
 tools/blktap2/include/vhd-util.h           |   44 +
 tools/blktap2/include/vhd-uuid.h           |   63 +
 tools/blktap2/include/vhd.h                |  219 ++
 tools/blktap2/lvm/Makefile                 |   36 +
 tools/blktap2/lvm/lvm-util.c               |  349 +++
 tools/blktap2/vhd/Makefile                 |   51 +
 tools/blktap2/vhd/lib/Makefile             |   82 +
 tools/blktap2/vhd/lib/atomicio.c           |   61 +
 tools/blktap2/vhd/lib/libvhd-journal.c     | 1534 +++++++++++++
 tools/blktap2/vhd/lib/libvhd.c             | 3348 ++++++++++++++++++++++++++++
 tools/blktap2/vhd/lib/relative-path.c      |  299 +++
 tools/blktap2/vhd/lib/vhd-util-check.c     |  980 ++++++++
 tools/blktap2/vhd/lib/vhd-util-coalesce.c  |  218 ++
 tools/blktap2/vhd/lib/vhd-util-create.c    |   80 +
 tools/blktap2/vhd/lib/vhd-util-fill.c      |  105 +
 tools/blktap2/vhd/lib/vhd-util-modify.c    |  132 ++
 tools/blktap2/vhd/lib/vhd-util-query.c     |  159 ++
 tools/blktap2/vhd/lib/vhd-util-read.c      |  742 ++++++
 tools/blktap2/vhd/lib/vhd-util-repair.c    |   84 +
 tools/blktap2/vhd/lib/vhd-util-resize.c    | 1131 ++++++++++
 tools/blktap2/vhd/lib/vhd-util-revert.c    |  106 +
 tools/blktap2/vhd/lib/vhd-util-scan.c      | 1317 +++++++++++
 tools/blktap2/vhd/lib/vhd-util-set-field.c |  106 +
 tools/blktap2/vhd/lib/vhd-util-snapshot.c  |  216 ++
 tools/blktap2/vhd/lib/vhd-util-uuid.c      |  128 ++
 tools/blktap2/vhd/vhd-update.c             |  259 +++
 tools/blktap2/vhd/vhd-util.c               |  163 ++
 126 files changed, 40123 insertions(+)

diff --git a/tools/blktap2/Makefile b/tools/blktap2/Makefile
new file mode 100644
index 0000000..94200dc
--- /dev/null
+++ b/tools/blktap2/Makefile
@@ -0,0 +1,20 @@
+XEN_ROOT = $(CURDIR)/../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+CFLAGS  += $(CFLAGS_libxenctrl)
+LDLIBS += $(LDLIBS_libxenctrl)
+
+SUBDIRS-y :=
+SUBDIRS-y += include
+SUBDIRS-y += lvm
+SUBDIRS-y += vhd
+SUBDIRS-$(CONFIG_Linux) += drivers
+SUBDIRS-$(CONFIG_Linux) += control
+
+clean:
+       rm -rf *.a *.so *.o *.rpm $(LIB) *~ $(DEPS) TAGS
+
+distclean: clean
+
+.PHONY: all clean install distclean
+all clean install distclean: %: subdirs-%
diff --git a/tools/blktap2/README b/tools/blktap2/README
new file mode 100644
index 0000000..75fc614
--- /dev/null
+++ b/tools/blktap2/README
@@ -0,0 +1,321 @@
+Blktap2 Userspace Tools + Library
+================================
+
+Dutch Meyer
+4th June 2009
+
+Andrew Warfield and Julian Chesterfield
+16th June 2006
+
+
+The blktap2 userspace toolkit provides a user-level disk I/O
+interface. The blktap2 mechanism involves a kernel driver that acts
+similarly to the existing Xen/Linux blkback driver, and a set of
+associated user-level libraries.  Using these tools, blktap2 allows
+virtual block devices presented to VMs to be implemented in userspace
+and to be backed by raw partitions, files, network, etc.
+
+The key benefit of blktap2 is that it makes it easy and fast to write
+arbitrary block backends, and that these user-level backends actually
+perform very well.  Specifically:
+
+- Metadata disk formats such as Copy-on-Write, encrypted disks, sparse
+  formats and other compression features can be easily implemented.
+
+- Accessing file-based images from userspace avoids problems related
+  to flushing dirty pages which are present in the Linux loopback
+  driver.  (Specifically, doing a large number of writes to an
+  NFS-backed image don't result in the OOM killer going berserk.)
+
+- Per-disk handler processes enable easier userspace policing of block
+  resources, and process-granularity QoS techniques (disk scheduling
+  and related tools) may be trivially applied to block devices.
+
+- It's very easy to take advantage of userspace facilities such as
+  networking libraries, compression utilities, peer-to-peer
+  file-sharing systems and so on to build more complex block backends.
+
+- Crashes are contained -- incremental development/debugging is very
+  fast.
+
+How it works (in one paragraph):
+
+Working in conjunction with the kernel blktap2 driver, all disk I/O
+requests from VMs are passed to the userspace deamon (using a shared
+memory interface) through a character device. Each active disk is
+mapped to an individual device node, allowing per-disk processes to
+implement individual block devices where desired.  The userspace
+drivers are implemented using asynchronous (Linux libaio),
+O_DIRECT-based calls to preserve the unbuffered, batched and
+asynchronous request dispatch achieved with the existing blkback
+code.  We provide a simple, asynchronous virtual disk interface that
+makes it quite easy to add new disk implementations.
+
+As of June 2009 the current supported disk formats are:
+
+ - Raw Images (both on partitions and in image files)
+ - Fast sharable RAM disk between VMs (requires some form of 
+   cluster-based filesystem support e.g. OCFS2 in the guest kernel)
+ - VHD, including snapshots and sparse images
+ - Qcow, including snapshots and sparse images
+
+
+Build and Installation Instructions
+===================================
+
+Make to configure the blktap2 backend driver in your dom0 kernel.  It
+will inter-operate with the existing backend and frontend drivers.  It
+will also cohabitate with the original blktap driver.  However, some
+formats (currently aio and qcow) will default to their blktap2
+versions when specified in a vm configuration file.
+
+To build the tools separately, "make && make install" in
+tools/blktap2.
+
+
+Using the Tools
+===============
+
+Preparing an image for boot:
+
+The userspace disk agent is configured to start automatically via xend
+
+Customize the VM config file to use the 'tap:tapdisk' handler,
+followed by the driver type. e.g. for a raw image such as a file or
+partition:
+
+disk = ['tap:tapdisk:aio:<FILENAME>,sda1,w']
+
+Alternatively, the vhd-util tool (installed with make install, or in
+/blktap2/vhd) can be used to build sparse copy-on-write vhd images.
+
+For example, to build a sparse image -
+  vhd-util create -n MyVHDFile -s 1024
+
+This creates a sparse 1GB file named "MyVHDFile" that can be mounted
+and populated with data.
+
+One can also base the image on a raw file -
+  vhd-util snapshot -n MyVHDFile -p SomeRawFile -m
+
+This creates a sparse VHD file named "MyVHDFile" using "SomeRawFile"
+as a parent image.  Copy-on-write semantics ensure that writes will be
+stored in "MyVHDFile" while reads will be directed to the most
+recently written version of the data, either in "MyVHDFile" or
+"SomeRawFile" as is appropriate.  Other options exist as well, consult
+the vhd-util application for the complete set of VHD tools.
+
+VHD files can be mounted automatically in a guest similarly to the
+above AIO example simply by specifying the vhd driver.
+
+disk = ['tap:tapdisk:vhd:<VHD FILENAME>,sda1,w']
+
+
+Snapshots:
+
+Pausing a guest will also plug the corresponding IO queue for blktap2
+devices and stop blktap2 drivers.  This can be used to implement a
+safe live snapshot of qcow and vhd disks.  An example script "xmsnap"
+is shown in the tools/blktap2/drivers directory.  This script will
+perform a live snapshot of a qcow disk.  VHD files can use the
+"vhd-util snapshot" tool discussed above.  If this snapshot command is
+applied to a raw file mounted with tap:tapdisk:AIO, include the -m
+flag and the driver will be reloaded as VHD.  If applied to an already
+mounted VHD file, omit the -m flag.
+
+
+Mounting images in Dom0 using the blktap2 driver
+===============================================
+Tap (and blkback) disks are also mountable in Dom0 without requiring an
+active VM to attach. 
+
+The syntax is -
+  tapdisk2 -n <type>:<full path to file>
+
+For example -
+  tapdisk2  -n aio:/home/images/rawFile.img
+
+When successful the location of the new device will be provided by
+tapdisk2 to stdout and tapdisk2 will terminate.  From that point
+forward control of the device is provided through sysfs in the
+directory-
+
+  /sys/class/blktap2/blktap#/
+
+Where # is a blktap2 device number present in the path that tapdisk2
+printed before terminating.  The sysfs interface is largely intuitive,
+for example, to remove tap device 0 one would-
+  
+  echo 1 > /sys/class/blktap2/blktap0/remove
+
+Similarly, a pause control is available, which is can be used to plug
+the request queue of a live running guest.
+
+Previous versions of blktap mounted devices in dom0 by using blkfront
+in dom0 and the xm block-attach command.  This approach is still
+available, though slightly more cumbersome.
+
+
+Tapdisk Development
+===============================================
+
+People regularly ask how to develop their own tapdisk drivers, and
+while it has not yet been well documented, the process is relatively
+easy.  Here I will provide a brief overview.  The best reference, of
+course, comes from the existing drivers.  Specifically,
+blktap2/drivers/block-ram.c and blktap2/drivers/block-aio.c provide
+the clearest examples of simple drivers.
+ 
+
+Setup:
+
+First you need to register your new driver with blktap. This is done
+in disktypes.h.  There are five things that you must do.  To
+demonstrate, I will create a disk called "mynewdisk", you can name
+yours freely.
+
+1) Forward declare an instance of struct tap_disk.
+
+e.g. -  
+  extern struct tap_disk tapdisk_mynewdisk;
+
+2) Claim one of the unused disk type numbers, take care to observe the
+MAX_DISK_TYPES macro, increasing the number if necessary.
+
+e.g. -
+  #define DISK_TYPE_MYNEWDISK         10
+
+3) Create an instance of disk_info_t.  The bulk of this file contains examples 
of these.
+
+e.g. -
+  static disk_info_t mynewdisk_disk = {
+          DISK_TYPE_MYNEWDISK,
+          "My New Disk (mynewdisk)",
+          "mynewdisk",
+          0,
+  #ifdef TAPDISK
+          &tapdisk_mynewdisk,
+  #endif
+  };
+
+A few words about what these mean.  The first field must be the disk
+type number you claimed in step (2).  The second field is a string
+describing your disk, and may contain any relevant info.  The third
+field is the name of your disk as will be used by the tapdisk2 utility
+and xend (for example tapdisk2 -n mynewdisk:/path/to/disk.image, or in
+your xm create config file).  The forth is binary and determines
+whether you will have one instance of your driver, or many.  Here, a 1
+means that your driver is a singleton and will coordinate access to
+any number of tap devices.  0 is more common, meaning that you will
+have one driver for each device that is created.  The final field
+should contain a reference to the struct tap_disk you created in step
+(1).
+
+4) Add a reference to your disk info structure (from step (3)) to the
+dtypes array.  Take care here - you need to place it in the position
+corresponding to the device type number you claimed in step (2).  So
+we would place &mynewdisk_disk in dtypes[10].  Look at the other
+devices in this array and pad with "&null_disk," as necessary.
+
+5) Modify the xend python scripts.  You need to add your disk name to
+the list of disks that xend recognizes.
+
+edit:
+  tools/python/xen/xend/server/BlktapController.py
+
+And add your disk to the "blktap_disk_types" array near the top of
+your file.  Use the same name you specified in the third field of step
+(3).  The order of this list is not important.
+
+
+Now your driver is ready to be written.  Create a block-mynewdisk.c in
+tools/blktap2/drivers and add it to the Makefile.
+
+
+Development:
+
+Copying block-aio.c and block-ram.c would be a good place to start.
+Read those files as you go through this, I will be assisting by
+commenting on a few useful functions and structures.
+
+struct tap_disk:
+
+Remember the forward declaration in step (1) of the setup phase above?
+Now is the time to make that structure a reality.  This structure
+contains a list of function pointers for all the routines that will be
+asked of your driver.  Currently the required functions are open,
+close, read, write, get_parent_id, validate_parent, and debug.
+
+e.g. -
+  struct tap_disk tapdisk_mynewdisk = {
+          .disk_type          = "tapdisk_mynewdisk",
+          .flags              = 0,
+          .private_data_size  = sizeof(struct tdmynewdisk_state),
+          .td_open            = tdmynewdisk_open,
+                 ....
+
+The private_data_size field is used to provide a structure to store
+the state of your device.  It is very likely that you will want
+something here, but you are free to design whatever structure you
+want.  Blktap will allocate this space for you, you just need to tell
+it how much space you want.
+
+
+tdmynewdisk_open:
+
+This is the open routine.  The first argument is a structure
+representing your driver.  Two fields in this array are
+interesting. 
+
+driver->data will contain a block of memory of the size your requested
+in in the .private_data_size field of your struct tap_disk (above).
+
+driver->info contains a structure that details information about your
+disk.  You need to fill this out.  By convention this is done with a
+_get_image_info() function.  Assign a size (the total number of
+sectors), sector_size (the size of each sector in bytes, and set
+driver->info->info to 0.
+
+The second parameter contains the name that was specified in the
+creation of your device, either through xend, or on the command line
+with tapdisk2.  Usually this specifies a file that you will open in
+this routine.  The final parameter, flags, contains one of a number of
+flags specified in tapdisk.h that may change the way you treat the
+disk.
+
+
+_queue_read/write:
+
+These are your read and write operations.  What you do here will
+depend on your disk, but you should do exactly one of- 
+
+1) call td_complete_request with either error or success code.
+
+2) Call td_forward_request, which will forward the request to the next
+driver in the stack.
+
+3) Queue the request for asynchronous processing with
+td_prep_read/write.  In doing so, you will also register a callback
+for request completion.  When the request completes you must do one of
+options (1) or (2) above.  Finally, call td_queue_tiocb to submit the
+request to a wait queue.
+
+The above functions are defined in tapdisk-interface.c.  If you don't
+use them as specified you will run into problems as your driver will
+fail to inform blktap of the state of requests that have been
+submitted.  Blktap keeps track of all requests and does not like losing track.
+
+
+_close, _get_parent_id, _validate_parent:
+
+These last few tend to be very routine.  _close is called when the
+device is closed, and also when it is paused (in this case, open will
+also be called later).  The other functions are used in stacking
+drivers.  Most often drivers will return TD_NO_PARENT and -EINVAL,
+respectively.
+
+
+
+
+
+
diff --git a/tools/blktap2/control/Makefile b/tools/blktap2/control/Makefile
new file mode 100644
index 0000000..767f52a
--- /dev/null
+++ b/tools/blktap2/control/Makefile
@@ -0,0 +1,80 @@
+XEN_ROOT := $(CURDIR)/../../../
+include $(XEN_ROOT)/tools/Rules.mk
+
+MAJOR              = 1.0
+MINOR              = 0
+LIBNAME            = libblktapctl
+LIBSONAME          = $(LIBNAME).so.$(MAJOR)
+
+IBIN               = tap-ctl
+
+CFLAGS            += -Werror
+CFLAGS            += -Wno-unused
+CFLAGS            += -I../include -I../drivers
+CFLAGS            += $(CFLAGS_xeninclude)
+CFLAGS            += $(CFLAGS_libxenctrl)
+CFLAGS            += -D_GNU_SOURCE
+CFLAGS            += -DTAPCTL
+
+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
+
+CTL_PICS  = $(patsubst %.o,%.opic,$(CTL_OBJS))
+
+OBJS = $(CTL_OBJS) tap-ctl.o
+PICS = $(CTL_PICS)
+
+LIB_STATIC = $(LIBNAME).a
+LIB_SHARED = $(LIBSONAME).$(MINOR)
+IBIN = tap-ctl
+
+all: build
+
+build: $(IBIN) $(LIB_STATIC) $(LIB_SHARED)
+
+$(LIBNAME).so: $(LIBSONAME)
+       ln -sf $< $@
+
+$(LIBSONAME): $(LIB_SHARED)
+       ln -sf $< $@
+
+tap-ctl: tap-ctl.o $(LIBNAME).so
+       $(CC) $(LDFLAGS) -o $@ $^ $(APPEND_LDFLAGS)
+
+$(LIB_STATIC): $(CTL_OBJS)
+       $(AR) r $@ $^
+
+$(LIB_SHARED): $(CTL_PICS)
+       $(CC) $(LDFLAGS) -fPIC  -Wl,$(SONAME_LDFLAG) -Wl,$(LIBSONAME) 
$(SHLIB_LDFLAGS) -rdynamic $^ -o $@  $(APPEND_LDFLAGS)
+
+install: $(IBIN) $(LIB_STATIC) $(LIB_SHARED)
+       $(INSTALL_DIR) -p $(DESTDIR)$(sbindir)
+       $(INSTALL_PROG) $(IBIN) $(DESTDIR)$(sbindir)
+       $(INSTALL_DATA) $(LIB_STATIC) $(DESTDIR)$(libdir)
+       $(INSTALL_PROG) $(LIB_SHARED) $(DESTDIR)$(libdir)
+       ln -sf $(LIBSONAME) $(DESTDIR)$(libdir)/$(LIBNAME).so
+       ln -sf $(LIB_SHARED) $(DESTDIR)$(libdir)/$(LIBSONAME)
+
+clean:
+       rm -f $(OBJS) $(PICS) $(DEPS) $(IBIN) $(LIB_STATIC) $(LIB_SHARED)
+       rm -f $(LIBNAME).so $(LIBSONAME)
+       rm -f *~
+
+distclean: clean
+
+.PHONY: all build clean distclean install
+
+-include $(DEPS)
diff --git a/tools/blktap2/control/tap-ctl-allocate.c 
b/tools/blktap2/control/tap-ctl-allocate.c
new file mode 100644
index 0000000..8a6471e
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-allocate.c
@@ -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 --git a/tools/blktap2/control/tap-ctl-attach.c 
b/tools/blktap2/control/tap-ctl-attach.c
new file mode 100644
index 0000000..3cb933c
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-attach.c
@@ -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 --git a/tools/blktap2/control/tap-ctl-check.c 
b/tools/blktap2/control/tap-ctl-check.c
new file mode 100644
index 0000000..e98583a
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-check.c
@@ -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 --git a/tools/blktap2/control/tap-ctl-close.c 
b/tools/blktap2/control/tap-ctl-close.c
new file mode 100644
index 0000000..2e5f80b
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-close.c
@@ -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 --git a/tools/blktap2/control/tap-ctl-create.c 
b/tools/blktap2/control/tap-ctl-create.c
new file mode 100644
index 0000000..f4c47f1
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-create.c
@@ -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.
+ */
+#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) {
+               err = id;
+               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 --git a/tools/blktap2/control/tap-ctl-destroy.c 
b/tools/blktap2/control/tap-ctl-destroy.c
new file mode 100644
index 0000000..dc5dbaa
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-destroy.c
@@ -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 --git a/tools/blktap2/control/tap-ctl-detach.c 
b/tools/blktap2/control/tap-ctl-detach.c
new file mode 100644
index 0000000..7d7bbf3
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-detach.c
@@ -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 --git a/tools/blktap2/control/tap-ctl-free.c 
b/tools/blktap2/control/tap-ctl-free.c
new file mode 100644
index 0000000..9ae7295
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-free.c
@@ -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 --git a/tools/blktap2/control/tap-ctl-ipc.c 
b/tools/blktap2/control/tap-ctl-ipc.c
new file mode 100644
index 0000000..c7e42d9
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-ipc.c
@@ -0,0 +1,249 @@
+/*
+ * 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) {
+                       if (errno == EINTR)
+                               continue;
+                       break;
+               }
+               else if (FD_ISSET(fd, &readfds)) {
+                       ret = read(fd, message + offset, len - offset);
+                       if (ret <= 0) {
+                               if (errno == EINTR)
+                                       continue;
+                               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) {
+                       if (errno == EINTR)
+                               continue;
+                       break;
+               }
+               else if (FD_ISSET(fd, &writefds)) {
+                       ret = write(fd, message + offset, len - offset);
+                       if (ret <= 0) {
+                               if (errno == EINTR)
+                                       continue;
+                               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 --git a/tools/blktap2/control/tap-ctl-list.c 
b/tools/blktap2/control/tap-ctl-list.c
new file mode 100644
index 0000000..f8d49c3
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-list.c
@@ -0,0 +1,536 @@
+/*
+ * 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, *next;
+
+               list_for_each_entry_safe(tl, next, &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;
+       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;
+}
+
+int
+tap_ctl_find(const char *type, const char *path, tap_list_t *tap)
+{
+       tap_list_t **list, **_entry;
+       int ret = -ENOENT, err;
+
+       err = tap_ctl_list(&list);
+       if (err)
+               return err;
+
+       for (_entry = list; *_entry != NULL; ++_entry) {
+               tap_list_t *entry  = *_entry;
+
+               if (type && (!entry->type || strcmp(entry->type, type)))
+                       continue;
+
+               if (path && (!entry->path || strcmp(entry->path, path)))
+                       continue;
+
+               *tap = *entry;
+               tap->type = tap->path = NULL;
+               ret = 0;
+               break;
+       }
+
+       tap_ctl_free_list(list);
+
+       return ret;
+}
diff --git a/tools/blktap2/control/tap-ctl-major.c 
b/tools/blktap2/control/tap-ctl-major.c
new file mode 100644
index 0000000..847af28
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-major.c
@@ -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 --git a/tools/blktap2/control/tap-ctl-open.c 
b/tools/blktap2/control/tap-ctl-open.c
new file mode 100644
index 0000000..5961c99
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-open.c
@@ -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 --git a/tools/blktap2/control/tap-ctl-pause.c 
b/tools/blktap2/control/tap-ctl-pause.c
new file mode 100644
index 0000000..5e31a58
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-pause.c
@@ -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 --git a/tools/blktap2/control/tap-ctl-spawn.c 
b/tools/blktap2/control/tap-ctl-spawn.c
new file mode 100644
index 0000000..31a651e
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-spawn.c
@@ -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 --git a/tools/blktap2/control/tap-ctl-unpause.c 
b/tools/blktap2/control/tap-ctl-unpause.c
new file mode 100644
index 0000000..dfb7450
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl-unpause.c
@@ -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 --git a/tools/blktap2/control/tap-ctl.c b/tools/blktap2/control/tap-ctl.c
new file mode 100644
index 0000000..e254f07
--- /dev/null
+++ b/tools/blktap2/control/tap-ctl.c
@@ -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);

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

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