ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
デバイスドライバの記述 Oracle Solaris 10 8/11 Information Library (日本語) |
ドライバ強化テストハーネスは、入出力障害サービスおよび防御的プログラミングの要件が正しく満たされていることをテストします。強化されたデバイスドライバは、潜在的なハードウェア障害に対する耐性を備えています。開発者は、デバイスドライバ開発プロセスの一環として、ドライバの回復性能をテストする必要があります。この種類のテストでは、広範囲の一般的なハードウェア障害を、制御された反復可能な方法でドライバが処理できることを確認します。ドライバ強化テストハーネスを使用すると、開発者はそのようなハードウェア障害をソフトウェアでシミュレートできます。
ドライバ強化テストハーネスは、Solaris デバイスのドライバ開発ツールです。このテストハーネスは、開発中のドライバがそのハードウェアにアクセスするときに、広範囲の擬似的なハードウェア障害を投入します。この節では、テストハーネスを構成し、エラー投入仕様 (errdef) を作成して、デバイスドライバのテストを実行する方法について説明します。
テストハーネスはドライバからの各種 DDI ルーチンの呼び出しを横取りし、あたかもハードウェアが原因であるかのように、呼び出しの結果を破壊します。ハーネスでは、特定のレジスタへのアクセスに対する破壊に加えて、よりランダムな種類の破壊も定義できます。
テストハーネスでは、指定されたワークロードの実行中に、すべてのレジスタアクセスのほか、ダイレクトメモリーアクセス (DMA) と割り込みの使用状況を追跡することにより、テストスクリプトを自動生成できます。生成されたスクリプトでは、そのワークロードが再実行されるのと並行して、アクセスのたびに一連の障害が投入されます。
ドライバのテスト担当者は、生成されたスクリプトから、重複しているテストケースを削除するようにしてください。
テストハーネスは、bofi という名前 (バス操作への障害投入を意味する) のデバイスドライバと、2 つのユーザーレベルユーティリティー th_define(1M) および th_manage(1M) として実装されています。
テストハーネスは次の作業を行います。
Solaris DDI サービスが仕様に準拠して使用されていることを検証する
プログラム式入出力 (PIO) および DMA 要求の破壊と、割り込みに対する干渉を管理のもとで行い、ドライバが管理するハードウェアで発生する障害をシミュレートする
親ネクサスドライバから報告される、CPU とデバイス間のデータパスにおいて、障害のシミュレーションを行う
指定されたワークロードの間、ドライバのアクセスを監視し、障害投入スクリプトを生成する
ドライバ強化テストハーネスは、ドライバがハードウェアにアクセスするたびにそれを横取りし、必要に応じてアクセスを破壊します。この節では、ドライバの回復性能をテストする障害を作成するにあたり、理解しておくことが望ましい情報を提供します。
Solaris のデバイスは、デバイスツリー (devinfo ツリー) と呼ばれるツリー状構造の内部で管理されます。devinfo ツリーの各ノードには、システムに存在するデバイスの特定のインスタンスに関する情報が格納されます。各リーフノードはデバイスドライバに対応し、ほかのすべてのノードはネクサスノードと呼ばれます。通常は、1 つのネクサスが 1 つのバスを表します。バスノードはリーフドライバをバスへの依存性から切り離し、アーキテクチャー的に独立したドライバを生成できるようにします。
多くの DDI 関数、特にデータアクセス関数は、結果としてバスネクサスドライバへの上位呼び出しになります。リーフドライバはハードウェアにアクセスするとき、アクセスルーチンにハンドルを渡します。バスネクサスは、ハンドルを操作して要求に応じる方法を理解しています。DDI 準拠のドライバはこれらの DDI アクセスルーチンを使用してのみ、ハードウェアにアクセスします。テストハーネスは、指定されたバスネクサスにこれらの上位呼び出しが到達する前に横取りします。ドライバのテスト担当者が指定した基準にデータアクセスが一致すれば、アクセスは破壊されます。基準に一致しなかったデータアクセスは、バスネクサスに渡されて通常どおり処理されます。
ドライバは ddi_regs_map_setup(9F) 関数を使用してアクセスハンドルを取得します。
ddi_regs_map_setup(dip, rset, ma, offset, size, handle)
引数では、対応づけ対象の「オフボード」メモリーを指定します。ハンドルはドライバをバス階層構造の詳細から分離するためのものなので、対応づけされた入出力アドレスをドライバが参照するときは、返されたハンドルを使用する必要があります。したがって、返される対応づけされたアドレスである ma を直接使用しないでください。対応づけされたアドレスを直接使用すると、その時点以降、データアクセス関数の機構を使用しないことになります。
プログラム式入出力では、データアクセス関数の組み合わせは次のようになります。
入出力からホストへ:
ddi_getX(handle, ma) ddi_rep_getX(handle, buf, ma, repcnt, flag)
ホストから入出力へ:
ddi_putX(handle, ma, value) ddi_rep_putX()
X および repcnt は転送されるバイト数です。X はバス転送サイズ (8、16、32、または 64 バイト) です。
DMA にはこれに類似した、より充実したデータアクセス関数の集合が用意されています。
ドライバ強化テストハーネスは Solaris Developer Cluster に含まれています。この Solaris クラスタがインストールされていない場合、プラットフォームに適合したテストハーネスパッケージを手作業でインストールする必要があります。
テストハーネスパッケージ (SUNWftduu および SUNWftdur) をインストールするには、pkgadd(1M) コマンドを使用します。
スーパーユーザーとして、パッケージが存在するディレクトリに移動し、次のように入力します。
# pkgadd -d . SUNWftduu SUNWftdur
テストハーネスをインストールしたら、/kernel/drv/bofi.conf ファイルのプロパティーを設定して、テストするドライバと対話するようにハーネスを設定します。ハーネスの設定が完了したら、システムを再起動してハーネスドライバをロードします。
テストハーネスの動作は、/kernel/drv/bofi.conf 設定ファイルで設定される起動時プロパティーによって制御されます。
ハーネスを最初にインストールするときに、次のプロパティーを設定して、テストするドライバへの DDI アクセスをハーネスが横取りするようにします。
バスのネクサスタイプ (例: PCI バス)
テストするドライバの名前
たとえば、xyznetdrv という名前の PCI バスネットワークドライバをテストするには、プロパティー値を次のように設定します。
bofi-nexus="pci" bofi-to-test="xyznetdrv"
上記以外のプロパティーは、PIO を使用する周辺機器との間の読み書きと、DMA を使用する周辺機器との間のデータ転送のための Solaris DDI データアクセス機構の使用状況やハーネスチェックに関連するプロパティーです。
このプロパティーを設定すると、テストハーネスは PIO データアクセス関数に渡される引数の整合性をチェックします。
このプロパティーを設定すると、テストハーネスは、 ddi_map_regs_setup(9F) によって返される対応づけされたアドレスが、データアクセス関数のコンテキスト以外で使用されていないことを検証します。
このプロパティーを設定すると、テストハーネスは DMA 関数の使用方法が正しいことを検証し、ドライバが仕様に準拠して ddi_dma_sync(9F) を使用していることを確認します。
この節では、th_define(1M) および th_manage(1M) コマンドを使用して、障害を作成および投入する方法について説明します。
th_define ユーティリティーは、errdef を定義するための、bofi デバイスドライバへのインタフェースを提供します。1 つの errdef が、デバイスドライバによるハードウェアへのアクセスを破壊する方法に関する 1 つの仕様に対応します。th_define のコマンド行引数は、投入する障害の正確な種類を指定します。指定した引数によって矛盾のない errdef が定義される場合、th_define プロセスは bofi ドライバに errdef を格納します。errdef で定められている基準に達するまで、プロセスは一時停止状態になります。実際には、アクセスカウントが 0 になると一時停止状態が終了します。
テストハーネスはデータアクセスのレベルで動作します。データアクセスには次のような特性があります。
アクセスしているハードウェアの種類 (ドライバ名)
アクセスしているハードウェアのインスタンス (ドライバインスタンス)
テストされているレジスタセット
ターゲットとなるレジスタセットのサブセット
転送の方向 (読み取りまたは書き込み)
アクセスの種類 (PIO または DMA)
テストハーネスはデータアクセスを横取りし、適切な障害をドライバに投入します。th_define(1M) コマンドで指定された errdef によって、次の情報がエンコードされます。
テストされているドライバインスタンスおよびレジスタセット (-n name、-i instance、および -r reg_number)。
破壊の対象となるレジスタセットのサブセット。このサブセットは、レジスタセット内のオフセットと、そのオフセットからの長さを指定することによって指示されます (-l offset [ len])。
横取りするアクセスの種類: log、pio、dma、pio_r、pio_w、dma_r、dma_w、intr (-a acc_types)。
障害が発生するアクセスの数 (-c count [failcount ])。
該当するアクセスに適用する破壊の種類 (-o operator [ operand])。
データを固定値に置き換える (EQUAL)
データに対するビット単位の演算を実行する (AND、OR、XOR)
転送を無視する (ホストから入出力へのアクセス、NO_TRANSFER)
割り込みを失う、遅らせる、または偽の割り込みを投入する (LOSE、DELAY、EXTRA)
errdef でフレームワークの障害をシミュレートするには、-a acc_chk オプションを使用します。
障害投入のプロセスには 2 つの段階があります。
th_define(1M) コマンドを使用して errdef を作成します。
errdef を作成するときは、定義を格納する bofi ドライバにテスト定義を渡し、th_manage(1M) コマンドによって定義にアクセスできるようにします。
ワークロードを作成し、th_manage コマンドを使用して errdef を起動および管理します。
th_manage コマンドは、bofi ハーネスドライバが認識する各種の ioctl へのユーザーインタフェースです。th_manage コマンドはドライバの名前およびインスタンスのレベルで動作し、アクセスハンドルを列挙する get_handles、errdef を起動する start、errdef を停止する stop などのコマンドを含んでいます。
errdef を起動すると、対象となるデータアクセスで障害が発生します。th_manage ユーティリティーは、errdef の現在の状態を表示する broadcast と、errdef をクリアする clear_errors の各コマンドをサポートします。
詳細は、th_define(1M) および th_manage(1M) のマニュアルページを参照してください。
次の方法で警告メッセージを処理するようにテストハーネスを構成できます。
警告メッセージをコンソールに書き込む
警告メッセージをコンソールに書き込んでからシステムをパニック状態にする
2 番目の方法を使用すると、問題の根本原因を特定しやすくなります。
bofi-range-check プロパティーの値を warn に設定した場合、テスト対象のドライバによる DDI 関数の範囲違反をハーネスが検出した時点で、ハーネスは次のメッセージを出力します (パニック動作が設定されている場合はパニック状態に移行します)。
ddi_getX() out of range addr %x not in %x ddi_putX() out of range addr %x not in %x ddi_rep_getX() out of range addr %x not in %x ddi_rep_putX() out of range addr %x not in %x
X は 8、16、32、または 64 です。
ハーネスが 1000 を超える割り込みを挿入するように要求されており、ドライバが割り込みジャバーを検出しない場合、次のメッセージが出力されます。
undetected interrupt jabber - %s %d
th_define(1M) ユーティリティーのロギングアクセスタイプを使用すると、障害投入テストスクリプトを作成できます。
# th_define -n name -i instance -a log [-e fixup_script]
th_define コマンドはインスタンスをオフラインにし、またオンラインに戻します。th_define は次に、fixup_script によって記述されたワークロードを実行し、ドライバインスタンスが行う入出力アクセスをログに記録します。
fixup_script は、省略可能ないくつかの引数を指定して 2 回呼び出されます。このスクリプトはインスタンスがオフラインにされる直前に 1 回呼び出され、オンラインに戻されたあとにふたたび呼び出されます。
次の変数が、呼び出される実行可能ファイルの環境に渡されます。
インスタンスのデバイスパス
ドライバのインスタンス番号
インスタンスが間もなくオフラインにされるときは 1 に設定
インスタンスがオンラインに戻されたときは 1 に設定
fixup_script は通常、テスト中のデバイスがオフラインになってもよい状態 (未構成) であること、またはエラー投入に適した状態 (構成済み、エラーなし、ワークロードを処理中など) であることを確認します。次に示すのは、ネットワークドライバ用の最小限のスクリプトの例です。
#!/bin/ksh driver=xyznetdrv ifnum=$driver$DRIVER_INSTANCE if [[ $DRIVER_CONFIGURE = 1 ]]; then ifconfig $ifnum plumb ifconfig $ifnum ... ifworkload start $ifnum elif [[ $DRIVER_UNCONFIGURE = 1 ]]; then ifworkload stop $ifnum ifconfig $ifnum down ifconfig $ifnum unplumb fi exit $?
注 - ifworkload コマンドは、バックグラウンドタスクとしてワークロードを開始する必要があります。障害の投入は、fixup_script がテスト中のドライバを構成し、オンラインに戻したあとに行われます (DRIVER_CONFIGURE は 1 に設定されます)。
-e fixup_script オプションを指定する場合、コマンド行の最後のオプションとして指定する必要があります。-e オプションを指定しない場合、デフォルトのスクリプトが使用されます。デフォルトのスクリプトは、テスト中のデバイスのオフライン化とオンライン化を繰り返し試行します。そのため、ワークロードはドライバの attach() および detach() パスで構成されます。
結果のログは、自動での障害投入テストの実行に適した、いくつかの実行可能スクリプトに変換されます。これらのスクリプトは、driver.test.id という名前で、カレントディレクトリのサブディレクトリに作成されます。スクリプトは、fixup_script によって記述されたワークロードの実行中、一度に 1 つずつ障害を投入します。
ドライバのテスト担当者は、テスト自動化プロセスによって生成された errdef の大部分を制御できます。th_define(1M) のマニュアルページを参照してください。
テスト担当者がテストスクリプトに適した範囲のワークロードを選択すると、ハーネスはドライバ強化の多くの側面をテストできます。ただし、すべてを網羅するためには、テスト担当者が追加のテストケースを手作業で作成しなければならない場合があります。これらのケースをテストスクリプトに追加します。テストを時間内に完了させるために、重複したテストケースを手作業で削除することが必要になる場合があります。
自動テストのプロセスは、次のようになります。
ドライバのどの部分をテストするかを識別します。
次に示すような、ドライバがハードウェアと対話する部分はすべてテストします。
接続と切り離し
スタック下の plumb と unplumb
通常のデータ転送
ドキュメント化されたデバッグモード
使用モードごとに別個のワークロードスクリプト (fixup_script) を生成する必要があります。
使用モードごとに、デバイスを設定および設定解除し、ワークロードを作成および終了する実行可能プログラム ( fixup_script) を準備します。
errdef とアクセスの種類 (-a log) を指定して、th_define(1M) コマンドを実行します。
ログがいっぱいになるまで待ちます。
ログの内容は bofi ドライバの内部バッファーのダンプです。このデータはスクリプトの先頭部分に含まれています。
ログの作成には数秒から数分かかるため、th_manage broadcast コマンドを使用して進捗状況を確認します。
作成されたテストディレクトリに移動し、マスターテストスクリプトを実行します。
マスタースクリプトは、生成された個々のテストスクリプトを順に実行します。レジスタセットごとに個別のテストスクリプトが生成されます。
分析のために結果を格納します。
success (corruption reported) や success (corruption undetected) のような成功したテスト結果は、テスト中のドライバが正常に動作していることを示します。ドライバが障害を報告したあとにサービスへの影響を報告できなかったことをハーネスが検出した場合や、アクセスハンドルまたは DMA ハンドルが障害とマーク付けされたことをドライバが検出できない場合、failure (no service impact reported) という結果が報告されます。
test not triggered エラーが出力にいくつか含まれていても問題はありません。ただし、そのようなエラーが多数にのぼる場合は、テストが適切に機能していないことを示しています。これらのエラーは、テストスクリプトが生成されたときと同じレジスタにドライバがアクセスしていない場合に発生することがあります。
ドライバの複数のインスタンスに対して同時にテストを実行し、エラーパスのマルチスレッド化をテストします。
たとえば、th_define コマンドは毎回、テストスクリプトとマスタースクリプトを収めたディレクトリを新しく作成します。
# th_define -n xyznetdrv -i 0 -a log -e script # th_define -n xyznetdrv -i 1 -a log -e script
マスタースクリプトが作成されたら、それらを同時に実行します。
注 - 生成されたスクリプトは、ログ記録対象の errdef がアクティブであった期間中に記録されたログ内容に基づく障害投入のシミュレーションのみを実行します。開発者がワークロードを定義するときは、必要な結果が確実にログに記録されるようにします。また、結果のログと障害投入仕様を分析します。生成されたテストスクリプトによるハードウェアアクセスの範囲が、必要な基準を満たしていることを確認してください。