追記(2008/07/28)vmware-vdiskmanagerコマンドと組み合わせれば

こんなページを見つけた。仮想ディスクの小技
vmware-vdiskmanagerコマンドについては、そう言えば以前、仮想ディスクをオフラインでデフラグするときに使ったような気もするが余り深く調べなかったので忘れていた。

上で紹介した、物理ディスクイメージと仮想ディスクの相互変換に、更にvmware-vdiskmanagerコマンドを使えば仮想ディスクを柔軟に変更できる。ちょっと試したところ、vmware-vdiskmanagerコマンドは(ディスクサイズを変更しないのであれば)変換の前後でジオメトリは同じようだ。例えば、上の方法で"windows98"という固定サイズのディスクを用意する。(実験用に小さいサイズにしてある。ジオメトリは63セクタ、15ヘッド、150シリンダである。)

[root@server Fedora-8]# ls -l windows98.vmdk windows98-flat.vmdk
-rw------- 1 vmware vmware   72576000 2008-07-28 09:28 windows98-flat.vmdk
-rw------- 1 vmware vmware        344 2008-07-28 09:27 windows98.vmdk
[root@server Fedora-8]# cat windows98.vmdk

# Disk DescriptorFile
version=1
CID=19454c09
parentCID=ffffffff
createType="monolithicFlat"

# Extent description
RW 141750 FLAT "windows98-flat.vmdk" 0

# The Disk Data Base
#DDB

ddb.toolsVersion = "7394"
ddb.adapterType = "ide"
ddb.geometry.sectors = "63"
ddb.geometry.heads = "15"
ddb.geometry.cylinders = "150"
ddb.virtualHWVersion = "4"
[root@server Fedora-8]# 

これをvmware-vdiskmanagerを使って可変長の仮想ディスクに変換する。

[root@server Fedora-8]# vmware-vdiskmanager -r windows98.vmdk -t 0 test.vmdk
Using log file /tmp/vmware-root/vdiskmanager.log
Creating a monolithic growable disk 'test.vmdk'
  Convert: 100% done.
Virtual disk conversion successful.
[root@server Fedora-8]#

ファイルとしてはtest.vmdkが出来る。

root@server Fedora-8]# ls -l
total 10343488
-rw------- 1 vmware vmware 4386586624 2008-07-28 09:26 Fedora-8.vmdk
-rw------- 1 vmware vmware        598 2008-07-26 12:22 Fedora-8.vmsd
-rwxr-xr-x 1 vmware vmware       1444 2008-07-28 09:24 Fedora-8.vmx
-rw------- 1 vmware vmware       8664 2008-07-28 09:26 nvram
-rw------- 1 root   root      2293760 2008-07-28 09:31 test.vmdk
-rw-r--r-- 1 vmware vmware      39930 2008-07-28 09:26 vmware.log
-rw------- 1 vmware vmware   72576000 2008-07-28 09:28 windows98-flat.vmdk
-rw------- 1 vmware vmware        344 2008-07-28 09:27 windows98.vmdk
[root@server Fedora-8]#

さて、このtest.vmdkのジオメトリだが、ファイルの先頭部分に記述されているので覗いてみると、

[root@server Fedora-8]# head -20 test.vmdk
KDMVカ)"

# Disk DescriptorFile
version=1
CID=19454c09
parentCID=ffffffff
createType="monolithicSparse"

# Extent description
RW 141750 SPARSE "test.vmdk"

# The Disk Data Base
#DDB

ddb.toolsVersion = "7394"
ddb.virtualHWVersion = "4"
ddb.geometry.cylinders = "150"
ddb.geometry.heads = "15"
ddb.geometry.sectors = "63"
ddb.adapterType = "ide"
[root@server Fedora-8]#

ジオメトリは変換前と同じ、63セクタ、15ヘッド、150シリンダである。
今度は逆変換を試みる。一旦、元のwindows98という仮想ディスクを消去した後、vmware-vdiskmanagerで変換する。

[root@server Fedora-8]# rm windows98.vmdk windows98-flat.vmdk
[root@server Fedora-8]# vmware-vdiskmanager -r test.vmdk -t 2 windows98.vmdk
Using log file /tmp/vmware-root/vdiskmanager.log
Creating monolithic preallocated disk 'windows98.vmdk'
  Convert: 100% done.
Virtual disk conversion successful.
[root@server Fedora-8]#

さて、ファイルサイズとジオメトリは?

[root@server Fedora-8]# ls -l
total 10343488
-rw------- 1 vmware vmware 4386586624 2008-07-28 09:26 Fedora-8.vmdk
-rw------- 1 vmware vmware        598 2008-07-26 12:22 Fedora-8.vmsd
-rwxr-xr-x 1 vmware vmware       1444 2008-07-28 09:24 Fedora-8.vmx
-rw------- 1 vmware vmware       8664 2008-07-28 09:26 nvram
-rw------- 1 root   root      2293760 2008-07-28 09:31 test.vmdk
-rw-r--r-- 1 vmware vmware      39930 2008-07-28 09:26 vmware.log
-rw------- 1 root   root     72576000 2008-07-28 09:36 windows98-flat.vmdk
-rw------- 1 root   root          344 2008-07-28 09:36 windows98.vmdk
[root@server Fedora-8]#

