気の向くままに辿るIT/ICT/IoT
システム開発

VMwareとLinuxカーネル

ホーム前へ次へ
古いパソコンの活用方法は?

VMwareとLinuxカーネル

VMwareとLinuxカーネル

 VMware PlayerをLinux上で使用していると(Linux版/Linux用VMware Playerでは、)カーネルのバージョンによってパッチを当てるか手作業によるソース修正が必要となることがあります。

Linuxカーネルアップデート後、VMwareの初回起動時に表示されるポップアップメッセージ
[Install]ボタンをクリックすれば自動解決が試みられる

 Linux上でVMware Player( Plus)を使用している場合には、Linuxカーネルのアップデートを行った後、VMwareを起動する際に一度だけ一部のモジュールのコンパイルとLinuxカーネルへの読み込みを要求されます。

 ここで失敗してVMware Playerを起動できない(VMware Playerが起動しない)場合、それは、VMwareが、まだ最新のLinuxカーネルに対応していなかったり、既にVMware Playerの新しいバージョンがリリースされていてインストール済みのバージョンでは新たなLinuxカーネルに対応していなかったり、時にVMwareのソースにバグがあることに起因します。

 その場合、VMwareモジュールのソースを修正したり、用意されていれば、当該対策用のパッチをあてたり、時にアップグレードしたりする(のもうまくできなかったりするので改めてダウンロードしてインストールしたりする)必要があります(が、ちなみにVMware Player 7/VMware Workstation 11からはLinuxホスト用も64ビット版のみのサポートとなったようです)。

エラーを認識したカーネルと対処方法

VMwareとLinuxカーネル 3.17.4-200

注意 / Linuxカーネル 3.17.4-200

 Fedoraのアップグレードに伴いカーネルもアップデートされたのか、以下は、Fedora 20(Heisenbug)、かつ、Linuxカーネル3.17.4-200の話でFedora 21(Twenty One)にアップグレード後は、逆にFedora 20で以下の対策をしていた場合、元に戻しておく必要があります。(というか、元に戻さないとVMware Playerが起動しません。)

 当サイトでは、VistaのHDDが寿命、HDD交換後Fedoraをメインに使うことにしたのですが、その時のLinuxカーネルは、3.15.xだったようで、1〜2度カーネルアップグレードした後、初めてFedoraにVMware Player 6.0.3をインストールした際は、3.15のパッチをあてた覚えもなく、既に3.16.xだったのか、ちょうど上手いこと対策済みだったのか、その時は何もなかったように、更に1〜2度カーネルアップデートした時も先のモジュールインストールは上手くいったと記憶しており、3.17.xにアップデートしてからかと思いますが、これに失敗し、VMware Playerを起動できなくなりました。

$ ls /usr/src/kernels/
3.15.10-200.fc20.i686  3.15.8-200.fc20.i686  3.17.3-200.fc20.i686
3.15.6-200.fc20.i686  3.16.6-203.fc20.i686  3.17.4-200.fc20.i686
$

 ポップアップメッセージにあったログを読むとvmnetが。。。といった内容があり、あ!そういえば、デスクトップ上のネットワーク情報を見てもvmnet1とかvmnet8とかがない。。。ということに気づきました。

 調べてみるとcommunities.vmware.comに行き着き、それによると[netif.c](C言語のソースファイル)にあるネットワークデバイスの領域確保用と思われる[alloc_netdev()]関数の引数として定義済みのマクロ値が1つ足りないのが原因のようです。

 他方、情報を探している中、いつも頼れる存在Arch Linux WikiにLinuxカーネル3.14と3.15のパッチの当て方が分かり易く書いてありました。

 rmコマンドにfオプションはなかったので追記したものの、先のQ&Aと、これを参考にすると3.17における修正については、次のようにすればよさそうです。

