Skip to content

Commit a082a70

Browse files
committed
Fixes on part20
1 parent e5d29f9 commit a082a70

File tree

1 file changed

+60
-24
lines changed

1 file changed

+60
-24
lines changed

part20.md

+60-24
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,76 @@
1-
ハイパーバイザーの作り方 第20回 bhyveにおける仮想ディスクの実装
1+
---
2+
authors:
3+
- 'Takuya ASADA [email protected]'
4+
title: |
5+
ハイパーバイザの作り方~ちゃんと理解する仮想化技術~
6+
第20回 bhyveにおける仮想ディスクの実装
7+
...
28

39
はじめに
10+
========
411
前回の記事では、bhyveにおける仮想NICの実装についてTAPデバイスを用いたホストドライバの実現方法を例に挙げ解説しました。
12+
513
今回の記事では、bhyveにおける仮想ディスクの実装について解説していきます。
614

715
bhyveにおける仮想ディスクの実装
16+
===============================
817
bhyveがゲストマシンに提供する仮想IOデバイスは、全てユーザプロセスである/usr/sbin/bhyve上に実装されています(図1)。
18+
919
bhyveは実機上のディスクコントローラと異なり、ホストOSのファイルシステム上のディスクイメージファイルに対してディスクIOを行います。
20+
1021
これを実現するために、/usr/sbin/bhyve上の仮想ディスクコントローラは、ゲストOSからのIOリクエストをディスクイメージファイルへのファイルIOへ変換します。
1122

1223
以下に、ディスク読み込み手順と全体図(図1)を示します。
13-
1,ゲストOSはvirtio-blkドライバを用いて、共有メモリ上のリングバッファにIOリクエストを書き込みます。そして、IOポートアクセスによってハイパーバイザにリクエスト送出を通知する。IOポートアクセスによってVMExitが発生し、CPUの制御がホストOSのvmm.koのコードに戻る。
24+
25+
1. ゲストOSはvirtio-blkドライバを用いて、共有メモリ上のリングバッファにIOリクエストを書き込みます。そして、IOポートアクセスによってハイパーバイザにリクエスト送出を通知する。IOポートアクセスによってVMExitが発生し、CPUの制御がホストOSのvmm.koのコードに戻る。
1426
bhyveの仮想ディスクコントローラのエミュレーションは、ユーザランドで行われています。vmm.koはこのVMExitを受けてioctlをreturnし/usr/sbin/bhyveへ制御を移す。
15-
2,ioctlのreturnを受け取った/usr/sbin/bhyveは、仮想ディスクコントローラの共有メモリ上のリングバッファからリクエストを取り出します。
16-
3,2で取り出したリクエストをパースし、ディスクイメージファイルにread()を行います。
17-
4,読み出したデータを共有メモリ上のリングバッファに乗せ、ゲストOSに割り込みを送ります。5,ゲストOSは割り込みを受け、リングバッファからデータを読み出します。
18-
図1,ディスク読み込み手順
27+
2. ioctlのreturnを受け取った/usr/sbin/bhyveは、仮想ディスクコントローラの共有メモリ上のリングバッファからリクエストを取り出します。
28+
3. 2で取り出したリクエストをパースし、ディスクイメージファイルにread()を行います。
29+
4. 読み出したデータを共有メモリ上のリングバッファに乗せ、ゲストOSに割り込みを送ります。
30+
5. ゲストOSは割り込みを受け、リングバッファからデータを読み出します。
31+
32+
![ディスク読み込み手順](figures/part20_fig1)
1933

2034
書き込み処理では、リクエストと共にデータをリングバッファを用いて送りますが、それ以外は読み込みと同様です。
2135

