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.