VMware Server with kernel 2.6.20

昨日あたりに Fedora coreカーネルのリビジョンが 2.6.20 にあがったみたいで,vmware-config.pl を実行すると,

make[1]: Entering directory `/usr/src/kernels/2.6.20-1.2300.fc5-smp-i686'
  CC [M]  /tmp/vmware-config0/vmmon-only/linux/driver.o
In file included from /tmp/vmware-config0/vmmon-only/linux/driver.c:80:
/tmp/vmware-config0/vmmon-only/./include/compat_kernel.h:21: error: expected
 declaration specifiers or ‘...’ before ‘compat_exit’
/tmp/vmware-config0/vmmon-only/./include/compat_kernel.h:21: error: expected
 declaration specifiers or ‘...’ before ‘exit_code’
/tmp/vmware-config0/vmmon-only/./include/compat_kernel.h:21: 警告: type
 defaults to ‘int’ in declaration of ‘_syscall1’
make[2]: *** [/tmp/vmware-config0/vmmon-only/linux/driver.o] エラー 1
make[1]: *** [_module_/tmp/vmware-config0/vmmon-only] エラー 2
make[1]: Leaving directory `/usr/src/kernels/2.6.20-1.2300.fc5-smp-i686'

のようにへくってしまいました。ということで,対応メモ。

といっても先人の知恵(⇒【MYN - 404】)に感謝感謝なのです。

vmmon.tar の include/compat_kernel.h というファイルが原因なので上記ページのように

--- include/compat_kernel.h.orig        2006-08-10 07:59:13.000000000 +0900
+++ include/compat_kernel.h     2007-03-19 10:38:01.726433300 +0900
@@ -19,5 +19,7 @@
  */
 #define __NR_compat_exit __NR_exit
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
 static inline _syscall1(int, compat_exit, int, exit_code);
+#endif

こんな感じのパッチを作っておいて,

# cd /tmp
# tar xf /usr/lib/vmware/modules/source/vmmon.tar
# cd vmmon-only
# patch -p0 < ~/compat_kernel.h.patch
# rm include/compat_kernel.h.orig
# cd ..
# tar cpf vmmon.tar vmmon-only
# mv -f vmmon.tar /usr/lib/vmware/modules/source
# rm -rf vmmon-only

# vmware-config.pl
...

のように vmmon.tar を作りなおして vmware-config.pl を実行したらうまくいきました。
今時の vmware-any-any-update なら対応してるかもしれません。独自の vmmon.tar を内包してるし。でも未確認。

なお,vmnet のビルド中に

/tmp/vmware-config0/vmnet-only/procfs.c:33:26: error: linux/config.h:
 そのようなファイルやディレクトリはありません

のように怒られる場合は,

# touch /usr/src/kernels/バージョン名/include/linux/config.h

のように空でもいいのでファイルを作ればいいらしいです。


あと,以前も書きましたが,ゲスト OS 側で vmware-tools-config.pl がへくる場合は,http://bbs.fedora.jp/read.php?FID=9&TID=4460 に解が載っています。ここで紹介されている vmware-tools-any-update2.tar.gz というファイルは http://ftp.cvut.cz/vmware/ から消えているんですが(obsolete フォルダにありました。でも後述のとおり今時の Vmware Server だと不要の過程であることは同じ),VMware Server 1.0.2 に付属の tools だと該当パッチをあてなくてもうまく動きました。ですから,この掲示板の 3, 4, 5, 6, 7 だけを実行すれば OK みたいです。

ちなみにこの対処を行うモジュール vmhgfs とは,ホスト OS 側のファイルをゲスト側の OS からアクセスできるようにするための fs らしいのですが,VMware Server のホスト側が対応していないみたいなので,実は意味がありません*1。ので面倒だったら,エラーメッセージは無視しても大丈夫です。

2007/07/19 追記

inode構造体のメンバーi_blksizeがなくなっているのは気になりますが、今のところ問題ないようです。

http://bbs.fedora.jp/read.php?FID=9&TID=4460

ちょっと気になったんでやや追いしてみました。

i_blksize がなくなったのは kernel-2.6.18 から,というより,inode 構造体をコンパクトにしようという 2.6.17-mm5 向けのパッチ*2を 2.6.18 以降 RedHat が採用しているからみたいです。だから 2.6.18(-8) 単体には*3 i_blksize は残っています。