[root@server Fedora-8]# cat windows98.vmdk
# Disk DescriptorFile
version=1
CID=19454c09
parentCID=ffffffff
createType="monolithicFlat"

# Extent description
RW 141750 FLAT "windows98-flat.vmdk" 0

# The Disk Data Base
#DDB

ddb.toolsVersion = "7394"
ddb.virtualHWVersion = "4"
ddb.geometry.cylinders = "150"
ddb.geometry.heads = "15"
ddb.geometry.sectors = "63"
ddb.adapterType = "ide"
[root@server Fedora-8]#

元のHDDイメージファイルと全く同じジオメトリで、大きさも同じである。つまり、vmware-vdiskmanaコマンドと組み合わせることで、

	物理HDD ⇔ HDDイメージファイル ⇔ 固定長仮想ディスク ⇔ 可変長仮想ディスク

という相互変換が可能となる。

VMwareの仮想ディスクをLinuxでマウントして使う

タイトルが良くなかった。「VMwareの仮想ディスクをLinuxでマウントして使う」のであれば、vmware-mountというコマンド使えば簡単に出来る。ここに書いてあるのはその逆で、Linux上のHDDのイメージファイルを仮想マシン上(ゲストOS上)の仮想ディスクとして使う方法。

具体的な方法は後で書くが、そもそもの動機と経緯は次のようになる。(ちょっと前置きが長くなるが。)Linux上に小容量のHDDのイメージファイルがあった。これを仮想マシンでマウントして使いたい。できればルートファイルシステムとして使いたい、というのが動機だ。組込み系の開発とかOSに近いところの開発を行っている人であれば、これがどれ程便利なことか分かってもらえるかと思う。ターゲットマシンのHDDがそのまま仮想マシンで使えるわけだし、仮想マシンで開発した仮想ディスクの内容をそのまま実マシンで利用できるようになる。(ただ単に、マウントして使えるだけでなく、実際のHDDと仮想ディスクの間で相互変換(P2V/V2P変換)が可能となる。)

VMwareの仮想ディスクをLinuxでマウントして使うには“vmware-mount”というコマンドを使わないで出来ない、と思いがちだが、フラットディスクに関しては言えば、結果的に普通のLinuxのmountでOKということが分かった。

VMwareの仮想ディスクは独自仕様か?

最初はXenを使おうと思い最新のXen Express 4.1.0をインストールしてみた。1年ぶり(「Xen Expressのインストール 」参照)にXenを使ったが、昔のXen Expressと異なり、仮想ディスク(Storage Repository)へLinuxからアクセスできなくなっているし、Storage Repositoryの管理コマンド、smコマンドもなくなっていて、使い勝手が大変悪くなっていた。そこで次に普段使っているVMware環境を再度調べてみた。
VMwareの仮想ディスクの内部フォーマットはズーッと独自仕様だと思い込んでいた。私が仮想マシンを使い始めたころ参考にしたいくつかの本でも、Xenの仮想ディスクをLinuxからマウントして使う例は紹介されていたが、VMwareについてはそういう紹介記事がなく独自だと思い込んでいた。当然、ディスク・スペースをダイナミックに割り当てる方式の仮想ディスクは独自の使用にならざるおえないが、最初からディスク・スペースを確保するサイズ固定型の仮想ディスクはどうなっているのだろう?と思い調べてみた。

まず、VMwareのサイズ固定型(*-flat.vmdx)の内部フォーマットとみてみた。大きな仮想ディスクでは調べにくいので、一番小さなサイズの仮想ディスクを作ってフォーマットを調べてみた。まず、Linuxゲスト適当な仮想マシンに仮想ディスクを追加する。VMwareの仮想ディスクの最少サイズは0.1GBである。ここでは"smallest"という名前の仮想ディスクを追加している。

ゲストマシンをブートしてディスクを初期化&フォーマットする。

[root@fedora-8 ~]# ls /dev/sd*
/dev/sda  /dev/sda1  /dev/sda2  /dev/sdb		;: ←新しいディスクは/dev/sdb
[root@fedora-8 ~]# fdisk /dev/sdb			;: ←fdiskでパーティションを設定
Command (m for help): n					;:   ディスク全体を1つのパーティションに。
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-13, default 1): 1
Last cylinder or +size or +sizeM or +sizeK (1-13, default 13): 13
Command (m for help): w
The partition table has been altered!

[root@fedora-8 ~]# ls /dev/sd*
/dev/sda  /dev/sda1  /dev/sda2  /dev/sdb  /dev/sdb1	;: ←新しいパーティションは/dev/sdb1
[root@fedora-8 ~]# mkfs -t ext3 /dev/sdb1		;: ←フォーマットする
[root@fedora-8 ~]# mount /dev/sdb1 /mnt			;: ←さっそくマウントして確認する
[root@fedora-8 ~]# ls /mnt
lost+found
[root@fedora-8 ~]# df /mnt				;: ←約100MBであることを確認。
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sdb1               101086      5664     90203   6% /mnt
[root@fedora-8 ~]#