$ su -
Password:
# cd /usr/lib/vmware/modules/source
# tar -xf vmnet.tar
# vi vmnet-only/netif.c
...
/*
dev = alloc_netdev(sizeof *netIf, deviceName, VNetNetIfSetup);
*/
dev = alloc_netdev(sizeof *netIf, deviceName, NET_NAME_UNKNOWN, VNetNetIfSetup);
...
# tar -cf vmnet.tar vmnet-only
# rm -rf vmnet-only
# vmware-modconfig --console --install-all
# exit
$

 書き換えてもよかったのですが、ここでは、元のコードをコメントアウトしてコピーしたものに追記してみました。

 つまり、xxx.tarは、-Cオプションで展開先ディレクトリを指定しない場合、カレントディレクトリにxxx-onlyディレクトリを作成し、その中に展開される模様、当該ソースを修正後、xxx-onlyディレクトリを元のxxx.tarとしてアーカイブを作成、不要となったxxx-onlyディレクトリを削除、後でターミナルからモジュールをビルド可能なvmware-modconfigコマンドを使用するという流れというわけですね。

 これにより、Ethernetネットワークvmnet1とvmnet8も利用可能となり、VMware Playerを起動してみると無事、見慣れた操作画面が表示されました。

 VMware Playerと(Fedora 20(Heisenbug)上の)Linuxカーネル 3.17.4-200におけるこの対策は、Fedoraのアップグレードに伴いカーネルもアップデートされた為か、Fedora 21(Twenty One)には当てはまりませんが、一方、Fedora 20で上述の対策をしていた場合、Fedora 21へのアップグレード後においては、元に戻しておかないと逆にVMware Playerを起動させることができませんでした。

VMwareとLinuxカーネル 3.17.8-300

 更にFedora 21においてLinuxカーネル 3.17.8-300にアップデートしたところ、VMware Playerの起動に際し、VMwareのポップアップでエラーとなり、VMware Playerを起動することができませんでした。

$ ls /usr/src/kernels/
3.15.10-200.fc20.i686  3.15.8-200.fc20.i686
3.15.6-200.fc20.i686  3.17.8-300.fc21.i686
$

 よく見るとまたもEthernetネットワーク[vmnet1]や[vmnet8]が有効になっていません。

 先のLinuxカーネル 3.17.4-200の修正をFedora 21にアップグレードした際に元に戻したものの、これを再度修正する必要があるのかと思い、修正してみることにしました。

$ cd /usr/lib/vmware/modules/source
$ sudo tar -xf vmnet.tar
$ sudo vi vmnet-only/netif.c
...
/*
◆オリジナル
dev = alloc_netdev(sizeof *netIf, deviceName, VNetNetIfSetup);
◆Linuxカーネル 3.17.4-200対策で引数を追加
dev = alloc_netdev(sizeof *netIf, deviceName, NET_NAME_UNKNOWN, VNetNetIfSetup);
◆Fedora 21にアップグレードしたタイミングで
  またVMware Playerが起動不能となり、オリジナルに戻した
dev = alloc_netdev(sizeof *netIf, deviceName, VNetNetIfSetup);
◆更に更にLinuxカーネル 3.17.8-300で
  またVMware Playerが起動不能となり、引数を追加
*/
dev = alloc_netdev(sizeof *netIf, deviceName, NET_NAME_UNKNOWN, VNetNetIfSetup);
...
$

(ここで改めて[vmnet-only/netif.c]を修正する必要があったのかどうかは不明ですが、以降の対策で最終的に修正したままでも利用できていることもあり、調査していません。)

 その後、[vmware-modconfig]を実行してみると[vsock]関連でエラーとなっている模様。

$ pwd
/usr/lib/vmware/modules/source
$ sudo tar -cf vmnet.tar vmnet-only
$ sudo rm -rf vmnet-only
$ sudo vmware-modconfig --console --install-all
...
/tmp/modconfig-wTRC1W/vsock-only/linux/notifyQState.c:167:4: エラー: 関数 'sk_data_ready' への引数が多すぎます
    sk->sk_data_ready(sk, 0);
