バッファー付き I/O の使用

対話型操作または低速のデバイスを処理するドライバー、または通常は比較的少量のデータを一度に転送するドライバーは、バッファー I/O 転送方法を使用する必要があります。 小規模の対話型転送にバッファー I/O を使用すると、ダイレクト I/O を要求するドライバーのようにメモリ マネージャーが転送ごとに完全な物理ページをロック ダウンする必要がないため、全体的な物理メモリ使用量が向上します。 一般に、ビデオ、キーボード、マウス、シリアル、および並列ドライバーはバッファー I/O を要求します。

I/O マネージャーは、I/O 操作がバッファー I/O を使用していることを次のように判断します。

次の図は、I/O マネージャーがバッファー I/O を使用する転送操作の IRP_MJ_READ 要求を設定する方法を示しています。

diagram illustrating a buffered i/o for user buffers.

この図は、ドライバーが読み取り要求のデータを転送するために IRP の SystemBuffer ポインターを使用する方法の概要を示しています。ドライバーには、DO_BUFFERED_IO を持つデバイス オブジェクトのフラグが ORed に設定されています。

  1. ユーザー空間の仮想アドレスの一部の範囲は現在のスレッドのバッファーを表し、そのバッファーの内容はページ ベースの物理アドレスの範囲内のどこかに格納される場合があります (前の図の濃い網かけ)。

  2. I/O マネージャーは、現在のスレッドの読み取り要求を処理します。この要求に対して、スレッドはバッファーを表すユーザー空間の仮想アドレスの範囲を渡します。

  3. I/O マネージャーは、ユーザーが指定したバッファーをアクセシビリティ用にチェックし、ExAllocatePoolWithTag を呼び出して、ユーザーが指定したバッファーのサイズだけ非ページ システム空間バッファー (SystemBuffer) を作成します。

  4. I/O マネージャーは、ドライバーに送信する IRP で新しく割り当てられた SystemBuffer へのアクセスを提供します。

    図に書き込み要求が示されている場合、I/O マネージャーは IRP をドライバーに送信する前に、ユーザー バッファーからシステム バッファーにデータをコピーします。

  5. 前の図に示した読み取り要求の場合、ドライバーはデバイスからシステム空間バッファーにデータを読み取ります。 このバッファーのメモリは非ページであり、ドライバーは最初にバッファーをロックせずに安全にバッファーにアクセスできます。 読み取り要求が満たされると、ドライバーは IRP を使用して IoCompleteRequest を呼び出します。

  6. 元のスレッドが再びアクティブになると、I/O マネージャーはシステム バッファーからユーザー バッファーに読み取り込みデータをコピーします。 また、ExFreePool も呼び出してシステム バッファーを解放します。

I/O マネージャーがドライバーのシステム領域バッファーを作成した後、要求するユーザーモード スレッドをスワップ アウトし、その物理メモリを別のスレッド (場合によっては別のプロセスに属するスレッドによって) 再利用できます。 ただし、IRP で提供されるシステム空間仮想アドレス範囲は、ドライバーが IRP で IoCompleteRequest を呼び出すまで有効の状態を保持します。

一度に大量のデータを転送するドライバー、特にマルチページ転送を行うドライバーは、バッファー I/O を使用しないでください。 システムが実行されると、I/O マネージャーがこのようなドライバーの IRP で送信する大規模な連続したシステム空間バッファーを割り当てることができないように、非ページ プールが断片化する可能性があります。

通常、ドライバーは、ダイレクト I/O も使用する場合でも、IRP_MJ_DEVICE_CONTROL 要求など、一部の種類の IRP にバッファー I/O を使用します。 通常、ダイレクト I/O を使用するドライバーは、IRP_MJ_READ 要求と IRP_MJ_WRITE 要求、および場合によっては大きなデータ転送を必要とするドライバー定義の IRP_MJ_INTERNAL_DEVICE_CONTROL 要求に対してのみ行われます。

すべての IRP_MJ_DEVICE_CONTROL および IRP_MJ_INTERNAL_DEVICE_CONTROL 要求には、I/O 制御コードが含まれます。 I/O コントロール コードがバッファー I/O を使用して IRP をサポートする必要があることを示す場合、I/O マネージャーは、ユーザー アプリケーションの入力バッファーと出力バッファーを表す単一のシステム バッファーを使用します。 このような I/O 制御コードをサポートするドライバーは、バッファーから入力データ (存在する場合) を読み取り、入力データを上書きして出力データ (存在する場合) を提供する必要があります。 詳細については「I/O 制御コードの定義」参照してください。