SitefinderOracle and Sun
Secure Search

BigAdmin System Administration Portal
ZFS ソースツアー
Print-friendly VersionPrint-friendly Version

ZFS ソースツアー

ZFS POSIX Layer ZFS Emulated Volume Management Control Interface ZFS Intent Log ZFS Attribute Processor Pool Traversal Dataset and Snapshot Layer Data Management Unit Adaptive Replacment Cache ZFS I/O Pipeline Virtual Device Layer Pool Configuration ZFS Interface Library ZFS Java Interface Traditional Applications Raw Device Applications Java Based GUI zfs(1M) and zpool(1M) Layered Device Interface

このページは、ZFS ファイルシステムに関連するソースコードの概要を説明します。ZFS の紹介を目的とはしていません。ファイルシステムアーキテクチャーの一般的意味はもちろん、よく使用される用語や定義をすでにある程度理解していることを前提としています。

Sun では、ZFS が次の 3 つのコンポーネントから構成されていると通常説明しています。ZPL (ZFS POSIX Layer)、DMU (Data Management Unit)、および SPA (Storage Pool Allocator) の 3 つのコンポーネントです。この説明はスライドウェア用の例としては役に立つのですが、実際の話はもう少し複雑です。次のイメージに、もう少し詳しく概要を示します。領域の 1 つをクリックすると、詳細とソースコードへのリンクが表示されます。

この画像では前述の 3 つの基本レイヤーがあるのは同じですが、各レイヤー内の相当数の要素も記載されています。また、管理パス、すなわち zfs(1M) と zpool(1M) だけでなく、zvol コンシューマも記載されています。これらのサブシステムの概要については後述します。この概要は、すべての仕組みを完全に網羅したものではありません。詰まるところ、ソースコードこそが最終的なドキュメントになります。ソースコードをわかりやすく記載し、十分なコメントを付けたつもりです。そうなっていない箇所を発見された場合は、いつでも ZFS ディスカッションフォーラムに投稿してください。

ファイルシステムコンシューマ

次に、POSIX ファイルシステム API を介してもっぱら ZFS と対話する基本アプリケーションを示します。事実上すべてのアプリケーションがこのカテゴリに分類されます。システムコールが、汎用的な OpenSolaris VFS レイヤーを経由して ZPL に渡されます。

デバイスコンシューマ

ZFS は、「エミュレートされるボリューム」を作成できます。このボリュームはストレージプール内のストレージに基づいていますが、通常のデバイスとして /dev の下にあります。これはよく使用されるユースケースではありませんが、この機能が役に立つケースが少数ですがあります。これらのデバイスと直接対話する少数のアプリケーションがありますが、もっとも頻繁に使用するコンシューマはデバイスの上位層のターゲットドライバまたはカーネルファイルシステムです。

管理 GUI

Solaris はビルド 28 から Web ベースの ZFS GUI とともに出荷されます。ZFS GUI は現時点では OpenSolaris には同梱されていませんが、JNI の上位層の Java ベース GUI の一例になります。

管理コンシューマ

管理コンシューマになるアプリケーションとは、ZFS のファイルシステムやストレージプールを操作するアプリケーションで、この操作にはプロパティーやデータセット階層の調査が含まれます。zoneadm、zoneadmd、fstyp などの散在する例外もありますが、主なアプリケーションは zpool(1M) と zfs(1M) の 2 つです。

zpool(1M)

このコマンドは ZFS ストレージプールを作成および管理するのに使用されます。このコマンドの主目的はコマンド行入力の構文を解析して変換し、libzfs 呼び出しに渡して途中で発生するすべてのエラーを処理することです。このコマンドのソースは usr/src/cmd/zpool にあります。次のファイルが含まれています。

zpool_main.cコマンドの本体です。すべての引数およびサブコマンドを処理します
zpool_vdev.c一連の vdev を libzfs 用の nvlist 表現に変換するコードです
zpool_iter.cシステム内の一部またはすべてのプールに対する繰り返し処理を簡単に行えるようにするコードです
zpool_util.cそのほかのユーティリティー関数です

zfs(1M)

このコマンドは ZFS ファイルシステムの作成および管理に使用されます。zpool(1M) と同様に、目的はコマンド行の引数を解析して処理結果を libzfs に渡すことだけです。このコマンドのソースは usr/src/cmd/zfs にあります。そこには次のファイルが含まれています。

zfs_main.cコマンドの本体です。すべての引数およびサブコマンドを処理します
zfs_iter.cシステム内の一部またはすべてのデータセットに対する繰り返し処理を行うコードです

JNI