この状態で一旦仮想マシンをシャットダウンする。次にホストマシン上で、ゲストマシンのディレクトリを確認すると次のように "smallest.vmdk"と"smallest-flat.vmdx" というファイルができている。

[root@server Fedora-8]# ls -l
total 4398012
-rw------- 1 vmware vmware 4386586624 2008-07-25 16:47 Fedora-8.vmdk
-rw------- 1 vmware vmware          0 2008-07-11 20:28 Fedora-8.vmsd
-rwxr-xr-x 1 vmware vmware       1417 2008-07-25 16:20 Fedora-8.vmx
-rw------- 1 vmware vmware       8664 2008-07-25 16:47 nvram
-rw------- 1 vmware vmware  107374080 2008-07-25 16:47 smallest-flat.vmdk
-rw------- 1 vmware vmware        343 2008-07-25 16:34 smallest.vmdk
-rw-r--r-- 1 vmware vmware      39235 2008-07-25 16:47 vmware.log
[root@server Fedora-8]#

smallest.vmdkは仮想ディスクの情報が保存されているだけで、仮想ディスクの本体は smallest-flat.vmdk となる。さて、問題はこのフラットディスクだが、どのようなフォーマットだろうか? 最初の1セクタ分(=512バイト)だけダンプしてみると、

[root@server Fedora-8]# hexdump -C -n 512 smallest-flat.vmdk
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001b0  00 00 00 00 00 00 00 00  33 42 29 7a 00 00 00 01  |........3B)z....|
000001c0  01 00 83 fe 3f 0c 3f 00  00 00 8e 2f 03 00 00 00  |....?.?..../....|
000001d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 aa  |..............U.|
00000200
[root@server Fedora-8]#

おや? とこかで見たような。"55 aa"で終わっているということはHDDのMBRパーティション・テーブルではないか。しかもMBRと同じ512バイトの領域の終りが"55 aa"になっているということは....、最初の512バイトはMBRそのもの、と思いfdiskコマンドでフラット・ディスクのファイルのパーティションテーブルを確認してみると、

[root@server Fedora-8]# fdisk -l smallest-flat.vmdk
Disk smallest-flat.vmdk: 0 MB, 0 bytes
255 heads, 63 sectors/track, 0 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x7a294233

             Device Boot      Start         End      Blocks   Id  System
smallest-flat.vmdk1               1          13      104391   83  Linux
[root@server Fedora-8]#