22-
virtio-blkの仕組み
36+
virtio-blkのしくみ
37+
==================
2338
これまでに、準仮想化I/Oの仕組みとして、virtioとVirtqueue、virtio-netについて解説してきました。ここでは、ブロックデバイスを準仮想化する、virtio-blkについて解説を行います。
24-
virtio-netは受信キュー、送信キュー、コントロールキューの3つのVirtqueueからなっていましたが、virtio-blkでは単一のVirtqueueを用います。これは、ディスクコントローラの挙動がNICとは異なり、必ずOSからコマンド送信を行った後にデバイスからレスポンスが返るという順序になるためです。
39+
40+
virtio-netは受信キュー、送信キュー、コントロールキューの3つのVirtqueueからなっていましたが、virtio-blkでは単一のVirtqueueを用います。これは、ディスクコントローラの挙動がNICとは異なり、必ずOSからコマンド送信を行った後にデバイスからレスポンスが返るという順序になるためです[^1]。
41+
2542
ブロックIOのリクエストは連載第12回の「ゲスト→ホスト方向のデータ転送方法」で解説した手順で送信されます。
26-
virtio-blkでは1つのブロックIOリクエストに対して、以下のようにDescriptor群を使用します。1個目のDescriptorはstruct
27-
virtio~b~lk~o~uthdr(表1)を指します。
28-
この構造体にはリクエストの種類、リクエスト優先度、アクセス先オフセットを指定します。2〜(n−1)個目以降のDescriptorはリクエストに使用するバッファを指します。リクエストがreadな場合は読み込み結果を入れる空きバッファを、writeな場合は書き込むデータを含むバッファを指定します。
43+
44+
virtio-blkでは1つのブロックIOリクエストに対して、以下のようにDescriptor[^2]群を使用します。1個目のDescriptorはstruct virtio_blk_outhdr(表1)を指します。この構造体にはリクエストの種類、リクエスト優先度、アクセス先オフセットを指定します。2〜(n−1)個目以降のDescriptorはリクエストに使用するバッファを指します。リクエストがreadな場合は読み込み結果を入れる空きバッファを、writeな場合は書き込むデータを含むバッファを指定します
45+
2946
バッファのアドレスは物理アドレス指定になるため、仮想アドレスで連続した領域でも物理的配置がバラバラな状態な場合があります。これをサポートするためにバッファ用Descriptorを複数に別けて確保出来るようになっています。
30-
struct
31-
virtio~b~lk~o~uthdrにはバッファ長のフィールドがありませんが、これはDescriptorのlenフィールドを用いてホストへ通知されます。n個目のDescriptorは1byteのステータスコード(表2)のアドレスを指します。このフィールドはホスト側がリクエストの実行結果を返すために使われます。
3247

33-
表1,struct virtio~b~lk~o~uthdr
48+
struct virtio_blk_outhdrにはバッファ長のフィールドがありませんが、これはDescriptorのlenフィールドを用いてホストへ通知されます。n個目のDescriptorは1byteのステータスコード(表2)のアドレスを指します。このフィールドはホスト側がリクエストの実行結果を返すために使われます。
49+
50+
type member description
51+
----- ------- --------------------------------------------------
52+
u32 type リクエストの種類(read=0x0, write=0x1, ident=0x8)
53+
u32 ioprio リクエスト優先度
54+
u64 sector セクタ番号(オフセット値)
55+
56+
Table: struct virtio_blk_outhdr
57+
58+
type member description
59+
----- ------- ---------------------------
60+
0 OK 正常終了
61+
1 IOERR IOエラー
62+
2 UNSUPP サポートされないリクエスト
3463

35-
表2,ステータスコード
64+
Table: ステータスコード
3665

