彷徨えるフジワラ

年がら年中さまよってます

VMODSORT on ZFS

現行 Solarisファイルシステムフレームワークでは、ファイル内容をキャッシュするためのメモリページ一覧を、vnode_t 毎に管理している。

但し、キャッシュページのデフォルトサイズが 8K(2^13) バイトであるため、例えば 1G(2^30) バイトのファイルの場合、2^(30-13) = 2^17 = 128K 個のエントリがぶら下がることになる。

そうなると、何らかの契機で「ファイル全体のダーティページ書き出し」の必要が出たりしようものなら、各ページ毎に書き出し要否を確認するためには線形探索が必要になり、恐ろしくコストが掛かる結末に。

そこで、このような事態を回避するために、Solarisファイルシステムでは VMODSORT という仕組みを提供している。この仕組みは:

  • MMU が機能提供している(多分、ページ改変時のイベント通知等) ⇒ この場合、pvn_vmodsort_supported 変数が非0に設定される
  • vnode_t の v_flag フィールドに VMODSORT フラグが立っている

という場合に限り、そのファイル= vnode_t に関するキャッシュ内容保持リストは:

  • 前半は、改変済みページの offset 昇順
  • 後半は、未改変ページの offset 昇順

という感じに区分けされた状態に整列される、というもの。

こうすることで、未改変ページに行き当たったなら、改変済みページの確認を打ち切ることができるので、リスト全走査と比較すれば格段に効率化される。

当然「並べ替え」させるためのコストはゼロではないのだが:

  • 大規模ファイルの場合は、並べ替えによる効率化メリットで相殺
  • 小規模ファイルの場合は、そもそも並べ替えのコストが高くない

と考えれば、妥当なところだろう。

この VMODSORT 機構は、以前 OpenSolaris のソース調査をした際には:

  • ZFS/UFS は問答無用で VMODSORT フラグを立てる
  • それ以外の同梱ファイルシステムは VMODSORT を使用していない

という状況だったと記憶していたのだが、OpenSolaris 勉強会の最中に実際に ZFS が稼動しているマシン上で以下の要領により VMODSORT フラグを確認してみると:

walk vn_cache | ::print vnode_t
{ v_lock = { _opaque = [ 0 ] } v_flag = 0 v_count = 0 v_data = 0xffffff0e664e2858 ....

みたいな感じで v_flag フィールドに VMODSORT フラグが立っていない。

時間も無かったので結局その場は保留として、この件に関する調査が宿題ということに。

で、早速ソースを確認してみたところ、ZFS 実装で vnode 構築を一手に引き受けている zfs_znode.czfs_znode_alloc() における処理は以下のようになっている:

        switch (vp->v_type) {
.....
        case VREG:
                vp->v_flag |= VMODSORT;
....

うーむ、記憶通り、明らかに問答無用で VMODSORT を設定しているんだけどなぁ。

…………あ!わかった!VREG 以外には立てていない= VREG 以外を見てたんだ!

vn_cache から辿れる vnode_t の種別を確認すると:

> ::walk vn_cache | ::print vnode_t v_type ! sort | uniq
v_type = 0 (VNON)
v_type = 0t10 (VPORT)
v_type = 1 (VREG)
v_type = 2 (VDIR)
v_type = 3 (VBLK)
v_type = 4 (VCHR)
v_type = 5 (VLNK)
v_type = 6 (VFIFO)
v_type = 7 (VDOOR)
v_type = 8 (VPROC)
v_type = 9 (VSOCK)

VREG 以外も相当紛れ込んでいる。集計してみたら、1/4 は VREG 以外のものだったので、たまたま選択したものが VREG 以外だったとしても無理は無い。あるいはリスト冒頭に非 VREG 以外が集まり易い=参照され易いものが VREG 以外になり易いのかもね。