Kemari for KVM
[RFC] KVM Fault Tolerance: Kemari for KVM
Kemari(Xen向け高可用性ソフトウェア)がKVMへのポーティングを計画しているようです。
Sheepdogに比べるとKVMコミュニティの反応が芳しくないみたいですが、おそらくまだコードがないからだと思われます。
とりあえず今後の動向に期待ということで。
KVM関連ソフトウェア/プロジェクト/製品のまとめ
間違いやこれ忘れているよ!といったご指摘がありましたらコメントでツッコミを入れてくれると助かります。
11/6更新
VMM
要素技術
- qemu
- virtio
- 準仮想化I/Oフレームワーク
- Windowsドライバ*2
- 論文もあります*3
- vbus: Virtual-bus
- ↓と目標(高性能)は同じだけど、実装が違うもの
- vhost
- KSM: Kernel Samepage Merging
- ゲスト間のメモリをこっそりマージしてシステム全体の使用メモリを削減
- 2.6.32でマージされました
- d:id:kvm:20091025:1256477597
仮想マシン管理ソフトウェア
- libvirt
- virt-manager
- ↑のGUIフロントエンド
- oVirt
- Webベース
- virt-managerとoVirtの違いについては運用上の課題を解決する管理ツール (1/3):知って見るみるKVM(3) - @ITをどうぞ
- ConVirt
- Eucalyptus
- Cloud基盤ソフトウェア
- OpenNebula
- Private Cloud, Hybrid Cloud基盤ソフトウェア
- 元はGrid向けだったようです
ツール
- libcgroup (libcg)
- cgroupsユーザライブラリ
- KVMの細かい資源配分はcgroupsで制御することになるはず
- guestfish
- qemu(-kvm)を利用した仮想ディスクイメージ操作ツール
- d:id:kvm:20090711:1247323823
- VDE: Virtual Distributed Ethernet
- Open vSwitch
- 仮想マシン間の(仮想)ネットワーク構築を支援するもの?(いろいろ機能がありすぎてよくわからないです。。。)
- http://www.virtualization.info/jp/2009/08/citrix-open-vswitch200908024-10.html
- Sheepdog
- KVM向け分散ストレージ
- NTTの研究所が作成元
Linuxディストリビューション
- Fedora
- KVM正式サポート
- libvirt, virt-manager, guestfish, libcgroupなどの支援ソフトウェアを積極的に開発中
- Ubuntu
- KVM正式サポート
- Eucalyptus, OpenNebulaもレポジトリに入ってます
商用製品・サービス
- Red Hat Enterprise Linux (RHEL)
- 5.4から正式サポート
- KVMを使った商用製品の本命?
- Red Hat Enterprise Virtualization Hypervisor (REVH)/Red Hat Enterprise Virtualization Manager for Servers (REVMS)
- REVMSの方が噂の管理コンソール(のクライアント)がWindowsでしか動かないという例のやつです
- 詳しくは下記記事をご参照ください
- ニュース記事:ITPro, virtualization.info
- Proxmox VE
- NTTコミュニケーションズ グリーンホスティング ベーシック/グリーンストレージ
その他
sourceforgeに色々あるみたいです
更新履歴
- 11/6: virtio Windowsドライバ、sourceforgeリンク、REVH/REVMS追記。kazuさんThanks!
*1:http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=4cd8b5e2a159f18a1507f1187b44a1acbfa6341b
*2:ソース git://git.kernel.org/pub/scm/virt/kvm/kvm-guest-drivers-windows.git
*3:http://portal.acm.org/citation.cfm?id=1400097.1400108
*4:http://repo.or.cz/w/qemu.git?a=blob;f=qemu-options.hx;hb=dfb278bde1f6e6f6507607dc65d7bdacb5f5d77c#l818
KSM内部解析
概要
KSM(Kernel SamePage Merging)とは、ユーザプロセスのメモリ領域を走査して、同一内容のページを1つのページにマージすることで使用メモリ量を削減するLinuxカーネルの機能です。マージされたページはCoW(Copy on Write)状態に設定され、ページへの書き込みが発生すると再び個別のページに分裂されます。
KSMはバージョン2.6.32でマージされ、主に同一内容のページを重複して持つ可能性が比較的多いVM利用時の使用メモリ削減が期待されています。
この記事はKSMの内部構造と動作を解析するものです。
忙しい人のための解析概略
- ユーザインタフェースはmadvise(の新しいオプションMADV_MERGEABLEとMADV_UNMERGEABLE)と/sys/kernel/mm/ksm/以下のsysfsファイル
- ユーザプロセスがmadviseでマージしても良いページを指定
- 管理者がsysfs経由でKSMの動作パラメタを変更
- KSMの仕事は基本的にページをマージさせるところまでで、CoWの動作はLinuxの存在する機能をそのまま使う。
- UNMERGEするときも当該ページに擬似的に書き込みが起きたように見せかけるだけ
- 走査対象メモリはAnonymousメモリのみ(ほんとんどの場合ヒープ領域のはず)
- File Cacheは対象にならない
- 現在の実装ではマージされたページはSwap outされなくなる(制限)
- いずれ解消される予定
- ページを走査するのはksmdというカーネルスレッド
- 指定間隔で指定ページ数だけページ走査を行ない、見つかった同一内容のページをマージしていく
- ページ内容の比較(同定)にはmemcmp(つまり2つのページ全体を舐める)を用いる
- 同一内容ページの探索/挿入/削除は赤黒木を用いることで高速化している
- VMwareの特許を避けるための苦肉の策と思われる
KSMの使い方
この記事では、KSMはどう動いているかに着目するので、KSMのセットアップの方法等には触れません。その辺りは情報は以下のページを参照してください。
注意
解析:データ構造
備考
Stable & unstable trees
- 走査したページを格納するデータ構造
- 赤黒木(Red-Black tree)
- マージできたページをstableにマージできなかった(けど内容に変更がなかった)ページをunstalbe treeに入れる
- 内容に変更があったページは2つの木の中には入れない
- stable treeの要素(node == rmap_item)はリストになっている
- マージされたページは複数のrmap_itemから参照されている
- unstable treeの要素もrmap_item
- ただしリストにはなっていない
mm_slot
- 1 mm_struct (≒プロセス)につき1つ用意される?
- ksmはmm_slotのリストを保持し、そこからvm_area_struct, page tableとたどってpageを取得する
- @link: hash list?
- @mm_list: ksm_mm_head用
- @rmap_list: このmm_slotのrmap_itemリスト
- @mm: 当該mm_struct
- なおmadviseでmm_structと指定された領域をもつvm_area_structにMERGEABLEフラグが設定されている
vm_area_struct単位なのでそれより小さい領域を指定すると多少空回りする?addressを使って無駄をはぶいている
rmap_item
- reverse mapping item for virtual address
- @link: mm_slot用
- rmap_itemは明示的にremoveされない限り基本的に生成されたらmm_slotに繋がれたまま
- 指しているページがマージされてもrmap_itemは残る
- 例外:ただし走査中に変なアドレスを指すrmap_itemがあった場合はremove&freeする
- @address
- low bitはflag
- SENR_MASK:
- NODE_FLAG
- STABLE_FLAG
- low bitはflag
- 1つにつき1ページを指している
- 直接pageを持たない
- pageを得るときは@mm + @addressを使って毎回PTをたどる
- 繋がれている場所によって保持データも違う
- stable tree: @prev, @next, @node: 次のrmap
- 何に使ってるんだろ?
- unstable tree: @oldchecksum, @node
- @nodeがわからん
- stable tree: @prev, @next, @node: 次のrmap
- @oldchecksum: 内容が変更されたか否かの判定のみに利用される
グローバル変数
- ksm_mm_head
- mm_slotリスト
- ksm_scan
- cursor for scanning
- ページ走査カーソル
- 現在走査中のページを指している
- @mm_slot + @address + @rmap_item
- seqnrってどう使われているの?
- root_stable_tree
- root_unstable_tree
- rmap_item_cache?
- mm_slot_cache?
- mm_slots_hash
- mm_slotのリストを要素とするハッシュ
- mm_slotを削除するときだけに使われている
- 通常のmm_slotアクセスはmm_slot_headからリストをたどる
- ハッシュサイズは1,024
- スケールしない気が。。。
- まぁ削除するときだけならスケールする必要はないか
統計値
- ksm_pages_shared
- stable tree内のnode数(!=rmap_item数)
- ksm_page_sharing
- stable tree内の非node数
- ksm_pages_unshared
- unstable tree内のnode数(=rmap_item数)
- ksm_rmap_items
- allocされたrmap_itemの総数(のべ数ではない)
- ksm_pages_volatile
- ksm_rmap_items - ksm_pages_shared - ksm_pages_sharing - ksm_pages_unshared
- これ自体はカウントアップ/ダウンされない
コンフィグ
- ksm_max_kernel_pages (default = 2000)
- ksm_pages_sharedしても良い最大ページ数
- ksm_thread_pages_to_scan (default = 200)
- ksm_thread_sleep_millisecs (default = 20)
- ksm_run (default = 1)
- KSM_RUN_STOP=0
- KSM_RUN_MERGE=1
- KSM_RUN_UNMERGE=2 (強制unmerge)
解析:動作(API)
madvise
- madvise(MADV_MERGEABLE) -> ... -> madvise_behavior() -> ksm_madvise() -> __ksm_enter()
- madvise(MADV_UNMERGEABLE) -> ... -> ksm_madvise()
sysfs
- 個々のグローバル変数が変更される
- run = 1: wake_up_interruptible()
- run = 2: unmerge_and_remove_all_rmap_items()
- mm_slot_headをたどってひたすらKsmPageをunmerge & rmapをfree
- mm_slot自体は残しておく
- 使用メモリが大量に増えると思われるのでやらない方がいいような。。。
__ksm_exit() (ksm_exit())
static inline void ksm_exit(struct mm_struct *mm, struct mmu_gather **tlbp, unsigned long end) { if (test_bit(MMF_VM_MERGEABLE, &mm->flags)) __ksm_exit(mm, tlbp, end); }
- 引数
- struct mm_struct *mm
- struct mmu_gather **tlbp
- unsigned long end
- 動作
- OOM deadlockを考慮してちょっとトリッキーになっている
- mmからmm_slotを得る
- mm_slotがrmap_itemを一つも持っていなければfree_mm_slot()
- mm_structのMERGEABLEフラグを落とす
- そうでなければカーソルの位置を当該mm_slotにしておまじないをして終了
- mm_slotが解放されるタイミング
- unmerge_and_remove_all_rmap_items()
- echo 2 > /sys/kernel/mm/ksm/run
- scan_get_next_rmap_item()
- mm_slotリストを走査中
- unmerge_and_remove_all_rmap_items()
解析:動作(ksmd)
main loop
while (scan_pages--) { page, rmap_item = scan_get_next_rmap_item() if (PageKSM(page) && in_stable_tree(rmap_item) continue cmp_and_merge_page(page, rmap_item) }
scan_get_next_rmap_item()
- mm_slotがなければ終了(スレッドも休眠)
- カーソルがmm_slot_headだったら == mm_slotリストを全て走査した
- 最初から走査するための初期化
- カーソルが指す(mm+address)vm_area_structを走査
- find_vma(mm, ksm_scan.address)
- addressの位置のページから一つずつ取り出す
- 取り出すときは(*)のような感じ
- カーソルはどのタイミングからでもループを抜けて、再度ループの途中から走査を続行するためのもの
- PageAnonがあれば、該当pageとそのrmap_itemを持ってreturn
- rmap_itemはget_next_rmap_item()で取得する
- 正常パスはここで終了
- mm_slotにVM_MERGEABLEなvm_area_structがない場合
- mm_slotをmm_slotリストから外す
- 次のmm_slotを走査
- mm_slotがなければ終了
- 当該vm_area_structリストにこれ以上VM_MERGEABLEがなかった
- 次のmm_slotを走査
- ksm_scan.seqnr++
(*)
foreach (mm_slot in mm_slots where mm_slot->mm_struct is MERGEABLE) {
foreach (vm_area_struct in vm_area_structs of mm_slot->mm_struct where vm_area_struct is MERGEABLE) {
foreach (page in pages of vm_area_struct) { // follow PTs
do_something(page);
}
}
}
get_next_rmap_item()
- 引数
- mm_slot
- cur
- addr
- 動作
- mm_slotのrmap_itemリストをcurの位置からたどってaddrに対応するrmap_itemを得る
- rmap_item.address == addrならばそれを返す
- このときunstable treeに繋がっていれば取り外す
- なければalloc_rmap_item()
- 例外:rmap_item->address <= addrだったらfree_rmap_item()
- どういう場合にこうなる?
cmp_and_merge_page()
- rmap_itemがstable tree内にあったら木から外す
- stable & !KsmPageの場合 == CoWが壊れてた場合
- Stable treeを走査(stable_tree_search)
- 同一ページがあった場合
- pages_sharing++
- stable treeに繋げる
- 同一内容(&違うページ)のページがあった場合
- try_to_merge_with_ksm_page()
- *stable treeにあるページとマージ
- 成功したらstable_tree_append()
- otherwise
- fall through
- 同一ページがあった場合
- ページ内容のチェックサムを計算する
- ページサイズの1/4だけ使う
- チェックサムが変わっていた(== ページ内容が変化した)場合return
- つまりunstable treeにも入れない
- Unstable treeを走査&挿入(unstable_tree_search_insert)
- 同一内容のページがあればそれのrmap_itemを取り出し挿入はしない
- なければ当該rmap_itemを挿入し終了
- 取り出したrmap_itemをtree_rmap_itemと呼ぶ
- 二つのページをマージしようとする
- 成功の場合
- ksm_pages_unshared--
- stable treeにtree_rmap_itemを入れる(stable_tree_insert)
- *失敗したら、2つのページのCoWを壊す
- 成功:
- *stable_tree_insert()内でksm_pages_shared++
- *stable_tree_append()でtree_rmap_itemにrmap_itemを繋げる
- 同一内容のページがあればそれのrmap_itemを取り出し挿入はしない
stable_tree_append()
- 引数
- rmap_item: appendされるrmap_item
- tree_rmap_item: treeにあるrmap_item。NODE_FLAGが立っている(はず)
- 動作
- tree_rmap_itemの真後ろにrmap_itemを繋げる
- rmap_itemにSTABLE_FLAGを立てる
- ksm_pages_sharing++
- 備考
- appendされるrmap_itemはrbtreeの一部に'''ならない'''
try_to_merge_two_pages()
- 引数
- ページ1: page1, mm1, address1
- ページ2: page2, mm2, address2
- 動作
- if (ksm_max_kernel_pages <= ksm_pages_shared) return
- kpage = alloc_page(GFP_HIGHUSER)
- page1のvm_area_structを取ってくる => vma
- copy_user_highpage(kpage, page1, addr1, vma)
- try_to_merge_one_page(vma, page1, kpage)
- write_protect_page()
- ページ内容が同じかチェックしたのちreplace_page()
- *mm1, address1からたどれるpteをkpageのものに置き換える
- *当該pteに対してmmu_notifier->change_pte()を呼ぶ
- try_to_merge_with_ksm_page(mm2, addr2, page2, kpage)
- 失敗したらbreak_cow(mm1, addr1)
get_ksm_page()
- stable_tree_search(), stable_tree_insert()から呼ばれる
- treeにあるrmap_itemからpageを得る
- このときPTをたどる
- 以下の場合NULLが帰ってくる
- rmap_itemが指しているpageがPageKsm()でない
- つまりそのpageがunmergeして単なるPageAnon()になっていた
- rmap_itemが所属するvm_area_structがMERGEABLEでなかった
- rmap_itemが指しているpageがPageKsm()でない
KSM merged!!
どうやら無事にマージされたようです。
git.kernel.org - linux/kernel/git/torvalds/linux-2.6.git/search ksm
2.6.32に間に合って良かったですね(^^
そんなksmですが、どうやらFedora Rawhideでは既に2.6.31にバックポートされているみたいです。 http://cvs.fedoraproject.org/viewvc/rpms/kernel/devel/ にパッチが置いてありますね。
あとksmtunedと呼ばれる、走査ページ数や走査間隔を負荷に合わせて動的に変更するデーモンも開発中みたいです。
http://gitorious.org/ksm-control-scripts/ksm-control-scripts
First attempt to use guestfish/libguestfs
はじめに
Fedora 11にはVMディスクイメージ内のファイル操作のためのツール(guestfish)が用意されています。
VMディスクイメージ内のファイルにアクセスするには、rawイメージならば単純にループバックマウントすれば良いだけですが、qcow2フォーマット等の場合だとqemu-nbdを使う(qemu-nbdの使いかた - KVM日記)などイメージフォーマットを解釈できるツールの併用が必要になり、作業が煩雑になってしまいます。(さらにLVMだったりするとかなり悲惨です;<)
guestfishを使うと、イメージフォーマットやパーティションの位置、マウントポイントや一時ファイルなどを意識することなくスクリプトで、もしくはインタラクティブにファイル操作が可能になります。
準備
以下ではホストOS、ゲストOSともにFedora 11、guestfish(libguestfs)はバージョン1.0.57をhttp://libguestfs.org/download/からダウンロードしてコンパイルしたものを用います。libguestfsをコンパイルするとguestfishが生成されます。guestfishはlibguestfsライブラリを使ってファイル操作を実行します。(libguestfsをコンパイルする途中にfebootstrapが起動してなにやらyum installが始まりますが、これは後で説明するゲスト用カーネルとinitrdを生成するためです。気長に待ちましょう。)
あと準備としてゲストVMディスクイメージを用意します。私はすでにFedora 11がインストールされたイメージを持っていたので、これをベースとするqcow2イメージを作ってそれを使いました。
host$ qemu-img create -b f11.img -f qcow2 f11.qcow2.img
簡単な使い方
では試しに上記イメージ(f11.qcow2.img)内の/root/ディレクトリ(rootパーティションは/dev/sda3にあります)をlsしてみましょう。引数なしでguestfishを起動するとインタラクティブモードになります。(virshに似ていますね。) なおプロンプトは">
host$ guestfish Welcome to guestfish, the libguestfs filesystem interactive shell for editing virtual machine filesystems. Type: 'help' for help with commands 'quit' to quit the shell ><fs> add-drive f11.qcow2.img ><fs> launch ><fs> mount /dev/sda3 / ><fs> ls /root/ .bash_history .bash_logout .bash_profile .bashrc .cshrc .tcshrc anaconda-ks.cfg install.log install.log.syslog
このように無事ファイルリストを得ることができました。
次はホストにあるファイルをコピーしてみましょう。
host$ echo hoge > /tmp/fuga ><fs> ls /tmp/ .ICE-unix yum.log ><fs> upload /tmp/fuga /tmp/fuga ><fs> ls /tmp/ .ICE-unix fuga yum.log ><fs> cat /tmp/fuga hoge
うまくいきました。
guestfishではゲスト内にあるファイルをviで編集することもできます。
><fs> edit /tmp/fuga ><fs> cat /tmp/fuga hoge fuga
作業が終わったら以下のようにguestfishを終了させます。
><fs> umount-all ><fs> kill-subprocess ><fs> quit
launchやumount-allだけでなくlsやmountも実はguestfishの内部コマンドです。(commandというディスクイメージ内の任意のコマンドを実行するコマンドもあります。)使用可能なコマンドはオンラインマニュアル等を参照してください。
内部実装
さてここからは内部実装の話題です。(むしろこっちがメイン?)
guestfishはどうやってVMディスクイメージの内部にアクセスしているのでしょうか?実はguestfishはサブプロセスとしてqemu(VM)を起動し、そのqemuがVMディスクイメージのマウントやファイルアクセスを行なっています。
上記例では、launchコマンドの箇所でqemuが起動しています。psで見てみると下ようなqemuプロセスが立ち上がっているのがわかります。
host$ ps xa |grep qemu-kvm /usr/bin/qemu-kvm -drive file=f11.qcow2.img,cache=off,if=ide -m 500 -no-reboot -kernel /usr/local/lib/guestfs/vmlinuz.fedora-11.x86_64 -initrd /usr/local/lib/guestfs/initramfs.fedora-11.x86_64.img -append panic=1 console=ttyS0 guestfs=10.0.2.4:6666 -nographic -serial stdio -net channel,6666:unix:/tmp/libguestfsQz9LZs/sock,server,nowait -net user,vlan=0 -net nic,model=virtio,vlan=0 -no-hpet -rtc-td-hack
この中の-kernel, -initrdで指定しているのがlibguestfsのコンパイル時にゴリゴリと生成していたカーネルとinitrdです。
host$ file /usr/local/lib/guestfs/* /usr/local/lib/guestfs/initramfs.fedora-11.x86_64.img: gzip compressed data, from Unix, last modified: Sat Jul 11 01:02:44 2009, max compression /usr/local/lib/guestfs/vmlinuz.fedora-11.x86_64: Linux kernel x86 boot executable bzImage, version 2.6.29.5-191.fc11.x86_64 (mockb, RO-rootFS, root_dev 0x902, swap_dev 0x2, Normal VGA
つまり、guestfishで立ち上げるVMではVMディスクイメージ内部のカーネルは使っていないということですね。
さて今度は引数"-net channel,6666:unix:/tmp/libguestfsQz9LZs/sock,server,nowait"とゲストカーネル引数(-append)に指定している"guestfs=10.0.2.4:6666"に注目してみましょう。
前者は、/tmp/libguestfsQz9LZs/sock (UNIXソケット)へのtcp接続はゲスト内部の6666ポートへ転送しろ、という意味で、qemuの機能です。netstatで見ると確かにqemuがLISTENしていますね。
host$ sudo netstat -nap |grep libguestfs unix 2 [ ACC ] STREAM LISTENING 2203601 1993/qemu-kvm /tmp/libguestfsQz9LZs/sock unix 3 [ ] STREAM CONNECTED 2203606 1993/qemu-kvm /tmp/libguestfsQz9LZs/sock
guestfishはこのUNIXソケットを介してゲスト内のデーモンにコマンド実行をお願いしているようです。
では、ゲスト内で動いているのは誰か?それはguestfsdというデーモンです。(実行ファイルはinitrdの中に用意されています。)カーネル引数"guestfs=10.0.2.4:6666"は、カーネルではなく、このguestfsdに渡すために指定されているようです。
guestfishを使って確かめてみましょう。
><fs> sh 'ps | grep guestfsd' 1 ? 00:00:01 guestfsd ><fs> command 'netstat -nap' Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 10.0.2.10:40125 10.0.2.4:6666 ESTABLISHED 1/guestfsd Active UNIX domain sockets (servers and established) Proto RefCnt Flags Type State I-Node PID/Program name Path unix 2 [ ] DGRAM 3082 64/udevd @/org/kernel/udev/udevd
たしかに動いてますね。
というわけで、guestfishがlibguestfsで決められたAPIでguestfsdにリクエストを出して、ゲストVMディスクを操作しているらしいということがわかりました。なかなかアクロバティックなことをやっていますね ;-)
まとめ
guestfishはVMディスクイメージ内のファイル操作を、雑多な手順を踏む事なくインタラクティブに実行したり、(上記例では取り上げなかった)スクリプト処理することを可能にするとても便利なツールです。仮想化基盤システムの自動化などに大いに役立つのではないかと思います。
最後に試用中に発見した不具合を報告 ;)
## FIXED!! #><fs> add-drive ~/f11.qcow2.img #libguestfs: error: ~/f11.qcow2.img: No such file or directory ><fs> download /tmp/fuga /tmp/fuga libguestfs: error: guestfs_download: internal error: reply callback called twice libguestfs: error: guestfs_download: internal error: reply callback called twice libguestfs: error: guestfs_download reply failed, see earlier error messages
ホストのファイル指定に~が使えないようです。(不具合というか単に未実装なだけだと思いますが。)またゲストのファイルをホストにコピーするdownloadコマンドもうまく動きませんでした。
(追記)libguestfsの作者のRichardさんが颯爽と現れて前者の機能を作ってくれました!最新1.0.62では上記コマンドは成功します。すばらしい!
Two documents
という2つのドキュメントが登場しました。
KVM関連技術はドキュメントがあまり存在せず、困ったときは"read the source!"という感じだったのですが、多少は状況が良くなるかもしれません。徐々にドキュメントを充実させようという気運が高まってきたのでしょうか。
virtioの詳細はMonaOSにvirtioを移植中のid:higeponさんのお役に立つかもしれないですね。(ちょっと遅かったかもしれませんが。。。)
追記:
あ、ちゃんとまとめてらっしゃるのですね。すばらしい!
qemu-kvm-0.10.4 released
KVMのユーザスペースコンポーネント(要するにQEMU)の安定版がリリースされました。実は初めての安定版です。
つい先日リリースされたqemu-0.10.4の修正が含まれています。
ダウンロードはこちらからどうぞ。
ところでkvm-XXやqemu-0.10.Xとの関係がいまいちわからなかったのですが、gitのコミットログを見てみると
- kvm-84から派生したstable-0.10ブランチであり
- QEMUの安定版ブランチ(stable-0.10, qemu-0.10.X)がマージされていて
- さらにKVMの開発版(kvm-XX)へのbug fixがマージされたもの
のようです。
ちなみにgitのコミットログを調べるときにgitkを使いました。以下のようにqemuレポジトリもマージ(?)するとqemu側のタグも表示されて、より判りやすくなります。
git clone git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git cd qemu-kvm git remote add qemu git://git.sv.gnu.org/qemu git fetch qemu git diff v0.10.4 qemu-kvm-0.10.4 # qemu-0.10.4とqemu-kvm-0.10.4の差分 git checkout origin/stable-0.10 gitk