3766
ディスクイメージへのIO
38-
/usr/sbin/bhyveはvirtio-blkを通じてゲストOSからディスクIOリクエストを受け取り、ディスクイメージへ読み書きを行います。bhyveが対応するディスクイメージはRAW形式のみなので、ディスクイメージへの読み書きはとても単純です。ゲストOSから指定されたオフセット値とバッファ長をそのまま用いてディスクイメージへ読み書きを行えばよいだけです。
67+
======================
68+
/usr/sbin/bhyveはvirtio-blkを通じてゲストOSからディスクIOリクエストを受け取り、ディスクイメージへ読み書きを行います。bhyveが対応するディスクイメージはRAW形式のみなので、ディスクイメージへの読み書きはとても単純です。ゲストOSから指定されたオフセット値とバッファ長をそのまま用いてディスクイメージへ読み書きを行えばよいだけです[^3]。
69+
3970
それでは、このディスクイメージへのIOの部分についてbhyveのコードを実際に確認してみましょう。/usr/sbin/bhyveの仮想ディスクIO処理のコードをコードリスト1に示します。
4071

72+
コードリスト1,/usr/sbin/bhyveの仮想ディスクIO処理
73+
---------------------------------------------------
4174
```
4275
/* ゲストOSからIO要求があった時に呼ばれる */
4376
static void
@@ -54,11 +87,14 @@ pci_vtblk_proc(struct pci_vtblk_softc *sc, struct vqueue_info *vq)
5487
uint16_t flags[VTBLK_MAXSEGS + 2];
5588
/* iovに1リクエスト分のDescriptorを取り出し */
5689
n = vq_getchain(vq, iov, VTBLK_MAXSEGS + 2, flags);
57-
〜 略 〜
 /* 一つ目のDescriptorはstruct virtio_blk_outhdr */
58-
vbh = iov[0].iov_base;
 /* 最後のDescriptorはステータスコード */
90+
〜 略 〜
91+
/* 一つ目のDescriptorはstruct virtio_blk_outhdr */
92+
vbh = iov[0].iov_base;
93+
/* 最後のDescriptorはステータスコード */
5994
status = iov[--n].iov_base;
6095
〜 略 〜
61-
/* リクエストの種類 */
 type = vbh->vbh_type;
96+
/* リクエストの種類 */
97+
type = vbh->vbh_type;
6298
writeop = (type == VBH_OP_WRITE);
6399
/* オフセットをsectorからbyteに変換 */
64100
offset = vbh->vbh_sector * DEV_BSIZE;
@@ -104,12 +140,12 @@ pci_vtblk_proc(struct pci_vtblk_softc *sc, struct vqueue_info *vq)
104140
vq_relchain(vq, 1);
105141
}
106142
```
107-
コードリスト1,/usr/sbin/bhyveの仮想ディスクIO処理
108143

109-
(1) NICではOSから何もリクエストを送らなくてもネットワーク上の他のノードからパケットが届くのでデータが送られてきます。このため、必ずOSからリクエストを送ってから届くというような処理にはなりません。
110-
(2) Virtqueue上でデータ転送をおこなうための構造体。第12回のVirtqueueの項目を参照。
111-
(3) QCOW2形式などのより複雑なフォーマットでは未使用領域を圧縮するため、ゲスト・ホスト間でオフセット値が一致しなくなり、またメタデータを持つ必要が出てくるのでRAWイメージと比較して複雑な実装になります。
144+
[^1]: NICではOSから何もリクエストを送らなくてもネットワーク上の他のノードからパケットが届くのでデータが送られてきます。このため、必ずOSからリクエストを送ってから届くというような処理にはなりません。
145+
[^2]: Virtqueue上でデータ転送をおこなうための構造体。第12回のVirtqueueの項目を参照。
146+
[^3]: QCOW2形式などのより複雑なフォーマットでは未使用領域を圧縮するため、ゲスト・ホスト間でオフセット値が一致しなくなり、またメタデータを持つ必要が出てくるのでRAWイメージと比較して複雑な実装になります。
112147

113-
## まとめ
148+
まとめ
149+
======
114150
今回は仮想マシンのストレージデバイスについて解説しました。
115151
次回は、仮想マシンのコンソールデバイスについて解説します。

0 commit comments

Comments
 (0)