バッファー付き I/O の使用
対話型操作または低速のデバイスを処理するドライバー、または通常は比較的少量のデータを一度に転送するドライバーは、バッファー I/O 転送方法を使用する必要があります。 小規模の対話型転送にバッファー I/O を使用すると、ダイレクト I/O を要求するドライバーのようにメモリ マネージャーが転送ごとに完全な物理ページをロック ダウンする必要がないため、全体的な物理メモリ使用量が向上します。 一般に、ビデオ、キーボード、マウス、シリアル、および並列ドライバーはバッファー I/O を要求します。
I/O マネージャーは、I/O 操作がバッファー I/O を使用していることを次のように判断します。
IRP_MJ_READ 要求と IRP_MJ_WRITE 要求の場合、DO_BUFFERED_IO は DEVICE_OBJECT 構造体の フラグ メンバーに設定されます。 詳細については「デバイス オブジェクトの初期化」を参照してください。
IRP_MJ_DEVICE_CONTROL 要求と IRP_MJ_INTERNAL_DEVICE_CONTROL 要求の場合、IOCTL コードの値には、IOCTL 値の TransferType 値として METHOD_BUFFERED が含まれます。 詳細については「I/O 制御コードの定義」参照してください。
次の図は、I/O マネージャーがバッファー I/O を使用する転送操作の IRP_MJ_READ 要求を設定する方法を示しています。
この図は、ドライバーが読み取り要求のデータを転送するために IRP の SystemBuffer ポインターを使用する方法の概要を示しています。ドライバーには、DO_BUFFERED_IO を持つデバイス オブジェクトのフラグが ORed に設定されています。
ユーザー空間の仮想アドレスの一部の範囲は現在のスレッドのバッファーを表し、そのバッファーの内容はページ ベースの物理アドレスの範囲内のどこかに格納される場合があります (前の図の濃い網かけ)。
I/O マネージャーは、現在のスレッドの読み取り要求を処理します。この要求に対して、スレッドはバッファーを表すユーザー空間の仮想アドレスの範囲を渡します。
I/O マネージャーは、ユーザーが指定したバッファーをアクセシビリティ用にチェックし、ExAllocatePoolWithTag を呼び出して、ユーザーが指定したバッファーのサイズだけ非ページ システム空間バッファー (SystemBuffer) を作成します。
I/O マネージャーは、ドライバーに送信する IRP で新しく割り当てられた SystemBuffer へのアクセスを提供します。
図に書き込み要求が示されている場合、I/O マネージャーは IRP をドライバーに送信する前に、ユーザー バッファーからシステム バッファーにデータをコピーします。
前の図に示した読み取り要求の場合、ドライバーはデバイスからシステム空間バッファーにデータを読み取ります。 このバッファーのメモリは非ページであり、ドライバーは最初にバッファーをロックせずに安全にバッファーにアクセスできます。 読み取り要求が満たされると、ドライバーは IRP を使用して IoCompleteRequest を呼び出します。
元のスレッドが再びアクティブになると、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 制御コードの定義」参照してください。