I/O マネージャーは、階層化されたドライバーのチェーン内の各ドライバーに、設定するすべての IRP の I/O スタックの場所を提供します。 各 I/O スタックの場所は 、IO_STACK_LOCATION 構造体で構成されます。
I/O マネージャーは、階層化されたドライバーのチェーン内の各ドライバーに対応する配列要素を持つ、各 IRP の I/O スタックの場所の配列を作成します。 各ドライバーは、パケット内のスタックの場所のいずれかを所有し、 IoGetCurrentIrpStackLocation を呼び出して、I/O 操作に関するドライバー固有の情報を取得します。
このようなチェーン内の各ドライバーは、 IoGetNextIrpStackLocation を呼び出し、次に下位のドライバーの I/O スタックの場所を設定します。 上位レベルのドライバーの I/O スタックの場所を使用して、ドライバーの IoCompletion ルーチンがクリーンアップ操作を実行できるように、操作に関するコンテキストを格納することもできます。
階層化ドライバーの処理 IRP 図は、ファイル システム ドライバーと大容量記憶装置デバイス ドライバーの 2 つのドライバーを示しているため、元の IRP の 2 つの I/O スタックの場所を示しています。 処理 IRP が描かれている階層化ドライバーの図におけるドライバー割り当ての IRP は、それらを作成した FSD (ファイル システム ドライバー) のスタック ロケーションを持っていません。 下位レベルのドライバーに IRP を割り当てる上位レベルのドライバーは、次の下位ドライバーのデバイス オブジェクトの StackSize 値に従って、新しい IRP が必要な I/O スタックの場所の数も決定します。
次の図は、IRP の内容の詳細を示しています。
図に示すように、IRP の各ドライバー固有の I/O スタックの場所には、次の一般的な情報が含まれています。
ドライバーが実行する必要がある基本的な操作を示す主要な関数コード (IRP_MJ_XXX)
FSD、上位レベルの SCSI ドライバー、およびすべての PnP ドライバーによって処理される一部の主要な関数コードについては、ドライバーが実行する必要がある基本操作のサブケースを示すマイナー関数コード (IRP_MN_XXX)
ドライバーがデータを転送するバッファーの長さと開始位置など、操作固有の引数のセット
要求された操作のターゲット (物理、論理、または仮想) デバイスを表す、ドライバーによって作成されたデバイス オブジェクトへのポインター
開いているファイル、デバイス、ディレクトリ、またはボリュームを表すファイル オブジェクトへのポインター
ファイル システム ドライバーは、IRP 内の I/O スタックの場所を介してファイル オブジェクトにアクセスします。 通常、他のドライバーはファイル オブジェクトを無視します。
特定のドライバーが処理する IRP のメジャーおよびマイナー関数コードのセットは、デバイスの種類に固有です。 ただし、最下位レベルのドライバーと中間ドライバー (PnP 関数とフィルター ドライバーを含む) は、通常、次の基本要求のセットを処理します。
IRP_MJ_CREATE — ターゲット デバイス オブジェクトを開き、I/O 操作で使用可能であることを示します。
IRP_MJ_READ — デバイスからデータを転送する
IRP_MJ_WRITE — デバイスにデータを転送する
IRP_MJ_DEVICE_CONTROL — システム定義のデバイスの種類固有の I/O 制御コード (IOCTL) に従って、デバイスを設定 (またはリセット) します。
IRP_MJ_CLOSE — ターゲット デバイス オブジェクトを閉じます
IRP_MJ_PNP — デバイスでプラグ アンド プレイ操作を実行します。 IRP_MJ_PNP要求は、PnP マネージャーによって I/O マネージャーを介して送信されます。
IRP_MJ_POWER — デバイスで電源操作を実行します。 IRP_MJ_POWER要求は、電源マネージャーから I/O マネージャーを介して送信されます。
ドライバーが処理するために必要な主要な IRP 関数コードの詳細については、「 IRP の主要な機能コード」を参照してください。
一般に、I/O マネージャーは、ファイル システムが大容量記憶装置用の他のドライバーに重なっているため、少なくとも 2 つの I/O スタックの場所を持つ IRP を大容量記憶装置デバイス ドライバーに送信します。 I/O マネージャーは、1 つのスタック位置を持つ IRP を、その上に他のドライバーが階層化されていないドライバーに送信します。
ただし、I/O マネージャーは、システム内の既存のドライバーのチェーンに新しいドライバーを追加するためのサポートを提供します。 たとえば、特定のディスク パーティション上のデータをバックアップする中間 ミラー ドライバー は、ファイル システム ドライバーと、 レイヤード ドライバーの処理 IRP 図に示されている最下位レベルのドライバーなどのドライバーのペアの間に挿入される場合があります。 この新しいドライバーがデバイス スタックにアタッチされると、I/O マネージャーは、ファイル システム、ミラー、および最下位レベルのドライバーに送信するすべての IRP の I/O スタックの場所の数を調整します。 階層化ドライバーの処理を示す図においてファイルシステムが割り当てたすべてのIRPには、新しいミラードライバー用の別のI/Oスタックの場所も含まれています。
既存のチェーンに新しいドライバーを追加するこのサポートは、IRP の I/O スタックの場所への特定のドライバーのアクセスに対する特定の制限を意味します。
階層化されたドライバーのチェーン内の上位レベルのドライバーは、IRP 内のそれ自体と次の下位レベルのドライバーの I/O スタックの場所にのみ安全にアクセスできます。 このようなドライバーは、IRP の次の下位レベルのドライバーの I/O スタックの場所を設定する必要があります。 ただし、このような上位レベルのドライバーを設計する場合、新しいドライバーがドライバーのすぐ下の既存のチェーンに追加されるタイミング (または追加されるかどうか) を予測することはできません。
したがって、後続に追加されたドライバーは、移動された次の下位レベルのドライバーと同じ IRP の主要な関数コード (IRP_MJ_XXX) を処理することを想定する必要があります。
階層化されたドライバーのチェーン内の最下位レベルのドライバーは、任意の IRP 内の独自の I/O スタックの場所にのみ安全にアクセスできます。 このようなドライバーを設計する場合、新しいドライバーがデバイス ドライバーの上の既存のチェーンに追加されるタイミング (または追加されるかどうか) を予測することはできません。
最下位レベルのドライバーを設計する場合、ドライバーは、特定の IRP の元のソースに関係なく、独自の I/O スタックの場所で渡された情報を使用して IRP を処理し続けることができると仮定します。ただし、多くのドライバーはその上に階層化されています。