ホスト上の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である。また、ディスクの容量によってもアルゴリズムが変わってくる可能性もある。