このライブラリは libzfs の Java インタフェースを提供します。これは現在非公開インタフェースで、libzfs の GUI 専用に作成されたものです。したがって、主な目的は操作をビジュアルに行うことです。大部分のアクションは CLI を介して行われるからです。このライブラリのソースは usr/src/lib/libzfs_jni にあります。

libzfs

これは、管理アプリケーションが ZFS カーネルモジュールと対話するための主要インタフェースです。このライブラリは、ストレージプールおよびファイルシステムをアクセスおよび操作するための統合されたオブジェクトベースの機構を提供します。カーネルとの通信を行う背後の機構として、ioctl(2) による /dev/zfs の呼び出しが使用されます。このライブラリのソースは usr/src/lib/libzfs にあります。次のファイルが含まれています。

libzfs_dataset.cデータセットを操作する主要インタフェースです
libzfs_pool.cプールを操作する主要インタフェースです
libzfs_changelist.cプロパティーの変更をすべての子に伝播するユーティリティールーチンです
libzfs_config.cプール構成情報を読み取り、操作します
libzfs_graph.cデータセットの依存リストを作成します
libzfs_import.cプールを発見し、インポートします
libzfs_mount.cデータセットをマウントおよびマウント解除し、データセットを共有します
libzfs_status.cプール状態に基づいて FMA のナレッジベースの記事にリンクします
libzfs_util.cその他のルーチン

ZPL (ZFS POSIX Layer)

ZPL は ZFS ファイルシステムと対話するための主要インタフェースです。これは DMU の上位に位置する比較的薄い層で、ファイルおよびディレクトリからなる抽象化したファイルシステムを提供します。ZPL は OpenSolaris VFS インタフェースと背後の DMU インタフェースの間のギャップを埋めます。また、アクセス制御リスト (Access Control List、ACL) 規則や同期 (O_DSYNC) セマンティクスを適用します。

zfs_vfsops.cOpenSolaris VFS インタフェース
zfs_vnops.cOpenSolaris vnode インタフェース
zfs_znode.c各 vnode は背後の znode に対応します
zfs_dir.cディレクトリ操作
zfs_acl.cACL の適用
zfs_ctldir.c疑似ファイルシステムの実装 .zfs/snapshot
zfs_log.c授受特性ログエントリを記録する ZPL インタフェース
zfs_replay.c授受特性ログエントリを再実行する ZPL インタフェース
zfs_byteswap.cZPL データ構造のバイトスワップルーチン

ZVOL (ZFS エミュレートされるボリューム)

ZFS には、ストレージプール内の領域に基礎を置く raw デバイスを表示する機能が搭載されています。これらのデバイスはソースコード内では 'zvols' と呼ばれ、ZFS のソース内では単一ファイルによって実装されます。

zvol.cボリュームエミュレーションインタフェース

/dev/zfs

このデバイスは libzfs のメイン制御点です。コンシューマは ioctl(2) インタフェースを直接利用できますが、これは libzfs と密接に絡み合っているため、公開インタフェースではありません。libzfs もそうです。これは単一ファイルで、ioctl() のパラメータの妥当性検査を行い、要求を ZFS 内の該当する場所に転送します。

zfs_ioctl.c/dev/zfs と ioctl() の間のインタフェースです
zfs.hカーネルとユーザーランドの間で共有されるインタフェースです

DMU (Data Management Unit)

DMU は SPA によって提供されるフラットアドレス空間に構築される トランザクションオブジェクトモデルを提供します。コンシューマは DMU と対話するのにオブジェクトセット、オブジェクト、およびトランザクションを使用します。オブジェクトセットはオブジェクトのコレクションで、さらに、各オブジェクトは SPA からのストレージのさまざまな断片です。各トランザクションは一続きの操作で、グループとしてディスクにコミットする必要があります。トランザクションは ZFS のオンディスク整合性チェックの主要対象になるものです。

dmu.c DMU の主要な外部インタフェースです
dmu_objset.c オブジェクトセットを開いたり 閉じたり 操作したりするための外部インタフェースです
dmu_object.c オブジェクトを割り当てたり解放したりするためのインタフェースです
txg.c トランザクションモデル制御スレッドです
dmu_tx.c トランザクションを作成したり操作したりするインタフェースです
dnode.c オープンコンテキストのオブジェクトレベルの操作関数です
dnode_sync.c 同期コンテキストのオブジェクトレベルの操作関数です
dbuf.c バッファー管理関数です
dmu_zfetch.c データストリーム先読みロジック
refcount.c 一般参照カウントインタフェースです
dmu_send.c スナップショットの送信および受信関数です

