DISK GC on archlinux
10月になってTVの番組編成が変わり、女房がぶつぶつ言ってます。
半ば唐突と言っていいぐらいで終了しちゃった『梅ちゃん先生』。女房は女医版の赤ひげ先生 みたいのを期待してたようなんですが。。。何だか、昭和を紹介する、3丁目の夕日 の リメークだったんですかね?
昼の時間帯にやってる、アニメ3本立てが無くなってしまって悲しんでおります。他にどんな 番組が無くなったか、TV版のHTMLを真剣に表情で眺めてましたよ。
おいらが気になるのは、各局間での音量の差低減、およびCM時のわめき声撲滅なんですが、確認は これからですかね。1年も待ったんだぞーーー。
vmware-toolbox-cmd on ArchLinux
Archのパッケージになってるやつを入れて、disk shrink すると、えらーで実行出来なかった。 そう、こやつは俺的に言うと、DISKのGCなんだな。GC大好き人間としては、是非動かしてみたい訳よ。 そんな下心があって、ArchLinuxをVMWARE上にインストールしたんだ。
ウブでソースを御取り寄せして、ソース嫁したら、大体あの片を追えばよさそうってのがあった ので、今回はそれをやってみる。
付属文書のINSTALLを読むと、configure、make、make installで行けるはず。
[sakae@arch open-vm-tools-2011.12.20-562307]$ ./configure checking build system type... i686-pc-linux-gnu checking host system type... i686-pc-linux-gnu configure: error: Can't find include dir under /lib/modules/3.5.4-1-ARCH
あれ、頭っからエラったるな。カーネルべったりがお好きなんだな。モジュールも作るんかいな。 それには、カーネルの使用(仕様)書が欲しいとな。そんなの入れてないから、探してみる。
[sakae@arch open-vm-tools-2011.12.20-562307]$ pacman -Ss header
:
core/linux-api-headers 3.5.1-1 [installed]
Kernel headers sanitized for use in userspace
core/linux-headers 3.5.4-1
Header files and scripts for building modules for linux kernel
core/linux-lts-headers 3.0.43-1
Header files and scripts for building modules for linux-lts kernel
:
[sakae@arch open-vm-tools-2011.12.20-562307]$ sudo pacman -S linux-headers
どれを入れればいいんかいな。3種出てきたんで、いいかげんに真ん中のやつを取り合えず 選んでみる。で、早速、先ほどと続きを実行。
configure: error: gtkmm library not found. Please install the libgtkmm devel package(s), or re-configure using --without-gtkmm.
またconfiguのエラーですよ。gtkなんて嫌いなんで、スキップさせましょ。こんな調子で、もう一発 configureをやり直しましたよ。そしてmake。今度は、コンパイルエラー発症。
でもいいんだ。vmware-toolbox-cmdはちゃんと出来てるっぽい。
[sakae@arch toolbox]$ ls -F COPYING toolboxcmd-devices.c vmware_toolbox_cmd-toolbox-cmd.o Makefile toolboxcmd-scripts.c vmware_toolbox_cmd-toolboxcmd-devices.o Makefile.am toolboxcmd-shrink.c vmware_toolbox_cmd-toolboxcmd-scripts.o Makefile.in toolboxcmd-stat.c vmware_toolbox_cmd-toolboxcmd-shrink.o l10n toolboxcmd-time.c vmware_toolbox_cmd-toolboxcmd-stat.o toolbox-cmd.c toolboxcmd_version.h vmware_toolbox_cmd-toolboxcmd-time.o toolboxCmdInt.h vmware-toolbox-cmd*
早速、gdbにかけて、追跡開始
[sakae@arch toolbox]$ sudo -s [root@arch toolbox]# gdb vmware-toolbox-cmd disk shrink / Excess command line arguments ignored. (shrink ...) : "/home/sakae/open-vm-tools-2011.12.20-562307/toolbox/vmware-toolbox-cmd": not in executable format: File format not recognized /home/sakae/open-vm-tools-2011.12.20-562307/toolbox/disk: そのようなファイルやディレクトリはありません.
あれ? アーギュメントが無効と言ってる。それから、コマンドは実行出来ないとも言ってるな。 はてな? の偉い人に聞いてみたいぞ。
聞くより自助努力。調べてみたら、コマンドはbashのスクリプトになってた。と言う事は、本体は、 .libsの中にあるんかな? やっぱりそうだったんで、下に下りて実行してみると、
おっとその前に、toolbox-cmd.cの中にmain中で、VMware worldの中に居るかのチェックを 外しておかないと、gdbが袋小路に入っちゃうよ。(ひょっとして、おいらのgdb操縦方法が悪い んだろうけど)
/*
* Check if we are in a VM
*/
/* if (!VmCheck_IsVirtualWorld()) {
g_printerr(SU_(error.novirtual, "%s must be run inside a virtual machine.\n"),
argv[0]);
goto exit;
}
*/
適当に nextで進めて行くと
481 ToolsCmd_MissingEntityError(argv[0], SU_(arg.command, "command")); (gdb) /home/sakae/open-vm-tools-2011.12.20-562307/toolbox/.libs/vmware-toolbox-cmd: コマンド が見つかりません 507 g_printerr(SU_(help.hint, "Try '%s %s%s%s' for more information.\n"), (gdb) 詳細については、「/home/sakae/open-vm-tools-2011.12.20-562307/toolbox/.libs/vmware-toolbox-cmd help」を参照してください。
何か、怪しい動きしてるな。そもそも、bashのスクリプトを噛ませてるって事は、いろいろと環境を 整えているんだろうな。それをすっかり無視して強引に実行しちゃったから、どんなエラーを 喰らってもしょうがナイト。。。
コマンドの動きを追いかける
ええい、強引にインストールしちゃえ。
[sakae@arch open-vm-tools-2011.12.20-562307]$ sudo make -k install
vmware-toolbox-cmdは、i10n仕様になってて、ちょいと日本語がうざいので、LANGをCに切り替えて おきます。(気分の問題だけど)そして、実行してみると、
[root@arch bin]# gdb vmware-toolbox-cmd disk shrink / Excess command line arguments ignored. (shrink ...) : Reading symbols from /usr/local/bin/vmware-toolbox-cmd...done. /usr/local/bin/disk: No such file or directory.
何かおかしいね。vmware-toolbox-cmd内で、引数のポインタを一つずらしてるっぽい。 しょうがないので、
[root@arch bin]# gdb -q vmware-toolbox-cmd Reading symbols from /usr/local/bin/vmware-toolbox-cmd...done. (gdb) set args disk shrink / (gdb) b main Breakpoint 1 at 0x8049270: file toolbox-cmd.c, line 404.
引数は、gdbを起動した後、set args を使って設定してみます。そして、next してきます。
(gdb)
483 } else if ((cmd = ParseCommand(argv, argc)) == NULL) {
(gdb)
486 } else if (cmd->requireRoot && !System_IsUserAdmin()) {
(gdb)
499 } else if (cmd->requireArguments && ++optind >= argc) {
(gdb)
503 retval = cmd->func(argv, argc, gQuiet);
(gdb) s
Disk_Command (argv=0x8050250, argc=4, quiet=0) at toolboxcmd-shrink.c:528
528 {
関数ポインターで disk関係のコマンドを呼び出しているので、そこだけは、stepに切り替え ました。これで、舞台は、toolboxcmd-shrink.c の中に移ります。
Diskコマンドには、Listとshrinkが有り、ShrinkDoWipeAndShrinkが、shrinkルーチンです。 これ、ファイルシステム内の使われなくなったファイル(ようするに、rmされたファイル)のエリアを マーキング宜しくゼロクリア(Wipeって言うらしい)、それが終わった後VMware側の力を借りて 圧縮(shrink)する。Disk側から見れば、sweepしてるって事になる。
366 ShrinkDoWipeAndShrink(char *mountPoint, // IN: mount point
367 gboolean quiet, // IN: verbosity flag
368 gboolean performShrink) // IN: perform a shrink operation
369 {
370 int i;
371 int progress = 0;
372 unsigned char *err;
373 WiperPartition *part;
(gdb) n
379 signal(SIGINT, ShrinkWiperDestroy);
(gdb)
382 part = ShrinkGetPartition(mountPoint);
(gdb)
379 signal(SIGINT, ShrinkWiperDestroy);
(gdb)
369 {
(gdb)
371 int progress = 0;
(gdb)
379 signal(SIGINT, ShrinkWiperDestroy);
(gdb)
382 part = ShrinkGetPartition(mountPoint);
(gdb)
383 if (part == NULL) {
(gdb)
390 if (part->type == PARTITION_UNSUPPORTED) {
(gdb)
391 ToolsCmd_PrintErr(SU_(disk.shrink.partition.unsupported,
(gdb)
394 rc = EX_UNAVAILABLE;
前回の見立て通りに、エラーを検出してますな。
それじゃ上の部分でさっと通り過ぎちゃった部分を見て気ます。
(gdb) bt
#0 ShrinkGetMountPoints (pl=0xbffffb4c) at toolboxcmd-shrink.c:142
#1 0x0804a71a in ShrinkGetPartition (mountPoint=0x80504f0 "/")
at toolboxcmd-shrink.c:168
#2 0x0804aa1a in ShrinkDoWipeAndShrink (mountPoint=0x80504f0 "/", quiet=0,
performShrink=1) at toolboxcmd-shrink.c:382
#3 0x0804ad8d in Disk_Command (argv=0x8050250, argc=4, quiet=0)
at toolboxcmd-shrink.c:535
#4 0x0804956e in main (argc=4, argv=0x8050250) at toolbox-cmd.c:503
(gdb) n
ShrinkGetPartition (mountPoint=0x80504f0 "/") at toolboxcmd-shrink.c:172
172 DblLnkLst_ForEach(curr, &plist.link) {
(gdb)
173 p = DblLnkLst_Container(curr, WiperPartition, link);
(gdb)
174 if (toolbox_strcmp(p->mountPoint, mountPoint) == 0) {
(gdb)
175 part = p;
(gdb)
180 DblLnkLst_Unlink1(&part->link);
(gdb)
181 break;
(gdb)
185 WiperPartition_Close(&plist);
(gdb) p *p
$10 = {mountPoint = "/", '\000' <repeats 254 times>, type =
PARTITION_UNSUPPORTED, attemptUnmaps = 1 '\001', comment =
0x8071510 "Unknown filesystem. Contact VMware.", link = {prev = 0x8071504,
next = 0x8071504}}
丹念の追っていくと、lib/wiper/wiperPosix.cの中にある、WiperPartitionFilterにたどり着く。
item->type = PARTITION_UNSUPPORTED;
for (i = 0; i < ARRAYSIZE(gKnownPartitions); i++) {
info = &gKnownPartitions[i];
if (strcmp(info->name, fsname) == 0) {
item->type = info->type;
comment = info->comment;
break;
}
}
if (i == ARRAYSIZE(gKnownPartitions)) {
comment = "Unknown filesystem. Contact VMware.";
上記は、あらかじめ登録されたファイルシステムから、現ファイルシステムを検索してる。 登録されたファイルシステムってのは、こういうのね。
static const PartitionInfo gKnownPartitions[] = {
{ "autofs", PARTITION_UNSUPPORTED, "autofs filesystem.", FALSE },
{ "ext3", PARTITION_EXT3, NULL, TRUE },
{ "ext4", PARTITION_EXT4, NULL, TRUE },
左側から、登録名、タイプ、コメント、shrinkの可否。
(gdb)
432 if (strcmp(info->name, fsname) == 0) {
(gdb) p fsname
$5 = 0x8071628 "rootfs"
登録名にrootfsなんてのは、無いんで、そんなファイルシステム知らんと、コメントに書かれ、 最後にコメントが書かれてると、サポートしないよってtypeになっちまう。
マウントポイントは、/ なのに、途中で/etc/mtabあたりを検索して、rootfsなんてのを 引っ張ってきてるみたいだ。
そこで、検索テーブルに、rootfsなんてのを増やしてあげる。(あるいは、ext4を書き換える) そして、再コンパイルしてから実行すると、
(gdb) n
449 if (Posix_Stat(MNTINFO_NAME(mnt), &s) < 0) {
(gdb) n
450 comment = "Unknown device.";
(gdb) p s
$12 = {st_dev = 13257260167990345984, __pad1 = 64368, __st_ino = 0, st_mode =
3086802932, st_nlink = 256, st_uid = 0, st_gid = 3086532626, st_rdev =
1102732852032, __pad2 = 16354, st_size = -4611691134807180436,
st_blksize = -1208164364, st_blocks = 0, st_atim = {tv_sec = -1073742968,
tv_nsec = -1208014912}, st_mtim = {tv_sec = -1208270878, tv_nsec =
-1208164364}, st_ctim = {tv_sec = 0, tv_nsec = 0}, st_ino =
13256559649160690568}
(gdb) p *mnt
$14 = {mnt_fsname = 0x8071e28 "rootfs", mnt_dir = 0x8071e38 "/", mnt_type =
0x8071e48 "rootfs", mnt_opts = 0x8071e58 "rw", mnt_freq = 0, mnt_passno =
0}
まだ、コメント欄にエラーを書き込んでいるよ。雰囲気からすると、Posix_Statが失敗してるな。 どんな事をやってるか、後で見る事にして、先へ進みます。
(gdb) n
464 if (comment != NULL) {
(gdb) set comment=0
(gdb) n
469 if (item->type == PARTITION_UNSUPPORTED) {
(gdb) n
473 }
(gdb) n
WiperPartition_Open (pl=0xbffffbcc) at wiperPosix.c:661
661 DblLnkLst_LinkLast(&pl->link, &part->link);
(gdb) c
Progress: 100 [===========>]
ディスクの圧縮が完了しました。
[Inferior 1 (process 20187) exited normally]
(gdb) q
もう、強引に、エラーは無かった事にして継続したら、GCが始まりましたよ。
Quick Hackで良しとするか。
Posix_Statって調べてみたら、ただのstatだった。これがエラーを返すって何だろう? 次の9のうちから、一つを選べ、って、LPCだかの問題に出るんでしょうか?
ERRORS
EACCES Search permission is denied for one of the directories in the
path prefix of path. (See also path_resolution(7).)
EBADF fd is bad.
EFAULT Bad address.
ELOOP Too many symbolic links encountered while traversing the path.
ENAMETOOLONG
path is too long.
ENOENT A component of path does not exist, or path is an empty string.
ENOMEM Out of memory (i.e., kernel memory).
ENOTDIR
A component of the path prefix of path is not a directory.
EOVERFLOW
(stat()) path refers to a file whose size cannot be represented
in the type off_t. This can occur when an application compiled
on a 32-bit platform without -D_FILE_OFFSET_BITS=64 calls stat()
on a file whose size exceeds (1<<31)-1 bits.