2009年01月19日

qcow2 仮想 DISK ドライバ化 Todo (1)

ちょっと vfd の オブジェクトに qemu の オブジェクトをくっつけて リンクしてみた。

少なくとも Linux のカーネルドライバでは ほとんどの libc 相当の関数はそのままは使えない。Windows でも 事情は同じだろう。当然ながら、多くの undefined シンボルが出てきた。あまりに多いので整理。

zlib :

malloc
free

こういう基本的な関数も ドライバでそのまま使ってはいけない。
qemu_malloc / qemu_free を定義して、それを使うように修正が必要。

libgcc :


__divdi3
__moddi3
__udivdi3
__umoddi3
_alloca

gcc が勝手に出力する関数で、libgcc に実体がある。
さすがに -lgcc をつけても大丈夫のような気がするが ... どうなのだろう?

qemu-img:
( 正確には、qemu-img.exe に必要な オブジェクト - qemu-img.o )

1)大文字で始まる win32 API の ファイル操作系 17 関数

これは使ってはダメなのか? ... ダメそうな気がするが TrueCrypt はいったいどうやっているのだろう? 要チェックだ。

2)qemu_ 関数 4 つ (と変更すべき メモリ系関数)

qemu_free
qemu_malloc
qemu_mallocz
qemu_strdup
free
malloc
(realloc)
calloc
(strdup)

これは使う側で用意することになっている。

3)libc系 関数

open, close, read, write,_lseeki64
(mkdir), (rmdir), unlink, (rename), stat
(_errno) ,_fullpath, (strerror)
_get_osfhandle, fprintf, (fwrite),
(opendir), (closedir), (readdir)
localtime, time
toupper, tolower, lstrlenA, strftime, sscanf, snprintf,
_assert


() は機能を落とすことで減らせるもの。

... これら全部なんとかしないと ...
なかなか先は長そうだ。




メモ : Linux カーネル関数について

toupper, tolower, sscanf, snprintf はカーネル内で用意されているので普通に使える。

時刻関係は、do_gettimeofday が使える。

open/close は、filp_open/filp_close ?
seek+read/seek+write は、vfs_readv/vfs_writev ?

malloc/free は、kmalloc/kfree
zlib もカーネルに存在する。(zlib_ プレフィックスが付く )

もちろん カーネルモードなので、使用には十分な注意が必要。

メモ : Windows カーネル関数について

open/close は、ZwCreateFile/ZwClose
seek+read/seek+write は、ZwReadFile/ZwWriteFile
_snwprintf がある。

時刻関係は、KeQuerySystemTime らしい。
ZwAllocateVirtualMemory/ZwFreeVirtualMemory ?
物理メモリ?は、MmAllocateContiguousMemory とか?
→ crosscrypt を見ると ExAllocatePool(NonPagedPool, ..) / ExFree() を使っていた。



filedisk の方が ビルドできたので、qcow2 を再考してみる。

まず、zlib .. malloc/free を使っているが、無理やり qemu_malloc/qemu_free に変更してしまうことにする。

で、本体。まず、いろいろなドライバをサポートしているが、とりあえず興味がある block-qcow2 のみにしてしまうことにする。

で、block-qcow2.c を見てみると、フォーマットする関数が 組み込まれている(qcow_create)。この関数の中で open/read/write/close している。ドライバの中でフォーマットする機能を持たなくとも良いことにして、全部切ってしまうことにする。

さて、上位関数である block.c を見ると、BDRV_O_SNAPSHOT が指定されると、元ファイルを変更せずに、テンポラリファイルを使うようになる。このテンポラリファイルで、create の機能を使うので、サポートするのは無理。BDRV_O_SNAPSHOT 関係は全部削る。

あと、block.c とか cutils.c に含まれる共通関数で使っていないものは削る。( block.c:set_temp_filename とか cutils.c:mktimegm とか )

まず必要な C のソースは、

    aes.c block.c block-cow2.c cutils.c + zlib