DSL (Dataset and Snapshot Layer)

DSL は DMU オブジェクトセットを、継承したプロパティー、割り当て制限適用、および予約適用とともに階層的名前空間に統合します。また、オブジェクトセットのスナップショットおよびクローンの管理も行います。

スナップショットの実装方法については、「Matt のブログエントリ」を参照してください。

dsl_dir.c 名前空間を管理する関数です
dsl_dataset.c スナップショット、ロールバック、クローンをサポートするインタフェースです
dsl_pool.c プールレベルをサポートするインタフェースです
dsl_prop.c プロパティーを操作する関数です
unique.c 一意のオブジェクトセット ID をサポートする関数です

ZAP (ZFS Attribute Processor)

ZAP は DMU の上位に構築され、スケーラブルなハッシュアルゴリズムを使用してオブジェクトセット内にさまざまな名前とオブジェクトの関連付けを作成します。ZAP は ZPL 内にディレクトリを実装するのにもっともよく使用されますが、拡張して DSL 全体で使用されたり、プール全体にわたるプロパティーを格納する方法としても使用されます。ZAP には、非常に異なった 2 つのアルゴリズムがあり、それぞれ異なる種類のディレクトリ用にデザインされています。「マイクロ ZAP」は、エントリ数が比較的少なく各エントリがかなり短い場合に使用されます。「ファット ZAP」はそれより大きめのディレクトリや非常に長い名前のディレクトリに使用されます。

zap.c ファット ZAP のインタフェースです
zap_leaf.c 低レベルサポート関数です
zap_micro.c Micro ZAP のインタフェースです

ZIL (ZFS Intent Log)

ZFS は常に一貫性のあるデータを提供しますが、データの大半がディスクに即座に書き込まれないという、従来からのセマンティクスを採用しています。このセマンティクスを採用しないと、パフォーマンスがひどく低下するためです。しかし、アプリケーションによっては、より厳格なセマンティクス、すなわち read(2) や write(2) 呼び出しが終了するまではデータがディスク上に残っていることが保証されるセマンティクスが要求されることがあります。このような動作 (O_DSYNC で指定されるもの) を要求するアプリケーションのために、ZIL では必要とされるセマンティクスを提供します。このセマンティクスでは、効率的なデータセット単位のトランザクションログを使用します。また、このログはクラッシュの場合に再実行できます。

ZIL 実装については、Neil の「 ブログエントリ」を参照してください。

zil.c授受特性ログです

トラバース

トラバースは、ライブプール内のすべてのデータを安全かつ効率的に調べることができる方法で、再起動可能です。これは再同期化および消し込みの基盤になっています。トラバースは、すべてのメタデータを調べて、一定の期間内に変更されたブロックを検索します。その際、ZFS には書き込み時コピー特性があるため、機能停止時間に変更されなかった大規模なサブツリーが検索されないで済むという利点があります。トラバースは基本的に SPA の機能ですが、いくつかの DMU 構造の詳細な情報を使用してスナップショット、クローンなどのオンディスク書式の特性を処理します。

dmu_traverse.cトラバースのコードです

ARC (Adaptive Replacement Cache)

ZFS は Adaptive Replacement Cache の修正バージョンを使用して、1 次キャッシュの使用に必要になるものを提供します。このキャッシュは DMU と SPA の中間の層になり、仮想のブロックレベルで動作します。これにより、ファイルシステムがキャッシュしたデータをそのスナップショットやクローンと共有できます。

arc.cAdaptive Replacement Cache の実装です

プール構成 (SPA)

プールレイヤー全体が SPA (Storage Pool Allocator) としばしば呼ばれますが、このうちの構成部分こそが本当の公開インタフェースです。SPA が ZIO と vdev のレイヤーを張り合わせて、一貫性のあるプールオブジェクトにします。SPA には、プールを作成したり構成情報から破棄したりするルーチンや、 データを vdev に定期的間隔で同期化するルーチンが含まれています。

spa.cプールを開く、インポートする、エクスポートする、および破棄するルーチンです
spa_misc.cロック実行など、その他の SPA ルーチンです
spa_config.cプール構成データを解析および更新します
spa_errlog.cプール全体にわたる持続データエラーのログです
spa_history.cプール状態の変更に成功したコマンドの持続的な循環バッファーです
zfs_fm.cFMA の使用に関するレポートを送信するルーチンです

ZIO (ZFS I/O Pipeline)