そう、VMwareのフラットディスクはHDDのイメージそのものだった!(⇒ゲストの仮想ディスクをホストでマウントして使う

ゲストの仮想ディスクをホストでマウントして使う

VMwareのフラット・ディスクはHDDのイメージそのもの、ということは、わざわざゲストマシンを立ち上げなくてもホストマシン上でマウントして使えることになる。 HDDのイメージファイルをマウントして使う方法はいくつかあるが、ここでは一番手間のかからないkpartxコマンドでパーティションにアクセスするためのデバイスファイルを作成し、そのデバイスファイルをマウントしてみる。(Linux上でHDDイメージファイルをマウントして使う詳しい方法は「HDDイメージファイルをマウントして使う方法」を参照。)

[root@server Fedora-8]# ls /dev/mapper/			;: ← 念のためmapperの下が空なのを確認
control
[root@server Fedora-8]# kpartx -v -a smallest-flat.vmdk	;: ←kpartxでパーティションのファイルを作る
add map loop0p1 : 0 208782 linear /dev/loop0 63
[root@server Fedora-8]# ls /dev/mapper/			;: ←mapperの下にデバイスファイルを確認
control  loop0p1
[root@server Fedora-8]# mount /dev/mapper/loop0p1 /mnt	;: ←そのデバイスファイルをマウントしてみると
[root@server Fedora-8]# ls /mnt				;: ←ゲストマシンのファイルにアクセス
lost+found
[root@server Fedora-8]#

これで、ゲストマシンのディスクにホストマシンから直接アクセスできることが確認できた。試しに、このマウントした状態で適当なファイルを書き込んでみる。

[root@server Fedora-8]# cp /boot/vmlinuz-2.6.25.10-47.fc8 /mnt	;: ←vmlinuzをコピーしてみる
[root@server Fedora-8]# ls -l /mnt				;: ←コピーしたファイルを確認
total 2039
drwx------ 2 root root   12288 2008-07-25 16:36 lost+found
-rw-r--r-- 1 root root 2065176 2008-07-25 17:24 vmlinuz-2.6.25.10-47.fc8
[root@server Fedora-8]# umount /mnt				;: ←デバイスをアンマウントし
[root@server Fedora-8]# kpartx -v -d smallest-flat.vmdk		;: ←loopデバイスを開放する
del devmap : loop0p1
loop deleted : /dev/loop0
[root@server Fedora-8]# ls /dev/mapper/				;: ←開放されたことを確認
control
[root@server Fedora-8]#

次にゲストマシンを立ち上げてsmallestディスクの内容を確認してみると、

[root@fedora-8 ~]# mount /dev/sdb1 /mnt
[root@fedora-8 ~]# ls -l /mnt
total 2039
drwx------ 2 root root   12288 2008-07-25 16:36 lost+found
-rw-r--r-- 1 root root 2065176 2008-07-25 17:24 vmlinuz-2.6.25.10-47.fc8
[root@fedora-8 ~]#

はい、ちゃんとホスト上でコピーしたファイルをゲスト上でも確認できました。

なお、フラットデバイスをゲストマシンとホストマシンで同時にアクセスすることはやめておいた方がいい。それぞれのマシンでキャッシュしているので、データの不整合が起き、ファイルシステムを壊してしまう筈(未確認)。
⇒ホスト上のHDDイメージファイルをゲストマシンでマウントして使う

ホスト上のHDDイメージファイルをゲストマシンでマウントして使う

ゲストマシンの仮想ディスクをホストマシン上でマウントして使えるということは、その逆も可能、ということになる。

例えば、ここに壊れたノートPCのHDDがあって(HDDは壊れていないこと!)、それをもったいないので仮想マシンで使おう、という場合を考える。VMwareでは物理ディスクを仮想マシンに接続して使うことも可能だが、古くなったHDDをホストマシンにつなぎ放して使うわけにもいかないので、先ずは、一旦HDDの内容をホストマシン上でイメージファイルとして保存する。(例えば、次のような感じでバックアップする。"bs="のパラメータは利用できるメモリとの兼ね合いで決める。大きすぎるとスワップが発生し時間がかかり、小さすぎるとIO回数が増えて時間がかかる。)

[root@server tmp]# dd if=/dev/sdc of=hdd.img bs=512M
[root@server tmp]# ls -l hdd.img
-rw-r--r-- 1 root root 6007357440 2008-07-26 01:53 hdd.img
[root@server tmp]#

さて、この約6GBの"hdd.img"をゲストマシンで読めるようにする。(ちなみにこのHDDにはノートPCで使っていたWindows 98が入っている。)hdd.imgをVMwareの固定サイズ仮想ディスクの形式に合わせるようにするわけだが、いくつか方法はあるが、ここでは次のようなアプローチで実現する。

まず、元のHDDを捨てる前に、HDDの“物理”セクタ/ヘッド/シリンダの情報(ジオメトリ)を記録しておく。ここでサンプルとして使ったHDDは次のような機種である。

メーカー/機種 IBM Travelstar
モデル名 DARA-206000
容量 6.00GB
インタフェース ATA/IDE
回転数 4200RPM
シリンダ/ヘッド/セクタ数 12416 / 15 / 63

以上の情報はHDDのラベルに書かれている。もし、ラベルがなかったり情報が書かれていない場合、IDESATAで接続されてたHDDであれば hdparmコマンドで確認できる。

[root@server ~]# hdparm -i /dev/sdc

/dev/sdc:

 Model=IBM-DARA-206000     , FwRev=AR2OA51A, SerialNo=   123456789AB
 Config={ HardSect NotMFM HdSw>15uSec Fixed DTR>10Mbs }
 RawCHS=12416/15/63, TrkSize=0, SectSize=0, ECCbytes=4
 BuffType=DualPortCache, BuffSize=418kB, MaxMultSect=16, MultSect=?16?
 CurCHS=12416/15/63, CurSects=11733120, LBA=yes, LBAsects=11733120
 IORDY=on/off, tPIO={min:240,w/IORDY:120}, tDMA={min:120,rec:120}
 PIO modes:  pio0 pio1 pio2 pio3 pio4
 DMA modes:  mdma0 mdma1 mdma2
 UDMA modes: udma0 udma1 *udma2 udma3 udma4
 AdvancedPM=yes: mode=0x80 (128) WriteCache=enabled
 Drive conforms to: ATA/ATAPI-4 T13 1153D revision 17:  ATA/ATAPI-1,2,3,4

  * signifies the current active mode

[root@server ~]#

ただし、USB変換機などで接続している場合は、次のようにエラーになりデータは読めないので、物理的なジオメトリが分からない場合は、後述するようは方法をとる。(「物理ジオメトリが分からない場合はどうするか?」参照)

[root@server ~]# hdparm -i /dev/sdg

/dev/sdg:
 HDIO_GET_IDENTITY failed: Invalid argument
[root@server ~]# 

さて次に読み込んだHDDのイメージファイル、hdd.imgをVMwareのディスクとして捏造する作業に入るが、そのために一旦、VMwareの管理画面でひな形となる仮想ディスクを作成する。新たにひな形仮想ディスクを作成しても良いが、ここでは先ほど解析用に作成したsmallestという仮想ディスクがあるので、これを流用する。まず、smallestのディスク情報が書かれて"smallest.vmdk"を適当な名前でコピーして編集する。(Windows 98が入っているディスクを仮想化するので"windows98"という名前にする。)

[root@server Fedora-8]# cp smallest.vmdk windows98.vmdk
[root@server Fedora-8]#

編集前の内容は次のようになっている

# Disk DescriptorFile
version=1
CID=89d1db2d
parentCID=ffffffff
createType="monolithicFlat"

# Extent description
RW 209715 FLAT "smallest-flat.vmdk" 0

# The Disk Data Base
#DDB

ddb.toolsVersion = "7394"
ddb.adapterType = "ide"
ddb.geometry.sectors = "63"
ddb.geometry.heads = "16"
ddb.geometry.cylinders = "208"
ddb.virtualHWVersion = "4"

これをテキストエディタ等で次のように編集する。

# Disk DescriptorFile
version=1
CID=89d1db2d
parentCID=ffffffff
createType="monolithicFlat"

# Extent description
RW 11733120 FLAT "windows98-flat.vmdk" 0

# The Disk Data Base
#DDB

ddb.toolsVersion = "7394"
ddb.adapterType = "ide"
ddb.geometry.sectors = "63"
ddb.geometry.heads = "15"
ddb.geometry.cylinders = "12416"
ddb.virtualHWVersion = "4"

編集するところは、

  • ディスクの総ブロック数。この場合は 11733120。総ブロック数は先ほど調べておいたディスクの物理セクタ/ヘッド/トラックを掛けた値となる。この例では 63 × 15 × 12416。また、先ほどddコマンドでバックアップしたイメージファイルの大きさはHDDのセクタサイズの倍数、つまり512の倍数になっているので、ファイルの大きさを512で割った値も11733120になっている筈である。( 6007357440÷512 )
  • ディスクのイメージ・ファイルの名前。ここでは "windows98-flat.vmdk" とした。
  • 物理セクタ数(ddb.geometry.sectors)。ここでは63。
  • 物理ヘッド数(ddb.geometry.heads)。ここでは15。
  • 物理シリンダ数(ddb.geometry.cylinders)。ここでは12416。

これで情報ファイルの設定は終わり。次にディスク本体のイメージファイルを"windows98-flat.vmdk"という名前でコピーしてくる。

[root@server Fedora-8]# mv /tmp/hdd.img windows98-flat.vmdk
[root@server Fedora-8]#

最後に、ファイルの持ち主や実行権をVMwareの環境に合わせる。私の場合はvmwareというユーザの管理下にしているので次のように設定する。

[root@server Fedora-8]# ls -l
total 10270328
-rw------- 1 vmware vmware 4386586624 2008-07-26 08:07 Fedora-8.vmdk
-rw------- 1 vmware vmware          0 2008-07-11 20:28 Fedora-8.vmsd
-rwxr-xr-x 1 vmware vmware       1417 2008-07-25 19:38 Fedora-8.vmx
-rw------- 1 vmware vmware       8664 2008-07-26 08:07 nvram
-rw------- 1 vmware vmware  107374080 2008-07-26 08:06 smallest-flat.vmdk
-rw------- 1 vmware vmware        343 2008-07-25 19:39 smallest.vmdk
-rw-r--r-- 1 vmware vmware      44622 2008-07-26 08:07 vmware.log
-rw-r--r-- 1 root   root   6007357440 2008-07-26 01:53 windows98-flat.vmdk
-rw------- 1 root   root          348 2008-07-26 11:13 windows98.vmdk
[root@server Fedora-8]# chown vmware.vmware windows98.vmdk windows98-flat.vmdk
[root@server Fedora-8]# chmod 600 windows98.vmdk windows98-flat.vmdk
[root@server Fedora-8]# ls -l
total 10270328
-rw------- 1 vmware vmware 4386586624 2008-07-26 08:07 Fedora-8.vmdk
-rw------- 1 vmware vmware          0 2008-07-11 20:28 Fedora-8.vmsd
-rwxr-xr-x 1 vmware vmware       1417 2008-07-25 19:38 Fedora-8.vmx
-rw------- 1 vmware vmware       8664 2008-07-26 08:07 nvram
-rw------- 1 vmware vmware  107374080 2008-07-26 08:06 smallest-flat.vmdk
-rw------- 1 vmware vmware        343 2008-07-25 19:39 smallest.vmdk
-rw-r--r-- 1 vmware vmware      44622 2008-07-26 08:07 vmware.log
-rw------- 1 vmware vmware 6007357440 2008-07-26 01:53 windows98-flat.vmdk
-rw------- 1 vmware vmware        348 2008-07-26 11:13 windows98.vmdk
[root@server Fedora-8]#

以上で設定は終了である。

捏造した(?)仮想ディスクを使う

それでは、捏造(?)した仮想ディスクのファイルをゲストマシンに追加する。仮想ディスクを追加するゲストマシンで、VMwareの管理画面から[Edit virtual machines settings]で設定ウィザードを立ち上げ“Hard Disk”を追加する。“Use an existing virtual disk”を選択し、“Selecting an Existing Disk”のところで先ほどの "windows98.vmdk" を指定する。


VMwareになれた人であればゲストマシンの設定ファイル(*.vmx)を直接編集した方が簡単だろう。)
これで仮想マシンを立ちあげる。ここで使ったゲストマシンはLinuxFedora 8)ベースで、Linuxが立ち上がる。まずは新しいディスクをマウントしてアクセスできることを確認する。

