仮想化環境ではディスクやメモリなどのリソースを必要に応じて増減できる点が魅力です。今回はKVMのゲストOSを動作させたまま、ディスクを追加する方法をご紹介します。
ディスクの動的追加について調べると、KVMの本家サイトにあるHotadd pci devicesというページに行き当たります。このページの方法を要約するとこんな感じです。
- HDDはPCIのSCSIコントローラと共に動的に追加する
- ゲストOSはPCIカードの動的な増減を検出しなければならない
- そこでpci_hotplug関連のカーネルモジュールをロードする
- qemuのモニタからPCIカードとHDDイメージを追加すると、ゲストOSが動的に検出してくれる
なるほど。ちょっと試してみましょう。
qemuモニタの使い方
本論のディスク追加の前に、qemuモニタの使い方に触れておきます。
qemuモニタはホストOS上からVMを操作するためのインターフェースです。qemuモニタへのアクセス方法は、オプションの指定によって選択できるのですが、telnet経由で利用するのが手っ取り早いと思います。そのためには、以下のようなオプションを指定します。
-monitor telnet::4444,server,nowait
指定している「4444」というのはポート番号です。環境に応じて適切なポート番号を選んでください。たとえば複数のVMを起動する場合なら、それぞれ異なるポート番号を付けなければいけません。さてqemuモニタは4444番ポートで待ち受けているので、telnetを使って繋いでみます。
host# telnet localhost 4444
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
QEMU 0.12.2 monitor - type 'help' for more infomation
(qemu)
以上のようにプロンプトが出て、コマンド入力待ちの状態になります。
qemuモニタは、仮想マシンであるVMに対してさまざまなコマンドを送ったり、状態を確認したりすることができます。helpコマンドを使うと長いリストが表示されるのでそれをご覧になるとよいでしょう。たとえばリセットボタンを押す(system_reset)、電源を切る(system_powerdown、quit)、VMを移動する(migrate)などのコマンドが用意されています。本稿では特に詳細の説明をしないままqemuモニタのコマンドを多用しますが、こちらのhelpを参照いただければ概要は理解していただけると思います。
本家サイトの手順を試す
それでは本家サイトの手順に沿って動的ディスクの追加を試してみましょう。まずはゲストOSを起動します。今回の実験では、ホストOSにFedora12、ゲストOSにはCentOS5.0.3を使いました。pci_hotplugというモジュールを探してみたのですが見つかりませんでした。しかし、どうやらacpiphpをロードしておけば大丈夫のようです。
guest# modprobe acpiphp
guest# dmesg | less
<SNIP>
acpiphp:ACPI Hot Plug PCI Controller Driver version:0.5
acpiphp_glue:can't get bus number,assuming 0
decode_hpp:Could not get hotplug parameters. Use defaults
:
:
この状態でqemuモニタからドライブを追加します。追加コマンドはpci_addで、SCSIのコントローラと同時にドライブを指定できます。
(qemu) pci_add auto storage file=/root/kvm/add.img,if=scsi
OK domain 0,bus 0,slot 4,function 0
「slot 4」とはPCIスロットの4番目という意味です。SCSI IDは特に指定しなければ0になるようです。モニタからファイル名を指定するときは絶対パスにしてください。-daemonizeオプションを付けている場合、シェルとqemuのcwdが同一でないため、ファイルが見つからないエラーになってしまいます。
qemuモニタでコマンドを投入すると、すぐにゲストOSで認識されます。dmesgをチェックするとこんなメッセージが残っているはずです。
guest# dmesg | less
<SNIP>
ACPI Exception (pci_bind-0302):AE_NOT_FOUND,Unable to get data from device S4 [20060707]
decode_hpp:Could not get hotplug parameters. Use defaults
PCI:Enabling device 0000:00:04.0 (0000 ->0003)
ACPI:PCI Interrupt Link [LNKD] enabled at IRQ 10
ACPI:PCI Interrupt 0000:00:04.0[A] ->Link [LNKD] ->GSI 10 (level,high) ->IRQ 10
sym0:<895a>rev 0x0 at pci 0000:00:04.0 irq 10
sym0:No NVRAM,ID 7,Fast-40,LVD,parity checking
sym0:SCSI BUS has been reset.
scsi0:sym-2.2.3
Vendor:QEMU Model:QEMU HARDDISK Rev:0.12
Type: Direct-Access ANSI SCSI revision:03
target0:0:0:tagged command queuing enabled,command queue depth 16.
target0:0:0:Beginning Domain Validation
target0:0:0:Domain Validation skipping write tests
target0:0:0:Ending Domain Validation
SCSI device sda:10485760 512-byte hdwr sectors (5369 MB)
sda:Write Protect is off
sda:Mode Sense:1c 00 00 08
SCSI device sda:drive cache:write through
SCSI device sda:10485760 512-byte hdwr sectors (5369 MB)
sda:Write Protect is off
sda:Mode Sense:1c 00 00 08
SCSI device sda:drive cache:write through
sda:sda1
sd 0:0:0:0:Attached scsi disk sda
sd 0:0:0:0:Attached scsi generic sg0 type 0
追加したディスクは/dev/sda1と認識されています。後は/dev/sda1をフォーマットして、好きなポイントにマウントするだけです。簡単ですね。
acpiphpモジュールを使わない方法
本家の方法は非常に簡単ですが、acpiphpモジュールを使わず、あらかじめSCSIドライバだけ入れておきたいときはどうすればよいでしょうか。
KVM(qemu)の起動時オプションでは、SCSIディスクを指定してやることはできますが、SCSIコントローラのみ有効にするオプションがありません。SCSIディスクを指定しない限り、SCSIコントローラを有効にすることができないのです。
一方、qemuモニタのpci_addコマンドは、ディスクイメージを指定しないで実行できます。このような非直交性は大変奇妙に思えるのですが、対応していないのでどうしようもありません。そこで次のようなトリックを考えてみます。
- qemuに-Sオプションを付けて起動し、VMをpause状態にする
- qemuモニタからSCSIコントローラを追加する
- pauseを解除してゲストOSをブートする
こうすれば、余計なディスクをマウントせずにブートできるはずです。実際に試してみましょう。まずは-Sオプションを付けて起動します。qemuモニタでステータスを確認すると、確かにpauseになっています。
(qemu) info status
VM status:paused
続いてSCSIコントローラを追加します。それにはpci_addコマンドを使います。
(qemu) pci_add auto storage if=scsi
OK domain 0,bus 0,slot 4,function 0
ここで「slot 4」と表示されていることに注意してください。後でこのパラメータが必要になります。このコマンドでは、SCSIコントローラは入りますが、ドライブは追加されません。この状態からpauseを解除します。
(qemu) c
ゲストOSが起動したらログインします。テスト環境では以下のようにSCSIドライバが見えています。
guest# lsmod | grep scsi
scsi_dh 41665 1 dm_multipath
scsi_transport_spi 59841 1 sym53c8xx
scsi_mod 196697 6 sg,scsi_dh,sym53c8xx,scsi_transport_spi,libata,sd_mod
qemuモニタに戻って、今度はディスクを追加します。drive_addの最初のパラメータは、SCSIコントローラに割り当てられたスロット番号です。pci_addを実行したときに表示されていましたね。ここでは 4 になります。
(qemu) drive_add 4 file=/root/kvm/add.img,if=scsi
OK bus 0,unit 0
(qemu) info block
ide0-hd0:type=hd removable=0 file=vm03.img ro=0 drv=raw encrypted=0
ide1-cd0:type=cdrom removable=1 locked=0 [not inserted]
floppy0:type=floppy removable=1 locked=0 [not inserted]
sd0:type=floppy removable=1 locked=0 [not inserted]
scsi0-hd0:type=hd removable=0 file=/root/kvm/add.img ro=0 drv=raw encrypted=0
info blockコマンドを使うと、現在VMが認識しているブロックデバイスのリストを確認できます。ご覧いただくと、きちんと追加されているのが分ります。
またゲストOSに戻ります。本家の方法ではacpiphpが動的に認識してくれましたが、今度は手動でディスクを認識させなければいけません。これを実行するには、/proc/scsi/scsiにコマンドを送りつけて行います。
/proc/scsi/scsiは、catすると現在の状態を表示し、echoを使ってコマンドをリダイレクトするとそれを実行してくれます。ディスクを追加するには以下のようにします。
guest# echo "scsi add-single-device 0 0 0 0" >/proc/scsi/scsi
guest# cat /proc/scsi/scsi
Attached devices:
Host:scsi0 Channel:00 Id:00 Lun:00
Vendor:QEMU Model:QEMU HARDDISK Rev:0.12
Type: Direct-Access ANSI SCSI revision:03
add-single-deviceに与えるパラメータの意味はThe Linux SCSI programming HOWTO:使用にあたって必要なものは? を参照ください。この場合SCSIカード=0、ID=0なので、全部0でOKです。続けて実行しているcatで、正しく認識されていることが確認できます。
ここまでくればディスクは/dev/sda1で認識できています。フォーマットしてマウントすれば終わりです。
利点と欠点
以上2つの方法をご紹介しましたが、利点と欠点についてそれぞれ考えてみます。
- acpiphpモジュールを使うとアタッチ・デタッチが非常に速くて楽
- acpiphpモジュールはNICの追加にも対応している
- しかし余計なモジュールを抱えているという欠点もある
- acpiphpモジュールを使わない場合、完全なデタッチができない。これはKVMの問題で、いったんSCSIコントローラに追加したドライブを削除できないため。モジュールがあればSCSIコントローラごとデタッチできるので、強引ながらも削除はできる
- acpiphpモジュールを使わない場合、ドライブのアタッチのために/proc/scsi/scsiに投げるコマンドが煩雑
なんとも丙丁つけがたい感じです。
FreeBSDの場合
ゲストOSをFreeBSDにした場合、どうなるでしょうか。FreeBSDの場合、acpiphpに相当する機能があるのか不明だったので、それなしで済ます手順を試してみました。起動時のKVMの操作部分はCentOSで行ったのと同じで;
- qemuモニタからSCSIコントローラを追加
- qemuに-Sオプションを付けて起動し、VMをpause
- pauseを解除してゲストOSをブート
とします。
起動したFreeBSDで動的に追加されたドライブを認識するには、camcontrolを使います。qemuモニタでドライブを指定した後、ごく簡単に次のコマンドを実行するだけで完了します。
freebsd# camcontrol rescan all
Re-scan of bus 0 was successful
freebsd# camcontrol devlist -v
scbus0 on sym0 bus 0:
<QEMU QEMU HARDDISK 0.12> at scbus0 target 0 lun 0 (da0,pass0)
<> at scbus0 target -1 lun -1 ()
scbus-1 on xpt0 bus 0:
<> at scbus-1 target -1 lun -1 (xpt0)
これで/dev/da0が見え、フォーマットが可能になります。
参考文献
- Hotadd pci devices
ディスクだけでなく、NICの追加についても説明しています。 - The Linux SCSI programming HOWTO





[...] This post was mentioned on Twitter by 田中邦裕 and Kazuhisa Hara,鷲北 賢. 鷲北 賢 said:さくらインターネット研究所ブログ KVMを使う(ディスクの動的追加編) http://research.sakura.ad.jp/2010/05/17/kvm-diskatta [...]