Mounting a .vhd disk image using blktap/tapdisk

This page describes how to mount a .vhd disk image on a Linux system, using blktap/tapdisk. This allows you to modify and manipulate a .vhd disk image before booting a VM from it.
== Overview ==
A .vhd disk image is a format originally created by Connectix for their Virtual PC and Virtual Server products, sold to Microsoft in 2003. The .vhd format is well-documented and supported by blktap/tapdisk. When using .vhd, blktap/tapdisk enable:
* thin-provisioning of disks: blocks are only allocated on first write
* snapshots, clones: gold master images can be used as read-only "parent" disks
Other similar formats exist, most notably [qcow2] used natively by qemu.
== How blktap/tapdisk works ==
"blktap" is a kernel module which is like "tuntap for blocks": it exposes a kernel block device and sends requests to user-space over a shared-memory ring. The only consumer of this ring is "tapdisk": a user-space process which understands the .vhd format (via a shared library called libvhd) and which performs read and write operations via AIO.
Note: when a tapdisk is connected to a blktap, it's important not to interfere with tapdisk (e.g. by killing it) because this will cause in-flight requests on the block device to block.
When tapdisk starts it will call mlockall() to prevent any of its pages being swapped out, which would otherwise lead to deadlocks.
== Prereqs ==
This example assumes Ubuntu 12.04, but similar packages should be available for other distributions. First install the user-space tools and the blktap kernel module (via DKMS):
 $ sudo apt-get install blktap-utils
 $ sudo modprobe blktap
== Attaching a disk ==
First, allocate a minor number in the kernel:
 $ sudo tap-ctl allocate 
 /dev/xen/blktap-2/tapdev0
This is the path which will be the block device later. The minor number is the number following "tapdev", i.e. 0 in this example.
Then, spawn a tapdisk process:
 $ sudo tap-ctl spawn
 tapdisk spawned with pid 5646
Now, you need to attach the two together:
 $ sudo tap-ctl attach -m 0 -p 5646
(where -m <minor> and -p <tapdisk pid>)
Finally, you can open a VHD:
 $ sudo tap-ctl open -m 0 -p 5646 -a vhd:/home/djs/smalltest.vhd
== Detaching a disk ==
Afterwards, you'll need to tear things down. Close the tapdisk image:
 $ sudo tap-ctl close -m 0 -p 5646
Detach the tapdisk process from the kernel - this also kills the tapdisk process
 $ sudo tap-ctl detach -m 0 -p 5646
Now free the kernel minor number:
 $ sudo tap-ctl free -m 0
== Other useful commands ==
To see the state of the system:
 $ sudo tap-ctl list
(nothing allocated or running)
 $ sudo tap-ctl list
 - 0 - - -
(a kernel minor number 0 allocated)
 $ sudo tap-ctl list
 5755 - - - -
 - 0 - - -
(kernel minor number 0 allocated, tapdisk with pid 5755 running, they are not connected together)
 $ sudo tap-ctl list
 5755 0 0 - -
(kernel minor number 0 is connected to tapdisk with pid 5755, but no file is open)
 $ sudo tap-ctl list
 5755 0 0 vhd /home/djs/smalltest.vhd
(kernel minor number 0 is connected to tapdisk with pid 5755, with file /home/djs/smalltest.vhd open)
 $ sudo tap-ctl stats -m 0 -p 5755
 { "name": "vhd:/home/djs/smalltest.vhd", "secs": [ 664, 0 ], "images": [ { "name":
 "/home/djs/smalltest.vhd", "hits": [ 664, 0 ], "fail": [ 0, 0 ], "driver": { "type": 4,
 "name": "vhd", "status": null } } ], "tap": { "minor": 0, "reqs": [ 83, 83 ], "kicks":
 [ 84, 83 ] }, "FIXME_enospc_redirect_count": 0 }
(various stats in .json format)
== Acknowledgements ==
Most of this information was taken from Jon Ludlam's xen-api post