なお、ゲストOSのLinuxから仮想ディスクの情報を見ると次のようになる。

[root@fedora-8 ~]# fdisk /dev/sdc

Command (m for help): p

Disk /dev/sdc: 6007 MB, 6007357440 bytes
255 heads, 63 sectors/track, 730 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sdc1   *           1         730     5863693+   c  W95 FAT32 (LBA)

Command (m for help): q

[root@fedora-8 ~]# hdparm -i /dev/sdc

/dev/sdc:

 Model=VMware Virtual IDE Hard Drive , FwRev=00000001, SerialNo=01000000000000000001
 Config={ HardSect NotMFM HdSw>15uSec SpinMotCtl Fixed DTR>5Mbs FmtGapReq }
 RawCHS=12416/15/63, TrkSize=0, SectSize=0, ECCbytes=0
 BuffType=unknown, BuffSize=32kB, MaxMultSect=64, MultSect=?16?
 CurCHS=12416/15/63, CurSects=11733120, LBA=yes, LBAsects=11733120
 IORDY=on/off, tPIO={min:160,w/IORDY:120}, tDMA={min:120,rec:120}
 PIO modes:  pio0 pio1 pio2 pio3 pio4 
 DMA modes:  mdma0 mdma1 mdma2 
 UDMA modes: udma0 udma1 *udma2 
 AdvancedPM=yes: disabled (255)
 Drive conforms to: ATA/ATAPI-4 T13 1153D revision 17:  ATA/ATAPI-1,2,3,4

  * signifies the current active mode

