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
(the minor number is the number following "tapdev", i.e. 0 in this example). This is the path which will be the block device later.
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