ということにして、コンパイルし、

    ld -o a.o -r aes.o block.o block-cow2.o cutils.o zlib-1.2.3/libz.a

として、a.o の undefined を見てみると

U ___divdi3 (libgcc)
U __assert  (どうしよう)
U _bdrv_host_device (block-raw-ddk.c )
U _bdrv_raw (block-raw-ddk.c )
U _memcpy (ntoskrnl.lib)
U _memmove (ntoskrnl.lib)
U _memset (ntoskrnl.lib)
U _qemu_aio_wait (block-raw-ddk.c )
U _qemu_aio_wait_end (block-raw-ddk.c )
U _qemu_aio_wait_start (block-raw-ddk.c )
U _qemu_free (ExFreePool で実装 )
U _qemu_malloc (ExAllocatePool で実装)
U _qemu_mallocz (ExAllocatePool で実装)
U _qemu_strdup ( qemu-img.c から抜いてくる)
U _snprintf (__snprintf → ntoskrnl.lib)
U _strchr (ntoskrnl.lib)
U _strcmp (ntoskrnl.lib)
U _strlen (ntoskrnl.lib)
U _strrchr (ntoskrnl.lib)
U _strtoul (linux カーネルの lib から抜いてくる)
U _toupper (適当に作る)

随分と undefined が減った。だが、問題は、block-raw-ddk.c。
これが、ファイルの I/O 全部受け持つ。カーネルの流儀に従ったものを 新たに作成する必要がある。

block-raw-ddk.c では、BlockDriver という構造体に

raw_open
raw_close
raw_flush
raw_pread
raw_pwrite
raw_trucate
raw_getlength

raw_aio_read
raw_aio_write
raw_aio_cancel

のメソッドを実装して登録する。

これを block.c で wrap して、qcow2 の下位レベル I/O に使用sる。

qcow2 は、同じように BlockDriver という構造体に

qcow_probe
qcow_open
qcow_close
qcow_flush

qcow_is_allocated
qcow_set_key
qcow_make_empty

qcow_aio_read
qcow_aio_write
qcow_aio_cancel

qcow_write_compressed

qcow_snapshot_create
qcow_snapshot_goto
qcow_snapshot_delete
qcow_snapshot_list

qcow_get_info

といったメソッドを実装して登録している。

で、こういった実装を使って、カーネルのリクエストを組む。
要するに filedisk を 2 つに切って、上位から qemu block インターフェスに変換し、qemu block インターフェイスから カーネルの I/O 関数に変換するという 2 つのインターフェイス変換を作る必要がある。

なかなか面倒。

とりあえずここまで → http://nmj.sumomo.ne.jp/arc/filedisk-qcow2-wk001.tgz

(続き)

assert() だが、ddk の場合 ASSERT()を使うらしい。とりあえず使用しているところ aes.c block-qcow2.c を変更。

次に、filedisk.c で ZwCreateFile/ZwCloseFile/ZwReadFile/ZwWriteFile を call しているところを参考に block-raw-ddk.c を作成してみた。ZwCreateFile のところは手続きが難しい。

ZwCreateFile のところで truncate しているところがあったので、これも 実装。

今度は、逆に ZwCreateFile/ZwCloseFile/ZwReadFile/ZwWriteFile 周りを bdrv_file_open/bdrv_close/bdrv_pread/bdriv_pwrite で置き換えていく。

bdrv_file_open のファイル名は、都合により char * ではなく、ANSI_STRING という型になってしまった。

こんな風にでっちあげ。(動くはずはないが)ビルドは通るようになった。

とりあえずここまで → http://nmj.sumomo.ne.jp/arc/filedisk-qcow2-wk002.tgz
posted by すz at 08:02| Comment(0) | TrackBack(0) | プログラミング
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス: [必須入力]

ホームページアドレス: [必須入力]

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
この記事へのトラックバックURL
http://blog.sakura.ne.jp/tb/30760565
※ブログオーナーが承認したトラックバックのみ表示されます。

この記事へのトラックバック