...
/tmp/modconfig-wTRC1W/vsock-only/linux/notifyQState.c:569:7: エラー: 関数 'sk_data_ready' への引数が多すぎます
    sk->sk_data_ready(sk, 0);
...
$

 [vsock]と言えば、3.17.4-200の修正において参照したArch Linuxの記事で過去これのパッチも要したと書いてあったはずと思い、確認してみるとファイル名は似て非なるものであるものの、記憶通りで、リンクを辿ってパッチの内容を見てみると当該関数の2つめの引数[0]をとればよいようです。

 [vmware-modconfig]実行時のエラー内容を見ても[引数が多すぎます]とあるので[vsock-only/linux/notifyQState.c]に2ヶ所ある[sk_data_ready]関数の第2引数[0]をとって再度、[vmware-modconfig]を実行してみると今度は、先のArchの記事にあった通りの[notify.c]でも同様の関数で同じエラーとなり、こちらも変更することにしました。

$ pwd
/usr/lib/vmware/modules/source
$ sudo tar -xf vsock.tar
$ sudo vi vsock-only/linux/notifyQState.c
...
$ sudo vi vsock-only/linux/notifyQState.c
...
static void
VSockVmciHandleWrote(struct sock *sk,  // IN
     VSockPacket *pkt,  // IN: unused
     Bool bottomHalf,  // IN: unused
     struct sockaddr_vm *dst,  // IN: unused
     struct sockaddr_vm *src)  // IN: unused
{
/*
 sk->sk_data_ready(sk, 0);
*/
 sk->sk_data_ready(sk);
}
...
...
...
static int32
VSockVmciNotifyPktRecvPostDequeue(struct sock *sk,   // IN
        size_t target,   // IN
        ssize_t copied,   // IN
        Bool dataRead,   // IN
        VSockVmciRecvNotifyData *data)   // IN
{
 VSockVmciSock *vsk;
 int err;
 Bool wasFull = FALSE;
 uint64 freeSpace;
 ASSERT(sk);
 ASSERT(data);
 vsk = vsock_sk(sk);
 err = 0;
 if (dataRead) {
  Atomic_MFence();
  freeSpace = vmci_qpair_consume_free_space(vsk->qpair);
  wasFull = freeSpace == copied;
  if (wasFull) {
   PKT_FIELD(vsk, peerWaitingWrite) = TRUE;
  }
  err = VSockVmciSendReadNotification(sk);
  if (err < 0) {
   return err;
  }
  /* See the comment in VSockVmciNotifyPktSendPostEnqueue */
/*
  sk->sk_data_ready(sk, 0);
*/
  sk->sk_data_ready(sk);
 }
 return err;
}
...
$ sudo tar -cf vsock.tar vsock-only
$ sudo rm -rf vsock-only
$ sudo vmware-modconfig --console --install-all
...
/tmp/modconfig-boyZjk/vsock-only/linux/notify.c:519:4: エラー: 関数 'sk_data_ready' への引数が多すぎます
    sk->sk_data_ready(sk, 0);
...
$

 エラーメッセージの指摘に従い、[vsock-only/linux/notify.c]も1ヶ所修正。

$ pwd
/usr/lib/vmware/modules/source
$ sudo tar -xf vsock.tar
$ sudo vi vsock-only/linux/notify.c
...
static void
VSockVmciHandleWrote(struct sock *sk,    // IN
    VSockPacket *pkt,   // IN: unused
    Bool bottomHalf,    // IN: unused
    struct sockaddr_vm *dst, // IN: unused
    struct sockaddr_vm *src) // IN: unused
{
#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
 VSockVmciSock *vsk;
 vsk = vsock_sk(sk);
 PKT_FIELD(vsk, sentWaitingRead) = FALSE;
#endif
/*
 sk->sk_data_ready(sk, 0);
*/
 sk->sk_data_ready(sk);
}
...
$ sudo tar -cf vsock.tar vsock-only
$ sudo rm -rf vsock-only
$ sudo vmware-modconfig --console --install-all
...
Starting vmware (via systemctl): Job for vmware.service failed.
See "systemctl status vmware.service" and "journalctl -xe" for details.
                     [失敗]
