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

[Xen-changelog] [xen-unstable] Added blktap support. Includes kernel driver (enabled as CONFIG_XEN_BLKDEV_TAP=y) and userspace tools. The userspace deamon (blktapctrl) is enabled by default when xend is activated. For further information on using and configuring blktap see tools/blktap/README.



# HG changeset patch
# User jchesterfield@xxxxxxxxxxxxxxxxxxxxxxx
# Node ID 2937703f0ed05099f829dea41ec7fdb67a1d2eaa
# Parent  af9809f51f81a3c43f276f00c81a52ef558afda4
Added blktap support. Includes kernel driver (enabled as 
CONFIG_XEN_BLKDEV_TAP=y) and userspace tools. The userspace deamon (blktapctrl) 
is enabled by default when xend is activated. For further information on using 
and configuring blktap see tools/blktap/README.
---
 buildconfigs/linux-defconfig_xen0_x86_32            |    1 
 buildconfigs/linux-defconfig_xen0_x86_64            |    1 
 buildconfigs/linux-defconfig_xen_x86_32             |    1 
 buildconfigs/linux-defconfig_xen_x86_64             |    1 
 linux-2.6-xen-sparse/drivers/xen/Kconfig            |   12 
 linux-2.6-xen-sparse/drivers/xen/Makefile           |    1 
 linux-2.6-xen-sparse/drivers/xen/blktap/Makefile    |    3 
 linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c    | 1439 ++++++++++++++++++++
 linux-2.6-xen-sparse/drivers/xen/blktap/common.h    |  120 +
 linux-2.6-xen-sparse/drivers/xen/blktap/interface.c |  165 ++
 linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c    |  354 ++++
 patches/linux-2.6.16.13/blktap-aio-16_03_06.patch   |  164 ++
 tools/Makefile                                      |    2 
 tools/blktap/Makefile                               |   28 
 tools/blktap/README                                 |  122 +
 tools/blktap/drivers/Makefile                       |   76 +
 tools/blktap/drivers/aes.c                          | 1319 ++++++++++++++++++
 tools/blktap/drivers/aes.h                          |   26 
 tools/blktap/drivers/blktapctrl.c                   |  704 +++++++++
 tools/blktap/drivers/blktapctrl.h                   |   55 
 tools/blktap/drivers/block-aio.c                    |  327 ++++
 tools/blktap/drivers/block-qcow.c                   | 1369 +++++++++++++++++++
 tools/blktap/drivers/block-ram.c                    |  296 ++++
 tools/blktap/drivers/block-sync.c                   |  242 +++
 tools/blktap/drivers/block-vmdk.c                   |  415 +++++
 tools/blktap/drivers/bswap.h                        |  202 ++
 tools/blktap/drivers/img2qcow.c                     |  289 ++++
 tools/blktap/drivers/qcow-create.c                  |   80 +
 tools/blktap/drivers/qcow2raw.c                     |  346 ++++
 tools/blktap/drivers/tapdisk.c                      |  671 +++++++++
 tools/blktap/drivers/tapdisk.h                      |  211 ++
 tools/blktap/lib/Makefile                           |   66 
 tools/blktap/lib/blkif.c                            |  185 ++
 tools/blktap/lib/blktaplib.h                        |  223 +++
 tools/blktap/lib/list.h                             |   55 
 tools/blktap/lib/xenbus.c                           |  387 +++++
 tools/blktap/lib/xs_api.c                           |  364 +++++
 tools/blktap/lib/xs_api.h                           |   50 
 tools/examples/Makefile                             |    1 
 tools/examples/blktap                               |   15 
 tools/examples/xen-backend.agent                    |    3 
 tools/examples/xen-backend.rules                    |    1 
 tools/libaio/COPYING                                |  515 +++++++
 tools/libaio/ChangeLog                              |   43 
 tools/libaio/INSTALL                                |   18 
 tools/libaio/Makefile                               |   40 
 tools/libaio/TODO                                   |    4 
 tools/libaio/harness/Makefile                       |   37 
 tools/libaio/harness/README                         |   19 
 tools/libaio/harness/attic/0.t                      |    9 
 tools/libaio/harness/attic/1.t                      |    9 
 tools/libaio/harness/cases/10.t                     |   53 
 tools/libaio/harness/cases/11.t                     |   39 
 tools/libaio/harness/cases/12.t                     |   49 
 tools/libaio/harness/cases/13.t                     |   66 
 tools/libaio/harness/cases/14.t                     |   90 +
 tools/libaio/harness/cases/2.t                      |   41 
 tools/libaio/harness/cases/3.t                      |   25 
 tools/libaio/harness/cases/4.t                      |   72 +
 tools/libaio/harness/cases/5.t                      |   47 
 tools/libaio/harness/cases/6.t                      |   57 
 tools/libaio/harness/cases/7.t                      |   27 
 tools/libaio/harness/cases/8.t                      |   49 
 tools/libaio/harness/cases/aio_setup.h              |   98 +
 tools/libaio/harness/cases/common-7-8.h             |   37 
 tools/libaio/harness/main.c                         |   39 
 tools/libaio/harness/runtests.sh                    |   19 
 tools/libaio/libaio.spec                            |  177 ++
 tools/libaio/man/aio.3                              |  315 ++++
 tools/libaio/man/aio_cancel.3                       |  137 +
 tools/libaio/man/aio_cancel64.3                     |   50 
 tools/libaio/man/aio_error.3                        |   81 +
 tools/libaio/man/aio_error64.3                      |   64 
 tools/libaio/man/aio_fsync.3                        |  139 +
 tools/libaio/man/aio_fsync64.3                      |   51 
 tools/libaio/man/aio_init.3                         |   96 +
 tools/libaio/man/aio_read.3                         |  146 ++
 tools/libaio/man/aio_read64.3                       |   60 
 tools/libaio/man/aio_return.3                       |   71 
 tools/libaio/man/aio_return64.3                     |   51 
 tools/libaio/man/aio_suspend.3                      |  123 +
 tools/libaio/man/aio_suspend64.3                    |   51 
 tools/libaio/man/aio_write.3                        |  176 ++
 tools/libaio/man/aio_write64.3                      |   61 
 tools/libaio/man/io.3                               |  351 ++++
 tools/libaio/man/io_cancel.1                        |   21 
 tools/libaio/man/io_cancel.3                        |   65 
 tools/libaio/man/io_destroy.1                       |   17 
 tools/libaio/man/io_fsync.3                         |   82 +
 tools/libaio/man/io_getevents.1                     |   29 
 tools/libaio/man/io_getevents.3                     |   79 +
 tools/libaio/man/io_prep_fsync.3                    |   89 +
 tools/libaio/man/io_prep_pread.3                    |   79 +
 tools/libaio/man/io_prep_pwrite.3                   |   77 +
 tools/libaio/man/io_queue_init.3                    |   63 
 tools/libaio/man/io_queue_release.3                 |   48 
 tools/libaio/man/io_queue_run.3                     |   50 
 tools/libaio/man/io_queue_wait.3                    |   56 
 tools/libaio/man/io_set_callback.3                  |   44 
 tools/libaio/man/io_setup.1                         |   15 
 tools/libaio/man/io_submit.1                        |  109 +
 tools/libaio/man/io_submit.3                        |  135 +
 tools/libaio/man/lio_listio.3                       |  229 +++
 tools/libaio/man/lio_listio64.3                     |   39 
 tools/libaio/src/Makefile                           |   64 
 tools/libaio/src/compat-0_1.c                       |   62 
 tools/libaio/src/io_cancel.c                        |   23 
 tools/libaio/src/io_destroy.c                       |   23 
 tools/libaio/src/io_getevents.c                     |   57 
 tools/libaio/src/io_queue_init.c                    |   33 
 tools/libaio/src/io_queue_release.c                 |   27 
 tools/libaio/src/io_queue_run.c                     |   39 
 tools/libaio/src/io_queue_wait.c                    |   31 
 tools/libaio/src/io_setup.c                         |   23 
 tools/libaio/src/io_submit.c                        |   23 
 tools/libaio/src/libaio.h                           |  222 +++
 tools/libaio/src/libaio.map                         |   22 
 tools/libaio/src/raw_syscall.c                      |   18 
 tools/libaio/src/syscall-alpha.h                    |  209 ++
 tools/libaio/src/syscall-i386.h                     |   72 +
 tools/libaio/src/syscall-ia64.h                     |   44 
 tools/libaio/src/syscall-ppc.h                      |   94 +
 tools/libaio/src/syscall-s390.h                     |  131 +
 tools/libaio/src/syscall-x86_64.h                   |   63 
 tools/libaio/src/syscall.h                          |   27 
 tools/libaio/src/vsys_def.h                         |   24 
 tools/misc/xend                                     |    7 
 tools/python/xen/xend/XendDomainInfo.py             |    2 
 tools/python/xen/xend/server/BlktapController.py    |   14 
 tools/python/xen/xm/create.py                       |    8 
 tools/python/xen/xm/main.py                         |    8 
 tools/xenstore/Makefile                             |    7 
 xen/common/grant_table.c                            |    6 
 133 files changed, 16795 insertions(+), 8 deletions(-)

diff -r af9809f51f81 -r 2937703f0ed0 buildconfigs/linux-defconfig_xen0_x86_32
--- a/buildconfigs/linux-defconfig_xen0_x86_32  Thu Jul 13 09:55:14 2006 +0100
+++ b/buildconfigs/linux-defconfig_xen0_x86_32  Thu Jul 13 10:13:26 2006 +0100
@@ -1322,6 +1322,7 @@ CONFIG_XEN_PCIDEV_BACKEND_PASS=y
 CONFIG_XEN_PCIDEV_BACKEND_PASS=y
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 CONFIG_XEN_BLKDEV_BACKEND=y
+CONFIG_XEN_BLKDEV_TAP=y
 CONFIG_XEN_NETDEV_BACKEND=y
 # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
 CONFIG_XEN_NETDEV_LOOPBACK=y
diff -r af9809f51f81 -r 2937703f0ed0 buildconfigs/linux-defconfig_xen0_x86_64
--- a/buildconfigs/linux-defconfig_xen0_x86_64  Thu Jul 13 09:55:14 2006 +0100
+++ b/buildconfigs/linux-defconfig_xen0_x86_64  Thu Jul 13 10:13:26 2006 +0100
@@ -1263,6 +1263,7 @@ CONFIG_XEN_PCIDEV_BACKEND_PASS=y
 CONFIG_XEN_PCIDEV_BACKEND_PASS=y
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 CONFIG_XEN_BLKDEV_BACKEND=y
+CONFIG_XEN_BLKDEV_TAP=y
 CONFIG_XEN_NETDEV_BACKEND=y
 # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
 CONFIG_XEN_NETDEV_LOOPBACK=y
diff -r af9809f51f81 -r 2937703f0ed0 buildconfigs/linux-defconfig_xen_x86_32
--- a/buildconfigs/linux-defconfig_xen_x86_32   Thu Jul 13 09:55:14 2006 +0100
+++ b/buildconfigs/linux-defconfig_xen_x86_32   Thu Jul 13 10:13:26 2006 +0100
@@ -3023,6 +3023,7 @@ CONFIG_XEN_PCIDEV_BACKEND_VPCI=y
 # CONFIG_XEN_PCIDEV_BACKEND_PASS is not set
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 CONFIG_XEN_BLKDEV_BACKEND=y
+CONFIG_XEN_BLKDEV_TAP=y
 CONFIG_XEN_NETDEV_BACKEND=y
 # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
 CONFIG_XEN_NETDEV_LOOPBACK=y
diff -r af9809f51f81 -r 2937703f0ed0 buildconfigs/linux-defconfig_xen_x86_64
--- a/buildconfigs/linux-defconfig_xen_x86_64   Thu Jul 13 09:55:14 2006 +0100
+++ b/buildconfigs/linux-defconfig_xen_x86_64   Thu Jul 13 10:13:26 2006 +0100
@@ -2855,6 +2855,7 @@ CONFIG_XEN_PCIDEV_BACKEND_PASS=y
 CONFIG_XEN_PCIDEV_BACKEND_PASS=y
 # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
 CONFIG_XEN_BLKDEV_BACKEND=y
+CONFIG_XEN_BLKDEV_TAP=y
 CONFIG_XEN_NETDEV_BACKEND=y
 # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
 CONFIG_XEN_NETDEV_LOOPBACK=y
diff -r af9809f51f81 -r 2937703f0ed0 linux-2.6-xen-sparse/drivers/xen/Kconfig
--- a/linux-2.6-xen-sparse/drivers/xen/Kconfig  Thu Jul 13 09:55:14 2006 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig  Thu Jul 13 10:13:26 2006 +0100
@@ -94,6 +94,18 @@ config XEN_XENBUS_DEV
        depends on PROC_FS
        default y
 
+config XEN_BLKDEV_TAP
+       tristate "Blockk device tap backend"
+       depends on XEN_BACKEND
+       default XEN_PRIVILEGED_GUEST
+       help
+         The block tap driver is an alternative to the block back driver 
+          and allows VM block requests to be redirected to userspace through
+          a device interface.  The tap allows user-space development of 
+          high-performance block backends, where disk images may be implemented
+          as files, in memory, or on other hosts across the network.  This 
+         driver can safely coexist with the existing blockback driver.
+
 config XEN_NETDEV_BACKEND
        tristate "Network-device backend driver"
         depends on XEN_BACKEND && NET
diff -r af9809f51f81 -r 2937703f0ed0 linux-2.6-xen-sparse/drivers/xen/Makefile
--- a/linux-2.6-xen-sparse/drivers/xen/Makefile Thu Jul 13 09:55:14 2006 +0100
+++ b/linux-2.6-xen-sparse/drivers/xen/Makefile Thu Jul 13 10:13:26 2006 +0100
@@ -8,6 +8,7 @@ obj-$(CONFIG_XEN_BALLOON)               += balloon/
 obj-$(CONFIG_XEN_BALLOON)              += balloon/
 obj-$(CONFIG_XEN_DEVMEM)               += char/
 obj-$(CONFIG_XEN_BLKDEV_BACKEND)       += blkback/
+obj-$(CONFIG_XEN_BLKDEV_TAP)           += blktap/
 obj-$(CONFIG_XEN_NETDEV_BACKEND)       += netback/
 obj-$(CONFIG_XEN_TPMDEV_BACKEND)       += tpmback/
 obj-$(CONFIG_XEN_BLKDEV_FRONTEND)      += blkfront/
diff -r af9809f51f81 -r 2937703f0ed0 tools/Makefile
--- a/tools/Makefile    Thu Jul 13 09:55:14 2006 +0100
+++ b/tools/Makefile    Thu Jul 13 10:13:26 2006 +0100
@@ -16,6 +16,8 @@ SUBDIRS-$(VTPM_TOOLS) += vtpm_manager
 SUBDIRS-$(VTPM_TOOLS) += vtpm_manager
 SUBDIRS-$(VTPM_TOOLS) += vtpm
 SUBDIRS-y += xenstat
+SUBDIRS-y += libaio
+SUBDIRS-y += blktap
 
 # These don't cross-compile
 ifeq ($(XEN_COMPILE_ARCH),$(XEN_TARGET_ARCH))
diff -r af9809f51f81 -r 2937703f0ed0 tools/examples/Makefile
--- a/tools/examples/Makefile   Thu Jul 13 09:55:14 2006 +0100
+++ b/tools/examples/Makefile   Thu Jul 13 10:13:26 2006 +0100
@@ -26,6 +26,7 @@ XEN_SCRIPTS += network-nat vif-nat
 XEN_SCRIPTS += network-nat vif-nat
 XEN_SCRIPTS += block
 XEN_SCRIPTS += block-enbd block-nbd
+XEN_SCRIPTS += blktap
 XEN_SCRIPTS += vtpm vtpm-delete
 XEN_SCRIPTS += xen-hotplug-cleanup
 XEN_SCRIPTS += external-device-migrate
diff -r af9809f51f81 -r 2937703f0ed0 tools/examples/xen-backend.agent
--- a/tools/examples/xen-backend.agent  Thu Jul 13 09:55:14 2006 +0100
+++ b/tools/examples/xen-backend.agent  Thu Jul 13 10:13:26 2006 +0100
@@ -7,6 +7,9 @@ claim_lock xenbus_hotplug_global
 claim_lock xenbus_hotplug_global
 
 case "$XENBUS_TYPE" in
+  tap)
+    /etc/xen/scripts/blktap "$ACTION"
+    ;;
   vbd)
     /etc/xen/scripts/block "$ACTION"
     ;;
diff -r af9809f51f81 -r 2937703f0ed0 tools/examples/xen-backend.rules
--- a/tools/examples/xen-backend.rules  Thu Jul 13 09:55:14 2006 +0100
+++ b/tools/examples/xen-backend.rules  Thu Jul 13 10:13:26 2006 +0100
@@ -1,3 +1,4 @@ SUBSYSTEM=="xen-backend", KERNEL=="vbd*"
+SUBSYSTEM=="xen-backend", KERNEL=="tap*", RUN+="/etc/xen/scripts/blktap 
$env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vbd*", RUN+="/etc/xen/scripts/block 
$env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vtpm*", RUN+="/etc/xen/scripts/vtpm 
$env{ACTION}"
 SUBSYSTEM=="xen-backend", KERNEL=="vif*", ACTION=="online", RUN+="$env{script} 
online"
diff -r af9809f51f81 -r 2937703f0ed0 tools/misc/xend
--- a/tools/misc/xend   Thu Jul 13 09:55:14 2006 +0100
+++ b/tools/misc/xend   Thu Jul 13 10:13:26 2006 +0100
@@ -92,6 +92,10 @@ def start_consoled():
 def start_consoled():
     if os.fork() == 0:
         os.execvp('xenconsoled', ['xenconsoled'])
+
+def start_blktapctrl():
+    if os.fork() == 0:
+        os.execvp('blktapctrl', ['blktapctrl'])
             
 def main():
     try:
@@ -106,16 +110,19 @@ def main():
     elif sys.argv[1] == 'start':
         start_xenstored()
         start_consoled()
+       start_blktapctrl()
         return daemon.start()
     elif sys.argv[1] == 'trace_start':
         start_xenstored()
         start_consoled()
+        start_blktapctrl()
         return daemon.start(trace=1)
     elif sys.argv[1] == 'stop':
         return daemon.stop()
     elif sys.argv[1] == 'restart':
         start_xenstored()
         start_consoled()
+        start_blktapctrl()
         return daemon.stop() or daemon.start()
     elif sys.argv[1] == 'status':
         return daemon.status()
diff -r af9809f51f81 -r 2937703f0ed0 tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py   Thu Jul 13 09:55:14 2006 +0100
+++ b/tools/python/xen/xend/XendDomainInfo.py   Thu Jul 13 10:13:26 2006 +0100
@@ -1701,6 +1701,7 @@ def addControllerClass(device_class, cls
 
 
 from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, usbif
+from xen.xend.server.BlktapController import BlktapController
 addControllerClass('vbd',  blkif.BlkifController)
 addControllerClass('vif',  netif.NetifController)
 addControllerClass('vtpm', tpmif.TPMifController)
@@ -1708,3 +1709,4 @@ addControllerClass('ioports', iopif.IOPo
 addControllerClass('ioports', iopif.IOPortsController)
 addControllerClass('irq',  irqif.IRQController)
 addControllerClass('usb',  usbif.UsbifController)
+addControllerClass('tap',  BlktapController)
diff -r af9809f51f81 -r 2937703f0ed0 tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py     Thu Jul 13 09:55:14 2006 +0100
+++ b/tools/python/xen/xm/create.py     Thu Jul 13 10:13:26 2006 +0100
@@ -479,7 +479,13 @@ def configure_disks(config_devs, vals):
     """Create the config for disks (virtual block devices).
     """
     for (uname, dev, mode, backend) in vals.disk:
-        config_vbd = ['vbd',
+
+        if uname.startswith('tap:'):
+            cls = 'tap'
+        else:
+            cls = 'vbd'
+
+        config_vbd = [cls,
                       ['uname', uname],
                       ['dev', dev ],
                       ['mode', mode ] ]
diff -r af9809f51f81 -r 2937703f0ed0 tools/python/xen/xm/main.py
--- a/tools/python/xen/xm/main.py       Thu Jul 13 09:55:14 2006 +0100
+++ b/tools/python/xen/xm/main.py       Thu Jul 13 10:13:26 2006 +0100
@@ -994,7 +994,13 @@ def xm_block_attach(args):
     arg_check(args, 'block-attach', 4, 5)
 
     dom = args[0]
-    vbd = ['vbd',
+
+    if args[1].startswith('tap:'):
+        cls = 'tap'
+    else:
+        cls = 'vbd'
+        
+    vbd = [cls,
            ['uname', args[1]],
            ['dev',   args[2]],
            ['mode',  args[3]]]
diff -r af9809f51f81 -r 2937703f0ed0 tools/xenstore/Makefile
--- a/tools/xenstore/Makefile   Thu Jul 13 09:55:14 2006 +0100
+++ b/tools/xenstore/Makefile   Thu Jul 13 10:13:26 2006 +0100
@@ -35,7 +35,7 @@ XENSTORED_OBJS += $(XENSTORED_$(OS))
 XENSTORED_OBJS += $(XENSTORED_$(OS))
 
 .PHONY: all
-all: libxenstore.so xenstored $(CLIENTS) xs_tdb_dump xenstore-control 
xenstore-ls
+all: libxenstore.so libxenstore.a xenstored $(CLIENTS) xs_tdb_dump 
xenstore-control xenstore-ls
 
 test_interleaved_transactions: test_interleaved_transactions.o
        $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -L. -lxenstore -o $@
@@ -89,6 +89,9 @@ talloc_test.o: talloc.c
 
 libxenstore.so: xs.opic xs_lib.opic
        $(CC) $(CFLAGS) $(LDFLAGS) -Wl,-soname -Wl,libxenstore.so -shared -o $@ 
$^ -lpthread
+
+libxenstore.a: libxenstore.so
+       ar rcs libxenstore.a $^
 
 .PHONY: clean
 clean: testsuite-clean
@@ -172,7 +175,7 @@ install: all
        $(INSTALL_PROG) xenstore-control $(DESTDIR)/usr/bin
        $(INSTALL_PROG) xenstore-ls $(DESTDIR)/usr/bin
        $(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR)
-       $(INSTALL_LIBS) libxenstore.so $(DESTDIR)/usr/$(LIBDIR)
+       $(INSTALL_DATA) libxenstore.* $(DESTDIR)/usr/$(LIBDIR)
        $(INSTALL_DATA) xs.h $(DESTDIR)/usr/include
        $(INSTALL_DATA) xs_lib.h $(DESTDIR)/usr/include
 
diff -r af9809f51f81 -r 2937703f0ed0 xen/common/grant_table.c
--- a/xen/common/grant_table.c  Thu Jul 13 09:55:14 2006 +0100
+++ b/xen/common/grant_table.c  Thu Jul 13 10:13:26 2006 +0100
@@ -110,8 +110,7 @@ __gnttab_map_grant_ref(
         return;
     }
 
-    if ( unlikely((rd = find_domain_by_id(op->dom)) == NULL) ||
-         unlikely(ld == rd) )
+    if ( unlikely((rd = find_domain_by_id(op->dom)) == NULL) )
     {
         if ( rd != NULL )
             put_domain(rd);
@@ -350,8 +349,7 @@ __gnttab_unmap_grant_ref(
     ref   = map->ref;
     flags = map->flags;
 
-    if ( unlikely((rd = find_domain_by_id(dom)) == NULL) ||
-         unlikely(ld == rd) )
+    if ( unlikely((rd = find_domain_by_id(dom)) == NULL) )
     {
         if ( rd != NULL )
             put_domain(rd);
diff -r af9809f51f81 -r 2937703f0ed0 
linux-2.6-xen-sparse/drivers/xen/blktap/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/blktap/Makefile  Thu Jul 13 10:13:26 
2006 +0100
@@ -0,0 +1,3 @@
+LINUXINCLUDE += -I../xen/include/public/io
+obj-y  := xenbus.o interface.o blktap.o 
+
diff -r af9809f51f81 -r 2937703f0ed0 
linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c  Thu Jul 13 10:13:26 
2006 +0100
@@ -0,0 +1,1439 @@
+/******************************************************************************
+ * drivers/xen/blktap/blktap.c
+ * 
+ * Back-end driver for user level virtual block devices. This portion of the
+ * driver exports a 'unified' block-device interface that can be accessed
+ * by any operating system that implements a compatible front end. Requests
+ * are remapped to a user-space memory region.
+ *
+ * Based on the blkback driver code.
+ * 
+ * Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/list.h>
+#include <asm/hypervisor.h>
+#include "common.h"
+#include <xen/balloon.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/gfp.h>
+#include <linux/poll.h>
+#include <asm/tlbflush.h>
+#include <linux/devfs_fs_kernel.h>
+
+#define MAX_TAP_DEV 100     /*the maximum number of tapdisk ring devices    */
+#define MAX_DEV_NAME 100    /*the max tapdisk ring device name e.g. blktap0 */
+
+/*
+ * The maximum number of requests that can be outstanding at any time
+ * is determined by 
+ *
+ *   [mmap_alloc * MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST] 
+ *
+ * where mmap_alloc < MAX_DYNAMIC_MEM.
+ *
+ * TODO:
+ * mmap_alloc is initialised to 2 and should be adjustable on the fly via
+ * sysfs.
+ */
+#define MAX_DYNAMIC_MEM 64
+#define MAX_PENDING_REQS 64   
+#define MMAP_PAGES (MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST)
+#define MMAP_VADDR(_start, _req,_seg)                                   \
+        (_start +                                                       \
+         ((_req) * BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE) +        \
+         ((_seg) * PAGE_SIZE))
+static int blkif_reqs = MAX_PENDING_REQS;
+static int mmap_pages = MMAP_PAGES;
+
+#define RING_PAGES 1 /* BLKTAP - immediately before the mmap area, we
+                     * have a bunch of pages reserved for shared
+                     * memory rings.
+                     */
+
+/*Data struct associated with each of the tapdisk devices*/
+typedef struct tap_blkif {
+       struct vm_area_struct *vma;   /*Shared memory area                   */
+       unsigned long rings_vstart;   /*Kernel memory mapping                */
+       unsigned long user_vstart;    /*User memory mapping                  */
+       unsigned long dev_inuse;      /*One process opens device at a time.  */
+       unsigned long dev_pending;    /*In process of being opened           */
+       unsigned long ring_ok;        /*make this ring->state                */
+       blkif_front_ring_t ufe_ring;  /*Rings up to user space.              */
+       wait_queue_head_t wait;       /*for poll                             */
+       unsigned long mode;           /*current switching mode               */
+       int minor;                    /*Minor number for tapdisk device      */
+       pid_t pid;                    /*tapdisk process id                   */
+       enum { RUNNING, CLEANSHUTDOWN } status; /*Detect a clean userspace 
+                                                 shutdown                   */
+       unsigned long *idx_map;       /*Record the user ring id to kern 
+                                       [req id, idx] tuple                  */
+       blkif_t *blkif;               /*Associate blkif with tapdev          */
+} tap_blkif_t;
+
+/*Private data struct associated with the inode*/
+typedef struct private_info {
+       int idx;
+} private_info_t;
+
+/*Data struct handed back to userspace for tapdisk device to VBD mapping*/
+typedef struct domid_translate {
+       unsigned short domid;
+       unsigned short busid;
+} domid_translate_t ;
+
+
+domid_translate_t  translate_domid[MAX_TAP_DEV];
+tap_blkif_t *tapfds[MAX_TAP_DEV];
+
+static int __init set_blkif_reqs(char *str)
+{
+       get_option(&str, &blkif_reqs);
+       return 1;
+}
+__setup("blkif_reqs=", set_blkif_reqs);
+
+/* Run-time switchable: /sys/module/blktap/parameters/ */
+static unsigned int log_stats = 0;
+static unsigned int debug_lvl = 0;
+module_param(log_stats, int, 0644);
+module_param(debug_lvl, int, 0644);
+
+/*
+ * Each outstanding request that we've passed to the lower device layers has a 
+ * 'pending_req' allocated to it. Each buffer_head that completes decrements 
+ * the pendcnt towards zero. When it hits zero, the specified domain has a 
+ * response queued for it, with the saved 'id' passed back.
+ */
+typedef struct {
+       blkif_t       *blkif;
+       unsigned long  id;
+       unsigned short mem_idx;
+       int            nr_pages;
+       atomic_t       pendcnt;
+       unsigned short operation;
+       int            status;
+       struct list_head free_list;
+       int            inuse;
+} pending_req_t;
+
+static pending_req_t *pending_reqs[MAX_PENDING_REQS];
+static struct list_head pending_free;
+static DEFINE_SPINLOCK(pending_free_lock);
+static DECLARE_WAIT_QUEUE_HEAD (pending_free_wq);
+static int alloc_pending_reqs;
+
+typedef unsigned int PEND_RING_IDX;
+
+static inline int MASK_PEND_IDX(int i) { 
+       return (i & (MAX_PENDING_REQS-1)); 
+}
+
+static inline unsigned int RTN_PEND_IDX(pending_req_t *req, int idx) {
+       return (req - pending_reqs[idx]);
+}
+
+#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
+
+#define BLKBACK_INVALID_HANDLE (~0)
+
+typedef struct mmap_page {
+       unsigned long start;
+       struct page *mpage;
+} mmap_page_t;
+
+static mmap_page_t mmap_start[MAX_DYNAMIC_MEM];
+static unsigned short mmap_alloc = 0;
+static unsigned short mmap_lock = 0;
+static unsigned short mmap_inuse = 0;
+static unsigned long *pending_addrs[MAX_DYNAMIC_MEM];
+
+/******************************************************************
+ * GRANT HANDLES
+ */
+
+/* When using grant tables to map a frame for device access then the
+ * handle returned must be used to unmap the frame. This is needed to
+ * drop the ref count on the frame.
+ */
+struct grant_handle_pair
+{
+        grant_handle_t kernel;
+        grant_handle_t user;
+};
+
+static struct grant_handle_pair 
+    pending_grant_handles[MAX_DYNAMIC_MEM][MMAP_PAGES];
+#define pending_handle(_id, _idx, _i) \
+    (pending_grant_handles[_id][((_idx) * BLKIF_MAX_SEGMENTS_PER_REQUEST) \
+    + (_i)])
+
+
+static int blktap_read_ufe_ring(int idx); /*local prototypes*/
+
+#define BLKTAP_MINOR 0  /*/dev/xen/blktap resides at device number
+                         major=254, minor numbers begin at 0            */ 
+#define BLKTAP_DEV_MAJOR 254         /* TODO: Make major number dynamic  *
+                                      * and create devices in the kernel *
+                                     */
+#define BLKTAP_DEV_DIR  "/dev/xen"
+
+/* blktap IOCTLs: */
+#define BLKTAP_IOCTL_KICK_FE         1
+#define BLKTAP_IOCTL_KICK_BE         2 /* currently unused */
+#define BLKTAP_IOCTL_SETMODE         3
+#define BLKTAP_IOCTL_SENDPID        4
+#define BLKTAP_IOCTL_NEWINTF        5
+#define BLKTAP_IOCTL_MINOR          6
+#define BLKTAP_IOCTL_MAJOR          7
+#define BLKTAP_QUERY_ALLOC_REQS      8
+#define BLKTAP_IOCTL_FREEINTF        9
+#define BLKTAP_IOCTL_PRINT_IDXS      100  
+
+/* blktap switching modes: (Set with BLKTAP_IOCTL_SETMODE)             */
+#define BLKTAP_MODE_PASSTHROUGH      0x00000000  /* default            */
+#define BLKTAP_MODE_INTERCEPT_FE     0x00000001
+#define BLKTAP_MODE_INTERCEPT_BE     0x00000002  /* unimp.             */
+
+#define BLKTAP_MODE_INTERPOSE \
+           (BLKTAP_MODE_INTERCEPT_FE | BLKTAP_MODE_INTERCEPT_BE)
+
+
+static inline int BLKTAP_MODE_VALID(unsigned long arg)
+{
+       return ((arg == BLKTAP_MODE_PASSTHROUGH ) ||
+               (arg == BLKTAP_MODE_INTERCEPT_FE) ||
+                (arg == BLKTAP_MODE_INTERPOSE   ));
+}
+
+/* Requests passing through the tap to userspace are re-assigned an ID.
+ * We must record a mapping between the BE [IDX,ID] tuple and the userspace
+ * ring ID. 
+ */
+
+static inline unsigned long MAKE_ID(domid_t fe_dom, PEND_RING_IDX idx)
+{
+        return ((fe_dom << 16) | MASK_PEND_IDX(idx));
+}
+
+extern inline PEND_RING_IDX ID_TO_IDX(unsigned long id)
+{
+        return (PEND_RING_IDX)(id & 0x0000ffff);
+}
+
+extern inline int ID_TO_MIDX(unsigned long id)
+{
+        return (int)(id >> 16);
+}
+
+#define INVALID_REQ 0xdead0000
+
+/*TODO: Convert to a free list*/
+static inline int GET_NEXT_REQ(unsigned long *idx_map)
+{
+       int i;
+       for (i = 0; i < MAX_PENDING_REQS; i++)
+               if (idx_map[i] == INVALID_REQ) return i;
+
+       return INVALID_REQ;
+}
+
+
+#define BLKTAP_INVALID_HANDLE(_g) \
+    (((_g->kernel) == 0xFFFF) && ((_g->user) == 0xFFFF))
+
+#define BLKTAP_INVALIDATE_HANDLE(_g) do {       \
+    (_g)->kernel = 0xFFFF; (_g)->user = 0xFFFF; \
+    } while(0)
+
+
+/******************************************************************
+ * BLKTAP VM OPS
+ */
+
+static struct page *blktap_nopage(struct vm_area_struct *vma,
+                                 unsigned long address,
+                                 int *type)
+{
+       /*
+        * if the page has not been mapped in by the driver then return
+        * NOPAGE_SIGBUS to the domain.
+        */
+
+       return NOPAGE_SIGBUS;
+}
+
+struct vm_operations_struct blktap_vm_ops = {
+       nopage:   blktap_nopage,
+};
+
+/******************************************************************
+ * BLKTAP FILE OPS
+ */
+ 
+/*Function Declarations*/
+static int get_next_free_dev(void);
+static int blktap_open(struct inode *inode, struct file *filp);
+static int blktap_release(struct inode *inode, struct file *filp);
+static int blktap_mmap(struct file *filp, struct vm_area_struct *vma);
+static int blktap_ioctl(struct inode *inode, struct file *filp,
+                        unsigned int cmd, unsigned long arg);
+static unsigned int blktap_poll(struct file *file, poll_table *wait);
+
+struct miscdevice *set_misc(int minor, char *name, int dev);
+
+static struct file_operations blktap_fops = {
+       .owner   = THIS_MODULE,
+       .poll    = blktap_poll,
+       .ioctl   = blktap_ioctl,
+       .open    = blktap_open,
+       .release = blktap_release,
+       .mmap    = blktap_mmap,
+};
+
+
+static int get_next_free_dev(void)
+{
+       tap_blkif_t *info;
+       int i = 0, ret = -1;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pending_free_lock, flags);
+       
+       while (i < MAX_TAP_DEV) {
+               info = tapfds[i];
+               if ( (tapfds[i] != NULL) && (info->dev_inuse == 0)
+                       && (info->dev_pending == 0) ) {
+                       info->dev_pending = 1;
+                       ret = i;
+                       goto done;
+               }
+               i++;
+       }
+       
+done:
+       spin_unlock_irqrestore(&pending_free_lock, flags);
+       return ret;
+}
+
+int dom_to_devid(domid_t domid, int xenbus_id, blkif_t *blkif) 
+{
+       int i;
+               
+       for (i = 0; i < MAX_TAP_DEV; i++)
+               if ( (translate_domid[i].domid == domid)
+                   && (translate_domid[i].busid == xenbus_id) ) {
+                       tapfds[i]->blkif = blkif;
+                       tapfds[i]->status = RUNNING;
+                       return i;
+               }
+       return -1;
+}
+
+void signal_tapdisk(int idx) 
+{
+       tap_blkif_t *info;
+       struct task_struct *ptask;
+
+       info = tapfds[idx];
+       if ( (idx > 0) && (idx < MAX_TAP_DEV) && (info->pid > 0) ) {
+               ptask = find_task_by_pid(info->pid);
+               if (ptask) { 
+                       info->status = CLEANSHUTDOWN;
+               }
+       }
+       info->blkif = NULL;
+       return;
+}
+
+static int blktap_open(struct inode *inode, struct file *filp)
+{
+       blkif_sring_t *sring;
+       int idx = iminor(inode) - BLKTAP_MINOR;
+       tap_blkif_t *info;
+       private_info_t *prv;
+       int i;
+       
+       if (tapfds[idx] == NULL) {
+               WPRINTK("Unable to open device /dev/xen/blktap%d\n",
+                      idx);
+               return -ENOMEM;
+       }
+       DPRINTK("Opening device /dev/xen/blktap%d\n",idx);
+       
+       info = tapfds[idx];
+       
+       /*Only one process can access device at a time*/
+       if (test_and_set_bit(0, &info->dev_inuse))
+               return -EBUSY;
+
+       info->dev_pending = 0;
+           
+       /* Allocate the fe ring. */
+       sring = (blkif_sring_t *)get_zeroed_page(GFP_KERNEL);
+       if (sring == NULL)
+               goto fail_nomem;
+
+       SetPageReserved(virt_to_page(sring));
+    
+       SHARED_RING_INIT(sring);
+       FRONT_RING_INIT(&info->ufe_ring, sring, PAGE_SIZE);
+       
+       prv = kzalloc(sizeof(private_info_t),GFP_KERNEL);
+       prv->idx = idx;
+       filp->private_data = prv;
+       info->vma = NULL;
+
+       info->idx_map = kmalloc(sizeof(unsigned long) * MAX_PENDING_REQS, 
+                               GFP_KERNEL);
+       
+       if (idx > 0) {
+               init_waitqueue_head(&info->wait);
+               for (i = 0; i < MAX_PENDING_REQS; i++) 
+                       info->idx_map[i] = INVALID_REQ;
+       }
+
+       DPRINTK("Tap open: device /dev/xen/blktap%d\n",idx);
+       return 0;
+
+ fail_nomem:
+       return -ENOMEM;
+}
+
+static int blktap_release(struct inode *inode, struct file *filp)
+{
+       int idx = iminor(inode) - BLKTAP_MINOR;
+       tap_blkif_t *info;
+       
+       if (tapfds[idx] == NULL) {
+               WPRINTK("Trying to free device that doesn't exist "
+                      "[/dev/xen/blktap%d]\n",idx);
+               return -1;
+       }
+       info = tapfds[idx];
+       info->dev_inuse = 0;
+       DPRINTK("Freeing device [/dev/xen/blktap%d]\n",idx);
+
+       /* Free the ring page. */
+       ClearPageReserved(virt_to_page(info->ufe_ring.sring));
+       free_page((unsigned long) info->ufe_ring.sring);
+
+       /* Clear any active mappings and free foreign map table */
+       if (info->vma) {
+               zap_page_range(
+                       info->vma, info->vma->vm_start, 
+                       info->vma->vm_end - info->vma->vm_start, NULL);
+               info->vma = NULL;
+       }
+       
+       if (filp->private_data) kfree(filp->private_data);
+
+       if ( (info->status != CLEANSHUTDOWN) && (info->blkif != NULL) ) {
+               kthread_stop(info->blkif->xenblkd);
+               info->blkif->xenblkd = NULL;
+               info->status = CLEANSHUTDOWN;
+       }       
+       return 0;
+}
+
+
+/* Note on mmap:
+ * We need to map pages to user space in a way that will allow the block
+ * subsystem set up direct IO to them.  This couldn't be done before, because
+ * there isn't really a sane way to translate a user virtual address down to a 
+ * physical address when the page belongs to another domain.
+ *
+ * My first approach was to map the page in to kernel memory, add an entry
+ * for it in the physical frame list (using alloc_lomem_region as in blkback)
+ * and then attempt to map that page up to user space.  This is disallowed
+ * by xen though, which realizes that we don't really own the machine frame
+ * underlying the physical page.
+ *
+ * The new approach is to provide explicit support for this in xen linux.
+ * The VMA now has a flag, VM_FOREIGN, to indicate that it contains pages
+ * mapped from other vms.  vma->vm_private_data is set up as a mapping 
+ * from pages to actual page structs.  There is a new clause in get_user_pages
+ * that does the right thing for this sort of mapping.
+ */
+static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       int size;
+       struct page **map;
+       int i;
+       private_info_t *prv;
+       tap_blkif_t *info;
+
+       /*Retrieve the dev info*/
+       prv = (private_info_t *)filp->private_data;
+       if (prv == NULL) {
+               WPRINTK("blktap: mmap, retrieving idx failed\n");
+               return -ENOMEM;
+       }
+       info = tapfds[prv->idx];
+       
+       vma->vm_flags |= VM_RESERVED;
+       vma->vm_ops = &blktap_vm_ops;
+
+       size = vma->vm_end - vma->vm_start;
+       if (size != ((mmap_pages + RING_PAGES) << PAGE_SHIFT)) {
+               WPRINTK("you _must_ map exactly %d pages!\n",
+                      mmap_pages + RING_PAGES);
+               return -EAGAIN;
+       }
+
+       size >>= PAGE_SHIFT;
+       info->rings_vstart = vma->vm_start;
+       info->user_vstart  = info->rings_vstart + (RING_PAGES << PAGE_SHIFT);
+    
+       /* Map the ring pages to the start of the region and reserve it. */
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+       if (remap_pfn_range(vma, vma->vm_start, 
+                           __pa(info->ufe_ring.sring) >> PAGE_SHIFT, 
+                           PAGE_SIZE, vma->vm_page_prot)) {
+               WPRINTK("Mapping user ring failed!\n");
+               goto fail;
+       }
+
+       /* Mark this VM as containing foreign pages, and set up mappings. */
+       map = kzalloc(((vma->vm_end - vma->vm_start) >> PAGE_SHIFT)
+                     * sizeof(struct page_struct*),
+                     GFP_KERNEL);
+       if (map == NULL) {
+               WPRINTK("Couldn't alloc VM_FOREIGN map.\n");
+               goto fail;
+       }
+
+       for (i = 0; i < ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT); i++)
+               map[i] = NULL;
+    
+       vma->vm_private_data = map;
+       vma->vm_flags |= VM_FOREIGN;
+
+       info->vma = vma;
+       info->ring_ok = 1;
+       return 0;
+ fail:
+       /* Clear any active mappings. */
+       zap_page_range(vma, vma->vm_start, 
+                      vma->vm_end - vma->vm_start, NULL);
+
+       return -ENOMEM;
+}
+
+
+static int blktap_ioctl(struct inode *inode, struct file *filp,
+                        unsigned int cmd, unsigned long arg)
+{
+       int idx = iminor(inode) - BLKTAP_MINOR;
+       switch(cmd) {
+       case BLKTAP_IOCTL_KICK_FE: 
+       {
+               /* There are fe messages to process. */
+               return blktap_read_ufe_ring(idx);
+       }
+       case BLKTAP_IOCTL_SETMODE:
+       {
+               tap_blkif_t *info = tapfds[idx];
+               
+               if ( (idx > 0) && (idx < MAX_TAP_DEV) 
+                    && (tapfds[idx] != NULL) ) 
+               {
+                       if (BLKTAP_MODE_VALID(arg)) {
+                               info->mode = arg;
+                               /* XXX: may need to flush rings here. */
+                               DPRINTK("blktap: set mode to %lx\n", 
+                                      arg);
+                               return 0;
+                       }
+               }
+               return 0;
+       }
+       case BLKTAP_IOCTL_PRINT_IDXS:
+        {
+               tap_blkif_t *info = tapfds[idx];
+               
+               if ( (idx > 0) && (idx < MAX_TAP_DEV) 
+                    && (tapfds[idx] != NULL) ) 
+               {
+                       printk("User Rings: \n-----------\n");
+                       printk("UF: rsp_cons: %2d, req_prod_prv: %2d "
+                               "| req_prod: %2d, rsp_prod: %2d\n",
+                               info->ufe_ring.rsp_cons,
+                               info->ufe_ring.req_prod_pvt,
+                               info->ufe_ring.sring->req_prod,
+                               info->ufe_ring.sring->rsp_prod);
+               }
+               return 0;
+        }
+       case BLKTAP_IOCTL_SENDPID:
+       {
+               tap_blkif_t *info = tapfds[idx];
+               
+               if ( (idx > 0) && (idx < MAX_TAP_DEV) 
+                    && (tapfds[idx] != NULL) ) 
+               {
+                       info->pid = (pid_t)arg;
+                       DPRINTK("blktap: pid received %d\n", 
+                              info->pid);
+               }
+               return 0;
+       }
+       case BLKTAP_IOCTL_NEWINTF:
+       {               
+               uint64_t val = (uint64_t)arg;
+               domid_translate_t *tr = (domid_translate_t *)&val;
+               int newdev;
+
+               DPRINTK("NEWINTF Req for domid %d and bus id %d\n", 
+                      tr->domid, tr->busid);
+               newdev = get_next_free_dev();
+               if (newdev < 1) {
+                       WPRINTK("Error initialising /dev/xen/blktap - "
+                               "No more devices\n");
+                       return -1;
+               }
+               translate_domid[newdev].domid = tr->domid;
+               translate_domid[newdev].busid = tr->busid;
+               return newdev;
+       }
+       case BLKTAP_IOCTL_FREEINTF:
+       {
+               unsigned long dev = arg;
+               tap_blkif_t *info = NULL;
+
+               if ( (dev > 0) && (dev < MAX_TAP_DEV) ) info = tapfds[dev];
+
+               if ( (info != NULL) && (info->dev_pending) )
+                       info->dev_pending = 0;
+               return 0;
+       }
+       case BLKTAP_IOCTL_MINOR:
+       {
+               unsigned long dev = arg;
+               tap_blkif_t *info = NULL;
+               
+               if ( (dev > 0) && (dev < MAX_TAP_DEV) ) info = tapfds[dev];
+               
+               if (info != NULL) return info->minor;
+               else return -1;
+       }
+       case BLKTAP_IOCTL_MAJOR:
+               return BLKTAP_DEV_MAJOR;
+
+       case BLKTAP_QUERY_ALLOC_REQS:
+       {
+               WPRINTK("BLKTAP_QUERY_ALLOC_REQS ioctl: %d/%d\n",
+                      alloc_pending_reqs, blkif_reqs);
+               return (alloc_pending_reqs/blkif_reqs) * 100;
+       }
+       }
+       return -ENOIOCTLCMD;
+}
+
+static unsigned int blktap_poll(struct file *file, poll_table *wait)
+{
+       private_info_t *prv;
+       tap_blkif_t *info;
+       
+       /*Retrieve the dev info*/
+       prv = (private_info_t *)file->private_data;
+       if (prv == NULL) {
+               WPRINTK(" poll, retrieving idx failed\n");
+               return 0;
+       }
+       
+       if (prv->idx == 0) return 0;
+       
+       info = tapfds[prv->idx];
+       
+       poll_wait(file, &info->wait, wait);
+       if (info->ufe_ring.req_prod_pvt != info->ufe_ring.sring->req_prod) {
+               flush_tlb_all();
+               RING_PUSH_REQUESTS(&info->ufe_ring);
+               return POLLIN | POLLRDNORM;
+       }
+       return 0;
+}
+
+void blktap_kick_user(int idx)
+{
+       tap_blkif_t *info;
+
+       if (idx == 0) return;
+       
+       info = tapfds[idx];
+       
+       if (info != NULL) wake_up_interruptible(&info->wait);
+       return;
+}
+
+static int do_block_io_op(blkif_t *blkif);
+static void dispatch_rw_block_io(blkif_t *blkif,
+                                blkif_request_t *req,
+                                pending_req_t *pending_req);
+static void make_response(blkif_t *blkif, unsigned long id, 
+                          unsigned short op, int st);
+
+/******************************************************************
+ * misc small helpers
+ */
+/* FIXME: Return ENOMEM properly on failure to allocate additional reqs. */
+static void req_increase(void)
+{
+       int i, j;
+       struct page *page;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pending_free_lock, flags);
+
+       if (mmap_alloc >= MAX_PENDING_REQS || mmap_lock) 
+               goto done;
+
+       pending_reqs[mmap_alloc]  = kzalloc(sizeof(pending_req_t) *
+                                       blkif_reqs, GFP_KERNEL);
+       pending_addrs[mmap_alloc] = kzalloc(sizeof(unsigned long) *
+                                       mmap_pages, GFP_KERNEL);
+
+       if (!pending_reqs[mmap_alloc] || !pending_addrs[mmap_alloc]) {
+               kfree(pending_reqs[mmap_alloc]);
+               kfree(pending_addrs[mmap_alloc]);
+               WPRINTK("%s: out of memory\n", __FUNCTION__); 
+               goto done;
+       }
+
+#ifdef __ia64__
+       extern unsigned long alloc_empty_foreign_map_page_range(
+               unsigned long pages);
+       mmap_start[mmap_alloc].start = (unsigned long)
+               alloc_empty_foreign_map_page_range(mmap_pages);
+#else /* ! ia64 */
+       page = balloon_alloc_empty_page_range(mmap_pages);
+       BUG_ON(page == NULL);
+
+       /* Pin all of the pages. */
+       for (i=0; i<mmap_pages; i++)
+               get_page(&page[i]);
+
+       mmap_start[mmap_alloc].start = 
+               (unsigned long)pfn_to_kaddr(page_to_pfn(page));
+       mmap_start[mmap_alloc].mpage = page;
+
+#endif
+       DPRINTK("%s: reqs=%d, pages=%d, mmap_vstart=0x%lx\n",
+               __FUNCTION__, blkif_reqs, mmap_pages, 
+              mmap_start[mmap_alloc].start);
+
+       BUG_ON(mmap_start[mmap_alloc].start == 0);
+
+       for (i = 0; i < mmap_pages; i++) 
+               pending_addrs[mmap_alloc][i] = 
+                       mmap_start[mmap_alloc].start + (i << PAGE_SHIFT);
+
+       for (i = 0; i < MAX_PENDING_REQS ; i++) {
+               list_add_tail(&pending_reqs[mmap_alloc][i].free_list, 
+                             &pending_free);
+               pending_reqs[mmap_alloc][i].mem_idx = mmap_alloc;
+               for (j = 0; j < BLKIF_MAX_SEGMENTS_PER_REQUEST; j++)
+                       BLKTAP_INVALIDATE_HANDLE(&pending_handle(mmap_alloc, 
+                                                                i, j));
+       }
+
+       mmap_alloc++;
+       DPRINTK("# MMAPs increased to %d\n",mmap_alloc);
+ done:
+       spin_unlock_irqrestore(&pending_free_lock, flags);
+
+}
+
+static void mmap_req_del(int mmap)
+{
+       int i;
+       struct page *page;
+
+       /*Spinlock already acquired*/
+       kfree(pending_reqs[mmap]);
+       kfree(pending_addrs[mmap]);
+
+#ifdef __ia64__
+       /*Not sure what goes here yet!*/
+#else
+
+       /* Unpin all of the pages. */
+       page = mmap_start[mmap].mpage;
+       for (i=0; i<mmap_pages; i++)
+               put_page(&page[i]);
+
+       balloon_dealloc_empty_page_range(mmap_start[mmap].mpage, mmap_pages);
+#endif
+
+       mmap_lock = 0;
+       DPRINTK("# MMAPs decreased to %d\n",mmap_alloc);
+       mmap_alloc--;
+}
+
+/*N.B. Currently unused - will be accessed via sysfs*/
+static void req_decrease(void)
+{
+       pending_req_t *req;
+       int i;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pending_free_lock, flags);
+
+       DPRINTK("Req decrease called.\n");
+       if (mmap_lock || mmap_alloc == 1) 
+               goto done;
+
+       mmap_lock = 1;
+       mmap_inuse = MAX_PENDING_REQS;
+       
+        /*Go through reqs and remove any that aren't in use*/
+       for (i = 0; i < MAX_PENDING_REQS ; i++) {
+               req = &pending_reqs[mmap_alloc-1][i];
+               if (req->inuse == 0) {
+                       list_del(&req->free_list);
+                       mmap_inuse--;
+               }
+       }
+       if (mmap_inuse == 0) mmap_req_del(mmap_alloc-1);
+ done:
+       spin_unlock_irqrestore(&pending_free_lock, flags);
+       return;
+}
+
+static pending_req_t* alloc_req(void)
+{
+       pending_req_t *req = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pending_free_lock, flags);
+
+       if (!list_empty(&pending_free)) {
+               req = list_entry(pending_free.next, pending_req_t, free_list);
+               list_del(&req->free_list);
+       }
+
+       if (req) {
+               req->inuse = 1;
+               alloc_pending_reqs++;
+       }
+       spin_unlock_irqrestore(&pending_free_lock, flags);
+
+       return req;
+}
+
+static void free_req(pending_req_t *req)
+{
+       unsigned long flags;
+       int was_empty;
+
+       spin_lock_irqsave(&pending_free_lock, flags);
+
+       alloc_pending_reqs--;
+       req->inuse = 0;
+       if (mmap_lock && (req->mem_idx == mmap_alloc-1)) {
+               mmap_inuse--;
+               if (mmap_inuse == 0) mmap_req_del(mmap_alloc-1);
+               spin_unlock_irqrestore(&pending_free_lock, flags);
+               return;
+       }
+       was_empty = list_empty(&pending_free);
+       list_add(&req->free_list, &pending_free);
+
+       spin_unlock_irqrestore(&pending_free_lock, flags);
+
+       if (was_empty)
+               wake_up(&pending_free_wq);
+}
+
+static void fast_flush_area(pending_req_t *req, int k_idx, int u_idx, int 
+                           tapidx)
+{
+       struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST*2];
+       unsigned int i, invcount = 0;
+       struct grant_handle_pair *khandle;
+       uint64_t ptep;
+       int ret, mmap_idx;
+       unsigned long kvaddr, uvaddr;
+
+       tap_blkif_t *info = tapfds[tapidx];
+       
+       if (info == NULL) {
+               WPRINTK("fast_flush: Couldn't get info!\n");
+               return;
+       }
+       mmap_idx = req->mem_idx;
+
+       for (i = 0; i < req->nr_pages; i++) {
+               kvaddr = MMAP_VADDR(mmap_start[mmap_idx].start, k_idx, i);
+               uvaddr = MMAP_VADDR(info->user_vstart, u_idx, i);
+
+               khandle = &pending_handle(mmap_idx, k_idx, i);
+               if (BLKTAP_INVALID_HANDLE(khandle)) {
+                       WPRINTK("BLKTAP_INVALID_HANDLE\n");
+                       continue;
+               }
+               gnttab_set_unmap_op(&unmap[invcount], 
+                       MMAP_VADDR(mmap_start[mmap_idx].start, k_idx, i), 
+                                   GNTMAP_host_map, khandle->kernel);
+               invcount++;
+
+               if (create_lookup_pte_addr(
+                   info->vma->vm_mm,
+                   MMAP_VADDR(info->user_vstart, u_idx, i), 
+                   &ptep) !=0) {
+                       WPRINTK("Couldn't get a pte addr!\n");
+                       return;
+               }
+
+               gnttab_set_unmap_op(&unmap[invcount], 
+                       ptep, GNTMAP_host_map,
+                       khandle->user);
+               invcount++;
+            
+               BLKTAP_INVALIDATE_HANDLE(khandle);
+       }
+       ret = HYPERVISOR_grant_table_op(
+               GNTTABOP_unmap_grant_ref, unmap, invcount);
+       BUG_ON(ret);
+       
+       if (info->vma != NULL)
+               zap_page_range(info->vma, 
+                              MMAP_VADDR(info->user_vstart, u_idx, 0), 
+                              req->nr_pages << PAGE_SHIFT, NULL);
+}
+
+/******************************************************************
+ * SCHEDULER FUNCTIONS
+ */
+
+static void print_stats(blkif_t *blkif)
+{
+       printk(KERN_DEBUG "%s: oo %3d  |  rd %4d  |  wr %4d\n",
+              current->comm, blkif->st_oo_req,
+              blkif->st_rd_req, blkif->st_wr_req);
+       blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
+       blkif->st_rd_req = 0;
+       blkif->st_wr_req = 0;
+       blkif->st_oo_req = 0;
+}
+
+int tap_blkif_schedule(void *arg)
+{
+       blkif_t *blkif = arg;
+
+       blkif_get(blkif);
+
+       if (debug_lvl)
+               printk(KERN_DEBUG "%s: started\n", current->comm);
+
+       while (!kthread_should_stop()) {
+               wait_event_interruptible(
+                       blkif->wq,
+                       blkif->waiting_reqs || kthread_should_stop());
+               wait_event_interruptible(
+                       pending_free_wq,
+                       !list_empty(&pending_free) || kthread_should_stop());
+
+               blkif->waiting_reqs = 0;
+               smp_mb(); /* clear flag *before* checking for work */
+
+               if (do_block_io_op(blkif))
+                       blkif->waiting_reqs = 1;
+
+               if (log_stats && time_after(jiffies, blkif->st_print))
+                       print_stats(blkif);
+       }
+
+       if (log_stats)
+               print_stats(blkif);
+       if (debug_lvl)
+               printk(KERN_DEBUG "%s: exiting\n", current->comm);
+
+       blkif->xenblkd = NULL;
+       blkif_put(blkif);
+
+       return 0;
+}
+
+/******************************************************************
+ * COMPLETION CALLBACK -- Called by user level ioctl()
+ */
+
+static int blktap_read_ufe_ring(int idx)
+{
+       /* This is called to read responses from the UFE ring. */
+       RING_IDX i, j, rp;
+       blkif_response_t *resp;
+       blkif_t *blkif=NULL;
+       int pending_idx, usr_idx, mmap_idx;
+       pending_req_t *pending_req;
+       tap_blkif_t *info;
+       
+       info = tapfds[idx];
+       if (info == NULL) {
+               return 0;
+       }
+
+       /* We currently only forward packets in INTERCEPT_FE mode. */
+       if (!(info->mode & BLKTAP_MODE_INTERCEPT_FE))
+               return 0;
+
+       /* for each outstanding message on the UFEring  */
+       rp = info->ufe_ring.sring->rsp_prod;
+       rmb();
+        
+       for (i = info->ufe_ring.rsp_cons; i != rp; i++) {
+               resp = RING_GET_RESPONSE(&info->ufe_ring, i);
+               ++info->ufe_ring.rsp_cons;
+
+               /*retrieve [usr_idx] to [mmap_idx,pending_idx] mapping*/
+               usr_idx = (int)resp->id;
+               pending_idx = MASK_PEND_IDX(ID_TO_IDX(info->idx_map[usr_idx]));
+               mmap_idx = ID_TO_MIDX(info->idx_map[usr_idx]);
+
+               if ( (mmap_idx >= mmap_alloc) || 
+                  (ID_TO_IDX(info->idx_map[usr_idx]) >= MAX_PENDING_REQS) )
+                       WPRINTK("Incorrect req map"
+                              "[%d], internal map [%d,%d (%d)]\n", 
+                              usr_idx, mmap_idx, 
+                              ID_TO_IDX(info->idx_map[usr_idx]),
+                              MASK_PEND_IDX(
+                                      ID_TO_IDX(info->idx_map[usr_idx])));
+
+               pending_req = &pending_reqs[mmap_idx][pending_idx];
+               blkif = pending_req->blkif;
+
+               for (j = 0; j < pending_req->nr_pages; j++) {
+
+                       unsigned long kvaddr, uvaddr;
+                       struct page **map = info->vma->vm_private_data;
+                       struct page *pg;
+                       int offset; 
+
+                       uvaddr  = MMAP_VADDR(info->user_vstart, usr_idx, j);
+                       kvaddr = MMAP_VADDR(mmap_start[mmap_idx].start, 
+                                           pending_idx, j);
+
+                       pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
+                       ClearPageReserved(pg);
+                       offset = (uvaddr - info->vma->vm_start) 
+                               >> PAGE_SHIFT;
+                       map[offset] = NULL;
+               }
+               fast_flush_area(pending_req, pending_idx, usr_idx, idx); 
+               make_response(blkif, pending_req->id, resp->operation,
+                             resp->status);
+               info->idx_map[usr_idx] = INVALID_REQ;
+               blkif_put(pending_req->blkif);
+               free_req(pending_req);
+       }
+               
+       return 0;
+}
+
+
+/******************************************************************************
+ * NOTIFICATION FROM GUEST OS.
+ */
+
+static void blkif_notify_work(blkif_t *blkif)
+{
+       blkif->waiting_reqs = 1;
+       wake_up(&blkif->wq);
+}
+
+irqreturn_t tap_blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+       blkif_notify_work(dev_id);
+       return IRQ_HANDLED;
+}
+
+
+
+/******************************************************************
+ * DOWNWARD CALLS -- These interface with the block-device layer proper.
+ */
+static int print_dbug = 1;
+static int do_block_io_op(blkif_t *blkif)
+{
+       blkif_back_ring_t *blk_ring = &blkif->blk_ring;
+       blkif_request_t *req;
+       pending_req_t *pending_req;
+       RING_IDX rc, rp;
+       int more_to_do = 0;
+       tap_blkif_t *info;
+
+       rc = blk_ring->req_cons;
+       rp = blk_ring->sring->req_prod;
+       rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+       /*Check blkif has corresponding UE ring*/
+       if (blkif->dev_num == -1) {
+               /*oops*/
+               if (print_dbug) {
+                       WPRINTK("Corresponding UE " 
+                              "ring does not exist!\n");
+                       print_dbug = 0; /*We only print this message once*/
+               }
+               return 1; 
+       }
+
+       info = tapfds[blkif->dev_num];
+       if (info == NULL || !info->dev_inuse) {
+               if (print_dbug) {
+                       WPRINTK("Can't get UE info!\n");
+                       print_dbug = 0;
+               }
+               return 1;
+       }
+
+       while (rc != rp) {
+               
+               if (RING_FULL(&info->ufe_ring)) {
+                       WPRINTK("RING_FULL! More to do\n");
+                       more_to_do = 1;
+                       break;
+               }
+               
+               if (RING_REQUEST_CONS_OVERFLOW(blk_ring, rc)) {
+                       WPRINTK("RING_REQUEST_CONS_OVERFLOW!"
+                              " More to do\n");
+                       more_to_do = 1;
+                       break;          
+               }
+
+               pending_req = alloc_req();
+               if (NULL == pending_req) {
+                       blkif->st_oo_req++;
+                       more_to_do = 1;
+                       break;
+               }
+
+               req = RING_GET_REQUEST(blk_ring, rc);
+               blk_ring->req_cons = ++rc; /* before make_response() */ 
+
+               switch (req->operation) {
+               case BLKIF_OP_READ:
+                       blkif->st_rd_req++;
+                       dispatch_rw_block_io(blkif, req, pending_req);
+                       break;
+
+               case BLKIF_OP_WRITE:
+                       blkif->st_wr_req++;
+                       dispatch_rw_block_io(blkif, req, pending_req);
+                       break;
+
+               default:
+                       WPRINTK("unknown operation [%d]\n",
+                               req->operation);
+                       make_response(blkif, req->id, req->operation,
+                                     BLKIF_RSP_ERROR);
+                       free_req(pending_req);
+                       break;
+               }
+       }
+               
+       blktap_kick_user(blkif->dev_num);
+
+       return more_to_do;
+}
+
+static void dispatch_rw_block_io(blkif_t *blkif,
+                                blkif_request_t *req,
+                                pending_req_t *pending_req)
+{
+       extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]); 
+       int op, operation = (req->operation == BLKIF_OP_WRITE) ? WRITE : READ;
+       struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST*2];
+       unsigned int nseg;
+       int ret, i;
+       tap_blkif_t *info = tapfds[blkif->dev_num];
+       uint64_t sector;
+       
+       blkif_request_t *target;
+       int pending_idx = RTN_PEND_IDX(pending_req,pending_req->mem_idx);
+       int usr_idx = GET_NEXT_REQ(info->idx_map);
+       uint16_t mmap_idx = pending_req->mem_idx;
+
+       /*Check we have space on user ring - should never fail*/
+       if(usr_idx == INVALID_REQ) goto fail_flush;
+       
+       /* Check that number of segments is sane. */
+       nseg = req->nr_segments;
+       if ( unlikely(nseg == 0) || 
+           unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST) ) {
+               WPRINTK("Bad number of segments in request (%d)\n", nseg);
+               goto fail_response;
+       }
+       
+       /* Make sure userspace is ready. */
+       if (!info->ring_ok) {
+               WPRINTK("blktap: ring not ready for requests!\n");
+               goto fail_response;
+       }
+
+       if (RING_FULL(&info->ufe_ring)) {
+               WPRINTK("blktap: fe_ring is full, can't add "
+                       "IO Request will be dropped. %d %d\n",
+                       RING_SIZE(&info->ufe_ring),
+                       RING_SIZE(&blkif->blk_ring));
+               goto fail_response;
+       }
+
+       pending_req->blkif     = blkif;
+       pending_req->id        = req->id;
+       pending_req->operation = operation;
+       pending_req->status    = BLKIF_RSP_OKAY;
+       pending_req->nr_pages  = nseg;
+       op = 0;
+       for (i = 0; i < nseg; i++) {
+               unsigned long uvaddr;
+               unsigned long kvaddr;
+               uint64_t ptep;
+               struct page *page;
+               uint32_t flags;
+
+               uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i);
+               kvaddr = MMAP_VADDR(mmap_start[mmap_idx].start, 
+                                   pending_idx, i);
+               page = virt_to_page(kvaddr);
+
+               sector = req->sector_number + (8*i);
+               if( (blkif->sectors > 0) && (sector >= blkif->sectors) ) {
+                       WPRINTK("BLKTAP: Sector request greater" 
+                              "than size\n");
+                       WPRINTK("BLKTAP: %s request sector" 
+                              "[%llu,%llu], Total [%llu]\n",
+                              (req->operation == 
+                               BLKIF_OP_WRITE ? "WRITE" : "READ"),
+                               (long long unsigned) sector,
+                               (long long unsigned) sector>>9,
+                               blkif->sectors);
+               }
+
+               flags = GNTMAP_host_map;
+               if (operation == WRITE)
+                       flags |= GNTMAP_readonly;
+               gnttab_set_map_op(&map[op], kvaddr, flags,
+                                 req->seg[i].gref, blkif->domid);
+               op++;
+
+               /* Now map it to user. */
+               ret = create_lookup_pte_addr(info->vma->vm_mm, 
+                                            uvaddr, &ptep);
+               if (ret) {
+                       WPRINTK("Couldn't get a pte addr!\n");
+                       fast_flush_area(pending_req, pending_idx, usr_idx, 
+                                       blkif->dev_num);
+                       goto fail_flush;
+               }
+
+               flags = GNTMAP_host_map | GNTMAP_application_map
+                       | GNTMAP_contains_pte;
+               if (operation == WRITE)
+                       flags |= GNTMAP_readonly;
+               gnttab_set_map_op(&map[op], ptep, flags,
+                                 req->seg[i].gref, blkif->domid);
+               op++;
+       }
+
+       ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, op);
+       BUG_ON(ret);
+
+       for (i = 0; i < (nseg*2); i+=2) {
+               unsigned long uvaddr;
+               unsigned long kvaddr;
+               unsigned long offset;
+               struct page *pg;
+
+               uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i/2);
+               kvaddr = MMAP_VADDR(mmap_start[mmap_idx].start, 
+                                   pending_idx, i/2);
+
+               if (unlikely(map[i].status != 0)) {
+                       WPRINTK("invalid kernel buffer -- "
+                               "could not remap it\n");
+                       goto fail_flush;
+               }
+
+               if (unlikely(map[i+1].status != 0)) {
+                       WPRINTK("invalid user buffer -- "
+                               "could not remap it\n");
+                       goto fail_flush;
+               }
+
+               pending_handle(mmap_idx, pending_idx, i/2).kernel 
+                       = map[i].handle;
+               pending_handle(mmap_idx, pending_idx, i/2).user   
+                       = map[i+1].handle;
+#ifdef CONFIG_XEN_IA64_DOM0_NON_VP
+               pending_addrs[mmap_idx][vaddr_pagenr(pending_req, i)] =
+                       (unsigned long)gnttab_map_vaddr(map[i]);
+#else
+               set_phys_to_machine(__pa(kvaddr) >> PAGE_SHIFT,
+                       FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT));
+#endif
+               offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT;
+               pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
+               ((struct page **)info->vma->vm_private_data)[offset] =
+                       pg;
+       }
+       /* Mark mapped pages as reserved: */
+       for (i = 0; i < req->nr_segments; i++) {
+               unsigned long kvaddr;
+               struct page *pg;
+
+               kvaddr = MMAP_VADDR(mmap_start[mmap_idx].start, 
+                                   pending_idx, i);
+               pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
+               SetPageReserved(pg);
+       }
+       
+       /*record [mmap_idx,pending_idx] to [usr_idx] mapping*/
+       info->idx_map[usr_idx] = MAKE_ID(mmap_idx, pending_idx);
+
+       blkif_get(blkif);
+       /* Finally, write the request message to the user ring. */
+       target = RING_GET_REQUEST(&info->ufe_ring,
+                                 info->ufe_ring.req_prod_pvt);
+       memcpy(target, req, sizeof(*req));
+       target->id = usr_idx;
+       info->ufe_ring.req_prod_pvt++;
+       return;
+
+ fail_flush:
+       WPRINTK("Reached Fail_flush\n");
+       fast_flush_area(pending_req, pending_idx, usr_idx, blkif->dev_num);
+ fail_response:
+       make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
+       free_req(pending_req);
+} 
+
+
+
+/******************************************************************
+ * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING
+ */
+
+
+static void make_response(blkif_t *blkif, unsigned long id, 
+                          unsigned short op, int st)
+{
+       blkif_response_t *resp;
+       unsigned long     flags;
+       blkif_back_ring_t *blk_ring = &blkif->blk_ring;
+       int more_to_do = 0;
+       int notify;
+
+       spin_lock_irqsave(&blkif->blk_ring_lock, flags);
+       /* Place on the response ring for the relevant domain. */ 
+       resp = RING_GET_RESPONSE(blk_ring, blk_ring->rsp_prod_pvt);
+       resp->id        = id;
+       resp->operation = op;
+       resp->status    = st;
+       blk_ring->rsp_prod_pvt++;
+       RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(blk_ring, notify);
+
+       if (blk_ring->rsp_prod_pvt == blk_ring->req_cons) {
+               /*
+                * Tail check for pending requests. Allows frontend to avoid
+                * notifications if requests are already in flight (lower
+                * overheads and promotes batching).
+                */
+               RING_FINAL_CHECK_FOR_REQUESTS(blk_ring, more_to_do);
+       } else if (RING_HAS_UNCONSUMED_REQUESTS(blk_ring)) {
+               more_to_do = 1;
+
+       }       
+       spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
+       if (more_to_do)
+               blkif_notify_work(blkif);
+       if (notify)
+               notify_remote_via_irq(blkif->irq);
+}
+
+static int __init blkif_init(void)
+{
+       int i,ret,blktap_dir;
+       tap_blkif_t *info;
+
+       if (!is_running_on_xen())
+               return -ENODEV;
+
+       INIT_LIST_HEAD(&pending_free);
+        for(i = 0; i < 2; i++) req_increase();
+
+       tap_blkif_interface_init();
+
+       alloc_pending_reqs = 0;
+
+       tap_blkif_xenbus_init();
+
+       /*Create the blktap devices, but do not map memory or waitqueue*/
+       for(i = 0; i < MAX_TAP_DEV; i++) translate_domid[i].domid = 0xFFFF;
+
+       ret = register_chrdev(BLKTAP_DEV_MAJOR,"blktap",&blktap_fops);
+       blktap_dir = devfs_mk_dir(NULL, "xen", 0, NULL);
+
+       if ( (ret < 0)||(blktap_dir < 0) ) {
+               WPRINTK("Couldn't register /dev/xen/blktap\n");
+               return -ENOMEM;
+       }       
+       
+       for(i = 0; i < MAX_TAP_DEV; i++ ) {
+               info = tapfds[i] = kzalloc(sizeof(tap_blkif_t),GFP_KERNEL);
+               if(tapfds[i] == NULL) return -ENOMEM;
+               info->minor = i;
+               info->pid = 0;
+               info->blkif = NULL;
+
+               ret = devfs_mk_cdev(MKDEV(BLKTAP_DEV_MAJOR, i),
+                       S_IFCHR|S_IRUGO|S_IWUSR, "xen/blktap%d", i);
+
+               if(ret != 0) return -ENOMEM;
+               info->dev_pending = info->dev_inuse = 0;
+
+               DPRINTK("Created misc_dev [/dev/xen/blktap%d]\n",i);
+       }
+       
+       DPRINTK("Blktap device successfully created\n");
+
+       return 0;
+}
+
+module_init(blkif_init);
+
+MODULE_LICENSE("Dual BSD/GPL");
diff -r af9809f51f81 -r 2937703f0ed0 
linux-2.6-xen-sparse/drivers/xen/blktap/common.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/blktap/common.h  Thu Jul 13 10:13:26 
2006 +0100
@@ -0,0 +1,120 @@
+/* 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __BLKIF__BACKEND__COMMON_H__
+#define __BLKIF__BACKEND__COMMON_H__
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/pgalloc.h>
+#include <xen/evtchn.h>
+#include <asm/hypervisor.h>
+#include <xen/interface/io/blkif.h>
+#include <xen/interface/io/ring.h>
+#include <xen/gnttab.h>
+#include <xen/driver_util.h>
+
+#define DPRINTK(_f, _a...) pr_debug("(file=%s, line=%d) " _f, \
+                                    __FILE__ , __LINE__ , ## _a )
+
+#define WPRINTK(fmt, args...) printk(KERN_WARNING "blk_tap: " fmt, ##args)
+
+struct backend_info; 
+
+typedef struct blkif_st {
+       /* Unique identifier for this interface. */
+       domid_t           domid;
+       unsigned int      handle;
+       /* Physical parameters of the comms window. */
+       unsigned int      evtchn;
+       unsigned int      irq;
+       /* Comms information. */
+       blkif_back_ring_t blk_ring;
+       struct vm_struct *blk_ring_area;
+       /* Back pointer to the backend_info. */
+       struct backend_info *be; 
+       /* Private fields. */
+       spinlock_t       blk_ring_lock;
+       atomic_t         refcnt;
+
+       wait_queue_head_t   wq;
+       struct task_struct  *xenblkd;
+       unsigned int        waiting_reqs;
+       request_queue_t     *plug;
+
+       /* statistics */
+       unsigned long       st_print;
+       int                 st_rd_req;
+       int                 st_wr_req;
+       int                 st_oo_req;
+
+       wait_queue_head_t waiting_to_free;
+
+       grant_handle_t shmem_handle;
+       grant_ref_t    shmem_ref;
+       
+       int             dev_num;
+       uint64_t        sectors;
+} blkif_t;
+
+blkif_t *tap_alloc_blkif(domid_t domid);
+void tap_blkif_free(blkif_t *blkif);
+int tap_blkif_map(blkif_t *blkif, unsigned long shared_page, 
+                 unsigned int evtchn);
+
+#define blkif_get(_b) (atomic_inc(&(_b)->refcnt))
+#define blkif_put(_b)                                  \
+       do {                                            \
+               if (atomic_dec_and_test(&(_b)->refcnt)) \
+                       wake_up(&(_b)->waiting_to_free);\
+       } while (0)
+
+
+struct phys_req {
+       unsigned short       dev;
+       unsigned short       nr_sects;
+       struct block_device *bdev;
+       blkif_sector_t       sector_number;
+};
+
+void tap_blkif_interface_init(void);
+
+void tap_blkif_xenbus_init(void);
+
+irqreturn_t tap_blkif_be_int(int irq, void *dev_id, struct pt_regs *regs);
+int tap_blkif_schedule(void *arg);
+
+int dom_to_devid(domid_t domid, int xenbus_id, blkif_t *blkif);
+void signal_tapdisk(int idx);
+
+#endif /* __BLKIF__BACKEND__COMMON_H__ */
diff -r af9809f51f81 -r 2937703f0ed0 
linux-2.6-xen-sparse/drivers/xen/blktap/interface.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/blktap/interface.c       Thu Jul 13 
10:13:26 2006 +0100
@@ -0,0 +1,165 @@
+/******************************************************************************
+ * drivers/xen/blktap/interface.c
+ * 
+ * Block-device interface management.
+ * 
+ * Copyright (c) 2004, Keir Fraser
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+
+ */
+
+#include "common.h"
+#include <xen/evtchn.h>
+
+static kmem_cache_t *blkif_cachep;
+
+blkif_t *tap_alloc_blkif(domid_t domid)
+{
+       blkif_t *blkif;
+
+       blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL);
+       if (!blkif)
+               return ERR_PTR(-ENOMEM);
+
+       memset(blkif, 0, sizeof(*blkif));
+       blkif->domid = domid;
+       spin_lock_init(&blkif->blk_ring_lock);
+       atomic_set(&blkif->refcnt, 1);
+       init_waitqueue_head(&blkif->wq);
+       blkif->st_print = jiffies;
+       init_waitqueue_head(&blkif->waiting_to_free);
+
+       return blkif;
+}
+
+static int map_frontend_page(blkif_t *blkif, unsigned long shared_page)
+{
+       struct gnttab_map_grant_ref op;
+       int ret;
+
+       gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr,
+                         GNTMAP_host_map, shared_page, blkif->domid);
+
+       lock_vm_area(blkif->blk_ring_area);
+       ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
+       unlock_vm_area(blkif->blk_ring_area);
+       BUG_ON(ret);
+
+       if (op.status) {
+               DPRINTK(" Grant table operation failure !\n");
+               return op.status;
+       }
+
+       blkif->shmem_ref = shared_page;
+       blkif->shmem_handle = op.handle;
+
+#ifdef CONFIG_XEN_IA64_DOM0_NON_VP
+       /* on some arch's, map_grant_ref behaves like mmap, in that the
+        * passed address is a hint and a different address may be returned */
+       blkif->blk_ring_area->addr = gnttab_map_vaddr(op);
+#endif
+
+       return 0;
+}
+
+static void unmap_frontend_page(blkif_t *blkif)
+{
+       struct gnttab_unmap_grant_ref op;
+       int ret;
+
+       gnttab_set_unmap_op(&op, (unsigned long)blkif->blk_ring_area->addr,
+                           GNTMAP_host_map, blkif->shmem_handle);
+
+       lock_vm_area(blkif->blk_ring_area);
+       ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
+       unlock_vm_area(blkif->blk_ring_area);
+       BUG_ON(ret);
+}
+
+int tap_blkif_map(blkif_t *blkif, unsigned long shared_page, 
+                 unsigned int evtchn)
+{
+       blkif_sring_t *sring;
+       int err;
+       struct evtchn_bind_interdomain bind_interdomain;
+
+       /* Already connected through? */
+       if (blkif->irq)
+               return 0;
+
+       if ( (blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL )
+               return -ENOMEM;
+
+       err = map_frontend_page(blkif, shared_page);
+       if (err) {
+               free_vm_area(blkif->blk_ring_area);
+               return err;
+       }
+
+       bind_interdomain.remote_dom  = blkif->domid;
+       bind_interdomain.remote_port = evtchn;
+
+       err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
+                                         &bind_interdomain);
+       if (err) {
+               unmap_frontend_page(blkif);
+               free_vm_area(blkif->blk_ring_area);
+               return err;
+       }
+
+       blkif->evtchn = bind_interdomain.local_port;
+
+       sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
+       BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE);
+
+       blkif->irq = bind_evtchn_to_irqhandler(
+               blkif->evtchn, tap_blkif_be_int, 0, "blkif-backend", blkif);
+
+       return 0;
+}
+
+void tap_blkif_free(blkif_t *blkif)
+{
+       atomic_dec(&blkif->refcnt);
+       wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
+
+       /* Already disconnected? */
+       if (blkif->irq)
+               unbind_from_irqhandler(blkif->irq, blkif);
+
+       if (blkif->blk_ring.sring) {
+               unmap_frontend_page(blkif);
+               free_vm_area(blkif->blk_ring_area);
+       }
+
+       kmem_cache_free(blkif_cachep, blkif);
+}
+
+void __init tap_blkif_interface_init(void)
+{
+       blkif_cachep = kmem_cache_create("blktapif_cache", sizeof(blkif_t), 
+                                        0, 0, NULL, NULL);
+}
diff -r af9809f51f81 -r 2937703f0ed0 
linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c  Thu Jul 13 10:13:26 
2006 +0100
@@ -0,0 +1,354 @@
+/* drivers/xen/blktap/xenbus.c
+ *
+ * Xenbus code for blktap
+ *
+ * Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield
+ *
+ * Based on the blkback xenbus code:
+ *
+ * Copyright (C) 2005 Rusty Russell <rusty@xxxxxxxxxxxxxxx>
+ * Copyright (C) 2005 XenSource Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdarg.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <xen/xenbus.h>
+#include "common.h"
+
+
+struct backend_info
+{
+       struct xenbus_device *dev;
+       blkif_t *blkif;
+       struct xenbus_watch backend_watch;
+       int xenbus_id;
+};
+
+
+static void connect(struct backend_info *);
+static int connect_ring(struct backend_info *);
+static int blktap_remove(struct xenbus_device *dev);
+static int blktap_probe(struct xenbus_device *dev,
+                        const struct xenbus_device_id *id);
+static void tap_backend_changed(struct xenbus_watch *, const char **,
+                           unsigned int);
+static void tap_frontend_changed(struct xenbus_device *dev,
+                            enum xenbus_state frontend_state);
+
+static int strsep_len(const char *str, char c, unsigned int len)
+{
+        unsigned int i;
+
+        for (i = 0; str[i]; i++)
+                if (str[i] == c) {
+                        if (len == 0)
+                                return i;
+                        len--;
+                }
+        return (len == 0) ? i : -ERANGE;
+}
+
+static long get_id(const char *str)
+{
+        int len,end;
+        const char *ptr;
+        char *tptr, num[10];
+       
+        len = strsep_len(str, '/', 2);
+        end = strlen(str);
+        if ( (len < 0) || (end < 0) ) return -1;
+       
+        ptr = str + len + 1;
+        strncpy(num,ptr,end - len);
+        tptr = num + (end - (len + 1));
+        *tptr = '\0';
+       DPRINTK("Get_id called for %s (%s)\n",str,num);
+       
+        return simple_strtol(num, NULL, 10);
+}                              
+
+static void tap_update_blkif_status(blkif_t *blkif)
+{ 
+       int err;
+
+       /* Not ready to connect? */
+       if(!blkif->irq || !blkif->sectors) {
+               return;
+       } 
+
+       /* Already connected? */
+       if (blkif->be->dev->state == XenbusStateConnected)
+               return;
+
+       /* Attempt to connect: exit if we fail to. */
+       connect(blkif->be);
+       if (blkif->be->dev->state != XenbusStateConnected)
+               return;
+
+       blkif->xenblkd = kthread_run(tap_blkif_schedule, blkif,
+                                    "xvd %d",
+                                    blkif->domid);
+
+       if (IS_ERR(blkif->xenblkd)) {
+               err = PTR_ERR(blkif->xenblkd);
+               blkif->xenblkd = NULL;
+               xenbus_dev_fatal(blkif->be->dev, err, "start xenblkd");
+               WPRINTK("Error starting thread\n");
+       }
+}
+
+static int blktap_remove(struct xenbus_device *dev)
+{
+       struct backend_info *be = dev->dev.driver_data;
+
+       if (be->backend_watch.node) {
+               unregister_xenbus_watch(&be->backend_watch);
+               kfree(be->backend_watch.node);
+               be->backend_watch.node = NULL;
+       }
+       if (be->blkif) {
+               if (be->blkif->xenblkd)
+                       kthread_stop(be->blkif->xenblkd);
+               signal_tapdisk(be->blkif->dev_num);
+               tap_blkif_free(be->blkif);
+               be->blkif = NULL;
+       }
+       kfree(be);
+       dev->dev.driver_data = NULL;
+       return 0;
+}
+
+/**
+ * Entry point to this code when a new device is created.  Allocate
+ * the basic structures, and watch the store waiting for the
+ * user-space program to tell us the physical device info.  Switch to
+ * InitWait.
+ */
+static int blktap_probe(struct xenbus_device *dev,
+                        const struct xenbus_device_id *id)
+{
+       int err;
+       struct backend_info *be = kzalloc(sizeof(struct backend_info),
+                                         GFP_KERNEL);
+       if (!be) {
+               xenbus_dev_fatal(dev, -ENOMEM,
+                                "allocating backend structure");
+               return -ENOMEM;
+       }
+
+       be->dev = dev;
+       dev->dev.driver_data = be;
+       be->xenbus_id = get_id(dev->nodename);
+
+       be->blkif = tap_alloc_blkif(dev->otherend_id);
+       if (IS_ERR(be->blkif)) {
+               err = PTR_ERR(be->blkif);
+               be->blkif = NULL;
+               xenbus_dev_fatal(dev, err, "creating block interface");
+               goto fail;
+       }
+
+       /* setup back pointer */
+       be->blkif->be = be; 
+       be->blkif->sectors = 0;
+
+       /* set a watch on disk info, waiting for userspace to update details*/
+       err = xenbus_watch_path2(dev, dev->nodename, "info",
+                                &be->backend_watch, tap_backend_changed);
+       if (err)
+               goto fail;
+       
+       err = xenbus_switch_state(dev, XenbusStateInitWait);
+       if (err)
+               goto fail;
+       return 0;
+
+fail:
+       DPRINTK("blktap probe failed");
+       blktap_remove(dev);
+       return err;
+}
+
+
+/**
+ * Callback received when the user space code has placed the device
+ * information in xenstore. 
+ */
+static void tap_backend_changed(struct xenbus_watch *watch,
+                           const char **vec, unsigned int len)
+{
+       int err;
+       unsigned long info;
+       struct backend_info *be
+               = container_of(watch, struct backend_info, backend_watch);
+       struct xenbus_device *dev = be->dev;
+       
+       /** 
+        * Check to see whether userspace code has opened the image 
+        * and written sector
+        * and disk info to xenstore
+        */
+       err = xenbus_gather(XBT_NIL, dev->nodename, "info", "%lu", &info, 
+                           NULL);      
+       if (err) {
+               xenbus_dev_error(dev, err, "getting info");
+               return;
+       }
+
+       DPRINTK("Userspace update on disk info, %lu\n",info);
+
+       err = xenbus_gather(XBT_NIL, dev->nodename, "sectors", "%llu", 
+                           &be->blkif->sectors, NULL);
+
+       /* Associate tap dev with domid*/
+       be->blkif->dev_num = dom_to_devid(be->blkif->domid, be->xenbus_id, 
+                                         be->blkif);
+       DPRINTK("Thread started for domid [%d], connecting disk\n", 
+               be->blkif->dev_num);
+
+       tap_update_blkif_status(be->blkif);
+}
+
+/**
+ * Callback received when the frontend's state changes.
+ */
+static void tap_frontend_changed(struct xenbus_device *dev,
+                            enum xenbus_state frontend_state)
+{
+       struct backend_info *be = dev->dev.driver_data;
+       int err;
+
+       DPRINTK("");
+
+       switch (frontend_state) {
+       case XenbusStateInitialising:
+               break;
+
+       case XenbusStateInitialised:
+       case XenbusStateConnected:
+               /* Ensure we connect even when two watches fire in 
+                  close successsion and we miss the intermediate value 
+                  of frontend_state. */
+               if (dev->state == XenbusStateConnected)
+                       break;
+
+               err = connect_ring(be);
+               if (err)
+                       break;
+               tap_update_blkif_status(be->blkif);
+               break;
+
+       case XenbusStateClosing:
+               xenbus_switch_state(dev, XenbusStateClosing);
+               break;
+
+       case XenbusStateClosed:
+               device_unregister(&dev->dev);
+               break;
+
+       case XenbusStateUnknown:
+       case XenbusStateInitWait:
+       default:
+               xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
+                                frontend_state);
+               break;
+       }
+}
+
+
+/**
+ * Switch to Connected state.
+ */
+static void connect(struct backend_info *be)
+{
+       int err;
+
+       struct xenbus_device *dev = be->dev;
+
+       err = xenbus_switch_state(dev, XenbusStateConnected);
+       if (err)
+               xenbus_dev_fatal(dev, err, "switching to Connected state",
+                                dev->nodename);
+
+       return;
+}
+
+
+static int connect_ring(struct backend_info *be)
+{
+       struct xenbus_device *dev = be->dev;
+       unsigned long ring_ref;
+       unsigned int evtchn;
+       int err;
+
+       DPRINTK("%s", dev->otherend);
+
+       err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu", 
+                           &ring_ref, "event-channel", "%u", &evtchn, NULL);
+       if (err) {
+               xenbus_dev_fatal(dev, err,
+                                "reading %s/ring-ref and event-channel",
+                                dev->otherend);
+               return err;
+       }
+
+       /* Map the shared frame, irq etc. */
+       err = tap_blkif_map(be->blkif, ring_ref, evtchn);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
+                                ring_ref, evtchn);
+               return err;
+       } 
+
+       return 0;
+}
+
+
+/* ** Driver Registration ** */
+
+
+static struct xenbus_device_id blktap_ids[] = {
+       { "tap" },
+       { "" }
+};
+
+
+static struct xenbus_driver blktap = {
+       .name = "tap",
+       .owner = THIS_MODULE,
+       .ids = blktap_ids,
+       .probe = blktap_probe,
+       .remove = blktap_remove,
+       .otherend_changed = tap_frontend_changed
+};
+
+
+void tap_blkif_xenbus_init(void)
+{
+       xenbus_register_backend(&blktap);
+}
diff -r af9809f51f81 -r 2937703f0ed0 
patches/linux-2.6.16.13/blktap-aio-16_03_06.patch
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/linux-2.6.16.13/blktap-aio-16_03_06.patch Thu Jul 13 10:13:26 
2006 +0100
@@ -0,0 +1,297 @@
+diff -pruN ../pristine-linux-2.6.16-rc5/fs/aio.c ./fs/aio.c
+--- ../pristine-linux-2.6.16-rc5/fs/aio.c      2006-03-14 14:10:10.827401387 
+0000
++++ ./fs/aio.c 2006-03-16 09:57:53.898316582 +0000
+@@ -34,6 +34,11 @@
+ #include <asm/uaccess.h>
+ #include <asm/mmu_context.h>
+ 
++#ifdef CONFIG_EPOLL
++#include <linux/poll.h>
++#include <linux/eventpoll.h>
++#endif
++
+ #if DEBUG > 1
+ #define dprintk               printk
+ #else
+@@ -1016,6 +1021,10 @@ put_rq:
+       if (waitqueue_active(&ctx->wait))
+               wake_up(&ctx->wait);
+ 
++#ifdef CONFIG_EPOLL
++      if (ctx->file && waitqueue_active(&ctx->poll_wait))
++              wake_up(&ctx->poll_wait);
++#endif
+       if (ret)
+               put_ioctx(ctx);
+ 
+@@ -1025,6 +1034,8 @@ put_rq:
+ /* aio_read_evt
+  *    Pull an event off of the ioctx's event ring.  Returns the number of 
+  *    events fetched (0 or 1 ;-)
++ *    If ent parameter is 0, just returns the number of events that would
++ *    be fetched.
+  *    FIXME: make this use cmpxchg.
+  *    TODO: make the ringbuffer user mmap()able (requires FIXME).
+  */
+@@ -1047,13 +1058,18 @@ static int aio_read_evt(struct kioctx *i
+ 
+       head = ring->head % info->nr;
+       if (head != ring->tail) {
+-              struct io_event *evp = aio_ring_event(info, head, KM_USER1);
+-              *ent = *evp;
+-              head = (head + 1) % info->nr;
+-              smp_mb(); /* finish reading the event before updatng the head */
+-              ring->head = head;
+-              ret = 1;
+-              put_aio_ring_event(evp, KM_USER1);
++              if (ent) { /* event requested */
++                      struct io_event *evp =
++                              aio_ring_event(info, head, KM_USER1);
++                      *ent = *evp;
++                      head = (head + 1) % info->nr;
++                      /* finish reading the event before updatng the head */
++                      smp_mb();
++                      ring->head = head;
++                      ret = 1;
++                      put_aio_ring_event(evp, KM_USER1);
++              } else /* only need to know availability */
++                      ret = 1;
+       }
+       spin_unlock(&info->ring_lock);
+ 
+@@ -1236,9 +1252,78 @@ static void io_destroy(struct kioctx *io
+ 
+       aio_cancel_all(ioctx);
+       wait_for_all_aios(ioctx);
++#ifdef CONFIG_EPOLL
++      /* forget the poll file, but it's up to the user to close it */
++      if (ioctx->file) {
++              ioctx->file->private_data = 0;
++              ioctx->file = 0;
++      }
++#endif
+       put_ioctx(ioctx);       /* once for the lookup */
+ }
+ 
++#ifdef CONFIG_EPOLL
++
++static int aio_queue_fd_close(struct inode *inode, struct file *file)
++{
++      struct kioctx *ioctx = file->private_data;
++      if (ioctx) {
++              file->private_data = 0;
++              spin_lock_irq(&ioctx->ctx_lock);
++              ioctx->file = 0;
++              spin_unlock_irq(&ioctx->ctx_lock);
++      }
++      return 0;
++}
++
++static unsigned int aio_queue_fd_poll(struct file *file, poll_table *wait)
++{     unsigned int pollflags = 0;
++      struct kioctx *ioctx = file->private_data;
++
++      if (ioctx) {
++
++              spin_lock_irq(&ioctx->ctx_lock);
++              /* Insert inside our poll wait queue */
++              poll_wait(file, &ioctx->poll_wait, wait);
++
++              /* Check our condition */
++              if (aio_read_evt(ioctx, 0))
++                      pollflags = POLLIN | POLLRDNORM;
++              spin_unlock_irq(&ioctx->ctx_lock);
++      }
++
++      return pollflags;
++}
++
++static struct file_operations aioq_fops = {
++      .release        = aio_queue_fd_close,
++      .poll           = aio_queue_fd_poll
++};
++
++/* make_aio_fd:
++ *  Create a file descriptor that can be used to poll the event queue.
++ *  Based and piggybacked on the excellent epoll code.
++ */
++
++static int make_aio_fd(struct kioctx *ioctx)
++{
++      int error, fd;
++      struct inode *inode;
++      struct file *file;
++
++      error = ep_getfd(&fd, &inode, &file, NULL, &aioq_fops);
++      if (error)
++              return error;
++
++      /* associate the file with the IO context */
++      file->private_data = ioctx;
++      ioctx->file = file;
++      init_waitqueue_head(&ioctx->poll_wait);
++      return fd;
++}
++#endif
++
++
+ /* sys_io_setup:
+  *    Create an aio_context capable of receiving at least nr_events.
+  *    ctxp must not point to an aio_context that already exists, and
+@@ -1251,18 +1336,30 @@ static void io_destroy(struct kioctx *io
+  *    resources are available.  May fail with -EFAULT if an invalid
+  *    pointer is passed for ctxp.  Will fail with -ENOSYS if not
+  *    implemented.
++ *
++ *    To request a selectable fd, the user context has to be initialized
++ *    to 1, instead of 0, and the return value is the fd.
++ *    This keeps the system call compatible, since a non-zero value
++ *    was not allowed so far.
+  */
+ asmlinkage long sys_io_setup(unsigned nr_events, aio_context_t __user *ctxp)
+ {
+       struct kioctx *ioctx = NULL;
+       unsigned long ctx;
+       long ret;
++      int make_fd = 0;
+ 
+       ret = get_user(ctx, ctxp);
+       if (unlikely(ret))
+               goto out;
+ 
+       ret = -EINVAL;
++#ifdef CONFIG_EPOLL
++      if (ctx == 1) {
++              make_fd = 1;
++              ctx = 0;
++      }
++#endif
+       if (unlikely(ctx || nr_events == 0)) {
+               pr_debug("EINVAL: io_setup: ctx %lu nr_events %u\n",
+                        ctx, nr_events);
+@@ -1273,8 +1370,12 @@ asmlinkage long sys_io_setup(unsigned nr
+       ret = PTR_ERR(ioctx);
+       if (!IS_ERR(ioctx)) {
+               ret = put_user(ioctx->user_id, ctxp);
+-              if (!ret)
+-                      return 0;
++#ifdef CONFIG_EPOLL
++              if (make_fd && ret >= 0)
++                      ret = make_aio_fd(ioctx);
++#endif
++              if (ret >= 0)
++                      return ret;
+ 
+               get_ioctx(ioctx); /* io_destroy() expects us to hold a ref */
+               io_destroy(ioctx);
+
+diff -pruN ../pristine-linux-2.6.16-rc5/fs/eventpoll.c ./fs/eventpoll.c
+--- ../pristine-linux-2.6.16-rc5/fs/eventpoll.c        2006-01-03 
03:21:10.000000000 +0000
++++ ./fs/eventpoll.c   2006-03-16 10:04:35.469956167 +0000
+@@ -235,8 +235,6 @@ struct ep_pqueue {
+ 
+ static void ep_poll_safewake_init(struct poll_safewake *psw);
+ static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t 
*wq);
+-static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
+-                  struct eventpoll *ep);
+ static int ep_alloc(struct eventpoll **pep);
+ static void ep_free(struct eventpoll *ep);
+ static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int 
fd);
+@@ -266,7 +264,7 @@ static int ep_events_transfer(struct eve
+ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
+                  int maxevents, long timeout);
+ static int eventpollfs_delete_dentry(struct dentry *dentry);
+-static struct inode *ep_eventpoll_inode(void);
++static struct inode *ep_eventpoll_inode(struct file_operations *fops);
+ static struct super_block *eventpollfs_get_sb(struct file_system_type 
*fs_type,
+                                             int flags, const char *dev_name,
+                                             void *data);
+@@ -525,7 +523,7 @@ asmlinkage long sys_epoll_create(int siz
+        * Creates all the items needed to setup an eventpoll file. That is,
+        * a file structure, and inode and a free file descriptor.
+        */
+-      error = ep_getfd(&fd, &inode, &file, ep);
++      error = ep_getfd(&fd, &inode, &file, ep, &eventpoll_fops);
+       if (error)
+               goto eexit_2;
+ 
+@@ -710,8 +708,8 @@ eexit_1:
+ /*
+  * Creates the file descriptor to be used by the epoll interface.
+  */
+-static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
+-                  struct eventpoll *ep)
++int ep_getfd(int *efd, struct inode **einode, struct file **efile,
++                  struct eventpoll *ep, struct file_operations *fops)
+ {
+       struct qstr this;
+       char name[32];
+@@ -727,7 +725,7 @@ static int ep_getfd(int *efd, struct ino
+               goto eexit_1;
+ 
+       /* Allocates an inode from the eventpoll file system */
+-      inode = ep_eventpoll_inode();
++      inode = ep_eventpoll_inode(fops);
+       error = PTR_ERR(inode);
+       if (IS_ERR(inode))
+               goto eexit_2;
+@@ -758,7 +756,7 @@ static int ep_getfd(int *efd, struct ino
+ 
+       file->f_pos = 0;
+       file->f_flags = O_RDONLY;
+-      file->f_op = &eventpoll_fops;
++      file->f_op = fops;
+       file->f_mode = FMODE_READ;
+       file->f_version = 0;
+       file->private_data = ep;
+@@ -1574,7 +1572,7 @@ static int eventpollfs_delete_dentry(str
+ }
+ 
+ 
+-static struct inode *ep_eventpoll_inode(void)
++static struct inode *ep_eventpoll_inode(struct file_operations *fops)
+ {
+       int error = -ENOMEM;
+       struct inode *inode = new_inode(eventpoll_mnt->mnt_sb);
+@@ -1582,7 +1580,7 @@ static struct inode *ep_eventpoll_inode(
+       if (!inode)
+               goto eexit_1;
+ 
+-      inode->i_fop = &eventpoll_fops;
++      inode->i_fop = fops;
+ 
+       /*
+        * Mark the inode dirty from the very beginning,
+
+diff -pruN ../pristine-linux-2.6.16-rc5/include/linux/aio.h 
./include/linux/aio.h
+--- ../pristine-linux-2.6.16-rc5/include/linux/aio.h   2006-03-14 
14:10:21.597916731 +0000
++++ ./include/linux/aio.h      2006-03-16 10:05:39.848833028 +0000
+@@ -191,6 +191,11 @@ struct kioctx {
+       struct aio_ring_info    ring_info;
+ 
+       struct work_struct      wq;
++#ifdef CONFIG_EPOLL
++      // poll integration
++      wait_queue_head_t       poll_wait;
++      struct file             *file;
++#endif
+ };
+ 
+ /* prototypes */
+
+diff -pruN ../pristine-linux-2.6.16-rc5/include/linux/eventpoll.h 
./include/linux/eventpoll.h
+--- ../pristine-linux-2.6.16-rc5/include/linux/eventpoll.h     2006-01-03 
03:21:10.000000000 +0000
++++ ./include/linux/eventpoll.h        2006-03-16 10:08:51.577809317 +0000
+@@ -86,6 +86,12 @@ static inline void eventpoll_release(str
+ }
+ 
+ 
++/*
++ * called by aio code to create fd that can poll the  aio event queueQ
++ */
++struct eventpoll;
++int ep_getfd(int *efd, struct inode **einode, struct file **efile,
++             struct eventpoll *ep, struct file_operations *fops);
+ #else
+ 
+ static inline void eventpoll_init_file(struct file *file) {}
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/Makefile     Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,28 @@
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+SUBDIRS-y :=
+SUBDIRS-y += lib
+SUBDIRS-y += drivers
+
+.PHONY: all
+all: build
+
+.PHONY: build
+build: mk-symlinks
+       @set -e; for subdir in $(SUBDIRS-y); do \
+       $(MAKE) -C $$subdir all;       \
+               done
+
+.PHONY: install
+install:
+       @set -e; for subdir in $(SUBDIRS-y); do \
+               $(MAKE) -C $$subdir install; \
+       done
+
+.PHONY: clean
+clean:
+       rm -rf *.a *.so *.o *.rpm $(LIB) *~ $(DEPS) xen TAGS
+       @set -e; for subdir in $(SUBDIRS-y); do \
+       $(MAKE) -C $$subdir clean;       \
+               done
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/README
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/README       Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,122 @@
+Blktap Userspace Tools + Library
+================================
+
+Andrew Warfield and Julian Chesterfield
+16th June 2006
+
+{firstname.lastname}@cl.cam.ac.uk
+
+The blktap userspace toolkit provides a user-level disk I/O
+interface. The blktap 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, blktap 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 blktap 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 blktap 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 2006 the current supported disk formats are:
+
+ - Raw Images (both on partitions and in image files)
+ - File-backed Qcow disks
+ - Standalone sparse Qcow disks
+ - Fast shareable RAM disk between VMs (requires some form of cluster-based 
+   filesystem support e.g. OCFS2 in the guest kernel)
+ - Some VMDK images - your mileage may vary
+
+Raw and QCow images have asynchronous backends and so should perform
+fairly well.  VMDK is based directly on the qemu vmdk driver, which is
+synchronous (a.k.a. slow).
+
+Build and Installation Instructions
+===================================
+
+Make to configure the blktap backend driver in your dom0 kernel.  It
+will cooperate fine with the existing backend driver, so you can
+experiment with tap disks without breaking existing VM configs.
+
+To build the tools separately, "make && make install" in 
+tools/blktap.
+
+
+Using the Tools
+===============
+
+Prepare the image for booting. For qcow files use the qcow utilities
+installed earlier. e.g. qcow-create generates a blank standalone image
+or a file-backed CoW image. img2qcow takes an existing image or
+partition and creates a sparse, standalone qcow-based file.
+
+The userspace disk agent is configured to start automatically via xend
+(alternatively you can start it manually => 'blktapctrl')
+
+Customise the VM config file to use the 'tap' handler, followed by the
+driver type. e.g. for a raw image such as a file or partition:
+
+disk = ['tap:aio:<FILENAME>,sda1,w']
+
+e.g. for a qcow image:
+
+disk = ['tap:qcow:<FILENAME>,sda1,w']
+
+
+Mounting images in Dom0 using the blktap driver
+===============================================
+Tap (and blkback) disks are also mountable in Dom0 without requiring an
+active VM to attach. You will need to build a xenlinux Dom0 kernel that
+includes the blkfront driver (e.g. the default 'make world' or 
+'make kernels' build. Simply use the xm command-line tool to activate
+the backend disks, and blkfront will generate a virtual block device that
+can be accessed in the same way as a loop device or partition:
+
+e.g. for a raw image file <FILENAME> that would normally be mounted using
+the loopback driver (such as 'mount -o loop <FILENAME> /mnt/disk'), do the
+following:
+
+xm block-attach 0 tap:aio:<FILENAME> /dev/xvda1 w 0
+mount /dev/xvda1 /mnt/disk        <--- don't use loop driver
+
+In this way, you can use any of the userspace device-type drivers built
+with the blktap userspace toolkit to open and mount disks such as qcow
+or vmdk images:
+
+xm block-attach 0 tap:qcow:<FILENAME> /dev/xvda1 w 0
+mount /dev/xvda1 /mnt/disk
+
+
+
+ 
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/Makefile     Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,76 @@
+XEN_ROOT = ../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+INCLUDES += -I.. -I../lib
+
+INSTALL      = install
+INSTALL_PROG = $(INSTALL) -m0755
+IBIN         = blktapctrl tapdisk
+QCOW_UTIL    = img2qcow qcow2raw qcow-create
+INSTALL_DIR  = /usr/sbin
+LIBAIO_DIR   = ../../libaio/src
+
+CFLAGS   += -fPIC
+CFLAGS   += -Wall
+CFLAGS   += -Werror
+CFLAGS   += -Wno-unused
+CFLAGS   += -g3
+CFLAGS   += -fno-strict-aliasing
+CFLAGS   += -I $(XEN_LIBXC) -I $(LIBAIO_DIR)
+CFLAGS   += $(INCLUDES) -I. -I../../xenstore 
+CFLAGS   += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
+CFLAGS   += -D_GNU_SOURCE
+
+# Get gcc to generate the dependencies for us.
+CFLAGS   += -Wp,-MD,.$(@F).d
+DEPS     = .*.d
+
+THREADLIB := -lpthread -lz
+LIBS      := -L. -L.. -L../lib
+LIBS      += -L$(XEN_LIBXC)
+LIBS      += -lblktap
+LIBS      += -lcrypto
+LIBS      += -lz
+LIBS      += -L$(XEN_XENSTORE) -lxenstore
+
+AIOLIBS   := -L $(LIBAIO_DIR)
+AIOLIBS   += -laio
+AIOLIBS   += -static
+
+BLK-OBJS  := block-aio.o 
+BLK-OBJS  += block-sync.o 
+BLK-OBJS  += block-vmdk.o
+BLK-OBJS  += block-ram.o 
+BLK-OBJS  += block-qcow.o
+BLK-OBJS  += aes.o
+
+all: $(IBIN) qcow-util
+
+LINUX_ROOT := $(wildcard $(XEN_ROOT)/linux-2.6.*-xen-sparse)
+
+
+blktapctrl: 
+       $(CC) $(CFLAGS) -o blktapctrl $(LIBS) blktapctrl.c
+
+tapdisk: $(BLK-OBJS)
+       $(CC) $(CFLAGS) -o tapdisk $(BLK-OBJS) tapdisk.c \
+               $(AIOLIBS) $(LIBS)
+
+
+qcow-util: $(BLK-OBJS)
+       $(CC) $(CFLAGS) -o img2qcow $(BLK-OBJS) img2qcow.c \
+               $(AIOLIBS)  $(LIBS)
+       $(CC) $(CFLAGS) -o qcow2raw $(BLK-OBJS) qcow2raw.c  \
+               $(AIOLIBS)  $(LIBS)
+       $(CC) $(CFLAGS) -o qcow-create $(BLK-OBJS) qcow-create.c  \
+               $(AIOLIBS)  $(LIBS)
+
+install: all
+       $(INSTALL_PROG) $(IBIN) $(QCOW_UTIL) $(DESTDIR)$(INSTALL_DIR)
+
+clean:
+       rm -rf *.o *~ $(DEPS) xen TAGS $(IBIN) $(LIB) $(QCOW_UTIL)
+
+.PHONY: clean install
+
+-include $(DEPS)
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/aes.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/aes.c        Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,1319 @@
+/**
+ * 
+ * aes.c - integrated in QEMU by Fabrice Bellard from the OpenSSL project.
+ */
+/*
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@xxxxxxxxxxxxxxxxxxx>
+ * @author Antoon Bosselaers <antoon.bosselaers@xxxxxxxxxxxxxxxxxxx>
+ * @author Paulo Barreto <paulo.barreto@xxxxxxxxxxxx>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS 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 "vl.h"
+#include <inttypes.h>
+#include <string.h>
+#include "aes.h"
+
+//#define NDEBUG
+#include <assert.h>
+
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+
+#define MAXKC   (256/32)
+#define MAXKB   (256/8)
+#define MAXNR   14
+
+/* This controls loop-unrolling in aes_core.c */
+#undef FULL_UNROLL
+# define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ 
((u32)(pt)[2] <<  8) ^ ((u32)(pt)[3]))
+# define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 
16); (ct)[2] = (u8)((st) >>  8); (ct)[3] = (u8)(st); }
+
+/*
+Te0[x] = S [x].[02, 01, 01, 03];
+Te1[x] = S [x].[03, 02, 01, 01];
+Te2[x] = S [x].[01, 03, 02, 01];
+Te3[x] = S [x].[01, 01, 03, 02];
+Te4[x] = S [x].[01, 01, 01, 01];
+
+Td0[x] = Si[x].[0e, 09, 0d, 0b];
+Td1[x] = Si[x].[0b, 0e, 09, 0d];
+Td2[x] = Si[x].[0d, 0b, 0e, 09];
+Td3[x] = Si[x].[09, 0d, 0b, 0e];
+Td4[x] = Si[x].[01, 01, 01, 01];
+*/
+
+static const u32 Te0[256] = {
+    0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+    0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+    0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+    0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+    0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+    0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+    0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+    0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+    0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+    0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+    0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+    0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+    0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+    0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+    0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+    0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+    0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+    0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+    0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+    0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+    0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+    0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+    0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+    0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+    0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+    0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+    0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+    0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+    0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+    0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+    0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+    0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+    0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+    0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+    0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+    0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+    0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+    0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+    0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+    0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+    0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+    0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+    0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+    0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+    0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+    0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+    0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+    0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+    0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+    0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+    0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+    0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+    0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+    0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+    0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+    0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+    0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+    0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+    0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+    0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+    0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+    0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+    0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+    0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+static const u32 Te1[256] = {
+    0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+    0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+    0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+    0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+    0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+    0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+    0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+    0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+    0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+    0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+    0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+    0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+    0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+    0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+    0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+    0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+    0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+    0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+    0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+    0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+    0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+    0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+    0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+    0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+    0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+    0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+    0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+    0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+    0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+    0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+    0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+    0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+    0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+    0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+    0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+    0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+    0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+    0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+    0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+    0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+    0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+    0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+    0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+    0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+    0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+    0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+    0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+    0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+    0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+    0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+    0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+    0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+    0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+    0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+    0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+    0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+    0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+    0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+    0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+    0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+    0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+    0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+    0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+    0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+};
+static const u32 Te2[256] = {
+    0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+    0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+    0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+    0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+    0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+    0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+    0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+    0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+    0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+    0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+    0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+    0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+    0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+    0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+    0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+    0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+    0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+    0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+    0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+    0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+    0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+    0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+    0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+    0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+    0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+    0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+    0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+    0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+    0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+    0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+    0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+    0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+    0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+    0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+    0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+    0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+    0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+    0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+    0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+    0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+    0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+    0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+    0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+    0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+    0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+    0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+    0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+    0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+    0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+    0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+    0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+    0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+    0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+    0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+    0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+    0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+    0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+    0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+    0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+    0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+    0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+    0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+    0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+    0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+};
+static const u32 Te3[256] = {
+
+    0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+    0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+    0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+    0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+    0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+    0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+    0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+    0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+    0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+    0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+    0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+    0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+    0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+    0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+    0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+    0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+    0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+    0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+    0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+    0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+    0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+    0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+    0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+    0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+    0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+    0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+    0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+    0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+    0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+    0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+    0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+    0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+    0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+    0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+    0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+    0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+    0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+    0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+    0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+    0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+    0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+    0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+    0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+    0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+    0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+    0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+    0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+    0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+    0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+    0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+    0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+    0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+    0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+    0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+    0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+    0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+    0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+    0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+    0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+    0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+    0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+    0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+    0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+    0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+};
+static const u32 Te4[256] = {
+    0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
+    0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
+    0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
+    0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
+    0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
+    0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
+    0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
+    0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
+    0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
+    0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
+    0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
+    0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
+    0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
+    0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
+    0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
+    0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
+    0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
+    0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
+    0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
+    0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
+    0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
+    0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
+    0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
+    0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
+    0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
+    0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
+    0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
+    0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
+    0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
+    0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
+    0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
+    0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
+    0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
+    0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
+    0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
+    0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
+    0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
+    0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
+    0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
+    0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
+    0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
+    0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
+    0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
+    0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
+    0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
+    0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
+    0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
+    0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
+    0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
+    0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
+    0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
+    0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
+    0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
+    0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
+    0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
+    0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
+    0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
+    0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
+    0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
+    0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
+    0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
+    0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
+    0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
+    0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
+};
+static const u32 Td0[256] = {
+    0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+    0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+    0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+    0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+    0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+    0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+    0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+    0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+    0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+    0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+    0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+    0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+    0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+    0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+    0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+    0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+    0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+    0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+    0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+    0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+    0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+    0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+    0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+    0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+    0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+    0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+    0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+    0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+    0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+    0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+    0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+    0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+    0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+    0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+    0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+    0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+    0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+    0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+    0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+    0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+    0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+    0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+    0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+    0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+    0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+    0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+    0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+    0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+    0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+    0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+    0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+    0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+    0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+    0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+    0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+    0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+    0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+    0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+    0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+    0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+    0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+    0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+    0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+    0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+static const u32 Td1[256] = {
+    0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+    0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+    0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+    0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+    0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+    0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+    0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+    0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+    0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+    0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+    0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+    0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+    0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+    0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+    0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+    0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+    0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+    0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+    0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+    0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+    0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+    0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+    0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+    0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+    0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+    0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+    0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+    0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+    0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+    0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+    0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+    0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+    0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+    0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+    0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+    0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+    0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+    0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+    0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+    0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+    0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+    0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+    0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+    0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+    0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+    0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+    0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+    0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+    0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+    0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+    0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+    0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+    0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+    0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+    0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+    0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+    0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+    0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+    0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+    0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+    0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+    0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+    0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+    0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+};
+static const u32 Td2[256] = {
+    0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+    0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+    0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+    0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+    0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+    0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+    0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+    0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+    0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+    0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+    0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+    0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+    0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+    0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+    0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+    0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+    0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+    0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+    0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+    0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+
+    0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+    0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+    0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+    0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+    0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+    0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+    0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+    0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+    0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+    0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+    0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+    0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+    0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+    0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+    0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+    0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+    0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+    0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+    0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+    0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+    0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+    0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+    0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+    0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+    0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+    0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+    0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+    0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+    0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+    0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+    0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+    0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+    0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+    0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+    0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+    0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+    0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+    0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+    0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+    0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+    0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+    0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+    0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+    0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+};
+static const u32 Td3[256] = {
+    0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+    0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+    0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+    0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+    0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+    0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+    0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+    0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+    0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+    0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+    0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+    0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+    0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+    0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+    0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+    0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+    0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+    0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+    0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+    0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+    0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+    0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+    0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+    0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+    0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+    0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+    0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+    0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+    0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+    0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+    0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+    0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+    0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+    0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+    0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+    0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+    0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+    0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+    0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+    0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+    0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+    0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+    0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+    0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+    0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+    0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+    0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+    0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+    0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+    0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+    0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+    0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+    0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+    0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+    0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+    0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+    0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+    0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+    0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+    0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+    0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+    0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+    0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+    0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+};
+static const u32 Td4[256] = {
+    0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
+    0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
+    0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
+    0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
+    0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
+    0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
+    0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
+    0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
+    0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
+    0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
+    0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
+    0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
+    0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
+    0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
+    0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
+    0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
+    0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
+    0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
+    0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
+    0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
+    0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
+    0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
+    0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
+    0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
+    0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
+    0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
+    0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
+    0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
+    0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
+    0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
+    0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
+    0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
+    0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
+    0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
+    0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
+    0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
+    0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
+    0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
+    0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
+    0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
+    0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
+    0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
+    0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
+    0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
+    0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
+    0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
+    0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
+    0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
+    0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
+    0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
+    0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
+    0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
+    0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
+    0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
+    0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
+    0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
+    0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
+    0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
+    0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
+    0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
+    0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
+    0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
+    0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
+    0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
+};
+static const u32 rcon[] = {
+       0x01000000, 0x02000000, 0x04000000, 0x08000000,
+       0x10000000, 0x20000000, 0x40000000, 0x80000000,
+       0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more 
than 10 rcon values */
+};
+
+/**
+ * Expand the cipher key into the encryption key schedule.
+ */
+int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
+                       AES_KEY *key) {
+
+       u32 *rk;
+       int i = 0;
+       u32 temp;
+
+       if (!userKey || !key)
+               return -1;
+       if (bits != 128 && bits != 192 && bits != 256)
+               return -2;
+
+       rk = key->rd_key;
+
+       if (bits==128)
+               key->rounds = 10;
+       else if (bits==192)
+               key->rounds = 12;
+       else
+               key->rounds = 14;
+
+       rk[0] = GETU32(userKey     );
+       rk[1] = GETU32(userKey +  4);
+       rk[2] = GETU32(userKey +  8);
+       rk[3] = GETU32(userKey + 12);
+       if (bits == 128) {
+               while (1) {
+                       temp  = rk[3];
+                       rk[4] = rk[0] ^
+                               (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+                               (Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+                               (Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+                               (Te4[(temp >> 24)       ] & 0x000000ff) ^
+                               rcon[i];
+                       rk[5] = rk[1] ^ rk[4];
+                       rk[6] = rk[2] ^ rk[5];
+                       rk[7] = rk[3] ^ rk[6];
+                       if (++i == 10) {
+                               return 0;
+                       }
+                       rk += 4;
+               }
+       }
+       rk[4] = GETU32(userKey + 16);
+       rk[5] = GETU32(userKey + 20);
+       if (bits == 192) {
+               while (1) {
+                       temp = rk[ 5];
+                       rk[ 6] = rk[ 0] ^
+                               (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+                               (Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+                               (Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+                               (Te4[(temp >> 24)       ] & 0x000000ff) ^
+                               rcon[i];
+                       rk[ 7] = rk[ 1] ^ rk[ 6];
+                       rk[ 8] = rk[ 2] ^ rk[ 7];
+                       rk[ 9] = rk[ 3] ^ rk[ 8];
+                       if (++i == 8) {
+                               return 0;
+                       }
+                       rk[10] = rk[ 4] ^ rk[ 9];
+                       rk[11] = rk[ 5] ^ rk[10];
+                       rk += 6;
+               }
+       }
+       rk[6] = GETU32(userKey + 24);
+       rk[7] = GETU32(userKey + 28);
+       if (bits == 256) {
+               while (1) {
+                       temp = rk[ 7];
+                       rk[ 8] = rk[ 0] ^
+                               (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
+                               (Te4[(temp >>  8) & 0xff] & 0x00ff0000) ^
+                               (Te4[(temp      ) & 0xff] & 0x0000ff00) ^
+                               (Te4[(temp >> 24)       ] & 0x000000ff) ^
+                               rcon[i];
+                       rk[ 9] = rk[ 1] ^ rk[ 8];
+                       rk[10] = rk[ 2] ^ rk[ 9];
+                       rk[11] = rk[ 3] ^ rk[10];
+                       if (++i == 7) {
+                               return 0;
+                       }
+                       temp = rk[11];
+                       rk[12] = rk[ 4] ^
+                               (Te4[(temp >> 24)       ] & 0xff000000) ^
+                               (Te4[(temp >> 16) & 0xff] & 0x00ff0000) ^
+                               (Te4[(temp >>  8) & 0xff] & 0x0000ff00) ^
+                               (Te4[(temp      ) & 0xff] & 0x000000ff);
+                       rk[13] = rk[ 5] ^ rk[12];
+                       rk[14] = rk[ 6] ^ rk[13];
+                       rk[15] = rk[ 7] ^ rk[14];
+
+                       rk += 8;
+               }
+       }
+       return 0;
+}
+
+/**
+ * Expand the cipher key into the decryption key schedule.
+ */
+int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
+                        AES_KEY *key) {
+
+        u32 *rk;
+       int i, j, status;
+       u32 temp;
+
+       /* first, start with an encryption schedule */
+       status = AES_set_encrypt_key(userKey, bits, key);
+       if (status < 0)
+               return status;
+
+       rk = key->rd_key;
+
+       /* invert the order of the round keys: */
+       for (i = 0, j = 4*(key->rounds); i < j; i += 4, j -= 4) {
+               temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
+               temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+               temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+               temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+       }
+       /* apply the inverse MixColumn transform to all round keys but the 
first and the last: */
+       for (i = 1; i < (key->rounds); i++) {
+               rk += 4;
+               rk[0] =
+                       Td0[Te4[(rk[0] >> 24)       ] & 0xff] ^
+                       Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
+                       Td2[Te4[(rk[0] >>  8) & 0xff] & 0xff] ^
+                       Td3[Te4[(rk[0]      ) & 0xff] & 0xff];
+               rk[1] =
+                       Td0[Te4[(rk[1] >> 24)       ] & 0xff] ^
+                       Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
+                       Td2[Te4[(rk[1] >>  8) & 0xff] & 0xff] ^
+                       Td3[Te4[(rk[1]      ) & 0xff] & 0xff];
+               rk[2] =
+                       Td0[Te4[(rk[2] >> 24)       ] & 0xff] ^
+                       Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
+                       Td2[Te4[(rk[2] >>  8) & 0xff] & 0xff] ^
+                       Td3[Te4[(rk[2]      ) & 0xff] & 0xff];
+               rk[3] =
+                       Td0[Te4[(rk[3] >> 24)       ] & 0xff] ^
+                       Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
+                       Td2[Te4[(rk[3] >>  8) & 0xff] & 0xff] ^
+                       Td3[Te4[(rk[3]      ) & 0xff] & 0xff];
+       }
+       return 0;
+}
+
+#ifndef AES_ASM
+/*
+ * Encrypt a single block
+ * in and out can overlap
+ */
+void AES_encrypt(const unsigned char *in, unsigned char *out,
+                const AES_KEY *key) {
+
+       const u32 *rk;
+       u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+       int r;
+#endif /* ?FULL_UNROLL */
+
+       assert(in && out && key);
+       rk = key->rd_key;
+
+       /*
+        * map byte array block to cipher state
+        * and add initial round key:
+        */
+       s0 = GETU32(in     ) ^ rk[0];
+       s1 = GETU32(in +  4) ^ rk[1];
+       s2 = GETU32(in +  8) ^ rk[2];
+       s3 = GETU32(in + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+       /* round 1: */
+       t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ 
Te3[s3 & 0xff] ^ rk[ 4];
+       t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ 
Te3[s0 & 0xff] ^ rk[ 5];
+       t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ 
Te3[s1 & 0xff] ^ rk[ 6];
+       t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ 
Te3[s2 & 0xff] ^ rk[ 7];
+       /* round 2: */
+       s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ 
Te3[t3 & 0xff] ^ rk[ 8];
+       s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ 
Te3[t0 & 0xff] ^ rk[ 9];
+       s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ 
Te3[t1 & 0xff] ^ rk[10];
+       s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ 
Te3[t2 & 0xff] ^ rk[11];
+       /* round 3: */
+       t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ 
Te3[s3 & 0xff] ^ rk[12];
+       t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ 
Te3[s0 & 0xff] ^ rk[13];
+       t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ 
Te3[s1 & 0xff] ^ rk[14];
+       t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ 
Te3[s2 & 0xff] ^ rk[15];
+       /* round 4: */
+       s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ 
Te3[t3 & 0xff] ^ rk[16];
+       s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ 
Te3[t0 & 0xff] ^ rk[17];
+       s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ 
Te3[t1 & 0xff] ^ rk[18];
+       s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ 
Te3[t2 & 0xff] ^ rk[19];
+       /* round 5: */
+       t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ 
Te3[s3 & 0xff] ^ rk[20];
+       t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ 
Te3[s0 & 0xff] ^ rk[21];
+       t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ 
Te3[s1 & 0xff] ^ rk[22];
+       t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ 
Te3[s2 & 0xff] ^ rk[23];
+       /* round 6: */
+       s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ 
Te3[t3 & 0xff] ^ rk[24];
+       s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ 
Te3[t0 & 0xff] ^ rk[25];
+       s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ 
Te3[t1 & 0xff] ^ rk[26];
+       s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ 
Te3[t2 & 0xff] ^ rk[27];
+       /* round 7: */
+       t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ 
Te3[s3 & 0xff] ^ rk[28];
+       t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ 
Te3[s0 & 0xff] ^ rk[29];
+       t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ 
Te3[s1 & 0xff] ^ rk[30];
+       t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ 
Te3[s2 & 0xff] ^ rk[31];
+       /* round 8: */
+       s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ 
Te3[t3 & 0xff] ^ rk[32];
+       s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ 
Te3[t0 & 0xff] ^ rk[33];
+       s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ 
Te3[t1 & 0xff] ^ rk[34];
+       s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ 
Te3[t2 & 0xff] ^ rk[35];
+       /* round 9: */
+       t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ 
Te3[s3 & 0xff] ^ rk[36];
+       t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ 
Te3[s0 & 0xff] ^ rk[37];
+       t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ 
Te3[s1 & 0xff] ^ rk[38];
+       t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ 
Te3[s2 & 0xff] ^ rk[39];
+    if (key->rounds > 10) {
+        /* round 10: */
+        s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 0xff] ^ 
Te3[t3 & 0xff] ^ rk[40];
+        s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 0xff] ^ 
Te3[t0 & 0xff] ^ rk[41];
+        s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 0xff] ^ 
Te3[t1 & 0xff] ^ rk[42];
+        s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 0xff] ^ 
Te3[t2 & 0xff] ^ rk[43];
+        /* round 11: */
+        t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 0xff] ^ 
Te3[s3 & 0xff] ^ rk[44];
+        t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 0xff] ^ 
Te3[s0 & 0xff] ^ rk[45];
+        t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 0xff] ^ 
Te3[s1 & 0xff] ^ rk[46];
+        t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 0xff] ^ 
Te3[s2 & 0xff] ^ rk[47];
+        if (key->rounds > 12) {
+            /* round 12: */
+            s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >>  8) & 
0xff] ^ Te3[t3 & 0xff] ^ rk[48];
+            s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >>  8) & 
0xff] ^ Te3[t0 & 0xff] ^ rk[49];
+            s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >>  8) & 
0xff] ^ Te3[t1 & 0xff] ^ rk[50];
+            s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >>  8) & 
0xff] ^ Te3[t2 & 0xff] ^ rk[51];
+            /* round 13: */
+            t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >>  8) & 
0xff] ^ Te3[s3 & 0xff] ^ rk[52];
+            t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >>  8) & 
0xff] ^ Te3[s0 & 0xff] ^ rk[53];
+            t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >>  8) & 
0xff] ^ Te3[s1 & 0xff] ^ rk[54];
+            t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >>  8) & 
0xff] ^ Te3[s2 & 0xff] ^ rk[55];
+        }
+    }
+    rk += key->rounds << 2;
+#else  /* !FULL_UNROLL */
+    /*
+     * Nr - 1 full rounds:
+     */
+    r = key->rounds >> 1;
+    for (;;) {
+        t0 =
+            Te0[(s0 >> 24)       ] ^
+            Te1[(s1 >> 16) & 0xff] ^
+            Te2[(s2 >>  8) & 0xff] ^
+            Te3[(s3      ) & 0xff] ^
+            rk[4];
+        t1 =
+            Te0[(s1 >> 24)       ] ^
+            Te1[(s2 >> 16) & 0xff] ^
+            Te2[(s3 >>  8) & 0xff] ^
+            Te3[(s0      ) & 0xff] ^
+            rk[5];
+        t2 =
+            Te0[(s2 >> 24)       ] ^
+            Te1[(s3 >> 16) & 0xff] ^
+            Te2[(s0 >>  8) & 0xff] ^
+            Te3[(s1      ) & 0xff] ^
+            rk[6];
+        t3 =
+            Te0[(s3 >> 24)       ] ^
+            Te1[(s0 >> 16) & 0xff] ^
+            Te2[(s1 >>  8) & 0xff] ^
+            Te3[(s2      ) & 0xff] ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Te0[(t0 >> 24)       ] ^
+            Te1[(t1 >> 16) & 0xff] ^
+            Te2[(t2 >>  8) & 0xff] ^
+            Te3[(t3      ) & 0xff] ^
+            rk[0];
+        s1 =
+            Te0[(t1 >> 24)       ] ^
+            Te1[(t2 >> 16) & 0xff] ^
+            Te2[(t3 >>  8) & 0xff] ^
+            Te3[(t0      ) & 0xff] ^
+            rk[1];
+        s2 =
+            Te0[(t2 >> 24)       ] ^
+            Te1[(t3 >> 16) & 0xff] ^
+            Te2[(t0 >>  8) & 0xff] ^
+            Te3[(t1      ) & 0xff] ^
+            rk[2];
+        s3 =
+            Te0[(t3 >> 24)       ] ^
+            Te1[(t0 >> 16) & 0xff] ^
+            Te2[(t1 >>  8) & 0xff] ^
+            Te3[(t2      ) & 0xff] ^
+            rk[3];
+    }
+#endif /* ?FULL_UNROLL */
+    /*
+        * apply last round and
+        * map cipher state to byte array block:
+        */
+       s0 =
+               (Te4[(t0 >> 24)       ] & 0xff000000) ^
+               (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+               (Te4[(t2 >>  8) & 0xff] & 0x0000ff00) ^
+               (Te4[(t3      ) & 0xff] & 0x000000ff) ^
+               rk[0];
+       PUTU32(out     , s0);
+       s1 =
+               (Te4[(t1 >> 24)       ] & 0xff000000) ^
+               (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+               (Te4[(t3 >>  8) & 0xff] & 0x0000ff00) ^
+               (Te4[(t0      ) & 0xff] & 0x000000ff) ^
+               rk[1];
+       PUTU32(out +  4, s1);
+       s2 =
+               (Te4[(t2 >> 24)       ] & 0xff000000) ^
+               (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+               (Te4[(t0 >>  8) & 0xff] & 0x0000ff00) ^
+               (Te4[(t1      ) & 0xff] & 0x000000ff) ^
+               rk[2];
+       PUTU32(out +  8, s2);
+       s3 =
+               (Te4[(t3 >> 24)       ] & 0xff000000) ^
+               (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+               (Te4[(t1 >>  8) & 0xff] & 0x0000ff00) ^
+               (Te4[(t2      ) & 0xff] & 0x000000ff) ^
+               rk[3];
+       PUTU32(out + 12, s3);
+}
+
+/*
+ * Decrypt a single block
+ * in and out can overlap
+ */
+void AES_decrypt(const unsigned char *in, unsigned char *out,
+                const AES_KEY *key) {
+
+       const u32 *rk;
+       u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+       int r;
+#endif /* ?FULL_UNROLL */
+
+       assert(in && out && key);
+       rk = key->rd_key;
+
+       /*
+        * map byte array block to cipher state
+        * and add initial round key:
+        */
+    s0 = GETU32(in     ) ^ rk[0];
+    s1 = GETU32(in +  4) ^ rk[1];
+    s2 = GETU32(in +  8) ^ rk[2];
+    s3 = GETU32(in + 12) ^ rk[3];
+#ifdef FULL_UNROLL
+    /* round 1: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ 
Td3[s1 & 0xff] ^ rk[ 4];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ 
Td3[s2 & 0xff] ^ rk[ 5];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ 
Td3[s3 & 0xff] ^ rk[ 6];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ 
Td3[s0 & 0xff] ^ rk[ 7];
+    /* round 2: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ 
Td3[t1 & 0xff] ^ rk[ 8];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ 
Td3[t2 & 0xff] ^ rk[ 9];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ 
Td3[t3 & 0xff] ^ rk[10];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ 
Td3[t0 & 0xff] ^ rk[11];
+    /* round 3: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ 
Td3[s1 & 0xff] ^ rk[12];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ 
Td3[s2 & 0xff] ^ rk[13];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ 
Td3[s3 & 0xff] ^ rk[14];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ 
Td3[s0 & 0xff] ^ rk[15];
+    /* round 4: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ 
Td3[t1 & 0xff] ^ rk[16];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ 
Td3[t2 & 0xff] ^ rk[17];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ 
Td3[t3 & 0xff] ^ rk[18];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ 
Td3[t0 & 0xff] ^ rk[19];
+    /* round 5: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ 
Td3[s1 & 0xff] ^ rk[20];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ 
Td3[s2 & 0xff] ^ rk[21];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ 
Td3[s3 & 0xff] ^ rk[22];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ 
Td3[s0 & 0xff] ^ rk[23];
+    /* round 6: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ 
Td3[t1 & 0xff] ^ rk[24];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ 
Td3[t2 & 0xff] ^ rk[25];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ 
Td3[t3 & 0xff] ^ rk[26];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ 
Td3[t0 & 0xff] ^ rk[27];
+    /* round 7: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ 
Td3[s1 & 0xff] ^ rk[28];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ 
Td3[s2 & 0xff] ^ rk[29];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ 
Td3[s3 & 0xff] ^ rk[30];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ 
Td3[s0 & 0xff] ^ rk[31];
+    /* round 8: */
+    s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ 
Td3[t1 & 0xff] ^ rk[32];
+    s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ 
Td3[t2 & 0xff] ^ rk[33];
+    s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ 
Td3[t3 & 0xff] ^ rk[34];
+    s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ 
Td3[t0 & 0xff] ^ rk[35];
+    /* round 9: */
+    t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ 
Td3[s1 & 0xff] ^ rk[36];
+    t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ 
Td3[s2 & 0xff] ^ rk[37];
+    t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ 
Td3[s3 & 0xff] ^ rk[38];
+    t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ 
Td3[s0 & 0xff] ^ rk[39];
+    if (key->rounds > 10) {
+        /* round 10: */
+        s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 0xff] ^ 
Td3[t1 & 0xff] ^ rk[40];
+        s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 0xff] ^ 
Td3[t2 & 0xff] ^ rk[41];
+        s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 0xff] ^ 
Td3[t3 & 0xff] ^ rk[42];
+        s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 0xff] ^ 
Td3[t0 & 0xff] ^ rk[43];
+        /* round 11: */
+        t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 0xff] ^ 
Td3[s1 & 0xff] ^ rk[44];
+        t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 0xff] ^ 
Td3[s2 & 0xff] ^ rk[45];
+        t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 0xff] ^ 
Td3[s3 & 0xff] ^ rk[46];
+        t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 0xff] ^ 
Td3[s0 & 0xff] ^ rk[47];
+        if (key->rounds > 12) {
+            /* round 12: */
+            s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >>  8) & 
0xff] ^ Td3[t1 & 0xff] ^ rk[48];
+            s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >>  8) & 
0xff] ^ Td3[t2 & 0xff] ^ rk[49];
+            s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >>  8) & 
0xff] ^ Td3[t3 & 0xff] ^ rk[50];
+            s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >>  8) & 
0xff] ^ Td3[t0 & 0xff] ^ rk[51];
+            /* round 13: */
+            t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >>  8) & 
0xff] ^ Td3[s1 & 0xff] ^ rk[52];
+            t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >>  8) & 
0xff] ^ Td3[s2 & 0xff] ^ rk[53];
+            t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >>  8) & 
0xff] ^ Td3[s3 & 0xff] ^ rk[54];
+            t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >>  8) & 
0xff] ^ Td3[s0 & 0xff] ^ rk[55];
+        }
+    }
+       rk += key->rounds << 2;
+#else  /* !FULL_UNROLL */
+    /*
+     * Nr - 1 full rounds:
+     */
+    r = key->rounds >> 1;
+    for (;;) {
+        t0 =
+            Td0[(s0 >> 24)       ] ^
+            Td1[(s3 >> 16) & 0xff] ^
+            Td2[(s2 >>  8) & 0xff] ^
+            Td3[(s1      ) & 0xff] ^
+            rk[4];
+        t1 =
+            Td0[(s1 >> 24)       ] ^
+            Td1[(s0 >> 16) & 0xff] ^
+            Td2[(s3 >>  8) & 0xff] ^
+            Td3[(s2      ) & 0xff] ^
+            rk[5];
+        t2 =
+            Td0[(s2 >> 24)       ] ^
+            Td1[(s1 >> 16) & 0xff] ^
+            Td2[(s0 >>  8) & 0xff] ^
+            Td3[(s3      ) & 0xff] ^
+            rk[6];
+        t3 =
+            Td0[(s3 >> 24)       ] ^
+            Td1[(s2 >> 16) & 0xff] ^
+            Td2[(s1 >>  8) & 0xff] ^
+            Td3[(s0      ) & 0xff] ^
+            rk[7];
+
+        rk += 8;
+        if (--r == 0) {
+            break;
+        }
+
+        s0 =
+            Td0[(t0 >> 24)       ] ^
+            Td1[(t3 >> 16) & 0xff] ^
+            Td2[(t2 >>  8) & 0xff] ^
+            Td3[(t1      ) & 0xff] ^
+            rk[0];
+        s1 =
+            Td0[(t1 >> 24)       ] ^
+            Td1[(t0 >> 16) & 0xff] ^
+            Td2[(t3 >>  8) & 0xff] ^
+            Td3[(t2      ) & 0xff] ^
+            rk[1];
+        s2 =
+            Td0[(t2 >> 24)       ] ^
+            Td1[(t1 >> 16) & 0xff] ^
+            Td2[(t0 >>  8) & 0xff] ^
+            Td3[(t3      ) & 0xff] ^
+            rk[2];
+        s3 =
+            Td0[(t3 >> 24)       ] ^
+            Td1[(t2 >> 16) & 0xff] ^
+            Td2[(t1 >>  8) & 0xff] ^
+            Td3[(t0      ) & 0xff] ^
+            rk[3];
+    }
+#endif /* ?FULL_UNROLL */
+    /*
+        * apply last round and
+        * map cipher state to byte array block:
+        */
+       s0 =
+               (Td4[(t0 >> 24)       ] & 0xff000000) ^
+               (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
+               (Td4[(t2 >>  8) & 0xff] & 0x0000ff00) ^
+               (Td4[(t1      ) & 0xff] & 0x000000ff) ^
+               rk[0];
+       PUTU32(out     , s0);
+       s1 =
+               (Td4[(t1 >> 24)       ] & 0xff000000) ^
+               (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
+               (Td4[(t3 >>  8) & 0xff] & 0x0000ff00) ^
+               (Td4[(t2      ) & 0xff] & 0x000000ff) ^
+               rk[1];
+       PUTU32(out +  4, s1);
+       s2 =
+               (Td4[(t2 >> 24)       ] & 0xff000000) ^
+               (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
+               (Td4[(t0 >>  8) & 0xff] & 0x0000ff00) ^
+               (Td4[(t3      ) & 0xff] & 0x000000ff) ^
+               rk[2];
+       PUTU32(out +  8, s2);
+       s3 =
+               (Td4[(t3 >> 24)       ] & 0xff000000) ^
+               (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
+               (Td4[(t1 >>  8) & 0xff] & 0x0000ff00) ^
+               (Td4[(t0      ) & 0xff] & 0x000000ff) ^
+               rk[3];
+       PUTU32(out + 12, s3);
+}
+
+#endif /* AES_ASM */
+
+void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
+                    const unsigned long length, const AES_KEY *key,
+                    unsigned char *ivec, const int enc) 
+{
+
+       unsigned long n;
+       unsigned long len = length;
+       unsigned char tmp[AES_BLOCK_SIZE];
+
+       assert(in && out && key && ivec);
+
+       if (enc) {
+               while (len >= AES_BLOCK_SIZE) {
+                       for(n=0; n < AES_BLOCK_SIZE; ++n)
+                               tmp[n] = in[n] ^ ivec[n];
+                       AES_encrypt(tmp, out, key);
+                       memcpy(ivec, out, AES_BLOCK_SIZE);
+                       len -= AES_BLOCK_SIZE;
+                       in += AES_BLOCK_SIZE;
+                       out += AES_BLOCK_SIZE;
+               }
+               if (len) {
+                       for(n=0; n < len; ++n)
+                               tmp[n] = in[n] ^ ivec[n];
+                       for(n=len; n < AES_BLOCK_SIZE; ++n)
+                               tmp[n] = ivec[n];
+                       AES_encrypt(tmp, tmp, key);
+                       memcpy(out, tmp, AES_BLOCK_SIZE);
+                       memcpy(ivec, tmp, AES_BLOCK_SIZE);
+               }                       
+       } else {
+               while (len >= AES_BLOCK_SIZE) {
+                       memcpy(tmp, in, AES_BLOCK_SIZE);
+                       AES_decrypt(in, out, key);
+                       for(n=0; n < AES_BLOCK_SIZE; ++n)
+                               out[n] ^= ivec[n];
+                       memcpy(ivec, tmp, AES_BLOCK_SIZE);
+                       len -= AES_BLOCK_SIZE;
+                       in += AES_BLOCK_SIZE;
+                       out += AES_BLOCK_SIZE;
+               }
+               if (len) {
+                       memcpy(tmp, in, AES_BLOCK_SIZE);
+                       AES_decrypt(tmp, tmp, key);
+                       for(n=0; n < len; ++n)
+                               out[n] = tmp[n] ^ ivec[n];
+                       memcpy(ivec, tmp, AES_BLOCK_SIZE);
+               }                       
+       }
+}
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/aes.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/aes.h        Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,26 @@
+#ifndef QEMU_AES_H
+#define QEMU_AES_H
+
+#define AES_MAXNR 14
+#define AES_BLOCK_SIZE 16
+
+struct aes_key_st {
+    uint32_t rd_key[4 *(AES_MAXNR + 1)];
+    int rounds;
+};
+typedef struct aes_key_st AES_KEY;
+
+int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
+       AES_KEY *key);
+int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
+       AES_KEY *key);
+
+void AES_encrypt(const unsigned char *in, unsigned char *out,
+       const AES_KEY *key);
+void AES_decrypt(const unsigned char *in, unsigned char *out,
+       const AES_KEY *key);
+void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
+                    const unsigned long length, const AES_KEY *key,
+                    unsigned char *ivec, const int enc);
+
+#endif
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/blktapctrl.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/blktapctrl.c Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,704 @@
+/*
+ * blktapctrl.c
+ * 
+ * userspace controller for the blktap disks.
+ * As requests for new block devices arrive,
+ * the controller spawns off a separate process
+ * per-disk.
+ *
+ *
+ * Copyright (c) 2005 Julian Chesterfield and Andrew Warfield.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/user.h>
+#include <err.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <linux/types.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <unistd.h>
+#include <xs.h>
+#include <printf.h>
+#include <sys/time.h>
+#include <syslog.h>
+                                                                     
+#include "blktaplib.h"
+#include "blktapctrl.h"
+#include "tapdisk.h"
+
+#define NUM_POLL_FDS 2
+#define MSG_SIZE 4096
+#define MAX_TIMEOUT 10
+#define MAX_RAND_VAL 0xFFFF
+
+int run = 1;
+int max_timeout = MAX_TIMEOUT;
+int ctlfd = 0;
+
+static int open_ctrl_socket(char *devname);
+static int write_msg(int fd, int msgtype, void *ptr, void *ptr2);
+static int read_msg(int fd, int msgtype, void *ptr);
+static driver_list_entry_t *active_disks[MAX_DISK_TYPES];
+
+void sig_handler(int sig)
+{
+       run = 0;        
+}
+
+static void init_driver_list(void)
+{
+       int i;
+
+       for (i = 0; i < MAX_DISK_TYPES; i++)
+               active_disks[i] = NULL;
+       return;
+}
+
+static void init_rng(void)
+{
+       static uint32_t seed;
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+       seed = tv.tv_usec;
+       srand48(seed);
+       return;
+}
+
+static void make_blktap_dev(char *devname, int major, int minor)
+{
+       struct stat st;
+       
+       if (lstat(devname, &st) != 0) {
+               /*Need to create device*/
+               if (mkdir(BLKTAP_DEV_DIR, 0755) == 0)
+                       DPRINTF("Created %s directory\n",BLKTAP_DEV_DIR);
+               if (mknod(devname, S_IFCHR|0600,
+                       makedev(major, minor)) == 0)
+                       DPRINTF("Created %s device\n",devname);
+       } else DPRINTF("%s device already exists\n",devname);
+}
+
+static int get_new_dev(int *major, int *minor, blkif_t *blkif)
+{
+       domid_translate_t tr;
+       int ret;
+       char *devname;
+       
+       tr.domid = blkif->domid;
+        tr.busid = (unsigned short)blkif->be_id;
+       ret = ioctl(ctlfd, BLKTAP_IOCTL_NEWINTF, tr );
+       
+       if ( (ret <= 0)||(ret > MAX_TAP_DEV) ) {
+               DPRINTF("Incorrect Dev ID [%d]\n",ret);
+               return -1;
+       }
+       
+       *minor = ret;
+       *major = ioctl(ctlfd, BLKTAP_IOCTL_MAJOR, ret );
+       if (*major < 0) {
+               DPRINTF("Incorrect Major ID [%d]\n",*major);
+               return -1;
+       }
+
+       asprintf(&devname,"%s/%s%d",BLKTAP_DEV_DIR, BLKTAP_DEV_NAME, *minor);
+       make_blktap_dev(devname,*major,*minor); 
+       DPRINTF("Received device id %d and major %d, "
+               "sent domid %d and be_id %d\n",
+               *minor, *major, tr.domid, tr.busid);
+       return 0;
+}
+
+static int get_tapdisk_pid(blkif_t *blkif)
+{
+       int ret;
+
+       if ((ret = write_msg(blkif->fds[WRITE], CTLMSG_PID, blkif, NULL)) 
+           <= 0) {
+               DPRINTF("Write_msg failed - CTLMSG_PID(%d)\n", ret);
+               return -EINVAL;
+       }
+
+       if ((ret = read_msg(blkif->fds[READ], CTLMSG_PID_RSP, blkif))
+            <= 0) {
+               DPRINTF("Read_msg failure - CTLMSG_PID(%d)\n", ret);
+               return -EINVAL;
+       }       
+       return 1;
+}
+
+static blkif_t *test_path(char *path, char **dev, int *type)
+{
+       char *ptr, handle[10];
+       int i, size;
+
+       size = sizeof(dtypes)/sizeof(disk_info_t *);
+       *type = MAX_DISK_TYPES + 1;
+
+       if ( (ptr = strstr(path, ":"))!=NULL) {
+               memcpy(handle, path, (ptr - path));
+               *dev = ptr + 1;
+               ptr = handle + (ptr - path);
+               *ptr = '\0';
+               DPRINTF("Detected handle: [%s]\n",handle);
+
+               for (i = 0; i < size; i++) {
+                       if (strncmp(handle, dtypes[i]->handle, (ptr - path))
+                           ==0) {
+                               *type = dtypes[i]->idnum;
+
+                               if (dtypes[i]->single_handler == 1) {
+                                       /* Check whether tapdisk process 
+                                          already exists */
+                                       if (active_disks[dtypes[i]->idnum] 
+                                           == NULL) return NULL;
+                                       else 
+                                               return 
active_disks[dtypes[i]->idnum]->blkif;
+                               }
+                       }
+               }
+       } else *dev = NULL;
+
+       return NULL;
+}
+
+static void add_disktype(blkif_t *blkif, int type)
+{
+       driver_list_entry_t *entry, *ptr, *last;
+
+       if (type > MAX_DISK_TYPES) return;
+
+       entry = malloc(sizeof(driver_list_entry_t));
+       entry->blkif = blkif;
+       entry->next = NULL;
+       ptr = active_disks[type];
+
+       if (ptr == NULL) {
+               active_disks[type] = entry;
+               entry->prev = NULL;
+               return;
+       }
+
+       while (ptr != NULL) {
+               last = ptr;
+               ptr = ptr->next;
+       }
+
+       /*We've found the end of the list*/
+        last->next = entry;
+       entry->prev = last;
+       
+       return;
+}
+
+static int del_disktype(blkif_t *blkif)
+{
+       driver_list_entry_t *ptr, *cur, *last;
+       int type = blkif->drivertype, count = 0, close = 0;
+
+       if (type > MAX_DISK_TYPES) return 1;
+
+       ptr = active_disks[type];
+       last = NULL;
+       while (ptr != NULL) {
+               count++;
+               if (blkif == ptr->blkif) {
+                       cur = ptr;
+                       if (ptr->next != NULL) {
+                               /*There's more later in the chain*/
+                               if (!last) {
+                                       /*We're first in the list*/
+                                       active_disks[type] = ptr->next;
+                                       ptr = ptr->next;
+                                       ptr->prev = NULL;
+                               }
+                               else {
+                                       /*We're sandwiched*/
+                                       last->next = ptr->next;
+                                       ptr = ptr->next;
+                                       ptr->prev = last;
+                               }
+                               
+                       } else if (last) {
+                               /*There's more earlier in the chain*/
+                               last->next = NULL;
+                       } else {
+                               /*We're the only entry*/
+                               active_disks[type] = NULL;
+                               if(dtypes[type]->single_handler == 1) 
+                                       close = 1;
+                       }
+                       DPRINTF("DEL_DISKTYPE: Freeing entry\n");
+                       free(cur);
+                       if (dtypes[type]->single_handler == 0) close = 1;
+
+                       return close;
+               }
+               last = ptr;
+               ptr = ptr->next;
+       }
+       DPRINTF("DEL_DISKTYPE: No match\n");
+       return 1;
+}
+
+static int write_msg(int fd, int msgtype, void *ptr, void *ptr2)
+{
+       blkif_t *blkif;
+       blkif_info_t *blk;
+       msg_hdr_t *msg;
+       msg_newdev_t *msg_dev;
+       char *p, *buf, *path;
+       int msglen, len, ret;
+       fd_set writefds;
+       struct timeval timeout;
+       image_t *image, *img;
+       uint32_t seed;
+
+       blkif = (blkif_t *)ptr;
+       blk = blkif->info;
+       image = blkif->prv;
+       len = 0;
+
+       switch (msgtype)
+       {
+       case CTLMSG_PARAMS:
+               path = (char *)ptr2;
+               DPRINTF("Write_msg called: CTLMSG_PARAMS, sending [%s, %s]\n",
+                       blk->params, path);
+
+               msglen = sizeof(msg_hdr_t) + strlen(path) + 1;
+               buf = malloc(msglen);
+
+               /*Assign header fields*/
+               msg = (msg_hdr_t *)buf;
+               msg->type = CTLMSG_PARAMS;
+               msg->len = msglen;
+               msg->drivertype = blkif->drivertype;
+
+               gettimeofday(&timeout, NULL);
+               msg->cookie = blkif->cookie;
+               DPRINTF("Generated cookie, %d\n",blkif->cookie);
+
+               /*Copy blk->params to msg*/
+               p = buf + sizeof(msg_hdr_t);
+               memcpy(p, path, strlen(path) + 1);
+
+               break;
+
+       case CTLMSG_NEWDEV:
+               DPRINTF("Write_msg called: CTLMSG_NEWDEV\n");
+
+               msglen = sizeof(msg_hdr_t) + sizeof(msg_newdev_t);
+               buf = malloc(msglen);
+               
+               /*Assign header fields*/
+               msg = (msg_hdr_t *)buf;
+               msg->type = CTLMSG_NEWDEV;
+               msg->len = msglen;
+               msg->drivertype = blkif->drivertype;
+               msg->cookie = blkif->cookie;
+               
+               msg_dev = (msg_newdev_t *)(buf + sizeof(msg_hdr_t));
+               msg_dev->devnum = blkif->minor;
+               msg_dev->domid = blkif->domid;
+
+               break;
+
+       case CTLMSG_CLOSE:
+               DPRINTF("Write_msg called: CTLMSG_CLOSE\n");
+
+               msglen = sizeof(msg_hdr_t);
+               buf = malloc(msglen);
+               
+               /*Assign header fields*/
+               msg = (msg_hdr_t *)buf;
+               msg->type = CTLMSG_CLOSE;
+               msg->len = msglen;
+               msg->drivertype = blkif->drivertype;
+               msg->cookie = blkif->cookie;
+               
+               break;
+
+       case CTLMSG_PID:
+               DPRINTF("Write_msg called: CTLMSG_PID\n");
+
+               msglen = sizeof(msg_hdr_t);
+               buf = malloc(msglen);
+               
+               /*Assign header fields*/
+               msg = (msg_hdr_t *)buf;
+               msg->type = CTLMSG_PID;
+               msg->len = msglen;
+               msg->drivertype = blkif->drivertype;
+               msg->cookie = blkif->cookie;
+               
+               break;
+               
+       default:
+               return -1;
+       }
+
+       /*Now send the message*/
+       ret = 0;
+       FD_ZERO(&writefds);
+       FD_SET(fd,&writefds);
+       timeout.tv_sec = max_timeout; /*Wait for up to max_timeout seconds*/
+       timeout.tv_usec = 0;
+       if (select(fd+1, (fd_set *) 0, &writefds, 
+                 (fd_set *) 0, &timeout) > 0) {
+               len = write(fd, buf, msglen);
+               if (len == -1) DPRINTF("Write failed: (%d)\n",errno);
+       }
+       free(buf);
+
+       return len;
+}
+
+static int read_msg(int fd, int msgtype, void *ptr)
+{
+       blkif_t *blkif;
+       blkif_info_t *blk;
+       msg_hdr_t *msg;
+       msg_pid_t *msg_pid;
+       char *p, *buf;
+       int msglen = MSG_SIZE, len, ret;
+       fd_set readfds;
+       struct timeval timeout;
+       image_t *image, *img;
+
+
+       blkif = (blkif_t *)ptr;
+       blk = blkif->info;
+       image = blkif->prv;
+
+       buf = malloc(MSG_SIZE);
+
+       ret = 0;
+       FD_ZERO(&readfds);
+       FD_SET(fd,&readfds);
+       timeout.tv_sec = max_timeout; /*Wait for up to max_timeout seconds*/ 
+       timeout.tv_usec = 0;
+       if (select(fd+1, &readfds,  (fd_set *) 0,
+                 (fd_set *) 0, &timeout) > 0) {
+               ret = read(fd, buf, msglen);
+               
+       }                       
+       if (ret > 0) {
+               msg = (msg_hdr_t *)buf;
+               switch (msg->type)
+               {
+               case CTLMSG_IMG:
+                       img = (image_t *)(buf + sizeof(msg_hdr_t));
+                       image->size = img->size;
+                       image->secsize = img->secsize;
+                       image->info = img->info;
+
+                       DPRINTF("Received CTLMSG_IMG: %lu, %lu, %lu\n",
+                               image->size, image->secsize, image->info);
+                       if(msgtype != CTLMSG_IMG) ret = 0;
+                       break;
+                       
+               case CTLMSG_IMG_FAIL:
+                       DPRINTF("Received CTLMSG_IMG_FAIL, "
+                               "unable to open image\n");
+                       ret = 0;
+                       break;
+                               
+               case CTLMSG_NEWDEV_RSP:
+                       DPRINTF("Received CTLMSG_NEWDEV_RSP\n");
+                       if(msgtype != CTLMSG_NEWDEV_RSP) ret = 0;
+                       break;
+                       
+               case CTLMSG_NEWDEV_FAIL:
+                       DPRINTF("Received CTLMSG_NEWDEV_FAIL\n");
+                       ret = 0;
+                       break;
+                       
+               case CTLMSG_CLOSE_RSP:
+                       DPRINTF("Received CTLMSG_CLOSE_RSP\n");
+                       if (msgtype != CTLMSG_CLOSE_RSP) ret = 0;
+                       break;
+
+               case CTLMSG_PID_RSP:
+                       DPRINTF("Received CTLMSG_PID_RSP\n");
+                       if (msgtype != CTLMSG_PID_RSP) ret = 0;
+                       else {
+                               msg_pid = (msg_pid_t *)
+                                       (buf + sizeof(msg_hdr_t));
+                               blkif->tappid = msg_pid->pid;
+                               DPRINTF("\tPID: [%d]\n",blkif->tappid);
+                       }
+                       break;
+               default:
+                       DPRINTF("UNKNOWN MESSAGE TYPE RECEIVED\n");
+                       ret = 0;
+                       break;
+               }
+       } 
+       
+       free(buf);
+       
+       return ret;
+
+}
+
+int blktapctrl_new_blkif(blkif_t *blkif)
+{
+       blkif_info_t *blk;
+       int major, minor, fd_read, fd_write, type, new;
+       char *rdctldev, *wrctldev, *cmd, *ptr;
+       image_t *image;
+       blkif_t *exist = NULL;
+
+       DPRINTF("Received a poll for a new vbd\n");
+       if ( ((blk=blkif->info) != NULL) && (blk->params != NULL) ) {
+               if (get_new_dev(&major, &minor, blkif)<0)
+                       return -1;
+
+               exist = test_path(blk->params, &ptr, &type);
+               blkif->drivertype = type;
+               blkif->cookie = lrand48() % MAX_RAND_VAL;
+
+               if (!exist) {
+                       DPRINTF("Process does not exist:\n");
+                       asprintf(&rdctldev, "/dev/xen/tapctrlread%d", minor);
+                       blkif->fds[READ] = open_ctrl_socket(rdctldev);
+
+
+                       asprintf(&wrctldev, "/dev/xen/tapctrlwrite%d", minor);
+                       blkif->fds[WRITE] = open_ctrl_socket(wrctldev);
+                       
+                       if (blkif->fds[READ] == -1 || blkif->fds[WRITE] == -1) 
+                               goto fail;
+
+                       /*launch the new process*/
+                       asprintf(&cmd, "tapdisk %s %s", wrctldev, rdctldev);
+                       DPRINTF("Launching process, CMDLINE [%s]\n",cmd);
+                       if (system(cmd) == -1) {
+                               DPRINTF("Unable to fork, cmdline: [%s]\n",cmd);
+                               return -1;
+                       }
+
+                       free(rdctldev);
+                       free(wrctldev);
+                       free(cmd);
+               } else {
+                       DPRINTF("Process exists!\n");
+                       blkif->fds[READ] = exist->fds[READ];
+                       blkif->fds[WRITE] = exist->fds[WRITE];
+               }
+
+               add_disktype(blkif, type);
+               blkif->major = major;
+               blkif->minor = minor;
+
+               image = (image_t *)malloc(sizeof(image_t));
+               blkif->prv = (void *)image;
+               blkif->ops = &tapdisk_ops;
+
+               /*Retrieve the PID of the new process*/
+               if (get_tapdisk_pid(blkif) <= 0) {
+                       DPRINTF("Unable to contact disk process\n");
+                       goto fail;
+               }
+
+               /* Both of the following read and write calls will block up to 
+                * max_timeout val*/
+               if (write_msg(blkif->fds[WRITE], CTLMSG_PARAMS, blkif, ptr) 
+                   <= 0) {
+                       DPRINTF("Write_msg failed - CTLMSG_PARAMS\n");
+                       goto fail;
+               }
+
+               if (read_msg(blkif->fds[READ], CTLMSG_IMG, blkif) <= 0) {
+                       DPRINTF("Read_msg failure - CTLMSG_IMG\n");
+                       goto fail;
+               }
+
+       } else return -1;
+
+       return 0;
+fail:
+       ioctl(ctlfd, BLKTAP_IOCTL_FREEINTF, minor);
+       return -EINVAL;
+}
+
+int map_new_blktapctrl(blkif_t *blkif)
+{
+       DPRINTF("Received a poll for a new devmap\n");
+       if (write_msg(blkif->fds[WRITE], CTLMSG_NEWDEV, blkif, NULL) <= 0) {
+               DPRINTF("Write_msg failed - CTLMSG_NEWDEV\n");
+               return -EINVAL;
+       }
+
+       if (read_msg(blkif->fds[READ], CTLMSG_NEWDEV_RSP, blkif) <= 0) {
+               DPRINTF("Read_msg failed - CTLMSG_NEWDEV_RSP\n");
+               return -EINVAL;
+       }
+       DPRINTF("Exiting map_new_blktapctrl\n");
+
+       return blkif->minor - 1;
+}
+
+int unmap_blktapctrl(blkif_t *blkif)
+{
+       DPRINTF("Unmapping vbd\n");
+
+       if (write_msg(blkif->fds[WRITE], CTLMSG_CLOSE, blkif, NULL) <= 0) {
+               DPRINTF("Write_msg failed - CTLMSG_CLOSE\n");
+               return -EINVAL;
+       }
+
+       if (del_disktype(blkif)) {
+               close(blkif->fds[WRITE]);
+               close(blkif->fds[READ]);
+
+       }
+       return 0;
+}
+
+int open_ctrl_socket(char *devname)
+{
+       int ret;
+       int ipc_fd;
+       char *cmd;
+       fd_set socks;
+       struct timeval timeout;
+
+       ret = mkfifo(devname,S_IRWXU|S_IRWXG|S_IRWXO);
+       if ( (ret != 0) && (errno != EEXIST) ) {
+               DPRINTF("ERROR: pipe failed (%d)\n", errno);
+               exit(0);
+       }
+
+       ipc_fd = open(devname,O_RDWR|O_NONBLOCK);
+
+       if (ipc_fd < 0) {
+               DPRINTF("FD open failed\n");
+               return -1;
+       }
+
+       return ipc_fd;
+}
+
+static void print_drivers(void)
+{
+       int i, size;
+
+       size = sizeof(dtypes)/sizeof(disk_info_t *);
+       DPRINTF("blktapctrl: v1.0.0\n");
+       for (i = 0; i < size; i++)
+               DPRINTF("Found driver: [%s]\n",dtypes[i]->name);
+} 
+
+int main(int argc, char *argv[])
+{
+       char *devname;
+       tapdev_info_t *ctlinfo;
+       int tap_pfd, store_pfd, xs_fd, ret, timeout, pfd_count;
+       struct xs_handle *h;
+       struct pollfd  pfd[NUM_POLL_FDS];
+       pid_t process;
+
+       __init_blkif();
+       openlog("BLKTAPCTRL", LOG_CONS|LOG_ODELAY, LOG_DAEMON);
+
+       print_drivers();
+       init_driver_list();
+       init_rng();
+
+       register_new_blkif_hook(blktapctrl_new_blkif);
+       register_new_devmap_hook(map_new_blktapctrl);
+       register_new_unmap_hook(unmap_blktapctrl);
+
+       /*Attach to blktap0 */  
+       asprintf(&devname,"%s/%s0", BLKTAP_DEV_DIR, BLKTAP_DEV_NAME);
+       make_blktap_dev(devname,254,0);
+       ctlfd = open(devname, O_RDWR);
+       if (ctlfd == -1) {
+               DPRINTF("blktap0 open failed\n");
+               goto open_failed;
+       }
+
+       /* Set up store connection and watch. */
+       h = xs_daemon_open();
+       if (h == NULL) {
+               DPRINTF("xs_daemon_open failed -- "
+                       "is xenstore running?\n");
+               goto open_failed;
+       }
+       
+       ret = add_blockdevice_probe_watch(h, "Domain-0");
+       if (ret != 0) {
+               DPRINTF("adding device probewatch\n");
+               goto open_failed;
+       }
+
+       ioctl(ctlfd, BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_INTERPOSE );
+
+       process = getpid();
+       ret = ioctl(ctlfd, BLKTAP_IOCTL_SENDPID, process );
+
+       /*Static pollhooks*/
+       pfd_count = 0;
+       tap_pfd = pfd_count++;
+       pfd[tap_pfd].fd = ctlfd;
+       pfd[tap_pfd].events = POLLIN;
+       
+       store_pfd = pfd_count++;
+       pfd[store_pfd].fd = xs_fileno(h);
+       pfd[store_pfd].events = POLLIN;
+
+       while (run) {
+               timeout = 1000; /*Milliseconds*/
+                ret = poll(pfd, pfd_count, timeout);
+
+               if (ret > 0) {
+                       if (pfd[store_pfd].revents) {
+                               ret = xs_fire_next_watch(h);
+                       }
+               }
+       }
+
+       ioctl(ctlfd, BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_PASSTHROUGH );
+       close(ctlfd);
+       closelog();
+
+       return 0;
+       
+ open_failed:
+       DPRINTF("Unable to start blktapctrl\n");
+       closelog();
+       return -1;
+}
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/blktapctrl.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/blktapctrl.h Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,55 @@
+/* blktapctrl.h
+ *
+ * controller image utils.
+ * 
+ * (c) 2004-6 Andrew Warfield and Julian Chesterfield
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+static inline long int tapdisk_get_size(blkif_t *blkif)
+{
+       image_t *img = (image_t *)blkif->prv;
+       return img->size;
+}
+
+static inline long int tapdisk_get_secsize(blkif_t *blkif)
+{
+       image_t *img = (image_t *)blkif->prv;
+       return img->secsize;
+}
+
+static inline unsigned tapdisk_get_info(blkif_t *blkif)
+{
+       image_t *img = (image_t *)blkif->prv;
+       return img->info;
+}
+
+struct blkif_ops tapdisk_ops = {
+       .get_size = tapdisk_get_size,
+       .get_secsize = tapdisk_get_secsize,
+       .get_info = tapdisk_get_info,
+};
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/block-aio.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/block-aio.c  Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,327 @@
+/* block-aio.c
+ *
+ * libaio-based raw disk implementation.
+ *
+ * (c) 2006 Andrew Warfield and Julian Chesterfield
+ *
+ * NB: This code is not thread-safe.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+#include <errno.h>
+#include <libaio.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/statvfs.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include "tapdisk.h"
+
+
+/**
+ * We used a kernel patch to return an fd associated with the AIO context
+ * so that we can concurrently poll on synchronous and async descriptors.
+ * This is signalled by passing 1 as the io context to io_setup.
+ */
+#define REQUEST_ASYNC_FD 1
+
+#define MAX_AIO_REQS (MAX_REQUESTS * MAX_SEGMENTS_PER_REQ * 8)
+
+struct pending_aio {
+       td_callback_t cb;
+       int id;
+       void *private;
+};
+
+struct tdaio_state {
+       int fd;
+       
+       /* libaio state */
+       io_context_t       aio_ctx;
+       struct iocb        iocb_list  [MAX_AIO_REQS];
+       struct iocb       *iocb_free  [MAX_AIO_REQS];
+       struct pending_aio pending_aio[MAX_AIO_REQS];
+       int                iocb_free_count;
+       struct iocb       *iocb_queue[MAX_AIO_REQS];
+       int                iocb_queued;
+       int                poll_fd; /* NB: we require aio_poll support */
+       struct io_event    aio_events[MAX_AIO_REQS];
+};
+
+#define IOCB_IDX(_s, _io) ((_io) - (_s)->iocb_list)
+
+/*Get Image size, secsize*/
+static int get_image_info(struct td_state *s, int fd)
+{
+       int ret;
+       long size;
+       unsigned long total_size;
+       struct statvfs statBuf;
+       struct stat stat;
+
+       ret = fstat(fd, &stat);
+       if (ret != 0) {
+               DPRINTF("ERROR: fstat failed, Couldn't stat image");
+               return -EINVAL;
+       }
+
+       if (S_ISBLK(stat.st_mode)) {
+               /*Accessing block device directly*/
+               s->size = 0;
+               if (ioctl(fd,BLKGETSIZE,&s->size)!=0) {
+                       DPRINTF("ERR: BLKGETSIZE failed, couldn't stat image");
+                       return -EINVAL;
+               }
+
+               DPRINTF("Image size: \n\tpre sector_shift  [%llu]\n\tpost "
+                       "sector_shift [%llu]\n",
+                       (long long unsigned)(s->size << SECTOR_SHIFT),
+                       (long long unsigned)s->size);
+
+               /*Get the sector size*/
+#if defined(BLKSSZGET)
+               {
+                       int arg;
+                       s->sector_size = DEFAULT_SECTOR_SIZE;
+                       ioctl(fd, BLKSSZGET, &s->sector_size);
+                       
+                       if (s->sector_size != DEFAULT_SECTOR_SIZE)
+                               DPRINTF("Note: sector size is %ld (not %d)\n",
+                                       s->sector_size, DEFAULT_SECTOR_SIZE);
+               }
+#else
+               s->sector_size = DEFAULT_SECTOR_SIZE;
+#endif
+
+       } else {
+               /*Local file? try fstat instead*/
+               s->size = (stat.st_size >> SECTOR_SHIFT);
+               s->sector_size = DEFAULT_SECTOR_SIZE;
+               DPRINTF("Image size: \n\tpre sector_shift  [%llu]\n\tpost "
+                       "sector_shift [%llu]\n",
+                       (long long unsigned)(s->size << SECTOR_SHIFT),
+                       (long long unsigned)s->size);
+       }
+
+       if (s->size == 0) {             
+               s->size =((uint64_t) 16836057);
+               s->sector_size = DEFAULT_SECTOR_SIZE;
+       }
+       s->info = 0;
+
+       return 0;
+}
+
+/* Open the disk file and initialize aio state. */
+int tdaio_open (struct td_state *s, const char *name)
+{
+       int i, fd, ret = 0;
+       struct tdaio_state *prv = (struct tdaio_state *)s->private;
+       s->private = prv;
+
+       DPRINTF("XXX: block-aio open('%s')", name);
+       /* Initialize AIO */
+       prv->iocb_free_count = MAX_AIO_REQS;
+       prv->iocb_queued     = 0;
+       
+       prv->aio_ctx = (io_context_t) REQUEST_ASYNC_FD;
+       prv->poll_fd = io_setup(MAX_AIO_REQS, &prv->aio_ctx);
+
+       if (prv->poll_fd < 0) {
+               ret = prv->poll_fd;
+               DPRINTF("Couldn't get fd for AIO poll support.  This is "
+                       "probably because your kernel does not have the "
+                       "aio-poll patch applied.\n");
+               goto done;
+       }
+
+       for (i=0;i<MAX_AIO_REQS;i++)
+               prv->iocb_free[i] = &prv->iocb_list[i];
+
+       /* Open the file */
+        fd = open(name, O_RDWR | O_DIRECT | O_LARGEFILE);
+
+        if ( (fd == -1) && (errno == EINVAL) ) {
+
+                /* Maybe O_DIRECT isn't supported. */
+                fd = open(name, O_RDWR | O_LARGEFILE);
+                if (fd != -1) DPRINTF("WARNING: Accessing image without"
+                                     "O_DIRECT! (%s)\n", name);
+
+        } else if (fd != -1) DPRINTF("open(%s) with O_DIRECT\n", name);
+       
+        if (fd == -1) {
+               DPRINTF("Unable to open [%s] (%d)!\n", name, 0 - errno);
+               ret = 0 - errno;
+               goto done;
+        }
+
+        prv->fd = fd;
+
+       ret = get_image_info(s, fd);
+done:
+       return ret;     
+}
+
+int tdaio_queue_read(struct td_state *s, uint64_t sector,
+                              int nb_sectors, char *buf, td_callback_t cb,
+                              int id, void *private)
+{
+       struct   iocb *io;
+       struct   pending_aio *pio;
+       struct   tdaio_state *prv = (struct tdaio_state *)s->private;
+       int      size    = nb_sectors * s->sector_size;
+       uint64_t offset  = sector * (uint64_t)s->sector_size;
+       long     ioidx;
+       
+       if (prv->iocb_free_count == 0)
+               return -ENOMEM;
+       io = prv->iocb_free[--prv->iocb_free_count];
+       
+       ioidx = IOCB_IDX(prv, io);
+       pio = &prv->pending_aio[ioidx];
+       pio->cb = cb;
+       pio->id = id;
+       pio->private = private;
+       
+       io_prep_pread(io, prv->fd, buf, size, offset);
+       io->data = (void *)ioidx;
+       
+       prv->iocb_queue[prv->iocb_queued++] = io;
+       
+       return 0;
+}
+                       
+int tdaio_queue_write(struct td_state *s, uint64_t sector,
+                              int nb_sectors, char *buf, td_callback_t cb,
+                              int id, void *private)
+{
+       struct   iocb *io;
+       struct   pending_aio *pio;
+       struct   tdaio_state *prv = (struct tdaio_state *)s->private;
+       int      size    = nb_sectors * s->sector_size;
+       uint64_t offset  = sector * (uint64_t)s->sector_size;
+       long     ioidx;
+       
+       if (prv->iocb_free_count == 0)
+               return -ENOMEM;
+       io = prv->iocb_free[--prv->iocb_free_count];
+       
+       ioidx = IOCB_IDX(prv, io);
+       pio = &prv->pending_aio[ioidx];
+       pio->cb = cb;
+       pio->id = id;
+       pio->private = private;
+       
+       io_prep_pwrite(io, prv->fd, buf, size, offset);
+       io->data = (void *)ioidx;
+       
+       prv->iocb_queue[prv->iocb_queued++] = io;
+       
+       return 0;
+}
+                       
+int tdaio_submit(struct td_state *s)
+{
+       int ret;
+       struct   tdaio_state *prv = (struct tdaio_state *)s->private;
+
+       ret = io_submit(prv->aio_ctx, prv->iocb_queued, prv->iocb_queue);
+       
+       /* XXX: TODO: Handle error conditions here. */
+       
+       /* Success case: */
+       prv->iocb_queued = 0;
+       
+       return ret;
+}
+
+int *tdaio_get_fd(struct td_state *s)
+{
+       struct tdaio_state *prv = (struct tdaio_state *)s->private;
+       int *fds, i;
+
+       fds = malloc(sizeof(int) * MAX_IOFD);
+       /*initialise the FD array*/
+       for(i=0;i<MAX_IOFD;i++) fds[i] = 0;
+
+       fds[0] = prv->poll_fd;
+
+       return fds;     
+}
+
+int tdaio_close(struct td_state *s)
+{
+       struct tdaio_state *prv = (struct tdaio_state *)s->private;
+       
+       io_destroy(prv->aio_ctx);
+       close(prv->fd);
+       
+       return 0;
+}
+
+int tdaio_do_callbacks(struct td_state *s, int sid)
+{
+       int ret, i, rsp = 0;
+       struct io_event *ep;
+       struct tdaio_state *prv = (struct tdaio_state *)s->private;
+
+       /* Non-blocking test for completed io. */
+       ret = io_getevents(prv->aio_ctx, 0, MAX_AIO_REQS, prv->aio_events,
+                          NULL);
+                       
+       for (ep=prv->aio_events,i=ret; i-->0; ep++) {
+               struct iocb        *io  = ep->obj;
+               struct pending_aio *pio;
+               
+               pio = &prv->pending_aio[(long)io->data];
+               
+               if (ep->res != io->u.c.nbytes) {
+                       /* TODO: handle this case better. */
+                       DPRINTF("AIO did less than I asked it to. \n");
+               }
+               rsp += pio->cb(s, ep->res2, pio->id, pio->private);
+
+               prv->iocb_free[prv->iocb_free_count++] = io;
+       }
+       return rsp;
+}
+       
+struct tap_disk tapdisk_aio = {
+       "tapdisk_aio",
+       sizeof(struct tdaio_state),
+       tdaio_open,
+       tdaio_queue_read,
+       tdaio_queue_write,
+       tdaio_submit,
+       tdaio_get_fd,
+       tdaio_close,
+       tdaio_do_callbacks,
+};
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/block-qcow.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/block-qcow.c Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,1369 @@
+/* block-qcow.c
+ *
+ * Asynchronous Qemu copy-on-write disk implementation.
+ * Code based on the Qemu implementation
+ * (see copyright notice below)
+ *
+ * (c) 2006 Andrew Warfield and Julian Chesterfield
+ *
+ */
+
+/*
+ * Block driver for the QCOW format
+ * 
+ * Copyright (c) 2004 Fabrice Bellard
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files(the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/statvfs.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <string.h>
+#include <zlib.h>
+#include <inttypes.h>
+#include <libaio.h>
+#include <openssl/md5.h>
+#include "bswap.h"
+#include "aes.h"
+#include "tapdisk.h"
+
+#if 1
+#define ASSERT(_p) \
+    if ( !(_p) ) { DPRINTF("Assertion '%s' failed, line %d, file %s", #_p , \
+    __LINE__, __FILE__); *(int*)0=0; }
+#else
+#define ASSERT(_p) ((void)0)
+#endif
+
+
+/******AIO DEFINES******/
+#define REQUEST_ASYNC_FD 1
+#define MAX_QCOW_IDS  0xFFFF
+#define MAX_AIO_REQS (MAX_REQUESTS * MAX_SEGMENTS_PER_REQ * 8)
+
+struct pending_aio {
+        td_callback_t cb;
+        int id;
+        void *private;
+       int nb_sectors;
+       char *buf;
+       uint64_t sector;
+       int qcow_idx;
+};
+
+#define IOCB_IDX(_s, _io) ((_io) - (_s)->iocb_list)
+
+#define ZERO_TEST(_b) (_b | 0x00)
+
+/**************************************************************/
+/* QEMU COW block driver with compression and encryption support */
+
+#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
+#define XEN_MAGIC  (('X' << 24) | ('E' << 16) | ('N' << 8) | 0xfb)
+#define QCOW_VERSION 1
+
+#define QCOW_CRYPT_NONE 0
+#define QCOW_CRYPT_AES  1
+
+#define QCOW_OFLAG_COMPRESSED (1LL << 63)
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+typedef struct QCowHeader {
+       uint32_t magic;
+       uint32_t version;
+       uint64_t backing_file_offset;
+       uint32_t backing_file_size;
+       uint32_t mtime;
+       uint64_t size; /* in bytes */
+       uint8_t cluster_bits;
+       uint8_t l2_bits;
+       uint32_t crypt_method;
+       uint64_t l1_table_offset;
+} QCowHeader;
+
+/*Extended header for Xen enhancements*/
+typedef struct QCowHeader_ext {
+        uint32_t xmagic;
+        uint32_t cksum;
+        uint32_t min_cluster_alloc;
+} QCowHeader_ext;
+
+#define L2_CACHE_SIZE 16  /*Fixed allocation in Qemu*/
+
+struct tdqcow_state {
+        int fd;                        /*Main Qcow file descriptor */
+       uint64_t fd_end;               /*Store a local record of file length */
+       int bfd;                       /*Backing file descriptor*/
+       char *name;                    /*Record of the filename*/
+       int poll_pipe[2];              /*dummy fd for polling on */
+       int encrypted;                 /*File contents are encrypted or plain*/
+       int cluster_bits;              /*Determines length of cluster as 
+                                       *indicated by file hdr*/
+       int cluster_size;              /*Length of cluster*/
+       int cluster_sectors;           /*Number of sectors per cluster*/
+       int cluster_alloc;             /*Blktap fix for allocating full 
+                                       *extents*/
+       int min_cluster_alloc;         /*Blktap historical extent alloc*/
+       int l2_bits;                   /*Size of L2 table entry*/
+       int l2_size;                   /*Full table size*/
+       int l1_size;                   /*L1 table size*/
+       uint64_t cluster_offset_mask;    
+       uint64_t l1_table_offset;      /*L1 table offset from beginning of 
+                                       *file*/
+       uint64_t *l1_table;            /*L1 table entries*/
+       uint64_t *l2_cache;            /*We maintain a cache of size 
+                                       *L2_CACHE_SIZE of most read entries*/
+       uint64_t l2_cache_offsets[L2_CACHE_SIZE];     /*L2 cache entries*/
+       uint32_t l2_cache_counts[L2_CACHE_SIZE];      /*Cache access record*/
+       uint8_t *cluster_cache;          
+       uint8_t *cluster_data;
+       uint8_t *sector_lock;          /*Locking bitmap for AIO reads/writes*/
+       uint64_t cluster_cache_offset; /**/
+       uint32_t crypt_method;         /*current crypt method, 0 if no 
+                                       *key yet */
+       uint32_t crypt_method_header;  /**/
+       AES_KEY aes_encrypt_key;       /*AES key*/
+       AES_KEY aes_decrypt_key;       /*AES key*/
+        /* libaio state */
+        io_context_t       aio_ctx;
+       int                nr_reqs [MAX_QCOW_IDS];
+        struct iocb        iocb_list  [MAX_AIO_REQS];
+        struct iocb       *iocb_free  [MAX_AIO_REQS];
+        struct pending_aio pending_aio[MAX_AIO_REQS];
+        int                iocb_free_count;
+        struct iocb       *iocb_queue[MAX_AIO_REQS];
+        int                iocb_queued;
+        int                poll_fd;      /* NB: we require aio_poll support */
+        struct io_event    aio_events[MAX_AIO_REQS];
+};
+
+static int decompress_cluster(struct tdqcow_state *s, uint64_t cluster_offset);
+
+static int init_aio_state(struct td_state *bs)
+{
+        int i;
+       struct tdqcow_state *s = (struct tdqcow_state *)bs->private;
+        long     ioidx;
+
+        /*Initialize Locking bitmap*/
+       s->sector_lock = calloc(1, bs->size);
+       
+       if (!s->sector_lock) {
+               DPRINTF("Failed to allocate sector lock\n");
+               goto fail;
+       }
+
+        /* Initialize AIO */
+        s->iocb_free_count = MAX_AIO_REQS;
+        s->iocb_queued     = 0;
+
+        /*Signal kernel to create Poll FD for Asyc completion events*/
+        s->aio_ctx = (io_context_t) REQUEST_ASYNC_FD;   
+        s->poll_fd = io_setup(MAX_AIO_REQS, &s->aio_ctx);
+
+        if (s->poll_fd < 0) {
+                DPRINTF("Retrieving Async poll fd failed\n");
+               goto fail;
+        }
+
+        for (i=0;i<MAX_AIO_REQS;i++)
+                s->iocb_free[i] = &s->iocb_list[i];
+       for (i=0;i<MAX_QCOW_IDS;i++)
+               s->nr_reqs[i] = 0;
+        DPRINTF("AIO state initialised\n");
+
+        return 0;
+
+ fail:
+       return -1;
+}
+
+/*
+ *Test if block is zero. 
+ * Return: 
+ *       1 for TRUE
+ *       0 for FALSE
+ */
+static inline int IS_ZERO(char *buf, int len)
+{
+       int i;
+
+       for (i = 0; i < len; i++) {
+               /*if not zero, return false*/
+               if (ZERO_TEST(*(buf + i))) return 0; 
+       }
+       return 1;
+}
+
+static uint32_t gen_cksum(char *ptr, int len)
+{
+       unsigned char *md;
+       uint32_t ret;
+
+       md = malloc(MD5_DIGEST_LENGTH);
+
+       if(!md) return 0;
+
+       if (MD5((unsigned char *)ptr, len, md) != md) return 0;
+
+       memcpy(&ret, md, sizeof(uint32_t));
+       free(md);
+       return ret;
+}
+
+static int qcow_set_key(struct td_state *bs, const char *key)
+{
+       struct tdqcow_state *s = (struct tdqcow_state *)bs->private;
+       uint8_t keybuf[16];
+       int len, i;
+       
+       memset(keybuf, 0, 16);
+       len = strlen(key);
+       if (len > 16)
+               len = 16;
+       /* XXX: we could compress the chars to 7 bits to increase
+          entropy */
+       for (i = 0; i < len; i++) {
+               keybuf[i] = key[i];
+       }
+       s->crypt_method = s->crypt_method_header;
+       
+       if (AES_set_encrypt_key(keybuf, 128, &s->aes_encrypt_key) != 0)
+               return -1;
+       if (AES_set_decrypt_key(keybuf, 128, &s->aes_decrypt_key) != 0)
+               return -1;
+#if 0
+       /* test */
+       {
+               uint8_t in[16];
+               uint8_t out[16];
+               uint8_t tmp[16];
+               for (i=0; i<16; i++)
+                       in[i] = i;
+               AES_encrypt(in, tmp, &s->aes_encrypt_key);
+               AES_decrypt(tmp, out, &s->aes_decrypt_key);
+               for (i = 0; i < 16; i++)
+                       DPRINTF(" %02x", tmp[i]);
+               DPRINTF("\n");
+               for (i = 0; i < 16; i++)
+                       DPRINTF(" %02x", out[i]);
+               DPRINTF("\n");
+       }
+#endif
+       return 0;
+}
+
+static int async_read(struct tdqcow_state *s, int fd, int size, 
+                    uint64_t offset,
+                    char *buf, td_callback_t cb,
+                    int id, uint64_t sector, int qcow_idx, void *private)
+{
+        struct   iocb *io;
+        struct   pending_aio *pio;
+       long     ioidx;
+
+        io = s->iocb_free[--s->iocb_free_count];
+
+        ioidx = IOCB_IDX(s, io);
+        pio = &s->pending_aio[ioidx];
+        pio->cb = cb;
+        pio->id = id;
+        pio->private = private;
+       pio->nb_sectors = size/512;
+       pio->buf = buf;
+       pio->sector = sector;
+       pio->qcow_idx = qcow_idx;
+
+        io_prep_pread(io, fd, buf, size, offset);
+        io->data = (void *)ioidx;
+
+        s->iocb_queue[s->iocb_queued++] = io;
+
+        return 1;
+}
+
+static int async_write(struct tdqcow_state *s, int fd, int size, 
+                    uint64_t offset,
+                    char *buf, td_callback_t cb,
+                     int id, uint64_t sector, int qcow_idx, void *private)
+{
+        struct   iocb *io;
+        struct   pending_aio *pio;
+       long     ioidx;
+
+        io = s->iocb_free[--s->iocb_free_count];
+
+        ioidx = IOCB_IDX(s, io);
+        pio = &s->pending_aio[ioidx];
+        pio->cb = cb;
+        pio->id = id;
+        pio->private = private;
+       pio->nb_sectors = size/512;
+       pio->buf = buf;
+       pio->sector = sector;
+       pio->qcow_idx = qcow_idx;
+
+        io_prep_pwrite(io, fd, buf, size, offset);
+        io->data = (void *)ioidx;
+
+        s->iocb_queue[s->iocb_queued++] = io;
+
+        return 1;
+}
+
+/*TODO: Fix sector span!*/
+static int aio_can_lock(struct tdqcow_state *s, uint64_t sector)
+{
+       return (s->sector_lock[sector] ? 0 : 1);
+}
+
+static int aio_lock(struct tdqcow_state *s, uint64_t sector)
+{
+       return ++s->sector_lock[sector];
+}
+
+static void aio_unlock(struct tdqcow_state *s, uint64_t sector)
+{
+       if (!s->sector_lock[sector]) return;
+
+       --s->sector_lock[sector];
+       return;
+}
+
+/*TODO - Use a freelist*/
+static int get_free_idx(struct tdqcow_state *s)
+{
+       int i;
+       
+       for(i = 0; i < MAX_QCOW_IDS; i++) {
+               if(s->nr_reqs[i] == 0) return i;
+       }
+       return -1;
+}
+
+/* 
+ * The crypt function is compatible with the linux cryptoloop
+ * algorithm for < 4 GB images. NOTE: out_buf == in_buf is
+ * supported .
+ */
+static void encrypt_sectors(struct tdqcow_state *s, int64_t sector_num,
+                            uint8_t *out_buf, const uint8_t *in_buf,
+                            int nb_sectors, int enc,
+                            const AES_KEY *key)
+{
+       union {
+               uint64_t ll[2];
+               uint8_t b[16];
+       } ivec;
+       int i;
+       
+       for (i = 0; i < nb_sectors; i++) {
+               ivec.ll[0] = cpu_to_le64(sector_num);
+               ivec.ll[1] = 0;
+               AES_cbc_encrypt(in_buf, out_buf, 512, key, 
+                               ivec.b, enc);
+               sector_num++;
+               in_buf += 512;
+               out_buf += 512;
+       }
+}
+
+
+/* 'allocate' is:
+ *
+ * 0 to not allocate.
+ *
+ * 1 to allocate a normal cluster (for sector indexes 'n_start' to
+ * 'n_end')
+ *
+ * 2 to allocate a compressed cluster of size
+ * 'compressed_size'. 'compressed_size' must be > 0 and <
+ * cluster_size 
+ *
+ * return 0 if not allocated.
+ */
+static uint64_t get_cluster_offset(struct td_state *bs,
+                                   uint64_t offset, int allocate,
+                                   int compressed_size,
+                                   int n_start, int n_end)
+{
+       struct tdqcow_state *s = (struct tdqcow_state *)bs->private;
+       int min_index, i, j, l1_index, l2_index, l2_sector, l1_sector;
+       char *tmp_ptr, *tmp_ptr2, *l2_ptr, *l1_ptr;
+       uint64_t l2_offset, *l2_table, cluster_offset, tmp;
+       uint32_t min_count;
+       int new_l2_table;
+
+       /*Check L1 table for the extent offset*/
+       l1_index = offset >> (s->l2_bits + s->cluster_bits);
+       l2_offset = s->l1_table[l1_index];
+       new_l2_table = 0;
+       if (!l2_offset) {
+               if (!allocate)
+                       return 0;
+               /* 
+                * allocating a new l2 entry + extent 
+                * at the end of the file, we must also
+                * update the L1 entry safely.
+                */
+               l2_offset = s->fd_end;
+
+               /* round to cluster size */
+               l2_offset = (l2_offset + s->cluster_size - 1) 
+                       & ~(s->cluster_size - 1);
+
+               /* update the L1 entry */
+               s->l1_table[l1_index] = l2_offset;
+               tmp = cpu_to_be64(l2_offset);
+               
+               /*Truncate file for L2 table 
+                *(initialised to zero in case we crash)*/
+               ftruncate(s->fd, l2_offset + (s->l2_size * sizeof(uint64_t)));
+               s->fd_end += (s->l2_size * sizeof(uint64_t));
+
+               /*Update the L1 table entry on disk
+                 * (for O_DIRECT we write 4KByte blocks)*/
+               l1_sector = (l1_index * sizeof(uint64_t)) >> 12;
+               l1_ptr = (char *)s->l1_table + (l1_sector << 12);
+
+               if (posix_memalign((void **)&tmp_ptr, 4096, 4096) != 0) {
+                       DPRINTF("ERROR allocating memory for L1 table\n");
+               }
+               memcpy(tmp_ptr, l1_ptr, 4096);
+
+               /*
+                * Issue non-asynchronous L1 write.
+                * For safety, we must ensure that
+                * entry is written before blocks.
+                */
+               lseek(s->fd, s->l1_table_offset + (l1_sector << 12), SEEK_SET);
+               if (write(s->fd, tmp_ptr, 4096) != 4096)
+                       return 0;
+               free(tmp_ptr);
+
+               new_l2_table = 1;
+               goto cache_miss;
+       } else if (s->min_cluster_alloc == s->l2_size) {
+               /*Fast-track the request*/
+               cluster_offset = l2_offset + (s->l2_size * sizeof(uint64_t));
+               l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
+               return cluster_offset + (l2_index * s->cluster_size);
+       }
+
+       /*Check to see if L2 entry is already cached*/
+       for (i = 0; i < L2_CACHE_SIZE; i++) {
+               if (l2_offset == s->l2_cache_offsets[i]) {
+                       /* increment the hit count */
+                       if (++s->l2_cache_counts[i] == 0xffffffff) {
+                               for (j = 0; j < L2_CACHE_SIZE; j++) {
+                                       s->l2_cache_counts[j] >>= 1;
+                               }
+                       }
+                       l2_table = s->l2_cache + (i << s->l2_bits);
+                       goto found;
+               }
+       }
+
+cache_miss:
+       /* not found: load a new entry in the least used one */
+       min_index = 0;
+       min_count = 0xffffffff;
+       for (i = 0; i < L2_CACHE_SIZE; i++) {
+               if (s->l2_cache_counts[i] < min_count) {
+                       min_count = s->l2_cache_counts[i];
+                       min_index = i;
+               }
+       }
+       l2_table = s->l2_cache + (min_index << s->l2_bits);
+
+       /*If extent pre-allocated, read table from disk, 
+        *otherwise write new table to disk*/
+       if (new_l2_table) {
+               /*Should we allocate the whole extent? Adjustable parameter.*/
+               if (s->cluster_alloc == s->l2_size) {
+                       cluster_offset = l2_offset + 
+                               (s->l2_size * sizeof(uint64_t));
+                       cluster_offset = (cluster_offset + s->cluster_size - 1)
+                               & ~(s->cluster_size - 1);
+                       ftruncate(s->fd, cluster_offset + 
+                                 (s->cluster_size * s->l2_size));
+                       s->fd_end = cluster_offset + 
+                               (s->cluster_size * s->l2_size);
+                       for (i = 0; i < s->l2_size; i++) {
+                               l2_table[i] = cpu_to_be64(cluster_offset + 
+                                                         (i*s->cluster_size));
+                       }  
+               } else memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
+
+               lseek(s->fd, l2_offset, SEEK_SET);
+               if (write(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) !=
+                   s->l2_size * sizeof(uint64_t))
+                       return 0;
+       } else {
+               lseek(s->fd, l2_offset, SEEK_SET);
+               if (read(s->fd, l2_table, s->l2_size * sizeof(uint64_t)) != 
+                   s->l2_size * sizeof(uint64_t))
+                       return 0;
+       }
+       
+       /*Update the cache entries*/ 
+       s->l2_cache_offsets[min_index] = l2_offset;
+       s->l2_cache_counts[min_index] = 1;
+
+found:
+       /*The extent is split into 's->l2_size' blocks of 
+        *size 's->cluster_size'*/
+       l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
+       cluster_offset = be64_to_cpu(l2_table[l2_index]);
+
+       if (!cluster_offset || 
+           ((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1) ) {
+               if (!allocate)
+                       return 0;
+               
+               if ((cluster_offset & QCOW_OFLAG_COMPRESSED) &&
+                   (n_end - n_start) < s->cluster_sectors) {
+                       /* cluster is already allocated but compressed, we must
+                          decompress it in the case it is not completely
+                          overwritten */
+                       if (decompress_cluster(s, cluster_offset) < 0)
+                               return 0;
+                       cluster_offset = lseek(s->fd, 0, SEEK_END);
+                       cluster_offset = (cluster_offset + s->cluster_size - 1)
+                               & ~(s->cluster_size - 1);
+                       /* write the cluster content - not asynchronous */
+                       lseek(s->fd, cluster_offset, SEEK_SET);
+                       if (write(s->fd, s->cluster_cache, s->cluster_size) != 
+                           s->cluster_size)
+                           return -1;
+               } else {
+                       /* allocate a new cluster */
+                       cluster_offset = lseek(s->fd, 0, SEEK_END);
+                       if (allocate == 1) {
+                               /* round to cluster size */
+                               cluster_offset = 
+                                       (cluster_offset + s->cluster_size - 1) 
+                                       & ~(s->cluster_size - 1);
+                               ftruncate(s->fd, cluster_offset + 
+                                         s->cluster_size);
+                               /* if encrypted, we must initialize the cluster
+                                  content which won't be written */
+                               if (s->crypt_method && 
+                                   (n_end - n_start) < s->cluster_sectors) {
+                                       uint64_t start_sect;
+                                       start_sect = (offset & 
+                                                     ~(s->cluster_size - 1)) 
+                                                             >> 9;
+                                       memset(s->cluster_data + 512, 
+                                              0xaa, 512);
+                                       for (i = 0; i < s->cluster_sectors;i++)
+                                       {
+                                               if (i < n_start || i >= n_end) 
+                                               {
+                                                       encrypt_sectors(s, 
start_sect + i, 
+                                                                       
s->cluster_data, 
+                                                                       
s->cluster_data + 512, 1, 1,
+                                                                       
&s->aes_encrypt_key);
+                                                       lseek(s->fd, 
cluster_offset + i * 512, SEEK_SET);
+                                                       if (write(s->fd, 
s->cluster_data, 512) != 512)
+                                                               return -1;
+                                               }
+                                       }
+                               }
+                       } else {
+                               cluster_offset |= QCOW_OFLAG_COMPRESSED | 
+                                       (uint64_t)compressed_size 
+                                               << (63 - s->cluster_bits);
+                       }
+               }
+               /* update L2 table */
+               tmp = cpu_to_be64(cluster_offset);
+               l2_table[l2_index] = tmp;
+
+               /*For IO_DIRECT we write 4KByte blocks*/
+               l2_sector = (l2_index * sizeof(uint64_t)) >> 12;
+               l2_ptr = (char *)l2_table + (l2_sector << 12);
+               
+               if (posix_memalign((void **)&tmp_ptr2, 4096, 4096) != 0) {
+                       DPRINTF("ERROR allocating memory for L1 table\n");
+               }
+               memcpy(tmp_ptr2, l2_ptr, 4096);
+               aio_lock(s, offset >> 9);
+               async_write(s, s->fd, 4096, l2_offset + (l2_sector << 12), 
+                           tmp_ptr2, 0, -2, offset >> 9, 0, NULL);
+       }
+       return cluster_offset;
+}
+
+static void init_cluster_cache(struct td_state *bs)
+{
+       struct tdqcow_state *s = (struct tdqcow_state *)bs->private;
+       uint32_t count = 0;
+       int i, cluster_entries;
+
+       cluster_entries = s->cluster_size / 512;
+       DPRINTF("Initialising Cluster cache, %d sectors per cluster (%d cluster 
size)\n",
+               cluster_entries, s->cluster_size);
+
+       for (i = 0; i < bs->size; i += cluster_entries) {
+               if (get_cluster_offset(bs, i << 9, 0, 0, 0, 1)) count++;
+               if (count >= L2_CACHE_SIZE) return;
+       }
+       DPRINTF("Finished cluster initialisation, added %d entries\n", count);
+       return;
+}
+
+static int qcow_is_allocated(struct td_state *bs, int64_t sector_num, 
+                             int nb_sectors, int *pnum)
+{
+       struct tdqcow_state *s = (struct tdqcow_state *)bs->private;
+
+       int index_in_cluster, n;
+       uint64_t cluster_offset;
+
+       cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
+       index_in_cluster = sector_num & (s->cluster_sectors - 1);
+       n = s->cluster_sectors - index_in_cluster;
+       if (n > nb_sectors)
+               n = nb_sectors;
+       *pnum = n;
+       return (cluster_offset != 0);
+}
+
+static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
+                             const uint8_t *buf, int buf_size)
+{
+       z_stream strm1, *strm = &strm1;
+       int ret, out_len;
+       
+       memset(strm, 0, sizeof(*strm));
+       
+       strm->next_in = (uint8_t *)buf;
+       strm->avail_in = buf_size;
+       strm->next_out = out_buf;
+       strm->avail_out = out_buf_size;
+       
+       ret = inflateInit2(strm, -12);
+       if (ret != Z_OK)
+               return -1;
+       ret = inflate(strm, Z_FINISH);
+       out_len = strm->next_out - out_buf;
+       if ( (ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
+           (out_len != out_buf_size) ) {
+               inflateEnd(strm);
+               return -1;
+       }
+       inflateEnd(strm);
+       return 0;
+}
+                              
+static int decompress_cluster(struct tdqcow_state *s, uint64_t cluster_offset)
+{
+       int ret, csize;
+       uint64_t coffset;
+
+       coffset = cluster_offset & s->cluster_offset_mask;
+       if (s->cluster_cache_offset != coffset) {
+               csize = cluster_offset >> (63 - s->cluster_bits);
+               csize &= (s->cluster_size - 1);
+               lseek(s->fd, coffset, SEEK_SET);
+               ret = read(s->fd, s->cluster_data, csize);
+               if (ret != csize) 
+                       return -1;
+               if (decompress_buffer(s->cluster_cache, s->cluster_size,
+                                     s->cluster_data, csize) < 0) {
+                       return -1;
+               }
+               s->cluster_cache_offset = coffset;
+       }
+       return 0;
+}
+
+/* Open the disk file and initialize qcow state. */
+int tdqcow_open (struct td_state *bs, const char *name)
+{
+       int fd, len, i, shift, ret, size, l1_table_size;
+       struct tdqcow_state *s = (struct tdqcow_state *)bs->private;
+       char *buf;
+       QCowHeader *header;
+       QCowHeader_ext *exthdr;
+       uint32_t cksum;
+
+       DPRINTF("QCOW: Opening %s\n",name);
+       /* set up a pipe so that we can hand back a poll fd that won't fire.*/
+       ret = pipe(s->poll_pipe);
+       if (ret != 0)
+               return (0 - errno);
+
+       fd = open(name, O_RDWR | O_DIRECT | O_LARGEFILE);
+       if (fd < 0) {
+               DPRINTF("Unable to open %s (%d)\n",name,0 - errno);
+               return -1;
+       }
+
+       s->fd = fd;
+       asprintf(&s->name,"%s", name);
+
+       ASSERT(sizeof(header) < 512);
+
+       ret = posix_memalign((void **)&buf, 512, 512);
+       if (ret != 0) goto fail;
+
+       if (read(fd, buf, 512) != 512)
+               goto fail;
+
+       header = (QCowHeader *)buf;
+       be32_to_cpus(&header->magic);
+       be32_to_cpus(&header->version);
+       be64_to_cpus(&header->backing_file_offset);
+       be32_to_cpus(&header->backing_file_size);
+       be32_to_cpus(&header->mtime);
+       be64_to_cpus(&header->size);
+       be32_to_cpus(&header->crypt_method);
+       be64_to_cpus(&header->l1_table_offset);
+   
+       if (header->magic != QCOW_MAGIC || header->version > QCOW_VERSION)
+               goto fail;
+       if (header->size <= 1 || header->cluster_bits < 9)
+               goto fail;
+       if (header->crypt_method > QCOW_CRYPT_AES)
+               goto fail;
+       s->crypt_method_header = header->crypt_method;
+       if (s->crypt_method_header)
+               s->encrypted = 1;
+       s->cluster_bits = header->cluster_bits;
+       s->cluster_size = 1 << s->cluster_bits;
+       s->cluster_sectors = 1 << (s->cluster_bits - 9);
+       s->l2_bits = header->l2_bits;
+       s->l2_size = 1 << s->l2_bits;
+       s->cluster_alloc = s->l2_size;
+       bs->size = header->size / 512;
+       s->cluster_offset_mask = (1LL << (63 - s->cluster_bits)) - 1;
+       
+       /* read the level 1 table */
+       shift = s->cluster_bits + s->l2_bits;
+       s->l1_size = (header->size + (1LL << shift) - 1) >> shift;
+       
+       s->l1_table_offset = header->l1_table_offset;
+
+       /*allocate a 4Kbyte multiple of memory*/
+       l1_table_size = s->l1_size * sizeof(uint64_t);
+       if (l1_table_size % 4096 > 0) {
+               l1_table_size = ((l1_table_size >> 12) + 1) << 12;
+       }
+       ret = posix_memalign((void **)&s->l1_table, 4096, l1_table_size);
+       if (ret != 0) goto fail;
+       memset(s->l1_table, 0x00, l1_table_size);
+
+       DPRINTF("L1 Table offset detected: %llu, size %d (%d)\n",
+               (long long)s->l1_table_offset,
+               (int) (s->l1_size * sizeof(uint64_t)), 
+               l1_table_size);
+
+       lseek(fd, s->l1_table_offset, SEEK_SET);
+       if (read(fd, s->l1_table, l1_table_size) != l1_table_size)
+               goto fail;
+/*     for(i = 0;i < s->l1_size; i++) {
+               //be64_to_cpus(&s->l1_table[i]);
+               DPRINTF("L1[%d] => %llu\n", i, s->l1_table[i]);
+               }*/
+
+       /* alloc L2 cache */
+       size = s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t);
+       ret = posix_memalign((void **)&s->l2_cache, 4096, size);
+       if(ret != 0) goto fail;
+
+       size = s->cluster_size;
+       ret = posix_memalign((void **)&s->cluster_cache, 4096, size);
+       if(ret != 0) goto fail;
+
+       ret = posix_memalign((void **)&s->cluster_data, 4096, size);
+       if(ret != 0) goto fail;
+       s->cluster_cache_offset = -1;
+
+       /* read the backing file name */
+       s->bfd = -1;
+       if (header->backing_file_offset != 0) {
+               DPRINTF("Reading backing file data\n");
+               len = header->backing_file_size;
+               if (len > 1023)
+                       len = 1023;
+
+                /*TODO - Fix read size for O_DIRECT and use original fd!*/
+               fd = open(name, O_RDONLY | O_LARGEFILE);
+
+               lseek(fd, header->backing_file_offset, SEEK_SET);
+               if (read(fd, bs->backing_file, len) != len)
+                       goto fail;
+               bs->backing_file[len] = '\0';
+               close(fd);
+               /***********************************/
+
+               /*Open backing file*/
+               fd = open(bs->backing_file, O_RDONLY | O_DIRECT | O_LARGEFILE);
+               if (fd < 0) {
+                       DPRINTF("Unable to open backing file: %s\n",
+                               bs->backing_file);
+                       goto fail;
+               }
+               s->bfd = fd;
+               s->cluster_alloc = 1; /*Cannot use pre-alloc*/
+       }
+
+        bs->sector_size = 512;
+        bs->info = 0;
+       
+       /*Detect min_cluster_alloc*/
+       s->min_cluster_alloc = 1; /*Default*/
+       if (s->bfd == -1 && (s->l1_table_offset % 4096 == 0) ) {
+               /*We test to see if the xen magic # exists*/
+               exthdr = (QCowHeader_ext *)(buf + sizeof(QCowHeader));
+               be32_to_cpus(&exthdr->xmagic);
+               if(exthdr->xmagic != XEN_MAGIC) 
+                       goto end_xenhdr;
+
+               /*Finally check the L1 table cksum*/
+               be32_to_cpus(&exthdr->cksum);
+               cksum = gen_cksum((char *)s->l1_table, s->l1_size * 
sizeof(uint64_t));
+               if(exthdr->cksum != cksum)
+                       goto end_xenhdr;
+                       
+               be32_to_cpus(&exthdr->min_cluster_alloc);
+               s->min_cluster_alloc = exthdr->min_cluster_alloc; 
+       }
+
+ end_xenhdr:
+       if (init_aio_state(bs)!=0) {
+               DPRINTF("Unable to initialise AIO state\n");
+               goto fail;
+       }
+       s->fd_end = lseek(s->fd, 0, SEEK_END);
+
+       return 0;
+       
+fail:
+       DPRINTF("QCOW Open failed\n");
+       free(s->l1_table);
+       free(s->l2_cache);
+       free(s->cluster_cache);
+       free(s->cluster_data);
+       close(fd);
+       return -1;
+}
+
+ int tdqcow_queue_read(struct td_state *bs, uint64_t sector,
+                              int nb_sectors, char *buf, td_callback_t cb,
+                              int id, void *private)
+{
+       struct tdqcow_state *s = (struct tdqcow_state *)bs->private;
+       int ret = 0, index_in_cluster, n, i, qcow_idx, asubmit = 0;
+       uint64_t cluster_offset;
+
+       /*Check we can get a lock*/
+       for (i = 0; i < nb_sectors; i++)
+               if (!aio_can_lock(s, sector + i)) {
+                       DPRINTF("AIO_CAN_LOCK failed [%llu]\n", 
+                               (long long) sector + i);
+                       return -EBUSY;
+               }
+       
+       /*We store a local record of the request*/
+       qcow_idx = get_free_idx(s);
+       while (nb_sectors > 0) {
+               cluster_offset = 
+                       get_cluster_offset(bs, sector << 9, 0, 0, 0, 0);
+               index_in_cluster = sector & (s->cluster_sectors - 1);
+               n = s->cluster_sectors - index_in_cluster;
+               if (n > nb_sectors)
+                       n = nb_sectors;
+
+               if (s->iocb_free_count == 0 || !aio_lock(s, sector)) {
+                       DPRINTF("AIO_LOCK or iocb_free_count (%d) failed" 
+                               "[%llu]\n", s->iocb_free_count, 
+                               (long long) sector);
+                       return -ENOMEM;
+               }
+               
+               if (!cluster_offset && (s->bfd > 0)) {
+                       s->nr_reqs[qcow_idx]++;
+                       asubmit += async_read(s, s->bfd, n * 512, sector << 9, 
+                                             buf, cb, id, sector, 
+                                             qcow_idx, private);
+               } else if(!cluster_offset) {
+                       memset(buf, 0, 512 * n);
+                       aio_unlock(s, sector);
+               } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
+                       if (decompress_cluster(s, cluster_offset) < 0) {
+                               ret = -1;
+                               goto done;
+                       }
+                       memcpy(buf, s->cluster_cache + index_in_cluster * 512, 
+                              512 * n);
+               } else {                        
+                       s->nr_reqs[qcow_idx]++;
+                       asubmit += async_read(s, s->fd, n * 512, 
+                                             (cluster_offset + 
+                                              index_in_cluster * 512), 
+                                             buf, cb, id, sector, 
+                                             qcow_idx, private);
+               }
+               nb_sectors -= n;
+               sector += n;
+               buf += n * 512;
+       }
+done:
+        /*Callback if no async requests outstanding*/
+        if (!asubmit) return cb(bs, ret == -1 ? -1 : 0, id, private);
+
+       return 0;
+}
+
+ int tdqcow_queue_write(struct td_state *bs, uint64_t sector,
+                              int nb_sectors, char *buf, td_callback_t cb,
+                              int id, void *private)
+{
+       struct tdqcow_state *s = (struct tdqcow_state *)bs->private;
+       int ret = 0, index_in_cluster, n, i, qcow_idx, asubmit = 0;
+       uint64_t cluster_offset;
+
+       /*Check we can get a lock*/
+       for (i = 0; i < nb_sectors; i++)
+               if (!aio_can_lock(s, sector + i))  {
+                       DPRINTF("AIO_CAN_LOCK failed [%llu]\n", 
+                               (long long) (sector + i));
+                       return -EBUSY;
+               }
+                  
+       /*We store a local record of the request*/
+       qcow_idx = get_free_idx(s);     
+       while (nb_sectors > 0) {
+               index_in_cluster = sector & (s->cluster_sectors - 1);
+               n = s->cluster_sectors - index_in_cluster;
+               if (n > nb_sectors)
+                       n = nb_sectors;
+
+               if (s->iocb_free_count == 0 || !aio_lock(s, sector)){
+                       DPRINTF("AIO_LOCK or iocb_free_count (%d) failed" 
+                               "[%llu]\n", s->iocb_free_count, 
+                               (long long) sector);
+                       return -ENOMEM;
+               }
+
+               if (!IS_ZERO(buf,n * 512)) {
+
+                       cluster_offset = get_cluster_offset(bs, sector << 9, 
+                                                           1, 0, 
+                                                           index_in_cluster, 
+                                                           index_in_cluster+n
+                               );
+                       if (!cluster_offset) {
+                               DPRINTF("Ooops, no write cluster offset!\n");
+                               ret = -1;
+                               goto done;
+                       }
+
+                       if (s->crypt_method) {
+                               encrypt_sectors(s, sector, s->cluster_data, 
+                                               (unsigned char *)buf, n, 1,
+                                               &s->aes_encrypt_key);
+                               s->nr_reqs[qcow_idx]++;
+                               asubmit += async_write(s, s->fd, n * 512, 
+                                                      (cluster_offset + 
+                                                       index_in_cluster*512), 
+                                                      (char *)s->cluster_data,
+                                                      cb, id, sector, 
+                                                      qcow_idx, private);
+                       } else {
+                               s->nr_reqs[qcow_idx]++;
+                               asubmit += async_write(s, s->fd, n * 512, 
+                                                      (cluster_offset + 
+                                                       index_in_cluster*512),
+                                                      buf, cb, id, sector, 
+                                                      qcow_idx, private);
+                       }
+               } else {
+                       /*Write data contains zeros, but we must check to see 
+                         if cluster already allocated*/
+                       cluster_offset = get_cluster_offset(bs, sector << 9, 
+                                                           0, 0, 
+                                                           index_in_cluster, 
+                                                           index_in_cluster+n
+                               );      
+                       if(cluster_offset) {
+                               if (s->crypt_method) {
+                                       encrypt_sectors(s, sector, 
+                                                       s->cluster_data, 
+                                                       (unsigned char *)buf, 
+                                                       n, 1,
+                                                       &s->aes_encrypt_key);
+                                       s->nr_reqs[qcow_idx]++;
+                                       asubmit += async_write(s, s->fd, 
+                                                              n * 512, 
+                                                              (cluster_offset+
+                                                               
index_in_cluster * 512), 
+                                                              (char 
*)s->cluster_data, cb, id, sector, 
+                                                              qcow_idx, 
private);
+                               } else {
+                                       s->nr_reqs[qcow_idx]++;
+                                       asubmit += async_write(s, s->fd, n*512,
+                                                              cluster_offset + 
index_in_cluster * 512, 
+                                                              buf, cb, id, 
sector, 
+                                                              qcow_idx, 
private);
+                               }
+                       }
+                       else aio_unlock(s, sector);
+               }
+               nb_sectors -= n;
+               sector += n;
+               buf += n * 512;
+       }
+       s->cluster_cache_offset = -1; /* disable compressed cache */
+
+done:
+       /*Callback if no async requests outstanding*/
+        if (!asubmit) return cb(bs, ret == -1 ? -1 : 0, id, private);
+
+       return 0;
+}
+               
+int tdqcow_submit(struct td_state *bs)
+{
+        int ret;
+        struct   tdqcow_state *prv = (struct tdqcow_state *)bs->private;
+
+        ret = io_submit(prv->aio_ctx, prv->iocb_queued, prv->iocb_queue);
+
+        /* XXX: TODO: Handle error conditions here. */
+
+        /* Success case: */
+        prv->iocb_queued = 0;
+
+        return ret;
+}
+
+
+int *tdqcow_get_fd(struct td_state *bs)
+{
+       struct tdqcow_state *s = (struct tdqcow_state *)bs->private;
+       int *fds, i;
+
+       fds = malloc(sizeof(int) * MAX_IOFD);
+       /*initialise the FD array*/
+       for(i=0;i<MAX_IOFD;i++) fds[i] = 0;
+
+       fds[0] = s->poll_fd;
+       return fds;
+}
+
+int tdqcow_close(struct td_state *bs)
+{
+       struct tdqcow_state *s = (struct tdqcow_state *)bs->private;
+       uint32_t cksum, out;
+       int fd, offset;
+
+       /*Update the hdr cksum*/
+       if(s->min_cluster_alloc == s->l2_size) {
+               cksum = gen_cksum((char *)s->l1_table, s->l1_size * 
sizeof(uint64_t));
+               printf("Writing cksum: %d",cksum);
+               fd = open(s->name, O_WRONLY | O_LARGEFILE); /*Open without 
O_DIRECT*/
+               offset = sizeof(QCowHeader) + sizeof(uint32_t);
+               lseek(fd, offset, SEEK_SET);
+               out = cpu_to_be32(cksum);
+               write(fd, &out, sizeof(uint32_t));
+               close(fd);
+       }
+
+       free(s->name);
+       free(s->l1_table);
+       free(s->l2_cache);
+       free(s->cluster_cache);
+       free(s->cluster_data);
+       close(s->fd);   
+       return 0;
+}
+
+int tdqcow_do_callbacks(struct td_state *s, int sid)
+{
+        int ret, i, rsp = 0,*ptr;
+        struct io_event *ep;
+        struct tdqcow_state *prv = (struct tdqcow_state *)s->private;
+
+        if (sid > MAX_IOFD) return 1;
+       
+       /* Non-blocking test for completed io. */
+        ret = io_getevents(prv->aio_ctx, 0, MAX_AIO_REQS, prv->aio_events,
+                           NULL);
+
+        for (ep=prv->aio_events, i = ret; i-->0; ep++) {
+                struct iocb        *io  = ep->obj;
+                struct pending_aio *pio;
+
+                pio = &prv->pending_aio[(long)io->data];
+
+                if (ep->res != io->u.c.nbytes) {
+                        /* TODO: handle this case better. */
+                       ptr = (int *)&ep->res;
+                        DPRINTF("AIO did less than I asked it to "
+                               "[%lu,%lu,%d]\n", 
+                               ep->res, io->u.c.nbytes, *ptr);
+                }
+               aio_unlock(prv, pio->sector);
+               if (pio->id >= 0) {
+                       if (prv->crypt_method)
+                               encrypt_sectors(prv, pio->sector, 
+                                               (unsigned char *)pio->buf, 
+                                               (unsigned char *)pio->buf, 
+                                               pio->nb_sectors, 0, 
+                                               &prv->aes_decrypt_key);
+                       prv->nr_reqs[pio->qcow_idx]--;
+                       if (prv->nr_reqs[pio->qcow_idx] == 0) 
+                               rsp += pio->cb(s, ep->res2, pio->id, 
+                                              pio->private);
+               } else if (pio->id == -2) free(pio->buf);
+
+                prv->iocb_free[prv->iocb_free_count++] = io;
+        }
+        return rsp;
+}
+
+int qcow_create(const char *filename, uint64_t total_size,
+                      const char *backing_file, int flags)
+{
+       int fd, header_size, backing_filename_len, l1_size, i;
+       int shift, length, adjust, ret = 0;
+       QCowHeader header;
+       QCowHeader_ext exthdr;
+       char backing_filename[1024], *ptr;
+       uint64_t tmp, size;
+       struct stat st;
+
+       DPRINTF("Qcow_create: size %llu\n",(long long unsigned)total_size);
+
+       fd = open(filename, 
+                 O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 
+                 0644);
+       if (fd < 0)
+               return -1;
+
+       memset(&header, 0, sizeof(header));
+       header.magic = cpu_to_be32(QCOW_MAGIC);
+       header.version = cpu_to_be32(QCOW_VERSION);
+
+       /*Create extended header fields*/
+       exthdr.xmagic = cpu_to_be32(XEN_MAGIC);
+
+       header_size = sizeof(header) + sizeof(QCowHeader_ext);
+       backing_filename_len = 0;
+       size = (total_size >> SECTOR_SHIFT);
+       if (backing_file) {
+               if (strcmp(backing_file, "fat:")) {
+                       const char *p;
+                       /* XXX: this is a hack: we do not attempt to 
+                        *check for URL like syntax */
+                       p = strchr(backing_file, ':');
+                       if (p && (p - backing_file) >= 2) {
+                               /* URL like but exclude "c:" like filenames */
+                               strncpy(backing_filename, backing_file,
+                                       sizeof(backing_filename));
+                       } else {
+                               realpath(backing_file, backing_filename);
+                               if (stat(backing_filename, &st) != 0) {
+                                       return -1;
+                               }
+                       }
+                       header.backing_file_offset = cpu_to_be64(header_size);
+                       backing_filename_len = strlen(backing_filename);
+                       header.backing_file_size = cpu_to_be32(
+                               backing_filename_len);
+                       header_size += backing_filename_len;
+                       
+                       /*Set to the backing file size*/
+                       size = (st.st_size >> SECTOR_SHIFT);
+                       DPRINTF("Backing file size detected: %lld sectors" 
+                               "(total %lld [%lld MB])\n", 
+                               (long long)total_size, 
+                               (long long)(total_size << SECTOR_SHIFT), 
+                               (long long)(total_size >> 11));
+               } else {
+                       backing_file = NULL;
+                       DPRINTF("Setting file size: %lld (total %lld)\n", 
+                               (long long) total_size, 
+                               (long long) (total_size << SECTOR_SHIFT));
+               }
+               header.mtime = cpu_to_be32(st.st_mtime);
+               header.cluster_bits = 9; /* 512 byte cluster to avoid copying
+                                           unmodifyed sectors */
+               header.l2_bits = 12; /* 32 KB L2 tables */
+               exthdr.min_cluster_alloc = cpu_to_be32(1);
+       } else {
+               DPRINTF("Setting file size: %lld sectors" 
+                       "(total %lld [%lld MB])\n", 
+                       (long long) size, 
+                       (long long) (size << SECTOR_SHIFT), 
+                       (long long) (size >> 11));
+               header.cluster_bits = 12; /* 4 KB clusters */
+               header.l2_bits = 9; /* 4 KB L2 tables */
+               exthdr.min_cluster_alloc = cpu_to_be32(1 << 9);
+       }
+       /*Set the header size value*/
+       header.size = cpu_to_be64(size * 512);
+       
+       header_size = (header_size + 7) & ~7;
+       if (header_size % 4096 > 0) {
+               header_size = ((header_size >> 12) + 1) << 12;
+       }
+
+       shift = header.cluster_bits + header.l2_bits;
+       l1_size = ((size * 512) + (1LL << shift) - 1) >> shift;
+
+       header.l1_table_offset = cpu_to_be64(header_size);
+       DPRINTF("L1 Table offset: %d, size %d\n",
+               header_size,
+               (int)(l1_size * sizeof(uint64_t)));
+       if (flags) {
+               header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
+       } else {
+               header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
+       }
+
+       ptr = calloc(1, l1_size * sizeof(uint64_t));
+       exthdr.cksum = cpu_to_be32(gen_cksum(ptr, l1_size * sizeof(uint64_t)));
+       printf("Created cksum: %d\n",exthdr.cksum);
+       free(ptr);
+       
+       /* write all the data */
+       ret += write(fd, &header, sizeof(header));
+       ret += write(fd, &exthdr, sizeof(exthdr));
+       if (backing_file) {
+               ret += write(fd, backing_filename, backing_filename_len);
+       }
+       lseek(fd, header_size, SEEK_SET);
+       tmp = 0;
+       for (i = 0;i < l1_size; i++) {
+               ret += write(fd, &tmp, sizeof(tmp));
+       }
+
+       /*adjust file length to 4 KByte boundary*/
+       length = header_size + l1_size * sizeof(uint64_t);
+       if (length % 4096 > 0) {
+               length = ((length >> 12) + 1) << 12;
+               ftruncate(fd, length);
+               DPRINTF("Adjusted filelength to %d for 4 "
+                       "Kbyte alignment\n",length);
+       }
+
+       close(fd);
+
+       return 0;
+}
+
+int qcow_make_empty(struct td_state *bs)
+{
+       struct tdqcow_state *s = (struct tdqcow_state *)bs->private;
+       uint32_t l1_length = s->l1_size * sizeof(uint64_t);
+
+       memset(s->l1_table, 0, l1_length);
+       lseek(s->fd, s->l1_table_offset, SEEK_SET);
+       if (write(s->fd, s->l1_table, l1_length) < 0)
+               return -1;
+       ftruncate(s->fd, s->l1_table_offset + l1_length);
+
+       memset(s->l2_cache, 0, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
+       memset(s->l2_cache_offsets, 0, L2_CACHE_SIZE * sizeof(uint64_t));
+       memset(s->l2_cache_counts, 0, L2_CACHE_SIZE * sizeof(uint32_t));
+
+       return 0;
+}
+
+int qcow_get_cluster_size(struct td_state *bs)
+{
+       struct tdqcow_state *s = (struct tdqcow_state *)bs->private;
+
+       return s->cluster_size;
+}
+
+/* XXX: put compressed sectors first, then all the cluster aligned
+   tables to avoid losing bytes in alignment */
+int qcow_compress_cluster(struct td_state *bs, int64_t sector_num, 
+                          const uint8_t *buf)
+{
+       struct tdqcow_state *s = (struct tdqcow_state *)bs->private;
+       z_stream strm;
+       int ret, out_len;
+       uint8_t *out_buf;
+       uint64_t cluster_offset;
+
+       out_buf = malloc(s->cluster_size + (s->cluster_size / 1000) + 128);
+       if (!out_buf)
+               return -1;
+
+       /* best compression, small window, no zlib header */
+       memset(&strm, 0, sizeof(strm));
+       ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
+                          Z_DEFLATED, -12, 
+                          9, Z_DEFAULT_STRATEGY);
+       if (ret != 0) {
+               free(out_buf);
+               return -1;
+       }
+
+       strm.avail_in = s->cluster_size;
+       strm.next_in = (uint8_t *)buf;
+       strm.avail_out = s->cluster_size;
+       strm.next_out = out_buf;
+
+       ret = deflate(&strm, Z_FINISH);
+       if (ret != Z_STREAM_END && ret != Z_OK) {
+               free(out_buf);
+               deflateEnd(&strm);
+               return -1;
+       }
+       out_len = strm.next_out - out_buf;
+
+       deflateEnd(&strm);
+
+       if (ret != Z_STREAM_END || out_len >= s->cluster_size) {
+               /* could not compress: write normal cluster */
+               //tdqcow_queue_write(bs, sector_num, buf, s->cluster_sectors);
+       } else {
+               cluster_offset = get_cluster_offset(bs, sector_num << 9, 2, 
+                                            out_len, 0, 0);
+               cluster_offset &= s->cluster_offset_mask;
+               lseek(s->fd, cluster_offset, SEEK_SET);
+               if (write(s->fd, out_buf, out_len) != out_len) {
+                       free(out_buf);
+                       return -1;
+               }
+       }
+       
+       free(out_buf);
+       return 0;
+}
+
+struct tap_disk tapdisk_qcow = {
+       "tapdisk_qcow",
+       sizeof(struct tdqcow_state),
+       tdqcow_open,
+       tdqcow_queue_read,
+       tdqcow_queue_write,
+       tdqcow_submit,
+       tdqcow_get_fd,
+       tdqcow_close,
+       tdqcow_do_callbacks,
+};
+
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/block-ram.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/block-ram.c  Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,296 @@
+/* block-ram.c
+ *
+ * Fast Ramdisk implementation.
+ *
+ * (c) 2006 Andrew Warfield and Julian Chesterfield
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/statvfs.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <string.h>
+#include "tapdisk.h"
+
+#define MAX_DISK_SIZE 1024000 /*500MB disk limit*/
+
+char *img;
+long int   disksector_size;
+long int   disksize;
+long int   diskinfo;
+static int connections = 0;
+
+struct tdram_state {
+        int fd;
+       int poll_pipe[2]; /* dummy fd for polling on */
+};
+
+/*Get Image size, secsize*/
+static int get_image_info(struct td_state *s, int fd)
+{
+       int ret;
+       long size;
+       unsigned long total_size;
+       struct statvfs statBuf;
+       struct stat stat;
+
+       ret = fstat(fd, &stat);
+       if (ret != 0) {
+               DPRINTF("ERROR: fstat failed, Couldn't stat image");
+               return -EINVAL;
+       }
+
+       if (S_ISBLK(stat.st_mode)) {
+               /*Accessing block device directly*/
+               s->size = 0;
+               if (ioctl(fd,BLKGETSIZE,&s->size)!=0) {
+                       DPRINTF("ERR: BLKGETSIZE failed, couldn't stat image");
+                       return -EINVAL;
+               }
+
+               DPRINTF("Image size: \n\tpre sector_shift  [%llu]\n\tpost "
+                       "sector_shift [%llu]\n",
+                       (long long unsigned)(s->size << SECTOR_SHIFT),
+                       (long long unsigned)s->size);
+
+               /*Get the sector size*/
+#if defined(BLKSSZGET)
+               {
+                       int arg;
+                       s->sector_size = DEFAULT_SECTOR_SIZE;
+                       ioctl(fd, BLKSSZGET, &s->sector_size);
+                       
+                       if (s->sector_size != DEFAULT_SECTOR_SIZE)
+                               DPRINTF("Note: sector size is %ld (not %d)\n",
+                                       s->sector_size, DEFAULT_SECTOR_SIZE);
+               }
+#else
+               s->sector_size = DEFAULT_SECTOR_SIZE;
+#endif
+
+       } else {
+               /*Local file? try fstat instead*/
+               s->size = (stat.st_size >> SECTOR_SHIFT);
+               s->sector_size = DEFAULT_SECTOR_SIZE;
+               DPRINTF("Image size: \n\tpre sector_shift  [%llu]\n\tpost "
+                       "sector_shift [%llu]\n",
+                       (long long unsigned)(s->size << SECTOR_SHIFT),
+                       (long long unsigned)s->size);
+       }
+
+       if (s->size == 0) {             
+               s->size =((uint64_t) MAX_DISK_SIZE);
+               s->sector_size = DEFAULT_SECTOR_SIZE;
+       }
+       s->info = 0;
+
+        /*Store variables locally*/
+       disksector_size = s->sector_size;
+       disksize        = s->size;
+       diskinfo        = s->info;
+       DPRINTF("Image sector_size: \n\t[%lu]\n",
+               s->sector_size);
+
+       return 0;
+}
+
+/* Open the disk file and initialize ram state. */
+int tdram_open (struct td_state *s, const char *name)
+{
+       int i, fd, ret = 0, count = 0;
+       struct tdram_state *prv = (struct tdram_state *)s->private;
+       uint64_t size;
+       char *p;
+       s->private = prv;
+
+       connections++;
+       
+       /* set up a pipe so that we can hand back a poll fd that won't fire.*/
+       ret = pipe(prv->poll_pipe);
+       if (ret != 0)
+               return (0 - errno);
+
+       if (connections > 1) {
+               s->sector_size = disksector_size;
+               s->size        = disksize;
+               s->info        = diskinfo; 
+               DPRINTF("Image already open, returning parameters:\n");
+               DPRINTF("Image size: \n\tpre sector_shift  [%llu]\n\tpost "
+                       "sector_shift [%llu]\n",
+                       (long long unsigned)(s->size << SECTOR_SHIFT),
+                       (long long unsigned)s->size);
+               DPRINTF("Image sector_size: \n\t[%lu]\n",
+                       s->sector_size);
+
+               prv->fd = -1;
+               goto done;
+       }
+
+       /* Open the file */
+        fd = open(name, O_RDWR | O_DIRECT | O_LARGEFILE);
+
+        if ((fd == -1) && (errno == EINVAL)) {
+
+                /* Maybe O_DIRECT isn't supported. */
+                fd = open(name, O_RDWR | O_LARGEFILE);
+                if (fd != -1) DPRINTF("WARNING: Accessing image without"
+                                     "O_DIRECT! (%s)\n", name);
+
+        } else if (fd != -1) DPRINTF("open(%s) with O_DIRECT\n", name);
+       
+        if (fd == -1) {
+               DPRINTF("Unable to open [%s]!\n",name);
+               ret = 0 - errno;
+               goto done;
+        }
+
+        prv->fd = fd;
+
+       ret = get_image_info(s, fd);
+       size = MAX_DISK_SIZE;
+
+       if (s->size > size) {
+               DPRINTF("Disk exceeds limit, must be less than [%d]MB",
+                       (MAX_DISK_SIZE<<SECTOR_SHIFT)>>20);
+               return -ENOMEM;
+       }
+
+       /*Read the image into memory*/
+       p = img = malloc(s->size << SECTOR_SHIFT);
+       if (img == NULL) {
+               DPRINTF("Mem malloc failed\n");
+               return -1;
+       }
+       DPRINTF("Reading %llu bytes.......",(long long unsigned)s->size << 
SECTOR_SHIFT);
+
+       for (i = 0; i < s->size; i++) {
+               ret = read(prv->fd, p, s->sector_size);
+               if (ret != s->sector_size) {
+                       ret = 0 - errno;
+                       break;
+               } else {
+                       count += ret;
+                       p = img + count;
+               }
+       }
+       DPRINTF("[%d]\n",count);
+       if (count != s->size << SECTOR_SHIFT) {
+               ret = -1;
+       } else {
+               ret = 0;
+       } 
+
+done:
+       return ret;
+}
+
+ int tdram_queue_read(struct td_state *s, uint64_t sector,
+                              int nb_sectors, char *buf, td_callback_t cb,
+                              int id, void *private)
+{
+       struct tdram_state *prv = (struct tdram_state *)s->private;
+       int      size    = nb_sectors * s->sector_size;
+       uint64_t offset  = sector * (uint64_t)s->sector_size;
+       int ret;
+
+       memcpy(buf, img + offset, size);
+       ret = size;
+
+       cb(s, (ret < 0) ? ret: 0, id, private);
+
+       return ret;
+}
+
+ int tdram_queue_write(struct td_state *s, uint64_t sector,
+                              int nb_sectors, char *buf, td_callback_t cb,
+                              int id, void *private)
+{
+       struct tdram_state *prv = (struct tdram_state *)s->private;
+       int      size    = nb_sectors * s->sector_size;
+       uint64_t offset  = sector * (uint64_t)s->sector_size;
+       int ret;
+       
+       /*We assume that write access is controlled at a higher level for 
multiple disks*/
+       memcpy(img + offset, buf, size);
+       ret = size;
+
+       cb(s, (ret < 0) ? ret : 0, id, private);
+
+       return ret;
+}
+               
+int tdram_submit(struct td_state *s)
+{
+       return 0;       
+}
+
+
+int *tdram_get_fd(struct td_state *s)
+{
+       struct tdram_state *prv = (struct tdram_state *)s->private;
+        int *fds, i;
+
+        fds = malloc(sizeof(int) * MAX_IOFD);
+        /*initialise the FD array*/
+        for(i=0;i<MAX_IOFD;i++) fds[i] = 0;
+
+        fds[0] = prv->poll_pipe[0];
+        return fds;    
+}
+
+int tdram_close(struct td_state *s)
+{
+       struct tdram_state *prv = (struct tdram_state *)s->private;
+       
+       connections--;
+       
+       return 0;
+}
+
+int tdram_do_callbacks(struct td_state *s, int sid)
+{
+       /* always ask for a kick */
+       return 1;
+}
+
+struct tap_disk tapdisk_ram = {
+       "tapdisk_ram",
+       sizeof(struct tdram_state),
+       tdram_open,
+       tdram_queue_read,
+       tdram_queue_write,
+       tdram_submit,
+       tdram_get_fd,
+       tdram_close,
+       tdram_do_callbacks,
+};
+
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/block-sync.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/block-sync.c Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,242 @@
+/* block-sync.c
+ *
+ * simple slow synchronous raw disk implementation.
+ *
+ * (c) 2006 Andrew Warfield and Julian Chesterfield
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/statvfs.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include "tapdisk.h"
+
+struct tdsync_state {
+       int fd;
+       int poll_pipe[2]; /* dummy fd for polling on */
+};
+       
+/*Get Image size, secsize*/
+static int get_image_info(struct td_state *s, int fd)
+{
+       int ret;
+       long size;
+       unsigned long total_size;
+       struct statvfs statBuf;
+       struct stat stat;
+
+       ret = fstat(fd, &stat);
+       if (ret != 0) {
+               DPRINTF("ERROR: fstat failed, Couldn't stat image");
+               return -EINVAL;
+       }
+
+       if (S_ISBLK(stat.st_mode)) {
+               /*Accessing block device directly*/
+               s->size = 0;
+               if (ioctl(fd,BLKGETSIZE,&s->size)!=0) {
+                       DPRINTF("ERR: BLKGETSIZE failed, couldn't stat image");
+                       return -EINVAL;
+               }
+
+               DPRINTF("Image size: \n\tpre sector_shift  [%llu]\n\tpost "
+                       "sector_shift [%llu]\n",
+                       (long long unsigned)(s->size << SECTOR_SHIFT),
+                       (long long unsigned)s->size);
+
+               /*Get the sector size*/
+#if defined(BLKSSZGET)
+               {
+                       int arg;
+                       s->sector_size = DEFAULT_SECTOR_SIZE;
+                       ioctl(fd, BLKSSZGET, &s->sector_size);
+                       
+                       if (s->sector_size != DEFAULT_SECTOR_SIZE)
+                               DPRINTF("Note: sector size is %ld (not %d)\n",
+                                       s->sector_size, DEFAULT_SECTOR_SIZE);
+               }
+#else
+               s->sector_size = DEFAULT_SECTOR_SIZE;
+#endif
+
+       } else {
+               /*Local file? try fstat instead*/
+               s->size = (stat.st_size >> SECTOR_SHIFT);
+               s->sector_size = DEFAULT_SECTOR_SIZE;
+               DPRINTF("Image size: \n\tpre sector_shift  [%lluu]\n\tpost "
+                       "sector_shift [%lluu]\n",
+                       (long long unsigned)(s->size << SECTOR_SHIFT),
+                       (long long unsigned)s->size);
+       }
+
+       if (s->size == 0)
+               return -EINVAL;
+
+       s->info = 0;
+
+       return 0;
+}
+
+/* Open the disk file and initialize aio state. */
+int tdsync_open (struct td_state *s, const char *name)
+{
+       int i, fd, ret = 0;
+       struct tdsync_state *prv = (struct tdsync_state *)s->private;
+       s->private = prv;
+       
+       /* set up a pipe so that we can hand back a poll fd that won't fire.*/
+       ret = pipe(prv->poll_pipe);
+       if (ret != 0)
+               return (0 - errno);
+       
+       /* Open the file */
+        fd = open(name, O_RDWR | O_DIRECT | O_LARGEFILE);
+
+        if ( (fd == -1) && (errno == EINVAL) ) {
+
+                /* Maybe O_DIRECT isn't supported. */
+                fd = open(name, O_RDWR | O_LARGEFILE);
+                if (fd != -1) DPRINTF("WARNING: Accessing image without"
+                                     "O_DIRECT! (%s)\n", name);
+
+        } else if (fd != -1) DPRINTF("open(%s) with O_DIRECT\n", name);
+       
+        if (fd == -1) {
+               DPRINTF("Unable to open [%s]!\n",name);
+               ret = 0 - errno;
+               goto done;
+        }
+
+        prv->fd = fd;
+
+       ret = get_image_info(s, fd);
+done:
+       return ret;     
+}
+
+ int tdsync_queue_read(struct td_state *s, uint64_t sector,
+                              int nb_sectors, char *buf, td_callback_t cb,
+                              int id, void *private)
+{
+       struct tdsync_state *prv = (struct tdsync_state *)s->private;
+       int      size    = nb_sectors * s->sector_size;
+       uint64_t offset  = sector * (uint64_t)s->sector_size;
+       int ret;
+       
+       ret = lseek(prv->fd, offset, SEEK_SET);
+       if (ret != (off_t)-1) {
+               ret = read(prv->fd, buf, size);
+               if (ret != size) {
+                       ret = 0 - errno;
+               } else {
+                       ret = 1;
+               } 
+       } else ret = 0 - errno;
+               
+       cb(s, (ret < 0) ? ret: 0, id, private);
+       
+       return 1;
+}
+
+ int tdsync_queue_write(struct td_state *s, uint64_t sector,
+                              int nb_sectors, char *buf, td_callback_t cb,
+                              int id, void *private)
+{
+       struct tdsync_state *prv = (struct tdsync_state *)s->private;
+       int      size    = nb_sectors * s->sector_size;
+       uint64_t offset  = sector * (uint64_t)s->sector_size;
+       int ret = 0;
+       
+       ret = lseek(prv->fd, offset, SEEK_SET);
+       if (ret != (off_t)-1) {
+               ret = write(prv->fd, buf, size);
+               if (ret != size) {
+                       ret = 0 - errno;
+               } else {
+                       ret = 1;
+               }
+       } else ret = 0 - errno;
+               
+       cb(s, (ret < 0) ? ret : 0, id, private);
+       
+       return 1;
+}
+               
+int tdsync_submit(struct td_state *s)
+{
+       return 0;       
+}
+
+
+int *tdsync_get_fd(struct td_state *s)
+{
+       struct tdsync_state *prv = (struct tdsync_state *)s->private;
+       
+       int *fds, i;
+
+       fds = malloc(sizeof(int) * MAX_IOFD);
+       /*initialise the FD array*/
+       for(i=0;i<MAX_IOFD;i++) fds[i] = 0;
+
+       fds[0] = prv->poll_pipe[0];
+       return fds;
+}
+
+int tdsync_close(struct td_state *s)
+{
+       struct tdsync_state *prv = (struct tdsync_state *)s->private;
+       
+       close(prv->fd);
+       close(prv->poll_pipe[0]);
+       close(prv->poll_pipe[1]);
+       
+       return 0;
+}
+
+int tdsync_do_callbacks(struct td_state *s, int sid)
+{
+       /* always ask for a kick */
+       return 1;
+}
+
+struct tap_disk tapdisk_sync = {
+       "tapdisk_sync",
+       sizeof(struct tdsync_state),
+       tdsync_open,
+       tdsync_queue_read,
+       tdsync_queue_write,
+       tdsync_submit,
+       tdsync_get_fd,
+       tdsync_close,
+       tdsync_do_callbacks,
+};
+
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/block-vmdk.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/block-vmdk.c Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,415 @@
+/* block-vmdk.c
+ *
+ * VMware Disk format implementation.
+ *
+ * (c) 2006 Andrew Warfield and Julian Chesterfield
+ *
+ * This is largely the same as the vmdk driver in Qemu, I've just twisted it
+ * to match our interfaces.  The original (BSDish) Copyright message appears 
+ * below:
+ */
+ 
+/*
+ * Block driver for the VMDK format
+ * 
+ * Copyright (c) 2004 Fabrice Bellard
+ * Copyright (c) 2005 Filip Navara
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to 
deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/statvfs.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <string.h>
+#include "tapdisk.h"
+#include "bswap.h"
+
+#define safer_free(_x)       \
+  do {                       \
+       if (NULL != _x) {    \
+               free(_x);    \
+               (_x) = NULL; \
+       }                    \
+  } while (0) ;
+
+#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
+#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
+
+typedef struct {
+    uint32_t version;
+    uint32_t flags;
+    uint32_t disk_sectors;
+    uint32_t granularity;
+    uint32_t l1dir_offset;
+    uint32_t l1dir_size;
+    uint32_t file_sectors;
+    uint32_t cylinders;
+    uint32_t heads;
+    uint32_t sectors_per_track;
+} VMDK3Header;
+
+typedef struct {
+    uint32_t version;
+    uint32_t flags;
+    int64_t capacity;
+    int64_t granularity;
+    int64_t desc_offset;
+    int64_t desc_size;
+    int32_t num_gtes_per_gte;
+    int64_t rgd_offset;
+    int64_t gd_offset;
+    int64_t grain_offset;
+    char filler[1];
+    char check_bytes[4];
+} __attribute__((packed)) VMDK4Header;
+
+#define L2_CACHE_SIZE 16
+
+struct tdvmdk_state {
+        int fd;
+       int poll_pipe[2]; /* dummy fd for polling on */
+       
+       unsigned int l1_size;
+       int64_t l1_table_offset;
+       int64_t l1_backup_table_offset;
+       uint32_t l1_entry_sectors;
+       unsigned int l2_size;
+       
+       uint32_t *l1_table;
+       uint32_t *l1_backup_table;
+       uint32_t *l2_cache;
+       uint32_t l2_cache_offsets[L2_CACHE_SIZE];
+       uint32_t l2_cache_counts[L2_CACHE_SIZE];
+       
+       unsigned int cluster_sectors;
+};
+
+
+/* Open the disk file and initialize aio state. */
+static int tdvmdk_open (struct td_state *s, const char *name)
+{
+       int ret, fd;
+       int l1_size, i;
+       uint32_t magic;
+       struct tdvmdk_state *prv = (struct tdvmdk_state *)s->private;
+
+       /* set up a pipe so that we can hand back a poll fd that won't fire.*/
+       ret = pipe(prv->poll_pipe);
+       if (ret != 0)
+               return -1;
+       
+       /* Open the file */
+        fd = open(name, O_RDWR | O_LARGEFILE); 
+
+        if ( (fd == -1) && (errno == EINVAL) ) {
+
+                /* Maybe O_DIRECT isn't supported. */
+                fd = open(name, O_RDWR | O_LARGEFILE);
+                if (fd != -1) DPRINTF("WARNING: Accessing image without"
+                                     "O_DIRECT! (%s)\n", name);
+
+        } else if (fd != -1) DPRINTF("open(%s) with O_DIRECT\n", name);
+       
+        if (fd == -1) {
+               DPRINTF("Unable to open [%s]!\n",name);
+               ret = 0 - errno;
+               return -1;
+        }
+        
+        prv->fd = fd;
+        
+        /* Grok the vmdk header. */
+       if ((ret = read(fd, &magic, sizeof(magic))) != sizeof(magic))
+               goto fail;
+       magic = be32_to_cpu(magic);
+       if (magic == VMDK3_MAGIC) {
+               VMDK3Header header;
+               if (read(fd, &header, sizeof(header)) != 
+                       sizeof(header)) 
+                       goto fail;
+               prv->cluster_sectors = le32_to_cpu(header.granularity);
+               prv->l2_size = 1 << 9;
+               prv->l1_size = 1 << 6;
+               s->size = le32_to_cpu(header.disk_sectors);
+               prv->l1_table_offset = le32_to_cpu(header.l1dir_offset) << 9;
+               prv->l1_backup_table_offset = 0;
+               prv->l1_entry_sectors = prv->l2_size * prv->cluster_sectors;
+       } else if (magic == VMDK4_MAGIC) {
+               VMDK4Header header;
+        
+               if (read(fd, &header, sizeof(header)) != sizeof(header))
+                       goto fail;
+               s->size = le32_to_cpu(header.capacity);
+               prv->cluster_sectors = le32_to_cpu(header.granularity);
+               prv->l2_size = le32_to_cpu(header.num_gtes_per_gte);
+               prv->l1_entry_sectors = prv->l2_size * prv->cluster_sectors;
+               if (prv->l1_entry_sectors <= 0)
+                       goto fail;
+               prv->l1_size = (s->size + prv->l1_entry_sectors - 1) 
+                              / prv->l1_entry_sectors;
+               prv->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
+               prv->l1_backup_table_offset = 
+                       le64_to_cpu(header.gd_offset) << 9;
+       } else {
+               goto fail;
+       }
+       /* read the L1 table */
+       l1_size = prv->l1_size * sizeof(uint32_t);
+       prv->l1_table = malloc(l1_size);
+       if (!prv->l1_table)
+               goto fail;
+       if (lseek(fd, prv->l1_table_offset, SEEK_SET) == -1)
+               goto fail;
+       if (read(fd, prv->l1_table, l1_size) != l1_size)
+               goto fail;
+       for (i = 0; i < prv->l1_size; i++) {
+               le32_to_cpus(&prv->l1_table[i]);
+       }
+
+       if (prv->l1_backup_table_offset) {
+               prv->l1_backup_table = malloc(l1_size);
+               if (!prv->l1_backup_table)
+                       goto fail;
+               if (lseek(fd, prv->l1_backup_table_offset, SEEK_SET) == -1)
+                       goto fail;
+               if (read(fd, prv->l1_backup_table, l1_size) != l1_size)
+                       goto fail;
+               for(i = 0; i < prv->l1_size; i++) {
+                       le32_to_cpus(&prv->l1_backup_table[i]);
+               }
+       }
+
+       prv->l2_cache = malloc(prv->l2_size * L2_CACHE_SIZE *sizeof(uint32_t));
+       if (!prv->l2_cache)
+               goto fail;
+       prv->fd = fd;
+       DPRINTF("VMDK File opened successfully\n");
+       return 0;
+       
+fail:
+       DPRINTF("VMDK File open failed.\n"); 
+       safer_free(prv->l1_backup_table);
+       free(prv->l1_table);
+       free(prv->l2_cache);
+       close(fd);
+       return -1;
+}
+
+static uint64_t get_cluster_offset(struct td_state *s, 
+                                   uint64_t offset, int allocate)
+{
+       struct tdvmdk_state *prv = (struct tdvmdk_state *)s->private;
+       unsigned int l1_index, l2_offset, l2_index;
+       int min_index, i, j;
+       uint32_t min_count, *l2_table, tmp;
+       uint64_t cluster_offset;
+    
+       l1_index = (offset >> 9) / prv->l1_entry_sectors;
+       if (l1_index >= prv->l1_size)
+               return 0;
+       l2_offset = prv->l1_table[l1_index];
+       if (!l2_offset)
+               return 0;
+       for (i = 0; i < L2_CACHE_SIZE; i++) {
+               if (l2_offset == prv->l2_cache_offsets[i]) {
+                       /* increment the hit count */
+                       if (++prv->l2_cache_counts[i] == 0xffffffff) {
+                               for(j = 0; j < L2_CACHE_SIZE; j++) {
+                                       prv->l2_cache_counts[j] >>= 1;
+                               }
+                       }
+                       l2_table = prv->l2_cache + (i * prv->l2_size);
+                       goto found;
+               }
+       }
+       /* not found: load a new entry in the least used one */
+       min_index = 0;
+       min_count = 0xffffffff;
+       for (i = 0; i < L2_CACHE_SIZE; i++) {
+               if (prv->l2_cache_counts[i] < min_count) {
+                       min_count = prv->l2_cache_counts[i];
+                       min_index = i;
+               }
+       }
+       l2_table = prv->l2_cache + (min_index * prv->l2_size);
+       lseek(prv->fd, (int64_t)l2_offset * 512, SEEK_SET);
+       if (read(prv->fd, l2_table, prv->l2_size * sizeof(uint32_t)) != 
+                prv->l2_size * sizeof(uint32_t))
+               return 0;
+       prv->l2_cache_offsets[min_index] = l2_offset;
+       prv->l2_cache_counts[min_index] = 1;
+ found:
+       l2_index = ((offset >> 9) / prv->cluster_sectors) % prv->l2_size;
+       cluster_offset = le32_to_cpu(l2_table[l2_index]);
+       if (!cluster_offset) {
+               if (!allocate)
+                       return 0;
+               cluster_offset = lseek(prv->fd, 0, SEEK_END);
+               ftruncate(prv->fd, cluster_offset + 
+                         (prv->cluster_sectors << 9));
+               cluster_offset >>= 9;
+               /* update L2 table */
+               tmp = cpu_to_le32(cluster_offset);
+               l2_table[l2_index] = tmp;
+               lseek(prv->fd, ((int64_t)l2_offset * 512) + 
+                     (l2_index * sizeof(tmp)), SEEK_SET);
+               if (write(prv->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
+                       return 0;
+               /* update backup L2 table */
+               if (prv->l1_backup_table_offset != 0) {
+                       l2_offset = prv->l1_backup_table[l1_index];
+               lseek(prv->fd, ((int64_t)l2_offset * 512) + 
+                       (l2_index * sizeof(tmp)), SEEK_SET);
+               if (write(prv->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
+                       return 0;
+               }
+       }
+       cluster_offset <<= 9;
+       return cluster_offset;
+}
+
+static int tdvmdk_queue_read(struct td_state *s, uint64_t sector,
+                              int nb_sectors, char *buf, td_callback_t cb,
+                              int id, void *private)
+{
+       struct tdvmdk_state *prv = (struct tdvmdk_state *)s->private;
+       int index_in_cluster, n;
+       uint64_t cluster_offset;
+       int ret = 0;
+       while (nb_sectors > 0) {
+               cluster_offset = get_cluster_offset(s, sector << 9, 0);
+               index_in_cluster = sector % prv->cluster_sectors;
+               n = prv->cluster_sectors - index_in_cluster;
+               if (n > nb_sectors)
+                       n = nb_sectors;
+               if (!cluster_offset) {
+                       memset(buf, 0, 512 * n);
+               } else {
+                       lseek(prv->fd, cluster_offset + index_in_cluster * 512,
+                             SEEK_SET);
+                       ret = read(prv->fd, buf, n * 512);
+                       if (ret != n * 512) {
+                               ret = -1;
+                               goto done;
+                       }
+               }
+               nb_sectors -= n;
+               sector     += n;
+               buf += n * 512;
+       }
+done:
+       cb(s, ret == -1 ? -1 : 0, id, private);
+       
+       return 1;
+}
+
+static  int tdvmdk_queue_write(struct td_state *s, uint64_t sector,
+                              int nb_sectors, char *buf, td_callback_t cb,
+                              int id, void *private)
+{
+       struct tdvmdk_state *prv = (struct tdvmdk_state *)s->private;
+       int index_in_cluster, n;
+       uint64_t cluster_offset;
+       int ret = 0;
+       
+
+       while (nb_sectors > 0) {
+               index_in_cluster = sector & (prv->cluster_sectors - 1);
+               n = prv->cluster_sectors - index_in_cluster;
+               if (n > nb_sectors)
+                       n = nb_sectors;
+               cluster_offset = get_cluster_offset(s, sector << 9, 1);
+               if (!cluster_offset) {
+                       ret = -1;
+                       goto done;
+               }
+               lseek(prv->fd, cluster_offset + index_in_cluster * 512, 
+                     SEEK_SET);
+               ret = write(prv->fd, buf, n * 512);
+               if (ret != n * 512) {
+                       ret = -1;
+                       goto done;
+               }
+               nb_sectors -= n;
+               sector     += n;
+               buf += n * 512;
+       }
+done:
+       cb(s, ret == -1 ? -1 : 0, id, private);
+       
+       return 1;
+}
+               
+static int tdvmdk_submit(struct td_state *s)
+{
+       return 0;       
+}
+
+
+static int *tdvmdk_get_fd(struct td_state *s)
+{
+       struct tdvmdk_state *prv = (struct tdvmdk_state *)s->private;
+        int *fds, i;
+
+        fds = malloc(sizeof(int) * MAX_IOFD);
+        /*initialise the FD array*/
+        for (i=0;i<MAX_IOFD;i++) fds[i] = 0;
+
+        fds[0] = prv->poll_pipe[0];
+        return fds;
+}
+
+static int tdvmdk_close(struct td_state *s)
+{
+       struct tdvmdk_state *prv = (struct tdvmdk_state *)s->private;
+       
+       safer_free(prv->l1_table);
+       safer_free(prv->l1_backup_table);
+       safer_free(prv->l2_cache);
+       close(prv->fd);
+       close(prv->poll_pipe[0]);
+       close(prv->poll_pipe[1]);
+       return 0;
+}
+
+static int tdvmdk_do_callbacks(struct td_state *s, int sid)
+{
+       /* always ask for a kick */
+       return 1;
+}
+
+struct tap_disk tapdisk_vmdk = {
+       "tapdisk_vmdk",
+       sizeof(struct tdvmdk_state),
+       tdvmdk_open,
+       tdvmdk_queue_read,
+       tdvmdk_queue_write,
+       tdvmdk_submit,
+       tdvmdk_get_fd,
+       tdvmdk_close,
+       tdvmdk_do_callbacks,
+};
+
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/bswap.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/bswap.h      Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,202 @@
+#ifndef BSWAP_H
+#define BSWAP_H
+
+//#include "config-host.h"
+
+#include <inttypes.h>
+
+#ifdef HAVE_BYTESWAP_H
+#include <byteswap.h>
+#else
+
+#define bswap_16(x) \
+({ \
+       uint16_t __x = (x); \
+       ((uint16_t)( \
+               (((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \
+               (((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \
+})
+
+#define bswap_32(x) \
+({ \
+       uint32_t __x = (x); \
+       ((uint32_t)( \
+               (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
+               (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
+               (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
+               (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \
+})
+
+#define bswap_64(x) \
+({ \
+       uint64_t __x = (x); \
+       ((uint64_t)( \
+               (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) 
<< 56) | \
+               (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) 
<< 40) | \
+               (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) 
<< 24) | \
+               (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) 
<<  8) | \
+               (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) 
>>  8) | \
+               (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) 
>> 24) | \
+               (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) 
>> 40) | \
+               (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) 
>> 56) )); \
+})
+
+#endif /* !HAVE_BYTESWAP_H */
+
+static inline uint16_t bswap16(uint16_t x)
+{
+    return bswap_16(x);
+}
+
+static inline uint32_t bswap32(uint32_t x) 
+{
+    return bswap_32(x);
+}
+
+static inline uint64_t bswap64(uint64_t x) 
+{
+    return bswap_64(x);
+}
+
+static inline void bswap16s(uint16_t *s)
+{
+    *s = bswap16(*s);
+}
+
+static inline void bswap32s(uint32_t *s)
+{
+    *s = bswap32(*s);
+}
+
+static inline void bswap64s(uint64_t *s)
+{
+    *s = bswap64(*s);
+}
+
+#if defined(WORDS_BIGENDIAN)
+#define be_bswap(v, size) (v)
+#define le_bswap(v, size) bswap ## size(v)
+#define be_bswaps(v, size)
+#define le_bswaps(p, size) *p = bswap ## size(*p);
+#else
+#define le_bswap(v, size) (v)
+#define be_bswap(v, size) bswap ## size(v)
+#define le_bswaps(v, size)
+#define be_bswaps(p, size) *p = bswap ## size(*p);
+#endif
+
+#define CPU_CONVERT(endian, size, type)\
+static inline type endian ## size ## _to_cpu(type v)\
+{\
+    return endian ## _bswap(v, size);\
+}\
+\
+static inline type cpu_to_ ## endian ## size(type v)\
+{\
+    return endian ## _bswap(v, size);\
+}\
+\
+static inline void endian ## size ## _to_cpus(type *p)\
+{\
+    endian ## _bswaps(p, size)\
+}\
+\
+static inline void cpu_to_ ## endian ## size ## s(type *p)\
+{\
+    endian ## _bswaps(p, size)\
+}\
+\
+static inline type endian ## size ## _to_cpup(const type *p)\
+{\
+    return endian ## size ## _to_cpu(*p);\
+}\
+\
+static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\
+{\
+     *p = cpu_to_ ## endian ## size(v);\
+}
+
+CPU_CONVERT(be, 16, uint16_t)
+CPU_CONVERT(be, 32, uint32_t)
+CPU_CONVERT(be, 64, uint64_t)
+
+CPU_CONVERT(le, 16, uint16_t)
+CPU_CONVERT(le, 32, uint32_t)
+CPU_CONVERT(le, 64, uint64_t)
+
+/* unaligned versions (optimized for frequent unaligned accesses)*/
+
+#if defined(__i386__) || defined(__powerpc__)
+
+#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v)
+#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v)
+#define le16_to_cpupu(p) le16_to_cpup(p)
+#define le32_to_cpupu(p) le32_to_cpup(p)
+
+#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v)
+#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v)
+
+#else
+
+static inline void cpu_to_le16wu(uint16_t *p, uint16_t v)
+{
+    uint8_t *p1 = (uint8_t *)p;
+
+    p1[0] = v;
+    p1[1] = v >> 8;
+}
+
+static inline void cpu_to_le32wu(uint32_t *p, uint32_t v)
+{
+    uint8_t *p1 = (uint8_t *)p;
+
+    p1[0] = v;
+    p1[1] = v >> 8;
+    p1[2] = v >> 16;
+    p1[3] = v >> 24;
+}
+
+static inline uint16_t le16_to_cpupu(const uint16_t *p)
+{
+    const uint8_t *p1 = (const uint8_t *)p;
+    return p1[0] | (p1[1] << 8);
+}
+
+static inline uint32_t le32_to_cpupu(const uint32_t *p)
+{
+    const uint8_t *p1 = (const uint8_t *)p;
+    return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24);
+}
+
+static inline void cpu_to_be16wu(uint16_t *p, uint16_t v)
+{
+    uint8_t *p1 = (uint8_t *)p;
+
+    p1[0] = v >> 8;
+    p1[1] = v;
+}
+
+static inline void cpu_to_be32wu(uint32_t *p, uint32_t v)
+{
+    uint8_t *p1 = (uint8_t *)p;
+
+    p1[0] = v >> 24;
+    p1[1] = v >> 16;
+    p1[2] = v >> 8;
+    p1[3] = v;
+}
+
+#endif
+
+#ifdef WORDS_BIGENDIAN
+#define cpu_to_32wu cpu_to_be32wu
+#else
+#define cpu_to_32wu cpu_to_le32wu
+#endif
+
+#undef le_bswap
+#undef be_bswap
+#undef le_bswaps
+#undef be_bswaps
+
+#endif /* BSWAP_H */
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/img2qcow.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/img2qcow.c   Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,289 @@
+/* img2qcow.c
+ *
+ * Generates a qcow format disk and fills it from an existing image.
+ *
+ * (c) 2006 Julian Chesterfield and Andrew Warfield
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/statvfs.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <string.h>
+#include "tapdisk.h"
+
+#if 1
+#define DFPRINTF(_f, _a...) fprintf ( stderr, _f , ## _a )
+#else
+#define DFPRINTF(_f, _a...) ((void)0)
+#endif
+
+#define TAPDISK 1
+#define BLOCK_PROCESSSZ 4096
+
+static int maxfds, *io_fd, running = 1, complete = 0;
+static int returned_events = 0, submit_events = 0;
+static uint64_t prev = 0;
+static char output[25];
+
+void print_bytes(void *ptr, int length) {
+
+  int i,k;
+  unsigned char *p = ptr;
+
+    DFPRINTF("Buf dump, length %d:\n",length);
+    for (k = 0; k < length; k++) {
+        DFPRINTF("%x",*p);
+        *p++;
+       if(k % 16 == 0) DFPRINTF("\n");
+        else if(k % 2 == 0) DFPRINTF(" ");     
+    }
+    DFPRINTF("\n");
+    return;
+}
+
+void debug_output(uint64_t progress, uint64_t size)
+{
+       uint64_t blocks = size/20;
+
+       /*Output progress every 5% */   
+       if (progress/blocks > prev) {
+               memcpy(output+prev+1,"=>",2);
+               prev++;
+               DFPRINTF("\r%s     %llu%%", output, 
+                       (long long)(prev-1)*5);
+       }
+       return;
+}
+
+static inline void LOCAL_FD_SET(fd_set *readfds) 
+{
+       FD_SET(io_fd[0], readfds);
+       maxfds = io_fd[0] + 1;
+       
+       return;
+}
+
+static int get_image_info(struct td_state *s, int fd)
+{
+       int ret;
+       long size;
+       unsigned long total_size;
+       struct statvfs statBuf;
+       struct stat stat;
+
+       ret = fstat(fd, &stat);
+       if (ret != 0) {
+               DFPRINTF("ERROR: fstat failed, Couldn't stat image");
+               return -EINVAL;
+       }
+
+       if (S_ISBLK(stat.st_mode)) {
+               /*Accessing block device directly*/
+               s->size = 0;
+               if (ioctl(fd,BLKGETSIZE,&s->size)!=0) {
+                       DFPRINTF("ERR: BLKGETSIZE failed, "
+                                "couldn't stat image");
+                       return -EINVAL;
+               }
+
+               DFPRINTF("Image size: \n\tpre sector_shift  [%llu]\n\tpost "
+                       "sector_shift [%llu]\n",
+                       (long long unsigned)(s->size << SECTOR_SHIFT),
+                       (long long unsigned)s->size);
+
+               /*Get the sector size*/
+#if defined(BLKSSZGET)
+               {
+                       int arg;
+                       s->sector_size = DEFAULT_SECTOR_SIZE;
+                       ioctl(fd, BLKSSZGET, &s->sector_size);
+                       
+                       if (s->sector_size != DEFAULT_SECTOR_SIZE)
+                               DFPRINTF("Note: sector size is %ld (not %d)\n",
+                                       s->sector_size, DEFAULT_SECTOR_SIZE);
+               }
+#else
+               s->sector_size = DEFAULT_SECTOR_SIZE;
+#endif
+
+       } else {
+               /*Local file? try fstat instead*/
+               s->size = (stat.st_size >> SECTOR_SHIFT);
+               s->sector_size = DEFAULT_SECTOR_SIZE;
+               DFPRINTF("Image size: [%llu]\n",
+                       (long long unsigned)s->size);
+       }
+
+       return 0;
+}
+
+static int send_responses(struct td_state *s, int res, int idx, void *private)
+{
+       if (res < 0) DFPRINTF("AIO FAILURE: res [%d]!\n",res);
+       
+       returned_events++;
+       
+       free(private);
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       struct tap_disk *drv;
+       struct td_state *s;
+       int ret = -1, fd, len;
+       fd_set readfds;
+       struct timeval timeout;
+       uint64_t i;
+       char *buf;
+
+       if (argc != 3) {
+               fprintf(stderr, "Qcow-utils: v1.0.0\n");
+               fprintf(stderr, "usage: %s <QCOW FILENAME> <SRC IMAGE>\n", 
+                       argv[0]);
+               exit(-1);
+       }
+
+       s = malloc(sizeof(struct td_state));
+       
+       /*Open image*/
+       fd = open(argv[2], O_RDONLY | O_LARGEFILE);
+       
+        if (fd == -1) {
+                DFPRINTF("Unable to open [%s], (err %d)!\n",argv[2],0 - errno);
+                exit(-1);
+        }
+       
+       get_image_info(s, fd);
+       
+       /*Create qcow file*/
+       ret = qcow_create(argv[1],s->size<<SECTOR_SHIFT,NULL,0);
+       
+       if (ret < 0) {
+               DFPRINTF("Unable to create QCOW file\n");
+               exit(-1);
+       } else DFPRINTF("Qcow file created: size %llu sectors\n",
+                       (long long unsigned)s->size);
+       
+       drv = &tapdisk_qcow;
+       s->private = malloc(drv->private_data_size);
+
+        /*Open qcow file*/
+        if (drv->td_open(s, argv[1])!=0) {
+               DFPRINTF("Unable to open Qcow file [%s]\n",argv[1]);
+               exit(-1);
+       }
+
+       io_fd = drv->td_get_fd(s);
+
+       /*Initialise the output string*/
+       memset(output,0x20,25);
+       output[0] = '[';
+       output[22] = ']';
+       output[23] = '\0';
+       DFPRINTF("%s",output);
+
+       i = 0;
+       while (running) {
+               timeout.tv_sec = 0;
+               
+               if (!complete) {
+                       /*Read sector from image*/
+                       if (lseek(fd, i, SEEK_SET) == (off_t)-1) {
+                               DFPRINTF("Unable to access file offset %llu\n",
+                                      (long long)i);
+                               exit(-1);
+                       }
+                       
+                       if( (ret = posix_memalign((void **)&buf, 
+                                                 BLOCK_PROCESSSZ, 
+                                                 BLOCK_PROCESSSZ)) != 0) {
+                               DFPRINTF("Unable to read memalign buf 
(%d)\n",ret);
+                               exit(-1);                               
+                       }
+               
+                       /*We attempt to read 4k sized blocks*/
+                       len = read(fd, buf, BLOCK_PROCESSSZ);
+                       if (len < 512) {
+                               DFPRINTF("Unable to read sector %llu\n",
+                                      (long long unsigned) (i >> 9));
+                               complete = 1;
+                               continue;
+                       }
+                       
+                       if (len % 512) {
+                               len = (len >> 9) << 9;
+                       }
+
+                       ret = drv->td_queue_write(s, i >> 9,
+                                                 len >> 9, buf, 
+                                                 send_responses, 0, buf);
+                               
+                       if (!ret) submit_events++;
+                               
+                       if (ret < 0) {
+                               DFPRINTF("UNABLE TO WRITE block [%llu]\n",
+                                      (long long unsigned) (i >> 9));
+                       } else i += len;
+                       
+                       if (i >> 9 == s->size) complete = 1;
+
+                       debug_output(i,s->size << 9);
+                       
+                       if ((submit_events % 10 == 0) || complete) 
+                               drv->td_submit(s);
+                       timeout.tv_usec = 0;
+                       
+               } else {
+                       timeout.tv_usec = 1000;
+                       if (!submit_events) running = 0;
+               }
+               
+
+               /*Check AIO FD*/
+               LOCAL_FD_SET(&readfds);
+                ret = select(maxfds + 1, &readfds, (fd_set *) 0,
+                             (fd_set *) 0, &timeout);
+                            
+               if (ret > 0) drv->td_do_callbacks(s, 0);
+               if (complete && (returned_events == submit_events)) 
+                       running = 0;
+       }
+       memcpy(output+prev+1,"=",1);
+       DFPRINTF("\r%s     100%%\nTRANSFER COMPLETE\n\n", output);
+        drv->td_close(s);
+        free(s->private);
+        free(s);
+               
+       return 0;
+}
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/qcow-create.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/qcow-create.c        Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,80 @@
+/* qcow-create.c
+ *
+ * Generates a qcow format disk.
+ *
+ * (c) 2006 Andrew Warfield and Julian Chesterfield
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/statvfs.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <string.h>
+#include "tapdisk.h"
+
+#if 1
+#define DFPRINTF(_f, _a...) fprintf ( stderr, _f , ## _a )
+#else
+#define DFPRINTF(_f, _a...) ((void)0)
+#endif
+
+
+int main(int argc, char *argv[])
+{
+       int ret = -1;
+       uint64_t size;
+
+       if ( (argc < 3) || (argc > 4) ) {
+               fprintf(stderr, "Qcow-utils: v1.0.0\n");
+               fprintf(stderr, 
+                       "usage: %s <SIZE(MB)> <FILENAME> "
+                       "[<BACKING_FILENAME>]\n", 
+                       argv[0]);
+               exit(-1);
+       }
+
+       size = atoi(argv[1]);
+       size = size << 20;
+       DFPRINTF("Creating file size %llu\n",(long long unsigned)size);
+       switch(argc) {
+       case 3: 
+               ret = qcow_create(argv[2],size,NULL,0);
+               break;
+       case 4:
+               ret = qcow_create(argv[2],size,argv[3],0);
+               break;          
+       }
+       if (ret < 0) DPRINTF("Unable to create QCOW file\n");
+       else DPRINTF("QCOW file successfully created\n");
+
+       return 0;
+}
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/qcow2raw.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/qcow2raw.c   Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,346 @@
+/* qcow2raw.c
+ *
+ * Generates raw image data from an existing qcow image
+ *
+ * (c) 2006 Julian Chesterfield and Andrew Warfield
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/statvfs.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <string.h>
+#include "tapdisk.h"
+
+#if 1
+#define DFPRINTF(_f, _a...) fprintf ( stderr, _f , ## _a )
+#else
+#define DFPRINTF(_f, _a...) ((void)0)
+#endif
+
+#define TAPDISK 1
+#define BLOCK_PROCESSSZ 4096
+
+static int maxfds, *qcowio_fd, *aio_fd, running = 1, complete = 0; 
+static int read_complete = 0, write_complete = 0;
+static int returned_read_events = 0, returned_write_events = 0;
+static int submit_events = 0;
+static uint32_t read_idx = 0, write_idx = 0;
+struct tap_disk *drv1, *drv2;
+struct td_state *sqcow, *saio;
+static uint64_t prev = 0, written = 0;
+static char output[25];
+
+void print_bytes(void *ptr, int length) {
+
+  int i,k;
+  unsigned char *p = ptr;
+
+    DFPRINTF("Buf dump, length %d:\n",length);
+    for (k = 0; k < length; k++) {
+        DFPRINTF("%x",*p);
+        *p++;
+       if (k % 16 == 0) DFPRINTF("\n");
+        else if (k % 2 == 0) DFPRINTF(" ");    
+    }
+    DFPRINTF("\n");
+    return;
+}
+
+void debug_output(uint64_t progress, uint64_t size)
+{
+       /*Output progress every 5% */   
+       uint64_t blocks = size/20;
+
+       if (progress/blocks > prev) {
+               memcpy(output+prev+1,"=>",2);
+               prev++;
+               DFPRINTF("\r%s     %llu%%", 
+                       output, (long long)((prev-1)*5));
+       }
+       return;
+}
+
+static inline void LOCAL_FD_SET(fd_set *readfds) 
+{
+       FD_SET(qcowio_fd[0], readfds);
+       FD_SET(aio_fd[0], readfds);
+       
+       maxfds = (qcowio_fd[0] > aio_fd[0] ? qcowio_fd[0] : aio_fd[0]) + 1;
+       
+       return;
+}
+
+static int send_write_responses(struct td_state *s, int res, int idx, void 
*private)
+{
+       if (res < 0) {
+               DFPRINTF("AIO FAILURE: res [%d]!\n",res);
+               return 0;
+       }
+       written += BLOCK_PROCESSSZ;
+       returned_write_events++;
+       write_idx = idx;
+       if (complete && (returned_write_events == submit_events)) 
+               write_complete = 1;
+
+       debug_output(written, s->size << 9);
+       free(private);
+       return 0;
+}
+
+static int send_read_responses(struct td_state *s, int res, int idx, void 
*private)
+{
+       int ret;
+
+       if (res < 0) DFPRINTF("AIO FAILURE: res [%d]!\n",res);
+       
+       returned_read_events++;
+       read_idx = idx;
+       if (complete && (returned_read_events == submit_events)) 
+               read_complete = 1;
+       
+       ret = drv2->td_queue_write(saio, idx, BLOCK_PROCESSSZ>>9, private, 
+                                  send_write_responses, idx, private);
+       if (ret != 0) {
+               DFPRINTF("ERROR in submitting queue write!\n");
+               return 0;
+       }
+
+       if ( (complete && returned_read_events == submit_events) || 
+            (returned_read_events % 10 == 0) ) {
+               drv2->td_submit(saio);
+       }
+
+       return 0;
+}
+
+int main(int argc, char *argv[])
+{
+       int ret = -1, fd, len,input;
+       long int size;
+       fd_set readfds;
+       struct timeval timeout;
+       uint64_t i;
+       char *buf;
+       struct stat finfo;
+
+       if (argc != 3) {
+               fprintf(stderr, "Qcow-utils: v1.0.0\n");
+               fprintf(stderr, "usage: %s <Dest File descriptor> "
+                       "<Qcow SRC IMAGE>\n", 
+                      argv[0]);
+               exit(-1);
+       }
+
+       sqcow = malloc(sizeof(struct td_state));
+       saio  = malloc(sizeof(struct td_state));
+       
+       /*Open qcow source file*/       
+       drv1 = &tapdisk_qcow;
+       sqcow->private = malloc(drv1->private_data_size);
+
+        if (drv1->td_open(sqcow, argv[2])!=0) {
+               DFPRINTF("Unable to open Qcow file [%s]\n",argv[2]);
+               exit(-1);
+       } else DFPRINTF("QCOW file opened, size %llu\n",
+                     (long long unsigned)sqcow->size);
+
+       qcowio_fd = drv1->td_get_fd(sqcow);
+
+        /*Setup aio destination file*/
+       ret = stat(argv[1],&finfo);
+       if (ret == -1) {
+               /*Check errno*/
+               switch(errno) {
+               case ENOENT:
+                       /*File doesn't exist, create*/
+                       fd = open(argv[1], 
+                                 O_RDWR | O_LARGEFILE | O_CREAT, 0644);
+                       if (fd < 0) {
+                               DFPRINTF("ERROR creating file [%s] "
+                                        "(errno %d)\n",
+                                      argv[1], 0 - errno);
+                               exit(-1);
+                       }
+                       if (ftruncate(fd, (off_t)sqcow->size<<9) < 0) {
+                               DFPRINTF("Unable to create file "
+                                       "[%s] of size %llu (errno %d). "
+                                        "Exiting...\n",
+                                       argv[1], 
+                                       (long long unsigned)sqcow->size<<9, 
+                                       0 - errno);
+                               close(fd);
+                               exit(-1);
+                       }
+                       close(fd);
+                       break;
+               case  ENXIO:
+                       DFPRINTF("ERROR Device [%s] does not exist\n",argv[1]);
+                       exit(-1);
+               default: 
+                       DFPRINTF("An error occurred opening Device [%s] "
+                                "(errno %d)\n",
+                              argv[1], 0 - errno);
+                       exit(-1);
+               }
+       } else {                
+               fprintf(stderr, "WARNING: All existing data in "
+                       "%s will be overwritten.\nDo you wish to continue? "
+                       "(y or n)  ",
+                       argv[1]);
+               if (getchar() != 'y') {
+                       DFPRINTF("Exiting...\n");
+                       exit(-1);
+               }
+               
+               /*TODO - Test the existing file or device for adequate space*/
+               fd = open(argv[1], O_RDWR | O_LARGEFILE);
+               if (fd < 0) {
+                       DFPRINTF("ERROR: opening file [%s] (errno %d)\n",
+                              argv[1], 0 - errno);
+                       exit(-1);
+               }
+
+               if (S_ISBLK(finfo.st_mode)) {
+                       if(ioctl(fd,BLKGETSIZE,&size)!=0) {
+                               DFPRINTF("ERROR: BLKGETSIZE failed, "
+                                       "couldn't stat image [%s]\n", 
+                                       argv[1]);
+                               close(fd);
+                               exit(-1);
+                       }
+                       if (size < sqcow->size<<9) {
+                               DFPRINTF("ERROR: Not enough space on device "
+                                       "%s (%lu bytes available, %llu bytes 
required\n",
+                                       argv[1], size, 
+                                       (long long unsigned)sqcow->size<<9);
+                               close(fd);
+                               exit(-1);                               
+                       }
+               } else {
+                       if (ftruncate(fd, (off_t)sqcow->size<<9) < 0) {
+                               DFPRINTF("Unable to create file "
+                                       "[%s] of size %llu (errno %d). "
+                                        "Exiting...\n",
+                                       argv[1], 
+                                       (long long unsigned)sqcow->size<<9, 
+                                        0 - errno);
+                               close(fd);
+                               exit(-1);
+                       } else DFPRINTF("File [%s] truncated to length %llu "
+                                       "(%llu)\n", 
+                                      argv[1], 
+                                      (long long unsigned)sqcow->size<<9, 
+                                      (long long unsigned)sqcow->size);
+               }
+               close(fd);
+       }
+
+       /*Open aio destination file*/   
+       drv2 = &tapdisk_aio;
+       saio->private = malloc(drv2->private_data_size);
+
+        if (drv2->td_open(saio, argv[1])!=0) {
+               DFPRINTF("Unable to open Qcow file [%s]\n", argv[1]);
+               exit(-1);
+       }
+
+       aio_fd = drv2->td_get_fd(saio);
+
+       /*Initialise the output string*/
+       memset(output,0x20,25);
+       output[0] = '[';
+       output[22] = ']';
+       output[23] = '\0';
+       DFPRINTF("%s",output);
+
+       i = 0;
+       while (running) {
+               timeout.tv_sec = 0;
+               
+               if (!complete) {
+                       /*Read Pages from qcow image*/
+                       if ( (ret = posix_memalign((void **)&buf, 
+                                                  BLOCK_PROCESSSZ, 
+                                                  BLOCK_PROCESSSZ))
+                            != 0) {
+                               DFPRINTF("Unable to alloc memory (%d)\n",ret);
+                               exit(-1);                               
+                       }
+               
+                       /*Attempt to read 4k sized blocks*/
+                       ret = drv1->td_queue_read(sqcow, i>>9,
+                                                 BLOCK_PROCESSSZ>>9, buf, 
+                                                 send_read_responses, i>>9, 
buf);
+
+                       if (ret < 0) {
+                               DFPRINTF("UNABLE TO READ block [%llu]\n",
+                                      (long long unsigned)i);
+                               exit(-1);
+                       } else {
+                               i += BLOCK_PROCESSSZ;
+                               submit_events++;
+                       }
+
+                       if (i >= sqcow->size<<9) {
+                               complete = 1;
+                       }
+                       
+                       if ((submit_events % 10 == 0) || complete) 
+                               drv1->td_submit(sqcow);
+                       timeout.tv_usec = 0;
+                       
+               } else {
+                       timeout.tv_usec = 1000;
+                       if (!submit_events) running = 0;
+               }
+               
+
+               /*Check AIO FD*/
+               LOCAL_FD_SET(&readfds);
+                ret = select(maxfds + 1, &readfds, (fd_set *) 0,
+                             (fd_set *) 0, &timeout);
+                            
+               if (ret > 0) {
+                       if (FD_ISSET(qcowio_fd[0], &readfds)) 
+                               drv1->td_do_callbacks(sqcow, 0);
+                       if (FD_ISSET(aio_fd[0], &readfds)) 
+                               drv2->td_do_callbacks(saio, 0);
+               }
+               if (complete && (returned_write_events == submit_events)) 
+                       running = 0;
+       }
+       memcpy(output+prev+1,"=",1);
+       DFPRINTF("\r%s     100%%\nTRANSFER COMPLETE\n\n", output);
+               
+       return 0;
+}
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/tapdisk.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/tapdisk.c    Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,671 @@
+/* tapdisk.c
+ *
+ * separate disk process, spawned by blktapctrl. Inherits code from driver 
+ * plugins
+ * 
+ * Copyright (c) 2005 Julian Chesterfield and Andrew Warfield.
+ *
+ */
+
+#define MSG_SIZE 4096
+#define TAPDISK
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/poll.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+#include <err.h>
+#include <poll.h>
+#include <sys/statvfs.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include "blktaplib.h"
+#include "tapdisk.h"
+
+#if 1                                                                        
+#define ASSERT(_p) \
+    if ( !(_p) ) { DPRINTF("Assertion '%s' failed, line %d, file %s", #_p , \
+    __LINE__, __FILE__); *(int*)0=0; }
+#else
+#define ASSERT(_p) ((void)0)
+#endif 
+
+#define INPUT 0
+#define OUTPUT 1
+
+static int maxfds, fds[2], run = 1;
+
+static pid_t process;
+int connected_disks = 0;
+fd_list_entry_t *fd_start = NULL;
+
+void usage(void) 
+{
+       fprintf(stderr, "blktap-utils: v1.0.0\n");
+       fprintf(stderr, "usage: tapdisk <READ fifo> <WRITE fifo>\n");
+        exit(-1);
+}
+
+void daemonize(void)
+{
+       int i;
+
+       if (getppid()==1) return; /* already a daemon */
+       if (fork() != 0) exit(0);
+
+#if 0
+       /*Set new program session ID and close all descriptors*/
+       setsid();
+       for (i = getdtablesize(); i >= 0; --i) close(i);
+
+       /*Send all I/O to /dev/null */
+       i = open("/dev/null",O_RDWR);
+       dup(i); 
+       dup(i);
+#endif
+       return;
+}
+
+static void unmap_disk(struct td_state *s)
+{
+       tapdev_info_t *info = s->ring_info;
+       struct tap_disk *drv = s->drv;
+       fd_list_entry_t *ptr, *prev;
+
+       drv->td_close(s);
+
+       if (info != NULL && info->mem > 0) 
+               munmap(info->mem, PAGE_SIZE * BLKTAP_MMAP_REGION_SIZE);
+
+       ptr = s->fd_entry;
+       prev = ptr->prev;
+
+       if (prev) {
+               /*There are entries earlier in the list*/
+               prev->next = ptr->next;
+               if (ptr->next) {
+                       ptr = ptr->next;
+                       ptr->prev = prev;
+               }
+       } else {
+               /*We are the first entry in list*/
+               if (ptr->next) {
+                       ptr = ptr->next;
+                       fd_start = ptr;
+                       ptr->prev = NULL;
+               } else fd_start = NULL;
+       }
+
+       close(info->fd);
+
+       free(s->fd_entry);
+       free(s->blkif);
+       free(s->ring_info);
+       free(s);
+
+       return;
+
+}
+
+void sig_handler(int sig)
+{
+       /*Received signal to close. If no disks are active, we close app.*/
+
+       if (connected_disks < 1) run = 0;       
+}
+
+static inline int LOCAL_FD_SET(fd_set *readfds)
+{
+       fd_list_entry_t *ptr;
+       int i;
+
+       ptr = fd_start;
+       while (ptr != NULL) {
+               if (ptr->tap_fd) {
+                       FD_SET(ptr->tap_fd, readfds);
+                       for (i = 0; i < MAX_IOFD; i++) {
+                               if (ptr->io_fd[i]) 
+                                       FD_SET(ptr->io_fd[i], readfds);
+                               maxfds = (ptr->io_fd[i] > maxfds ? 
+                                         ptr->io_fd[i]: maxfds);
+                       }
+                       maxfds = (ptr->tap_fd > maxfds ? ptr->tap_fd: maxfds);
+               }
+               ptr = ptr->next;
+       }
+
+       return 0;
+}
+
+static inline fd_list_entry_t *add_fd_entry(int tap_fd, int io_fd[MAX_IOFD], 
struct td_state *s)
+{
+       fd_list_entry_t *ptr, *last, *entry;
+       int i;
+       DPRINTF("Adding fd_list_entry\n");
+
+       /*Add to linked list*/
+       s->fd_entry = entry = malloc(sizeof(fd_list_entry_t));
+       entry->tap_fd = tap_fd;
+       for (i = 0; i < MAX_IOFD; i++) entry->io_fd[i] = io_fd[i];
+       entry->s = s;
+       entry->next = NULL;
+
+       ptr = fd_start;
+       if (ptr == NULL) {
+               /*We are the first entry*/
+               fd_start = entry;
+               entry->prev = NULL;
+               goto finish;
+       }
+
+       while (ptr != NULL) {
+               last = ptr;
+               ptr = ptr->next;
+       }
+       last->next = entry;
+       entry->prev = last;
+
+ finish:
+       return entry;
+}
+
+static inline struct td_state *get_state(int cookie)
+{
+       fd_list_entry_t *ptr;
+
+       ptr = fd_start;
+       while (ptr != NULL) {
+               if (ptr->cookie == cookie) return ptr->s;
+               ptr = ptr->next;
+       }
+       return NULL;
+}
+
+static struct tap_disk *get_driver(int drivertype)
+{
+       /* blktapctrl has passed us the driver type */
+       
+       return dtypes[drivertype]->drv;
+}
+
+static struct td_state *state_init(void)
+{
+       int i;
+       struct td_state *s;
+       blkif_t *blkif;
+
+       s = malloc(sizeof(struct td_state));
+       blkif = s->blkif = malloc(sizeof(blkif_t));
+       s->ring_info = malloc(sizeof(tapdev_info_t));
+
+       for (i = 0; i < MAX_REQUESTS; i++)
+               blkif->pending_list[i].count = 0;
+
+       return s;
+}
+
+static int map_new_dev(struct td_state *s, int minor)
+{
+       int tap_fd;
+       tapdev_info_t *info = s->ring_info;
+       char *devname;
+       fd_list_entry_t *ptr;
+
+       asprintf(&devname,"%s/%s%d", BLKTAP_DEV_DIR, BLKTAP_DEV_NAME, minor);
+       tap_fd = open(devname, O_RDWR);
+       if (tap_fd == -1) 
+       {
+               DPRINTF("open failed on dev %s!",devname);
+               goto fail;
+       } 
+       info->fd = tap_fd;
+
+       /*Map the shared memory*/
+       info->mem = mmap(0, PAGE_SIZE * BLKTAP_MMAP_REGION_SIZE, 
+                         PROT_READ | PROT_WRITE, MAP_SHARED, info->fd, 0);
+       if ((long int)info->mem == -1) 
+       {
+               DPRINTF("mmap failed on dev %s!\n",devname);
+               goto fail;
+       }
+
+       /* assign the rings to the mapped memory */ 
+       info->sring = (blkif_sring_t *)((unsigned long)info->mem);
+       BACK_RING_INIT(&info->fe_ring, info->sring, PAGE_SIZE);
+       
+       info->vstart = 
+               (unsigned long)info->mem + (BLKTAP_RING_PAGES << PAGE_SHIFT);
+
+       ioctl(info->fd, BLKTAP_IOCTL_SENDPID, process );
+       ioctl(info->fd, BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_INTERPOSE );
+       free(devname);
+
+       /*Update the fd entry*/
+       ptr = fd_start;
+       while (ptr != NULL) {
+               if (s == ptr->s) {
+                       ptr->tap_fd = tap_fd;
+                       break;
+               }
+               ptr = ptr->next;
+       }       
+
+       return minor;
+
+ fail:
+       free(devname);
+       return -1;
+}
+
+static int read_msg(char *buf)
+{
+       int length, len, msglen, tap_fd, *io_fd;
+       char *ptr, *path;
+       image_t *img;
+       struct timeval timeout;
+       msg_hdr_t *msg;
+       msg_newdev_t *msg_dev;
+       msg_pid_t *msg_pid;
+       struct tap_disk *drv;
+       int ret = -1;
+       struct td_state *s = NULL;
+       fd_list_entry_t *entry;
+
+       length = read(fds[READ], buf, MSG_SIZE);
+
+       if (length > 0 && length >= sizeof(msg_hdr_t)) 
+       {
+               msg = (msg_hdr_t *)buf;
+               DPRINTF("Tapdisk: Received msg, len %d, type %d, UID %d\n",
+                       length,msg->type,msg->cookie);
+
+               switch (msg->type) {
+               case CTLMSG_PARAMS:                     
+                       ptr = buf + sizeof(msg_hdr_t);
+                       len = (length - sizeof(msg_hdr_t));
+                       path = calloc(1, len);
+                       
+                       memcpy(path, ptr, len); 
+                       DPRINTF("Received CTLMSG_PARAMS: [%s]\n", path);
+
+                       /*Assign driver*/
+                       drv = get_driver(msg->drivertype);
+                       if (drv == NULL)
+                               goto params_done;
+                               
+                       DPRINTF("Loaded driver: name [%s], type [%d]\n",
+                               drv->disk_type, msg->drivertype);
+
+                       /* Allocate the disk structs */
+                       s = state_init();
+                       if (s == NULL)
+                               goto params_done;
+
+                       s->drv = drv;
+                       s->private = malloc(drv->private_data_size);
+                       if (s->private == NULL) {
+                               free(s);
+                               goto params_done;
+                       }
+
+                       /*Open file*/
+                       ret = drv->td_open(s, path);
+                       io_fd = drv->td_get_fd(s);
+
+                       entry = add_fd_entry(0, io_fd, s);
+                       entry->cookie = msg->cookie;
+                       DPRINTF("Entered cookie %d\n",entry->cookie);
+                       
+                       memset(buf, 0x00, MSG_SIZE); 
+                       
+               params_done:
+                       if (ret == 0) {
+                               msglen = sizeof(msg_hdr_t) + sizeof(image_t);
+                               msg->type = CTLMSG_IMG;
+                               img = (image_t *)(buf + sizeof(msg_hdr_t));
+                               img->size = s->size;
+                               img->secsize = s->sector_size;
+                               img->info = s->info;
+                       } else {
+                               msglen = sizeof(msg_hdr_t);
+                               msg->type = CTLMSG_IMG_FAIL;
+                               msg->len = msglen;
+                       }
+                       len = write(fds[WRITE], buf, msglen);
+                       free(path);
+                       return 1;
+                       
+                       
+                       
+               case CTLMSG_NEWDEV:
+                       msg_dev = (msg_newdev_t *)(buf + sizeof(msg_hdr_t));
+
+                       s = get_state(msg->cookie);
+                       DPRINTF("Retrieving state, cookie 
%d.....[%s]\n",msg->cookie, (s == NULL ? "FAIL":"OK"));
+                       if (s != NULL) {
+                               ret = ((map_new_dev(s, msg_dev->devnum) 
+                                       == msg_dev->devnum ? 0: -1));
+                               connected_disks++;
+                       }       
+
+                       memset(buf, 0x00, MSG_SIZE); 
+                       msglen = sizeof(msg_hdr_t);
+                       msg->type = (ret == 0 ? CTLMSG_NEWDEV_RSP 
+                                             : CTLMSG_NEWDEV_FAIL);
+                       msg->len = msglen;
+
+                       len = write(fds[WRITE], buf, msglen);
+                       return 1;
+
+               case CTLMSG_CLOSE:
+                       s = get_state(msg->cookie);
+                       if (s) unmap_disk(s);
+                       
+                       connected_disks--;
+                       sig_handler(SIGINT);
+
+                       return 1;                       
+
+               case CTLMSG_PID:
+                       memset(buf, 0x00, MSG_SIZE);
+                       msglen = sizeof(msg_hdr_t) + sizeof(msg_pid_t);
+                       msg->type = CTLMSG_PID_RSP;
+                       msg->len = msglen;
+
+                       msg_pid = (msg_pid_t *)(buf + sizeof(msg_hdr_t));
+                       process = getpid();
+                       msg_pid->pid = process;
+
+                       len = write(fds[WRITE], buf, msglen);
+                       return 1;
+
+               default:
+                       return 0;
+               }
+       }
+       return 0;
+}
+
+static inline int write_rsp_to_ring(struct td_state *s, blkif_response_t *rsp)
+{
+       tapdev_info_t *info = s->ring_info;
+       blkif_response_t *rsp_d;
+       
+       rsp_d = RING_GET_RESPONSE(&info->fe_ring, info->fe_ring.rsp_prod_pvt);
+       memcpy(rsp_d, rsp, sizeof(blkif_response_t));
+       wmb();
+       info->fe_ring.rsp_prod_pvt++;
+       
+       return 0;
+}
+
+static inline void kick_responses(struct td_state *s)
+{
+       tapdev_info_t *info = s->ring_info;
+
+       if (info->fe_ring.rsp_prod_pvt != info->fe_ring.sring->rsp_prod) 
+       {
+               RING_PUSH_RESPONSES(&info->fe_ring);
+               ioctl(info->fd, BLKTAP_IOCTL_KICK_FE);
+       }
+}
+
+void io_done(struct td_state *s, int sid)
+{
+       struct tap_disk *drv = s->drv;
+
+       if (!run) return; /*We have received signal to close*/
+
+       if (drv->td_do_callbacks(s, sid) > 0) kick_responses(s);
+
+       return;
+}
+
+int send_responses(struct td_state *s, int res, int idx, void *private)
+{
+       blkif_request_t *req;
+       int responses_queued = 0;
+       blkif_t *blkif = s->blkif;
+
+       req   = &blkif->pending_list[idx].req;
+                       
+       if ( (idx > MAX_REQUESTS-1) || 
+           (blkif->pending_list[idx].count == 0) )
+       {
+               DPRINTF("invalid index returned(%u)!\n", idx);
+               return 0;
+       }
+       
+       if (res != 0) {
+               DPRINTF("*** request error %d! \n", res);
+               return 0;
+       }
+
+       blkif->pending_list[idx].count--;
+       
+       if (blkif->pending_list[idx].count == 0) 
+       {
+               blkif_request_t tmp;
+               blkif_response_t *rsp;
+               
+               tmp = blkif->pending_list[idx].req;
+               rsp = (blkif_response_t *)req;
+               
+               rsp->id = tmp.id;
+               rsp->operation = tmp.operation;
+               rsp->status = blkif->pending_list[idx].status;
+               
+               write_rsp_to_ring(s, rsp);
+               responses_queued++;
+       }
+       return responses_queued;
+}
+
+static void get_io_request(struct td_state *s)
+{
+       RING_IDX          rp, rc, j, i, ret;
+       blkif_request_t  *req;
+       int idx, nsects;
+       uint64_t sector_nr;
+       char *page;
+       int early = 0; /* count early completions */
+       struct tap_disk *drv = s->drv;
+       blkif_t *blkif = s->blkif;
+       tapdev_info_t *info = s->ring_info;
+
+       if (!run) return; /*We have received signal to close*/
+
+       rp = info->fe_ring.sring->req_prod; 
+       rmb();
+       for (j = info->fe_ring.req_cons; j != rp; j++)
+       {
+               int done = 0; 
+
+               req = NULL;
+               req = RING_GET_REQUEST(&info->fe_ring, j);
+               ++info->fe_ring.req_cons;
+               
+               if (req == NULL) continue;
+               
+               idx = req->id;
+               ASSERT(blkif->pending_list[idx].count == 0);
+               memcpy(&blkif->pending_list[idx].req, req, sizeof(*req));
+               blkif->pending_list[idx].status = BLKIF_RSP_OKAY;
+               blkif->pending_list[idx].count = req->nr_segments;
+
+               sector_nr = req->sector_number;
+
+               for (i = 0; i < req->nr_segments; i++) {
+                       nsects = req->seg[i].last_sect - 
+                                req->seg[i].first_sect + 1;
+       
+                       if ((req->seg[i].last_sect >= PAGE_SIZE >> 9) ||
+                           (nsects <= 0))
+                               continue;
+
+                       page  = (char *)MMAP_VADDR(info->vstart, 
+                                                  (unsigned long)req->id, i);
+                       page += (req->seg[i].first_sect << SECTOR_SHIFT);
+
+                       if (sector_nr >= s->size) {
+                               DPRINTF("Sector request failed:\n");
+                               DPRINTF("%s request, idx [%d,%d] size [%llu], "
+                                       "sector [%llu,%llu]\n",
+                                       (req->operation == BLKIF_OP_WRITE ? 
+                                        "WRITE" : "READ"),
+                                       idx,i,
+                                       (long long unsigned) 
+                                               nsects<<SECTOR_SHIFT,
+                                       (long long unsigned) 
+                                               sector_nr<<SECTOR_SHIFT,
+                                       (long long unsigned) sector_nr);
+                               continue;
+                       }
+                       
+                       switch (req->operation) 
+                       {
+                       case BLKIF_OP_WRITE:
+                               ret = drv->td_queue_write(s, sector_nr,
+                                               nsects, page, send_responses, 
+                                               idx, NULL);
+                               if (ret > 0) early += ret;
+                               else if (ret == -EBUSY) {
+                                       /*
+                                        * TODO: Sector is locked         *
+                                        * Need to put req back on queue  *
+                                        */
+                               }
+                               break;
+                       case BLKIF_OP_READ:
+                               ret = drv->td_queue_read(s, sector_nr,
+                                               nsects, page, send_responses, 
+                                               idx, NULL);
+                               if (ret > 0) early += ret;
+                               else if (ret == -EBUSY) {
+                                       /*
+                                        * TODO: Sector is locked         *
+                                        * Need to put req back on queue  *
+                                        */
+                               }
+                               break;
+                       default:
+                               DPRINTF("Unknown block operation\n");
+                               break;
+                       }
+                       sector_nr += nsects;
+               }
+       }
+
+       /*Batch done*/
+       drv->td_submit(s);
+       
+       if (early > 0) 
+               io_done(s,10);
+               
+       return;
+}
+
+int main(int argc, char *argv[])
+{
+       int len, msglen, ret, i;
+       char *p, *buf;
+       fd_set readfds, writefds;
+       struct timeval timeout;
+       fd_list_entry_t *ptr;
+       struct tap_disk *drv;
+       struct td_state *s;
+       
+       if (argc != 3) usage();
+
+       daemonize();
+
+       openlog("TAPDISK", LOG_CONS|LOG_ODELAY, LOG_DAEMON);
+       /*Setup signal handlers*/
+       signal (SIGBUS, sig_handler);
+       signal (SIGINT, sig_handler);
+
+       /*Open the control channel*/
+       fds[READ] = open(argv[1],O_RDWR|O_NONBLOCK);
+       fds[WRITE] = open(argv[2],O_RDWR|O_NONBLOCK);
+
+       if ( (fds[READ] < 0) || (fds[WRITE] < 0) ) 
+       {
+               DPRINTF("FD open failed [%d,%d]\n",fds[READ], fds[WRITE]);
+               exit(-1);
+       }
+
+       buf = calloc(MSG_SIZE, 1);
+
+       if (buf == NULL) 
+        {
+               DPRINTF("ERROR: allocating memory.\n");
+               exit(-1);
+       }
+
+       while (run) 
+        {
+               ret = 0;
+               FD_ZERO(&readfds);
+               FD_SET(fds[READ], &readfds);
+               maxfds = fds[READ];
+
+               /*Set all tap fds*/
+               LOCAL_FD_SET(&readfds);
+
+               timeout.tv_sec = 0; 
+               timeout.tv_usec = 1000; 
+
+               /*Wait for incoming messages*/
+               ret = select(maxfds + 1, &readfds, (fd_set *) 0, 
+                            (fd_set *) 0, &timeout);
+
+               if (ret > 0) 
+                {
+                       ptr = fd_start;
+                       while (ptr != NULL) {
+                               if (FD_ISSET(ptr->tap_fd, &readfds)) 
+                                       get_io_request(ptr->s);
+                               for (i = 0; i < MAX_IOFD; i++) {
+                                       if (ptr->io_fd[i] && 
+                                          FD_ISSET(ptr->io_fd[i], &readfds)) 
+                                               io_done(ptr->s, i);
+                               }
+
+                               ptr = ptr->next;
+                       }
+
+                       if (FD_ISSET(fds[READ], &readfds))
+                               read_msg(buf);
+               }
+       }
+       free(buf);
+       close(fds[READ]);
+       close(fds[WRITE]);
+
+       ptr = fd_start;
+       while (ptr != NULL) {
+               s = ptr->s;
+               drv = s->drv;
+
+               unmap_disk(s);
+               drv->td_close(s);
+               free(s->private);
+               free(s->blkif);
+               free(s->ring_info);
+               free(s);
+               close(ptr->tap_fd);
+               ptr = ptr->next;
+       }
+       closelog();
+
+       return 0;
+}
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/drivers/tapdisk.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/drivers/tapdisk.h    Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,211 @@
+/* tapdisk.h
+ *
+ * Generic disk interface for blktap-based image adapters.
+ *
+ * (c) 2006 Andrew Warfield and Julian Chesterfield
+ * 
+ * Some notes on the tap_disk interface:
+ * 
+ * tap_disk aims to provide a generic interface to easily implement new 
+ * types of image accessors.  The structure-of-function-calls is similar
+ * to disk interfaces used in qemu/denali/etc, with the significant 
+ * difference being the expectation of asynchronous rather than synchronous 
+ * I/O.  The asynchronous interface is intended to allow lots of requests to
+ * be pipelined through a disk, without the disk requiring any of its own
+ * threads of control.  As such, a batch of requests is delivered to the disk
+ * using:
+ * 
+ *    td_queue_[read,write]()
+ * 
+ * and passing in a completion callback, which the disk is responsible for 
+ * tracking.  The end of a back is marked with a call to:
+ * 
+ *    td_submit()
+ * 
+ * The disk implementation must provide a file handle, which is used to 
+ * indicate that it needs to do work.  tapdisk will add this file handle 
+ * (returned from td_get_fd()) to it's poll set, and will call into the disk
+ * using td_do_callbacks() whenever there is data pending.
+ * 
+ * Two disk implementations demonstrate how this interface may be used to 
+ * implement disks with both asynchronous and synchronous calls.  block-aio.c
+ * maps this interface down onto the linux libaio calls, while block-sync uses 
+ * normal posix read/write.
+ * 
+ * A few things to realize about the sync case, which doesn't need to defer 
+ * io completions:
+ * 
+ *   - td_queue_[read,write]() call read/write directly, and then call the 
+ *     callback immediately.  The MUST then return a value greater than 0
+ *     in order to tell tapdisk that requests have finished early, and to 
+ *     force responses to be kicked to the clents.
+ * 
+ *   - The fd used for poll is an otherwise unused pipe, which allows poll to 
+ *     be safely called without ever returning anything.
+ * 
+ */
+
+#ifndef TAPDISK_H_
+#define TAPDISK_H_
+
+#include <stdint.h>
+#include <syslog.h>
+#include "blktaplib.h"
+
+/*If enabled, log all debug messages to syslog*/
+#if 1
+#define DPRINTF(_f, _a...) syslog( LOG_DEBUG, _f , ## _a )
+#else
+#define DPRINTF(_f, _a...) ((void)0)
+#endif
+
+/* Things disks need to know about, these should probably be in a higher-level
+ * header. */
+#define MAX_REQUESTS            64
+#define MAX_SEGMENTS_PER_REQ    11
+#define SECTOR_SHIFT             9
+#define DEFAULT_SECTOR_SIZE    512
+
+/* This structure represents the state of an active virtual disk.           */
+struct td_state {
+       void *private;
+       void *drv;
+       void *blkif;
+       void *image;
+       void *ring_info;
+       void *fd_entry;
+       char backing_file[1024]; /*Used by differencing disks, e.g. qcow*/
+       long int   sector_size;
+       uint64_t   size;
+       long int   info;
+};
+
+/* Prototype of the callback to activate as requests complete.              */
+typedef int (*td_callback_t)(struct td_state *s, int res, int id, void *prv);
+
+/* Structure describing the interface to a virtual disk implementation.     */
+/* See note at the top of this file describing this interface.              */
+struct tap_disk {
+       const char *disk_type;
+       int private_data_size;
+       int (*td_open)        (struct td_state *s, const char *name);
+       int (*td_queue_read)  (struct td_state *s, uint64_t sector,
+                              int nb_sectors, char *buf, td_callback_t cb,
+                              int id, void *prv);
+       int (*td_queue_write) (struct td_state *s, uint64_t sector,
+                              int nb_sectors, char *buf, td_callback_t cb,
+                              int id, void *prv);
+       int (*td_submit)      (struct td_state *s);
+       int *(*td_get_fd)      (struct td_state *s);
+       int (*td_close)       (struct td_state *s);
+       int (*td_do_callbacks)(struct td_state *s, int sid);
+};
+
+typedef struct disk_info {
+       int  idnum;
+       char name[50];       /* e.g. "RAMDISK" */
+       char handle[10];     /* xend handle, e.g. 'ram' */
+       int  single_handler; /* is there a single controller for all */
+                            /* instances of disk type? */
+#ifdef TAPDISK
+       struct tap_disk *drv;   
+#endif
+} disk_info_t;
+
+void debug_fe_ring(struct td_state *s);
+
+extern struct tap_disk tapdisk_aio;
+extern struct tap_disk tapdisk_sync;
+extern struct tap_disk tapdisk_vmdk;
+extern struct tap_disk tapdisk_ram;
+extern struct tap_disk tapdisk_qcow;
+
+#define MAX_DISK_TYPES  20
+#define MAX_IOFD        2
+
+#define DISK_TYPE_AIO   0
+#define DISK_TYPE_SYNC  1
+#define DISK_TYPE_VMDK  2
+#define DISK_TYPE_RAM   3
+#define DISK_TYPE_QCOW  4
+
+
+/*Define Individual Disk Parameters here */
+static disk_info_t aio_disk = {
+       DISK_TYPE_AIO,
+       "raw image (aio)",
+       "aio",
+       0,
+#ifdef TAPDISK
+       &tapdisk_aio,
+#endif
+};
+
+static disk_info_t sync_disk = {
+       DISK_TYPE_SYNC,
+       "raw image (sync)",
+       "sync",
+       0,
+#ifdef TAPDISK
+       &tapdisk_sync,
+#endif
+};
+
+static disk_info_t vmdk_disk = {
+       DISK_TYPE_VMDK,
+       "vmware image (vmdk)",
+       "vmdk",
+       1,
+#ifdef TAPDISK
+       &tapdisk_vmdk,
+#endif
+};
+
+static disk_info_t ram_disk = {
+       DISK_TYPE_RAM,
+       "ramdisk image (ram)",
+       "ram",
+       1,
+#ifdef TAPDISK
+       &tapdisk_ram,
+#endif
+};
+
+static disk_info_t qcow_disk = {
+       DISK_TYPE_QCOW,
+       "qcow disk (qcow)",
+       "qcow",
+       0,
+#ifdef TAPDISK
+       &tapdisk_qcow,
+#endif
+};
+
+/*Main disk info array */
+static disk_info_t *dtypes[] = {
+       &aio_disk,
+       &sync_disk,
+       &vmdk_disk,
+       &ram_disk,
+       &qcow_disk,
+};
+
+typedef struct driver_list_entry {
+       void *blkif;
+       void *prev;
+       void *next;
+} driver_list_entry_t;
+
+typedef struct fd_list_entry {
+       int cookie;
+       int  tap_fd;
+       int  io_fd[MAX_IOFD];
+       struct td_state *s;
+       void *prev;
+       void *next;
+} fd_list_entry_t;
+
+int qcow_create(const char *filename, uint64_t total_size,
+               const char *backing_file, int flags);
+
+#endif /*TAPDISK_H_*/
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/lib/Makefile
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/lib/Makefile Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,66 @@
+XEN_ROOT = ../../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+MAJOR    = 3.0
+MINOR    = 0
+SONAME   = libblktap.so.$(MAJOR)
+
+BLKTAP_INSTALL_DIR = /usr/sbin
+
+INSTALL            = install
+INSTALL_PROG       = $(INSTALL) -m0755
+INSTALL_DIR        = $(INSTALL) -d -m0755
+
+INCLUDES += -I. -I.. -I $(XEN_LIBXC) -I $(XEN_XENSTORE)
+
+LIBS     := -lz
+
+SRCS     :=
+SRCS     += xenbus.c blkif.c xs_api.c
+
+CFLAGS   += -Werror
+CFLAGS   += -Wno-unused
+CFLAGS   += -fno-strict-aliasing -fPIC
+CFLAGS   += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE
+# get asprintf():
+CFLAGS   += -D _GNU_SOURCE
+
+# Get gcc to generate the dependencies for us.
+CFLAGS   += -Wp,-MD,.$(@F).d
+CFLAGS   += $(INCLUDES) 
+DEPS     = .*.d
+
+OBJS     = $(patsubst %.c,%.o,$(SRCS))
+IBINS   :=
+
+LIB      = libblktap.a libblktap.so libblktap.so.$(MAJOR) 
libblktap.so.$(MAJOR).$(MINOR)
+
+all: build
+
+build:
+       $(MAKE) libblktap
+
+install: all
+       $(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR)
+       $(INSTALL_DIR) -p $(DESTDIR)/usr/include
+       $(INSTALL_PROG) $(LIB) $(DESTDIR)/usr/$(LIBDIR)
+       $(INSTALL_PROG) blktaplib.h $(DESTDIR)/usr/include
+
+clean:
+       rm -rf *.a *.so *.o *.rpm $(LIB) *~ $(DEPS) xen TAGS
+
+libblktap: $(OBJS) 
+       $(CC) $(CFLAGS) -Wl,-soname -Wl,$(SONAME) -shared         \
+             -L$(XEN_XENSTORE) -l xenstore                       \
+             -o libblktap.so.$(MAJOR).$(MINOR) $^ $(LIBS)
+       ln -sf libblktap.so.$(MAJOR).$(MINOR) libblktap.so.$(MAJOR)
+       ln -sf libblktap.so.$(MAJOR) $@.so
+       ar rc libblktap.a $@.so
+
+.PHONY: TAGS all build clean install libblktap
+
+TAGS:
+       etags -t $(SRCS) *.h
+
+-include $(DEPS)
+
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/lib/blkif.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/lib/blkif.c  Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,185 @@
+/*
+ * tools/blktap_user/blkif.c
+ * 
+ * The blkif interface for blktap.  A blkif describes an in-use virtual disk.
+ * (c) 2005 Andrew Warfield and Julian Chesterfield
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <err.h>
+#include <unistd.h>
+
+#include "blktaplib.h"
+
+#if 0
+#define DPRINTF(_f, _a...) printf ( _f , ## _a )
+#else
+#define DPRINTF(_f, _a...) ((void)0)
+#endif
+
+#define BLKIF_HASHSZ 1024
+#define BLKIF_HASH(_d,_h) (((int)(_d)^(int)(_h))&(BLKIF_HASHSZ-1))
+
+static blkif_t      *blkif_hash[BLKIF_HASHSZ];
+
+blkif_t *blkif_find_by_handle(domid_t domid, unsigned int handle)
+{
+       blkif_t *blkif = blkif_hash[BLKIF_HASH(domid, handle)];
+       while ( (blkif != NULL) && 
+               ((blkif->domid != domid) || (blkif->handle != handle)) )
+               blkif = blkif->hash_next;
+       return blkif;
+}
+
+blkif_t *alloc_blkif(domid_t domid)
+{
+       blkif_t *blkif;
+       DPRINTF("Alloc_blkif called [%d]\n",domid);
+       blkif = (blkif_t *)malloc(sizeof(blkif_t));
+       if (!blkif)
+               return NULL;
+       memset(blkif, 0, sizeof(*blkif));
+       blkif->domid = domid;
+       blkif->devnum = -1;
+       return blkif;
+}
+
+/*Controller callbacks*/
+static int (*new_devmap_hook)(blkif_t *blkif) = NULL;
+void register_new_devmap_hook(int (*fn)(blkif_t *blkif))
+{
+       new_devmap_hook = fn;
+}
+
+static int (*new_unmap_hook)(blkif_t *blkif) = NULL;
+void register_new_unmap_hook(int (*fn)(blkif_t *blkif))
+{
+       new_unmap_hook = fn;
+}
+
+static int (*new_blkif_hook)(blkif_t *blkif) = NULL;
+void register_new_blkif_hook(int (*fn)(blkif_t *blkif))
+{
+       new_blkif_hook = fn;
+}
+
+int blkif_init(blkif_t *blkif, long int handle, long int pdev, 
+               long int readonly)
+{
+       domid_t domid;
+       blkif_t **pblkif;
+       int devnum;
+       
+       if (blkif == NULL)
+               return -EINVAL;
+       
+       domid = blkif->domid;
+       blkif->handle   = handle;
+       blkif->pdev     = pdev;
+       blkif->readonly = readonly;
+       
+       /*
+        * Call out to the new_blkif_hook. 
+        * The tap application should define this,
+        * and it should return having set blkif->ops
+        * 
+        */
+       if (new_blkif_hook == NULL)
+       {
+               DPRINTF("Probe detected a new blkif, but no new_blkif_hook!");
+               return -1;
+       }
+       if (new_blkif_hook(blkif)!=0) {
+               DPRINTF("BLKIF: Image open failed\n");
+               return -1;
+       }
+       
+       /* Now wire it in. */
+       pblkif = &blkif_hash[BLKIF_HASH(domid, handle)];
+       DPRINTF("Created hash entry: %d [%d,%ld]\n", 
+               BLKIF_HASH(domid, handle), domid, handle);
+       
+       while ( *pblkif != NULL )
+       {
+               if ( ((*pblkif)->domid == domid) && 
+                    ((*pblkif)->handle == handle) )
+               {
+                       DPRINTF("Could not create blkif: already exists\n");
+                       return -1;
+               }
+               pblkif = &(*pblkif)->hash_next;
+       }
+       blkif->hash_next = NULL;
+       *pblkif = blkif;
+       
+       if (new_devmap_hook == NULL)
+       {
+               DPRINTF("Probe setting up new blkif but no devmap hook!");
+               return -1;
+       }
+       
+       devnum = new_devmap_hook(blkif);
+       if (devnum == -1)
+               return -1;
+       blkif->devnum = devnum;
+       
+       return 0;
+}
+
+void free_blkif(blkif_t *blkif)
+{
+       blkif_t **pblkif, *curs;
+       image_t *image;
+       
+       pblkif = &blkif_hash[BLKIF_HASH(blkif->domid, blkif->handle)];
+       while ( (curs = *pblkif) != NULL )
+       {
+               if ( blkif == curs )
+               {
+                       *pblkif = curs->hash_next;
+               }
+               pblkif = &curs->hash_next;
+       }
+       if (blkif != NULL) {
+               if ((image=(image_t *)blkif->prv)!=NULL) {
+                       free(blkif->prv);
+               }
+               if (blkif->info!=NULL) {
+                       free(blkif->info);
+               }
+               if (new_unmap_hook != NULL) new_unmap_hook(blkif);
+               free(blkif);
+       }
+}
+
+void __init_blkif(void)
+{    
+       memset(blkif_hash, 0, sizeof(blkif_hash));
+}
diff -r af9809f51f81 -r 2937703f0ed0 tools/blktap/lib/blktaplib.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/blktap/lib/blktaplib.h      Thu Jul 13 10:13:26 2006 +0100
@@ -0,0 +1,223 @@
+/* blktaplib.h
+ *
+ * Blktap library userspace code.
+ *
+ * (c) 2005 Andrew Warfield and Julian Chesterfield
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation; or, when distributed
+ * separately from the Linux kernel or incorporated into other
+ * software packages, subject to the following license:
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this source file (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy, modify,
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __BLKTAPLIB_H__
+#define __BLKTAPLIB_H__
+
+#include <xenctrl.h>
+#include <sys/user.h>
+#include <xen/xen.h>
+#include <xen/io/blkif.h>
+#include <xen/io/ring.h>
+#include <xs.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE)
+
+/* size of the extra VMA area to map in attached pages. */
+#define BLKTAP_VMA_PAGES BLK_RING_SIZE
+
+/* blktap IOCTLs: These must correspond with the blktap driver ioctls*/
+#define BLKTAP_IOCTL_KICK_FE         1
+#define BLKTAP_IOCTL_KICK_BE         2
+#define BLKTAP_IOCTL_SETMODE         3
+#define BLKTAP_IOCTL_SENDPID        4
+#define BLKTAP_IOCTL_NEWINTF        5
+#define BLKTAP_IOCTL_MINOR          6
+#define BLKTAP_IOCTL_MAJOR          7
+#define BLKTAP_QUERY_ALLOC_REQS      8
+#define BLKTAP_IOCTL_FREEINTF       9
+#define BLKTAP_IOCTL_PRINT_IDXS      100   
+
+/* blktap switching modes: (Set with BLKTAP_IOCTL_SETMODE)             */
+#define BLKTAP_MODE_PASSTHROUGH      0x00000000  /* default            */
+#define BLKTAP_MODE_INTERCEPT_FE     0x00000001
+#define BLKTAP_MODE_INTERCEPT_BE     0x00000002
+
+#define BLKTAP_MODE_INTERPOSE \
+           (BLKTAP_MODE_INTERCEPT_FE | BLKTAP_MODE_INTERCEPT_BE)
+
+static inline int BLKTAP_MODE_VALID(unsigned long arg)
+{
+       return (
+               ( arg == BLKTAP_MODE_PASSTHROUGH  ) ||
+               ( arg == BLKTAP_MODE_INTERCEPT_FE ) ||
+               ( arg == BLKTAP_MODE_INTERPOSE    ) );
+}
+
+#define MAX_REQUESTS            64

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


 


Rackspace

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