ZIO パイプラインは、ディスクに送受信されるすべてのデータが通過する場所です。これは DVA (Device Virtual Address) を vdev 上の論理的位置に変換するだけでなく、必要に応じてデータのチェックサムを計算したりデータを圧縮したりします。ZIO は複数ステージのパイプラインとして実装され、各 I/O に対してどのステージを実行するかを制御するビットマスクを持っています。パイプラインはきわめて複雑なため一言では説明できませんが、次の図で全体像がわかります。

I/O タイプ ZIO 状態 圧縮 チェックサム ギャングブロック DVA 管理 Vdev I/O
RWFCIオープン
RWFCI次を待機:
子の準備完了
-W---圧縮書き込み
-W---チェックサムの生成
-WFC-ギャングのパイプライン処理
-WFC-ギャングヘッダーの取得
-W---書き換え: ギャング
ヘッダー
--F--解放: ギャング
のメンバー
---C-取り込み: ギャング
のメンバー
-W---DVA の割り当て
--F--DVA の解放
---C-DVA の取り込み
-W---ギャングのチェックサム
の生成
RWFCI準備完了
RW--II/O 開始
RW--II/O 完了
RW--II/O 測定
RWFCI次を待機:
子の完了
R----チェックサム確認
R----読み取り: ギャング
のメンバー
R----非圧縮読み取り
RWFCI完了
I/O タイプ
I/O パイプラインの各フェーズは特定タイプの I/O に適用されます。各文字は読み取り (Read、R)、書き込み (Write、W)、解放 (Free、F)、取り込み (Claim、C)、および入出力制御 (Ioctl、I) を意味します。
ZIO 状態
これらは I/O の同期をとるための内部状態です。たとえば、子 I/O がある I/O は、すべての子でブロックポインタの割り当て準備が完了するまで待つ必要があり、またすべての子が完了になるまで終了できません。
圧縮
このフェーズは、適用可能な場合に任意の圧縮アルゴリズムを適用します。
チェックサム
このフェーズは、適用可能な場合に任意のチェックサムアルゴリズムを適用します。
ギャングブロック
ブロック全体を書き込めるだけの連続した十分な領域がない場合に、ZIO パイプラインは I/O を小さな「ギャングブロック」に分割し、あとで透過的にアセンブルして完全なブロックにします。
DVA 管理
各 I/O には、プール内の vdev の特定部分に対応する DVA (Device Virtual Address) を割り当てる必要があります。このフェーズは、metaslab および領域マップを使用して、必要とされるこのアドレスの割り当てを行います。
Vdev I/O
このフェーズは、プール内に含まれる vdev への I/O を実際に実行するフェーズです。
zio.cギャングブロック変換を含むメインの ZIO ステージです
zio_checksum.cチェックサム機能の中央インタフェースです
fletcher.cチェックサムアルゴリズム、Fletcher2 と fletcher4 です
sha256.cチェックサムアルゴリズム、SHA256 です
zio_compress.c圧縮機能の中央インタフェースです
lzjb.c圧縮アルゴリズム、LZJB です
uberblock.c基本的な uberblock (ルートブロック) ルーチンです
bplist.c一連のブロックポインタを追跡します
metaslab.cDVA 変換の本体です
space_map.cDVA 変換時に、使用する空き領域を追跡します
szio_inject.cデータおよびデバイスの持続エラーを挿入するフレームワークです

VDEV (Virtual Device)

これは仮想デバイスサブシステムで、デバイスを統一的に整列し、アクセスする手段になります。複数の仮想デバイスでツリーを構成し、ルート vdev が 1 つで、内部 vdev (ミラーおよび RAID-Z) およびリーフ vdev (ディスクおよびファイル) が複数存在します。各 vdev は利用可能な領域を表すとともに、物理ディスク上のブロックをレイアウトします。

vdev.cvdev の汎用ルーチンです
vdev_disk.cディスクの仮想デバイスです
vdev_file.cファイルの仮想デバイスです
vdev_mirror.c 多重のミラー化です
vdev_raidz.c RAID-Z のグループ化 (「Jeff のブログ」を参照) です
vdev_root.c最上位の疑似 vdev です
vdev_missing.cインポート専用デバイスです
vdev_label.c識別ラベルを読み取ったり書き込んだりするルーチンです
vdev_cache.c読み取りのためのシンプルなデバイスレベルのキャッシュ機能です
vdev_queue.cvdev の入出力のスケジューリングアルゴリズムです

LDI (Layered Driver Interface)

前述のスタックの最下部で、ZFS は、LDI (Layered Driver Interface) および VFS インタフェース (ファイルの処理時) を使用して背後の物理デバイスと対話しています。

BigAdmin
  
 
BigAdmin Solaris 10 Survey
 
Oracle - The Information Company