[root@fedora-8 ~]# 

ここで注意が必要なのは、hdparamで求めたセクタ、ヘッダ、シリンダ情報は仮想ディスクの情報ファイル windows98.vmdkに記述したとおり物理的な情報となっている。一方でfdiskで表示されるセクタ、ヘッダ、シリンダ情報はHDDのMBRから読まれる論理的な情報である。常々、何で物理的なジオメトリと論理的なジオメトリが異なるのか不思議で、Linuxの特性かと思っていたのだが、このHDDは“物理的に”Windows98のFDISK.EXEでパーティショニングしたものなので、Linux特有のものではないとわかった。今ではLBA(Logical Block Addressing)によるアクセスが主流なので、物理ジオメトリはどうでもいいようだ。

捏造した(?)仮想ディスクで立ち上げる

Linux環境から問題なくアクセスできたので、今度は捏造した(?)仮想ディスクをシステムディスクとして立ち上げてみる。当然、Windows 98が立ち上がる筈である。これまではゲストOSがLinux仮想マシンにセカンドディスクとして接続したが、ゲストOSがWindows 98仮想マシンを1つ作成し、作成時のディスクの指定のところで、先ほど作成した仮想ディスクを指定すればいい。これで、立ち上がる。が、昔のPCとVMwareの比較的に新しいPCで構成が違いすぎるためにハードウェアのプラグ&プレイ機能で、何回も新しいハードウェアのドライバを要求される。私のケースではCD-ROMドライブ自身が認識できなのでWindows 98のCDからドライバを読み込めず、そのまま[キャンセル]で立ち上げた。

このような状況でドライバを読み込ませたいのであれば、仮想ディスクを一旦、Linux仮想マシンに接続して立ち上げ、Windows 98のCDの内容をWindows 98の仮想ディスクへコピーする。そしてWindows 98仮想マシンで立ち上げ、ドライバ設定のウィザードでCDを要求されたら仮想ディスクにコピーされたホルダを指定すればいい。IDE関係のドライバがインストールできればCD-ROMも使えるようになった。(それでも、一部のデバイスWindows 98には新しすぎて、メーカーからのドライバをダウンロードしなければならない。)
昔のWindows 98VM上でサルベージするのは本題ではないので割愛する。

物理ジオメトリが分からない場合はどうするか?

ディスクのイメージファイルがあっても、もし、元のディスクの物理的なジオメトリ情報(セクタ数/ヘッド数/シリンダ数)が分からない場合はどうすればいいのだろうか? 元のディスクのメーカーやモデル名が分かればサポートホームページからこれらの情報を得ることが出来るかも知れない。一番良くあるケースとして、昔とったイメージで、既にHDDは手元になくメーカーが分かるがモデルを忘れたというケースだろう。その場合は....。
ここからの記述は憶測で書くので必ずしも合っているか分からないが、少なくとも検証した範囲では問題ない。
まず、仮想ディスクの定義ファイル windows98.vmdk を次のように定義して仮想マシンを立ち上げてみる。

# Disk DescriptorFile
version=1
CID=19454c09
parentCID=ffffffff
createType="monolithicFlat"

# Extent description
RW 11733120 FLAT "windows98-flat.vmdk" 0

# The Disk Data Base
#DDB

ddb.virtualHWVersion = "4"
ddb.geometry.cylinders = "0"
ddb.geometry.heads = "0"
ddb.geometry.sectors = "0"
ddb.adapterType = "ide"
ddb.toolsVersion = "7394"