Unable to start services
$

 エラーらしきメッセージはありますが、結果、これで[vmnet1]や[vmnet8]も有効になり、VMware Playerを起動することができました。

 その「[systemctl]経由でVMwareを起動してみたけど[vmware.service]用のジョブが失敗したよ。詳細については、[systemctl status vmware.service]や[journalctl -xe]を参照してね」といった旨の最後のエラーっぽいメッセージ、確認すると「[SYSV]の開始に失敗した」とあるものの、VMware Playerも起動できたので今のところ放置しています。

VMwareとLinuxカーネル 3.19.3-200

 Linuxカーネル 3.19.3-200にアップデートしたところVMware Playerが起動せず、ネットワークモニタを見るとvmnet8が起動していません。

 端末から起動してみると次のようなエラーが。

$ vmplayer ...
...
make[1]: Entering directory '/usr/src/kernels/3.19.3-200.fc21.i686'
  CC [M]  /tmp/modconfig-NuhYi9/vmnet-only/driver.o
  CC [M]  /tmp/modconfig-NuhYi9/vmnet-only/hub.o
/tmp/modconfig-NuhYi9/vmnet-only/driver.c: 関数 ‘VNetFileOpUnlockedIoctl’ 内:
/tmp/modconfig-NuhYi9/vmnet-only/driver.c:1239:20: エラー: ‘struct file’ は ‘f_dentry’ という名前のメンバを持っていません
    if (filp && filp->f_dentry) {
                    ^
/tmp/modconfig-NuhYi9/vmnet-only/driver.c:1240:19: エラー: ‘struct file’ は ‘f_dentry’ という名前のメンバを持っていません
       inode = filp->f_dentry->d_inode;
                   ^
scripts/Makefile.build:257: recipe for target '/tmp/modconfig-NuhYi9/vmnet-only/driver.o' failed
make[2]: *** [/tmp/modconfig-NuhYi9/vmnet-only/driver.o] Error 1
make[2]: *** 未完了のジョブを待っています....
Makefile:1386: recipe for target '_module_/tmp/modconfig-NuhYi9/vmnet-only' failed
...

 vmnetを展開して探してみたものの、ネット検索した方が早いかということで本家ディスカッションLinux host - Kernel 3.19 breaks VMware (vmnet)を発見し、解決した内容が以下。

 vmnet.tarを展開、vmnet-only以下のdriver.cを編集。

$ pwd
/usr/lib/vmware/modules/source
$ sudo tar -xf vmnet.tar
$ sudo vi vmnet-only/driver.c
...
vmnet-only/driver.cの
   if (filp && filp->f_dentry) {
      inode = filp->f_dentry->d_inode;
      }
のf_dentryを
f_path.dentry
とするか、
if文全体を
 inode = file_inode(filp);
で置き換える

 後片付けしてvmware-modconfigを実行。

/usr/lib/vmware/modules/source
$ sudo tar -cf vmnet.tar vmnet-only
$ sudo rm -rf vmnet-only
$ sudo vmware-modconfig --console --install-all

 次のようなエラーが表示されたら、後述のように対処。

/tmp/modconfig-Yf2PEX/vmnet-only/userif.c: 関数 ‘VNetCopyDatagram’ 内:
/tmp/modconfig-Yf2PEX/vmnet-only/userif.c:526:4: エラー: 関数 ‘skb_copy_datagram_iovec’ の暗黙的な宣言です [-Werror=implicit-function-declaration]
    return skb_copy_datagram_iovec(skb, 0, &iov, len);

 改めてvmnet.tarを展開、vmnet-only以下のuserif.cを編集。

$ pwd
/usr/lib/vmware/modules/source
$ sudo tar -xf vmnet.tar
$ sudo vi vmnet-only/userif.c
...
vmnet-only/userif.cの
return skb_copy_datagram_iovec(skb, 0, &iov, len);
を
   struct iov_iter to;
   iov_iter_init(&to, READ, &iov, 1, len);
   return skb_copy_datagram_iter(skb, 0, &to, len);
で置き換える

 後片付けしてvmware-modconfigを実行。

/usr/lib/vmware/modules/source
$ sudo tar -cf vmnet.tar vmnet-only
$ sudo rm -rf vmnet-only
$ sudo vmware-modconfig --console --install-all

 まだ、以下のようなエラーが表示されました。

 試してみると、とりあえず、VMware Playerの起動はできますが、毎度ポップアップが出るので解決策を探すことに。

/tmp/modconfig-MIZAuK/vmci-only/linux/vmciKernelIf.c: 関数 ‘__VMCIMemcpyFromQueue’ 内:
/tmp/modconfig-MIZAuK/vmci-only/linux/vmciKernelIf.c:1307:10: エラー: 関数 ‘memcpy_toiovec’ の暗黙的な宣言です [-Werror=implicit-function-declaration]
          err = memcpy_toiovec(iov, (uint8 *)va + pageOffset, toCopy);
          ^
cc1: some warnings being treated as errors
scripts/Makefile.build:257: recipe for target '/tmp/modconfig-MIZAuK/vmci-only/linux/vmciKernelIf.o' failed
make[2]: *** [/tmp/modconfig-MIZAuK/vmci-only/linux/vmciKernelIf.o] Error 1
make[2]: *** 未完了のジョブを待っています....

 すっかり検索づいてしまい、検索してみると、さすがArch Linux、AURにこのPackage Details: vmware-patch 11.1.0-3があり、ここにある通り、以下のようにinclude行を1行追加、2箇所修正で解決。

 今度は、vmci.tarを展開、vmci-only以下のuserif.c vmciKernelIf.cを編集。

$ pwd
/usr/lib/vmware/modules/source
$ sudo tar -xf vmci.tar
$ sudo vi vmci-only/linux/vmciKernelIf.c
...
#include <linux/socket.h> /* For memcpy_{to,from}iovec(). */
#include <linux/vmalloc.h>
#include <linux/wait.h>
#include <linux/skbuff.h>        /* <=追加 */
#include "compat_highmem.h"
...
...
...
if (isIovec) {
/*
↓これを↓
struct iovec *iov = (struct iovec *)dest;
↓これに変更↓
*/
struct msghdr *msg = dest;
int err;
/* The iovec will track bytesCopied internally. */
/*
↓これを↓
err = memcpy_toiovec(iov, (uint8 *)va + pageOffset, toCopy);
↓これに変更↓
*/
err = memcpy_to_msg(msg, (uint8 *)va + pageOffset, toCopy);
if (err != 0) {
if (!kernelIf->isDataMapped) {
kunmap(kernelIf->page[pageIndex]);
...

 後片付けしてvmware-modconfigを実行。

/usr/lib/vmware/modules/source
$ sudo tar -cf vmci.tar vmci-only
$ sudo rm -rf vmci-only
$ sudo vmware-modconfig --console --install-all

追記:2016/03/19

 Fedora 20にVMware Player 6.0.3を入れたのは、確か2年ほど前、ここでのLinuxカーネルにおける対処を行ったのも1〜2年前だったかと思います。

 今日、Debian jessie(8.3)に今更ながらVMware Player 6.0.3を入れることにしましたが、この記事の最後の対処のあと、Fedoraで起動しなくなり、対処にあぐねたからでしたが、最先端を追うFedoraとDebianの保守的な安定版では、採用するLinuxカーネルのバージョンもかなり違うことを知り、それなら、まだ動く。。。と思ったからです。

 現に今日時点でのDebian jessie 8.3におけるLinuxカーネルバージョンは、Fedora上でこの記事の最初の対処を行なうに至ったLinuxカーネルバージョン3.17.4よりも前のバージョン3.16.0ですから、まだ、しばらくは使えそうです。

ホーム前へ次へ