# 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
|