いままでのこと
  • Home
  • About
  • Categories
  • Tags
  • Archives

Linux 3.x の仮想マシンから VMware Fusion の共有フォルダが見えない

VMware Fusion 上の Linux 仮想マシンから Mac の共有フォルダが見えなくなることが、たびたび (Linux カーネルをアップデートするたび?) あります。

$ ls /mnt/hgfs/
(見えない...。)

どうも vmhgfs (VMware Host-Guest File System) というカーネルモジュールがロードされていないことが原因らしい。

$ lsmod | grep vmhgfs
(ロードされてない...。)

いままでこうなったときは VMware Tools を再インストールして修復していました。しかし、VMware Tools は Linux 3.x に対応していないのか、モジュールのビルドに失敗するなど、色々とおかしくなっており、今回は VMware Tools を再インストールしても問題は解消せず。仕方なく手で直しました。

とりえあず共有フォルダが使えるようになるところまでです。この記事は参考程度に、修復の実施は自己責任でお願いします。

環境

  • VMware Fusion 5.03
  • ホスト: OS X 10.8.5 (Mountain Lion)
  • ゲスト: Linux 3.10.11 (Debian GNU/Linux jessie amd-64)

そもそも

試していませんが open-vm-tools を使うとすぐに解消できるかもしれません。

はじめに

まずは VMware Tools を再インストールしましょう。それで直れば解決です。

ぼくは VMware Tools 9.2.3 を使いました。

VMware Fusion のメニューから [仮想マシン] -> [VMware Tools の再インストール] で Linux 側の /dev/cdrom に CD-ROM が入るので、それを適当にマウント、中にある tarball を展開、vmware-install.pl を実行すると再インストールできます。

再インストールしても修復できませんでしたので、手で直しました。

まず initscript の動作がおかしい

Debian 特有の問題かもしれませんが、vmware-tools のサービスを立ち上げると以下のような出力があります。

# /etc/init.d/vmware-tools start
   Checking acpi hot plug                                              done
Starting VMware Tools services in the virtual machine:
   Switching to guest configuration:                                   done
/etc/init.d/vmware-tools: 1090: local: ': bad variable name
/etc/init.d/vmware-tools: 1090: local: ': bad variable name
   Blocking file system:                                              failed
/etc/init.d/vmware-tools: 1187: local: ': bad variable name
   Guest operating system daemon:                                      done

原因は initscript 内の get_version_integer() 関数にあります。この関数で Linux カーネルのバージョンを取得するとき、uname -r した結果を使いますが、2.6.34 という風な 2 つ以上のピリオドで区切られた出力を期待しているため、動かないようです。実際に uname -r してみると、こんな感じ。

$ uname -r
3.10-3-amd64

ぼくは区切り文字に - (ハイフン) を追加して適当に直しました。実際は Linux 3.10.11 を使っていますが、この修正方法だと 3.10.3 と誤認識されます。

--- /etc/init.d/vmware-tools.orig
+++ /etc/init.d/vmware-tools
@@ -847,7 +847,7 @@

   # There is no double quote around the back-quoted expression on purpose
   # There is no double quote around $version_uts on purpose
-  set `IFS='.'; echo $version_uts`
+  set `IFS='.-'; echo $version_uts`
   v1="$1"
   v2="$2"
   v3="$3"

ちゃんとやるのであれば、uname の代わりに LINUX_VERSION_CODE から取得するのが正しそうです。(コマンドでサクッと取得できる方法があるとよいのですが、わからなかったです。)

#include <iostream>
#include <linux/version.h>

int main(void) {
    std::cout << ((LINUX_VERSION_CODE & 0xFF0000) >> 16)
              << "."
              << ((LINUX_VERSION_CODE & 0x00FF00) >> 8)
              << "."
              << (LINUX_VERSION_CODE & 0x0000FF)
              << std::endl;
    return 0;
}

修正すると、initscript の問題は解消されました。

vmhgfs モジュールをビルドする

VMware Tools の tarball の中にソースコードがあります。

$ tar xzf VMwareTools-9.2.3-1031360.tar.gz
$ tar xf vmware-tools-distrib/lib/modules/source/vmhgfs.tar
$ cd vmhgfs-only

make すると以下のような出力があり、失敗します。