じゃあ i_blksize に変わるものがあるのかというと i_blkbits というものがあります。

inode->i_blksize is equal to (1 << inode->i_blkbits) always, all the time.
It is just duplicated nonsense and usually leads to poorer code -
multiplications instead of shifts.

It should be a pretty easy incremental set of patches to ease i_blksize out
of the kernel.

http://search.luky.org/linux-kernel.2003/msg47958.html

似たようなのが重複してるからいらないよねというのが 2003 年あたりにすでに話題になってました。

じゃあ i_blkbits をセットする必要があるかどうか…と件のパッチを眺めてみたんですが,結構ためらいなく i_blksize をバッサバッサと削除しているだけで i_blkbits のケアはほとんどなされていないみたいですね。んじゃ i_blkbits はどこでセットすればいいんだ,と思ってソースをたぐってると,fs/inode.c の alloc_inode() で super_block の s_blocksize_bits からコピーしてるっぽい。おお,こっちをセットしたほうがいいのかな。

ということで,前述のパッチにちょっと付け足しをしたのが以下のとおり。

--- driver.c.orig	2007-04-13 11:41:57.000000000 +0900
+++ driver.c	2007-07-19 06:26:16.000000000 +0900
@@ -41,8 +41,13 @@
 #define HGFS_SB_TO_COMMON(sb)             ((HgfsSuperInfo *)(sb)->s_fs_info)
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
 #define INODE_SET_II_P(inode, info) do { (inode)->u.generic_ip = (info); } while (0)
 #define INODE_GET_II_P(inode) ((HgfsInodeInfo *)(inode)->u.generic_ip)
+#else
+#define INODE_SET_II_P(inode, info) do { (inode)->i_private = (info); } while (0)
+#define INODE_GET_II_P(inode) ((HgfsInodeInfo *)(inode)->i_private)
+#endif
 
 /*
  * 2.5.x kernels support nanoseconds timestamps.
@@ -760,7 +765,9 @@
    inode->i_uid = 0;   /* This is bogus, should be the mount owner. */
    inode->i_gid = 0;   /* This is bogus, should be the mount owner. */
    inode->i_rdev = 0;  /* Device nodes are not supported */
+#if 0 || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
    inode->i_blksize = HGFS_BLOCKSIZE;
+#endif
    inode->i_blocks = (attr->size + HGFS_BLOCKSIZE - 1) / HGFS_BLOCKSIZE;
    inode->i_size = attr->size;
    HGFS_SET_TIME(inode->i_atime, attr->accessTime);
@@ -4385,6 +4392,10 @@
    HGFS_SET_SB_TO_COMMON(sb, si);
    sb->s_magic = HGFS_SUPER_MAGIC;
    sb->s_blocksize = HGFS_BLOCKSIZE;
+#if 0 || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18)
+#else
+   sb->s_blocksize_bits = 8 * sizeof(unsigned int) - __builtin_clz(HGFS_BLOCKSIZE - 1);
+#endif
    sb->s_op = &HgfsSuperOperations;
 
    /*

ビット数を数えるのに ffs(2) を使ってもよかったんですが,ブロックサイズが 2 の累乗じゃないケースを考えて(ってそんなのないけど)gcc のビルトイン関数まで使ってごちゃごちゃやっています(see Binary Hacks #24,Using the GNU Compiler Collection (GCC): Other Builtins)。

あと,inode-diet パッチがあたっているかどうかを判断する方法や RedHat 系かどうかを判断する方法がわからなかったので,プリプロの条件式は弱気に「0」というのを含めてあります。RedHat 系でなければここを 1 にしていただければ無害化できるかと。

実は HGFS_BLOCKSIZE は標準的な 1024 という値にセットされているのでここまでいじくる必要はないんですが,そこはそれ自己満足というやつです。あと,テストしてないので無保証ということで。VMware Player 使えば確かめられるんでしょうけど,めんどくさーい*4

*1:と,思います。VMware Server でも hgfs を利用する方法があったらどなたか教えてください

*2:SRPM 的には linux-2.6-inode-diet-eliminate-i_blksize-and-use-a-per-superblock-default.patch

*3:あ〜2.6.19 以降はどうなんだろう〜調べるの忘れた

*4:そもそも VMware Workstation だと vmhgfs.tar はどんな内容なんでしょうね……