セクタ数=0、ヘッド数=0、シリンダ数=0として仮想マシンを立ち上げて見る、と、何と問題なく仮想ディスクを認識しアクセスできる。ゲストマシンからディスクの情報をを確認してみると、次のようになっている。

[root@fedora-8 ~]# fdisk -u -l /dev/sdb

Disk /dev/sdb: 6007 MB, 6007357440 bytes
255 heads, 63 sectors/track, 730 cylinders, total 11733120 sectors
Units = sectors of 1 * 512 = 512 bytes
Disk identifier: 0x00000000

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1   *          63    11727449     5863693+   c  W95 FAT32 (LBA)
[root@fedora-8 ~]# 

fdiskが読み込むMBRからの情報は、当然、前と同じ“論理”ジオメトリになっている。問題はhdparmで取得できる“物理”ジオメトリだが、

[root@fedora-8 ~]# hdparm -i /dev/sdb

/dev/sdb:

 Model=VMware Virtual IDE Hard Drive , FwRev=00000001, SerialNo=00000000000000000001
 Config={ HardSect NotMFM HdSw>15uSec SpinMotCtl Fixed DTR>5Mbs FmtGapReq }
 RawCHS=12416/15/63, TrkSize=0, SectSize=0, ECCbytes=0
 BuffType=unknown, BuffSize=32kB, MaxMultSect=64, MultSect=?16?
 CurCHS=12416/15/63, CurSects=11733120, LBA=yes, LBAsects=11733120
 IORDY=on/off, tPIO={min:160,w/IORDY:120}, tDMA={min:120,rec:120}
 PIO modes:  pio0 pio1 pio2 pio3 pio4 
 DMA modes:  mdma0 mdma1 mdma2 
 UDMA modes: udma0 udma1 *udma2 
 AdvancedPM=yes: disabled (255)
 Drive conforms to: ATA/ATAPI-4 T13 1153D revision 17:  ATA/ATAPI-1,2,3,4

  * signifies the current active mode

[root@fedora-8 ~]# 

となっている。ちなみにこの状態はゲストマシンを一旦インベントリから削除し、その上でホスト上でVMwareサービスを再起動しているのでキャッシュに保存されているとは考えられない。となると、可能性は2つ。VMwareの仮想ドライバが適当にジオメトリを作っているか、HDDのイメージファイルの何処かに物理ジオメトリの情報が書かれていたが、しかない。直感的に後者の可能性が低いと思い、確認のために(一旦、仮想ディスクのイメージファイル、windows98-flat.vmdkを退避した上で)次のように仮想ディスクの内容を全て“0”で潰して何の情報も書き込まれていない状態する。

[root@server Fedora-8]# dd if=/dev/zero of=windows98-flat.vmdk bs=512 count=11733120
11733120+0 records in
11733120+0 records out
6007357440 bytes (6.0 GB) copied, 169.256 s, 35.5 MB/s
[root@server Fedora-8]# chown vmware.vmware windows98-flat.vmdk
[root@server Fedora-8]# chmod 600 windows98-flat.vmdk
[root@server Fedora-8]# ls -l windows98-flat.vmdk
-rw------- 1 vmware vmware 6007357440 2008-07-26 20:54 windows98-flat.vmdk
[root@server Fedora-8]#

念のために完全に潰したかを確認して、

[root@server Fedora-8]# hexdump -C windows98-flat.vmdk
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
166110000
[root@server Fedora-8]#

さて、ゲストマシンをブートするとどうなるか。

[root@fedora-8 ~]# fdisk /dev/sdb
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel with disk identifier 0xc29e8b71.
Changes will remain in memory only, until you decide to write them.
After that, of course, the previous content won't be recoverable.

Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite)

Command (m for help): p

Disk /dev/sdb: 6007 MB, 6007357440 bytes
255 heads, 63 sectors/track, 730 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0xc29e8b71

   Device Boot      Start         End      Blocks   Id  System

Command (m for help): q

[root@fedora-8 ~]# 

MBRは完全に壊れているのでfdiskではパーティション・テーブルを表示することはできない。ただし、論理ジオメトリとしてセクタ数を63、ヘッダ数を255として割り当てることができる最大シリンダ数を730と想定していることがわかる。次に、クダンのhdparmコマンドではどうか?

[root@fedora-8 ~]# hdparm -i /dev/sdb

/dev/sdb:

 Model=VMware Virtual IDE Hard Drive , FwRev=00000001, SerialNo=00000000000000000001
 Config={ HardSect NotMFM HdSw>15uSec SpinMotCtl Fixed DTR>5Mbs FmtGapReq }
 RawCHS=12416/15/63, TrkSize=0, SectSize=0, ECCbytes=0
 BuffType=unknown, BuffSize=32kB, MaxMultSect=64, MultSect=?16?
 CurCHS=12416/15/63, CurSects=11733120, LBA=yes, LBAsects=11733120
 IORDY=on/off, tPIO={min:160,w/IORDY:120}, tDMA={min:120,rec:120}
 PIO modes:  pio0 pio1 pio2 pio3 pio4 
 DMA modes:  mdma0 mdma1 mdma2 
 UDMA modes: udma0 udma1 *udma2 
 AdvancedPM=yes: disabled (255)
 Drive conforms to: ATA/ATAPI-4 T13 1153D revision 17:  ATA/ATAPI-1,2,3,4

  * signifies the current active mode