$ make
Using 2.6.x kernel build system.
make -C /lib/modules/3.10-3-amd64/build/include/.. SUBDIRS=$PWD SRCROOT=$PWD/. \
          MODULEBUILDDIR= modules
make[1]: ディレクトリ `/usr/src/linux-headers-3.10-3-amd64' に入ります
  CC [M]  /home/yu/work/vmware/vmhgfs-only/backdoor.o
  CC [M]  /home/yu/work/vmware/vmhgfs-only/backdoorGcc64.o
  CC [M]  /home/yu/work/vmware/vmhgfs-only/bdhandler.o
  CC [M]  /home/yu/work/vmware/vmhgfs-only/cpName.o
  CC [M]  /home/yu/work/vmware/vmhgfs-only/cpNameLinux.o
  CC [M]  /home/yu/work/vmware/vmhgfs-only/cpNameLite.o
  CC [M]  /home/yu/work/vmware/vmhgfs-only/dentry.o
  CC [M]  /home/yu/work/vmware/vmhgfs-only/dir.o
  CC [M]  /home/yu/work/vmware/vmhgfs-only/file.o
/home/yu/work/vmware/vmhgfs-only/file.c: In function ‘HgfsAioRead’:
/home/yu/work/vmware/vmhgfs-only/file.c:754:32: error: dereferencing pointer to incomplete type
/home/yu/work/vmware/vmhgfs-only/file.c: In function ‘HgfsAioWrite’:
/home/yu/work/vmware/vmhgfs-only/file.c:803:32: error: dereferencing pointer to incomplete type
make[4]: *** [/home/yu/work/vmware/vmhgfs-only/file.o] エラー 1
make[3]: *** [_module_/home/yu/work/vmware/vmhgfs-only] エラー 2
make[2]: *** [sub-make] エラー 2
make[1]: *** [all] エラー 2
make[1]: ディレクトリ `/usr/src/linux-headers-3.10-3-amd64' から出ます
make: *** [vmhgfs.ko] エラー 2

初っ端に Using 2.6.x kernel build system. と出力されているあたりから、3.x に対応していないことが伺えます。

結局ぼくの環境では vmhgfs モジュールをビルドして動かすまでに file.c, inode.c 周り, vmci.c 周り を修正する必要がありました。

  1. file.c の修正

    make すると以下のようなエラーが発生しました。

    /home/yu/work/vmware/vmhgfs-only/file.c: In function ‘HgfsAioRead’:
    /home/yu/work/vmware/vmhgfs-only/file.c:754:32: error: dereferencing pointer to incomplete type
    /home/yu/work/vmware/vmhgfs-only/file.c: In function ‘HgfsAioWrite’:
    /home/yu/work/vmware/vmhgfs-only/file.c:803:32: error: dereferencing pointer to incomplete type
    

    これは kiocb 構造体の宣言が見つからないことが原因のようです。宣言は linux/aio.h にありますので、それをインクルードすると解消されました。

    vmware-tools-9.2.3-file.patch

    --- a/file.c.orig
    +++ b/file.c
    @@ -25,6 +25,7 @@
     /* Must come before any kernel header file. */
     #include "driver-config.h"
    
    +#include <linux/aio.h>
     #include <linux/errno.h>
     #include <linux/module.h>
     #include <linux/signal.h>
    
  2. inode.c 周りの修正

    make すると以下のようなエラーが発生しました。

    /home/yu/work/vmware/vmhgfs-only/inode.c: In function ‘HgfsTruncatePages’:
    /home/yu/work/vmware/vmhgfs-only/inode.c:888:4: error: implicit declaration of function ‘vmtruncate’ [-Werror=implicit-function-declaration]
    /home/yu/work/vmware/vmhgfs-only/inode.c: In function ‘HgfsPermission’:
    /home/yu/work/vmware/vmhgfs-only/inode.c:1821:64: error: macro "hlist_for_each_entry" passed 4 arguments, but takes just 3
    /home/yu/work/vmware/vmhgfs-only/inode.c:1821:7: error: ‘hlist_for_each_entry’ undeclared (first use in this function)
    /home/yu/work/vmware/vmhgfs-only/inode.c:1821:7: note: each undeclared identifier is reported only once for each function it appears in
    /home/yu/work/vmware/vmhgfs-only/inode.c:1821:66: error: expected ‘;’ before ‘{’ token
    /home/yu/work/vmware/vmhgfs-only/inode.c:1815:11: warning: unused variable ‘dcount’ [-Wunused-variable]
    /home/yu/work/vmware/vmhgfs-only/inode.c:1814:26: warning: unused variable ‘p’ [-Wunused-variable]
    

    エラーの発生原因は 2 つあります。

    ひとつは Linux 3.9 から hlist_for_each_entry マクロのインターフェースが変わったこと、もうひとつは Linux 3.8 から vmtruncate() 関数が廃止されたことです。

    hlist_for_each_entry マクロはいまのインターフェースを参考に使い方を変更し、vmtruncate() 関数は元の実装を参考にマクロ定義しました。inode_operations 構造体が truncate を持たなくなったようなので、その辺りも考慮します。

    • Linux 3.9 の hlist_for_each_entry マクロ
    • Linux 3.7 の vmtruncate() 関数

    vmware-tools-9.2.3-inode.patch

    --- a/inode.c.orig
    +++ b/inode.c
    @@ -1811,14 +1811,13 @@
         */
        if (mask & MAY_ACCESS) { /* For sys_access. */
           struct dentry *dentry;
    -      struct hlist_node *p;
           int dcount = 0;
    
           if (mask & MAY_NOT_BLOCK)
              return -ECHILD;
    
           /* Find a dentry with valid d_count. Refer bug 587879. */
    -      hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
    +      hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
              dcount = dentry->d_count;
              if (dcount) {
                 LOG(4, ("Found %s %d \n", dentry->d_name.name, dcount));
    --- a/shared/compat_mm.h.orig
    +++ b/shared/compat_mm.h
    @@ -90,9 +90,9 @@
     #endif
    
     /*
    - * In 2.4.10, vmtruncate was changed from returning void to returning int.
    + * In 3.8.0, vmtruncate was changed from returning void to returning int.
      */
    -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 10)
    +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
     #define compat_vmtruncate(inode, size)                                        \
     ({                                                                            \
        int result = 0;                                                            \
    @@ -100,5 +100,12 @@
        result;                                                                    \
     })
     #else
    -#define compat_vmtruncate(inode, size) vmtruncate(inode, size)
    +#define compat_vmtruncate(inode, size)                                        \
    +({                                                                            \
    +   int result = inode_newsize_ok(inode, size);                                \
    +   if (!result) {                                                             \
    +     truncate_setsize(inode, size);                                           \
    +   }                                                                          \
    +   result;                                                                    \
    +})
     #endif
    
  3. vmci.c 周りを修正する

    file.c と inode.c 周りを修正することでひとまずビルドは通るようになりますが、いざ動かしてみるとシンボルが見つからない旨のエラーが発生してしまいました。

    $ sudo insmod vmhgfs.ko
    Error: could not insert module vmhgfs.ko: Unknown symbol in module
    

    dmesg すると以下のようなエラーが出力されていました。

    $ dmesg | tail
    [42830.843944] vmhgfs: Unknown symbol VMCIDatagram_Send (err 0)
    [42830.844015] vmhgfs: Unknown symbol VMCIDatagram_DestroyHnd (err 0)
    [42830.844024] vmhgfs: Unknown symbol VMCIDatagram_CreateHnd (err 0)
    

    いつからかは調べていませんが、どうも VMCI の関数名が変わったようです。ぼくは open-vm-tools を参考に直してしまいました。(最初から open-vm-tools を使えばよかったのかもしれない...。)

    vmware-tools-9.2.3-vmci.patch

    (diff は長いので割愛。)

やっと

これでようやく共有フォルダが見えるようになりました。

$ sudo insmod vmhgfs.ko
$ lsmod | grep vmhgfs
vmhgfs                 52573  0
vmw_vmci               48221  1 vmhgfs
$ sudo mount -t vmhgfs .host:/ /mnt/hgfs/
$ ls /mnt/hgfs/
shared
Comments
comments powered by Disqus

  • « acpid を使ってサスペンド
  • Pelican へ移行 »

Published

Sep 28, 2013

Category

Computing

Tags

  • Debian 6
  • Linux 8
  • Mac 1
  • VMware 1

SNS

Tweet
このエントリーをはてなブックマークに追加
  • Powered by Pelican. Theme: Elegant by Talha Mansoor