[root@fedora-8 ~]# 

なんと、どこにも情報がないの筈なのに物理ジオメトリである、63セクタ、15ヘッド、12416シリンダとなっている。
以上から(+αの実験から)VMwareの仮想ディスクドライバは仮想OSからの問い合わせに対して、HDDの“仮想”物理ジオメトリとして次のように決定しているらしい*1

  1. 定義ファイ(*.vmdk)に記述された総セクタ数より、イメージファイル(*-flat.vmdk)の総セクタ数(=ファイルサイズ÷512)が小さい場合はエラーとなり仮想マシン自身が立ち上がらない。
  2. 定義ファイルに書かれている各値が、総セクタ数=セクタ数×ヘッド数×シリンダ数 となっていれば、そのジオメトリを採用する。ただし、セクタ数が63より大きな場合は、そのジオメトリは無視され、次の方法を適用する。
  3. もしそうでなければ、まず、記述された総セクタ数が63の倍数でなければ、その総セクタ数を超えない範囲で最大の63の倍数を総セクタとする。次に定義ファイルに書かれているジオメトリは無視して、セクタ数を63、ヘッド数を15として、記述されている総セクタ数を超えない範囲で最大のシリンダ数を算出してジオメトリとする、らいし。この場合は、実際の総セクタ数と算出された総セクタ数の間で端数がでるので、その部分は仮想ディスクとしては使えない。

結論:ディスクイメージの元のHDDのジオメトリが分からなければ、総セクタ数としてファイルサイズ÷512(の小数点以下を切り捨てた整数)を総セクタ数として記述しておき、セクタ数、ヘッド数、シリンダ数は“0”としておけばいい。その状態で仮想マシンを立ち上げると、適当なセクタ数、ヘッド数、シリンダ数をVMwareの仮想ディスクドライバが決定してくれる。もし、定義ファイルに“0”のままでは気になるのであれば、hdparmで得たドライバが決定したジオメトリの値を定義ファイルに書き込んでおけば良い。というところだろうか。

今時のコンピュータでは、ディスク上の情報の位置は先頭からのセクタ番号だけアクセスして、昔の様にヘッド番号とかシリンダ番号、トラック内のセクタ番号を使ってアクセスしないので、これでも問題ない、ということかもしれない。(fdiksがHDDの物理ジオメトリは無視して、セクタ数を63、ヘッド数を255にしてパーティションするのも、この考え方であれば納得できる。)
参考:Wikipedia, Cylinder head sector
参考:Wikipedia, Logical Block Addressing

*1:VMwareのバージョンにもよって異なるかも知れない。私が検証したのはVMware Server 1.0.5である。また、ディスクの容量によってもアルゴリズムが変わってくる可能性もある。

物理ディスクと仮想ディスクの完全互換は何につかえるか

何に使えるかって、こんなに便利なことはないと思う。仮想マシン自身大変便利な環境でほぼ毎日、仮想環境を使っている。仮想環境ではディスクを移動したりコピーしたりが自由に、しかも非常に簡単にできる。しかし、その仮想ディスクが最終的には物理ディスクに簡単に落とせるとなればさらに使い勝手が向上する。加えて、逆に物理的なHDDを仮想環境でもつかえるとなると色々と使える。(VMwareに限らず物理ディスクを仮想環境で使う機能はあるが、“物理ディスク”が使えるのと“物理ディスクのイメージ・ファイル”が使えるのは大きくことなる。)例えば、次のようなことに使えないだろうか。

  • 昔のPCのディスクを変換ツールを使わず、純粋にイメージとして保存、再活用する。仮想マシン製品は物理環境を仮想環境へ変換するツールを提供しているが、インストールしたり、重かったり、ネットワークで別のマシンを用意したり、また変換後は必要なくなったりで「いま一つだなぁ」と思っていたが、物理ディスクをイメージとして扱えるのであればわざわざツールも必要なく、また、完全にオリジナルの形でイメージを保存しておくことができる。
  • 非力なターゲットマシンでの開発を強力な仮想マシン環境で実現できる。物理ディスクと全く同じジオメトリの仮想ディスクを用意しておけば、仮想マシン環境で開発した結果をそのまま物理ディスクへコピーしてターゲットマシンで使えるし、ターゲットマシンで不具合が出た場合、そっくりそのままのディスクイメージを仮想環境へ持って来て使える。(但し、ターゲットとホストの間でマシンアーキテクチャに互換性がないとダメだが。

VMware Server製品では、新規に仮想ディスクを定義する際、単に0.1GB単位での大きさが指定できるだけだが、セクタ数、ヘッド数、シリンダ数といったジオメトリを指定して仮想ディスクを定義することも出来ればもっと使いやすくなるのではないだろうか。