BypassIO 操作のサポート
Windows 11 以降では、すべてのミニフィルターで BypassIO 操作のサポートを追加する必要があります。 BypassIO 操作は、以下を指定して FltFsControlFile または ZwFsControlFile を呼び出すことによって要求します。
- FSCTL_MANAGE_BYPASS_IO 制御コード。
- InputBuffer パラメーターによって示される FS_BPIO_INPUT 構造体内の要求固有の情報。
- OutputBuffer パラメーターによって示される、呼び出し元が割り当てた FS_BPIO_OUTPUT 構造体。システムはその中で操作の結果を返します。
このページでは、各 BypassIO 操作について詳しく説明します。 操作の要求は、FS_BPIO_INPUT の Operation メンバーの FS_BPIO_OPERATIONS 値として指定します。
BypassIO について詳しくは、フィルターの BypassIO に関する記事をご覧ください。
FS_BPIO_OP_ENABLE 要求
この要求は、ユーザー モードまたはカーネル モードから送信される可能性があります。 キャッシュされない書き込みに対する BypassIO は現在サポートされていません。
FS_BPIO_OP_ENABLE は、システムが特定のファイルに対して BypassIO を有効にすることを要求します。つまり、ドライバーは、そのファイルに対するすべてのキャッシュされない読み取りを認識しない可能性があります。
BypassIO は、ファイル オープンの概念に従います。つまり、FS_BPIO_OP_ENABLE 要求は、有効化要求に関連付けられているファイル オブジェクトにのみ影響し、同じファイルまたはストリームでの他のオープンの動作は変更しません。 同じファイル オブジェクトに対して複数の有効化要求が送信された場合は、最初の要求のみが意味を持ち、後続のすべての要求は無視されます。
ドライバーの操作前コールバックで次のことを行います。
特定のファイルについて BypassIO をサポートできるドライバーは、要求をスタックの下方に転送する必要があります。
特定のファイルについて BypassIO をサポートできないドライバーは、次の情報を使って FltVetoBypassIo を呼び出す必要があります。
- ドライバーの名前。FltObjects パラメーターが示している FLT_RELATED_OBJECTS 構造体内にあります。
- OperationStatus パラメーターでの、有効化要求を拒否する理由を説明する NTSTATUS エラー コード。
- FailureReason パラメーターでの、有効化要求を拒否した理由についての一意の詳細な説明文。
FltVetoBypassIo は、ドライバー名、エラー コード、ミニフィルターが有効化要求を拒否した理由の説明文を FS_BPIO_OUTPUT 構造体に書き込み、状態、フィルターから提供された理由、フィルターの名前を含む ETW イベントをイベント ログに書き込みます。
ミニフィルターは、FltVetoBypassIo が成功した場合は STATUS_SUCCESS で FSCTL_MANAGE_BYPASS_IO を完了し、それ以外の場合は FltVetoBypassIo から返されたエラーを返す必要があります。
操作後に、ドライバーは、その下にあるすべてのドライバーが BypassIO をサポートできるかどうかを確認できます。 できる場合、ドライバーはファイルについての必要な状態を保持し、完了処理を続ける必要があります。 フィルターとファイル システムは、BypassIO が有効な状態と互換性のない可能性がある要求を適切に処理するために、状態を維持する必要があります。
Note
ファイル システム スタック内のすべてのフィルターには、操作前の間に BypassIO 有効化要求を拒否する機会がありますが、可能な限り有効にしておくことをお勧めします。
次の種類のファイルの場合、ファイル システムは BypassIO 有効化要求を自動的に拒否します。
- ディレクトリ (ディレクトリ上の代替データ ストリームでは BypassIO を使用できます)
- ボリューム (DASD が開きます)
- NTFS 圧縮ファイル
- NTFS 暗号化ファイル
- スパース ファイル
- ページング ファイル
- DAX ボリューム上のすべてのファイル
ほとんどのフィルターでは、特定のストリームで BypassIO が有効にされた状態を保持する必要はありません。 代わりに、FsRtlGetBypassIoOpenCount を呼び出して、この情報を照会できます。
FS_BPIO_OP_ENABLE の例: 暗号化フィルター
暗号化フィルターがファイルに対する FS_BPIO_OP_ENABLE 操作を受け取ったとき:
ファイルが既に暗号化されている場合、フィルターは FltVetoBypassIo を呼び出して BypassIO 操作を拒否し、次のような適切な状態と診断メッセージを提供する必要があります。
- OpStatus = STATUS_NOT_SUPPORTED_WITH_ENCRYPTION
- FailureReason = "暗号化されたファイルはサポートされていません"
ファイルが現在暗号化されていない場合、フィルターは BypassIO を許可する必要があります。 後でこのファイルを暗号化する要求が行われた場合、フィルターは FS_BPIO_OP_STREAM_PAUSE 操作を使って BypassIO を無効にできます。
FS_BPIO_OP_DISABLE 要求
この要求は、ユーザー モードまたはカーネル モードから送信される可能性があります。 ドライバーが関連付けられている BypassIO 状態をクリーンアップできるようにします。
以前にドライバーがこのファイルで BypassIO を有効にすることを許可していて、ファイルの BypassIO サポートをオフにする必要がある場合は、関連付けられたハンドルを使用してファイル システム スタックの先頭に FS_BPIO_OP_DISABLE FSCTL_MANAGE_BYPASS_IO 操作を送信する必要があります。 たとえば、このファイルを暗号化する要求を受信した暗号化ドライバーで、この状態が発生する可能性があります。
ドライバーは、FS_BPIO_OP_DISABLE を受信しても、現在 BypassIO が有効になっていない場合は、要求を無視する必要があります。 この操作が、現在 BypassIO が有効になっていないファイルに対して送信された場合は、無視する必要があります。
この操作を失敗させないでください。
FS_BPIO_OP_QUERY要求
この要求は、ユーザー モードまたはカーネル モードから送信される可能性があります。
フィルターでは、FS_BPIO_OP_ENABLE 操作と同じように FS_BPIO_OP_QUERY 要求を処理する必要があり、適切なパラメーターで前に説明したのと同じ診断情報を使い、FltVetoBypassIo を呼び出して適切に拒否します。 主な違いは、QUERY の間にドライバーが BypassIO ENABLE 状態にならない点です。
FS_BPIO_OP_QUERY 操作は、ディレクトリとボリュームのハンドルに対して送信できます (FS_BPIO_OP_ENABLE 要求はディレクトリまたはボリュームのハンドルに対して送信できません)。
クエリの例: 暗号化フィルター
暗号化フィルターがファイルに対する FS_BPIO_OP_QUERY 操作を受け取ったとき:
ファイルが既に暗号化されている場合、フィルターは FltVetoBypassIo を呼び出して BypassIO 操作を拒否し、次のような適切な状態と診断メッセージを提供する必要があります。
- OpStatus = STATUS_NOT_SUPPORTED_WITH_ENCRYPTION
- FailureReason = "暗号化されたファイルはサポートされていません"
ファイルが現在暗号化されていない場合、クエリ要求はフィルターで成功するはずです。
FS_BPIO_OP_VOLUME_STACK_PAUSE 要求
この要求は、ユーザー モードまたはカーネル モードから送信される可能性があります。
ボリューム スタック ドライバーが以前にボリュームで BypassIO の有効化を許可していて、現在は BypassIO を停止する必要がある場合 (たとえば、外部要求が原因で)、ドライバーはボリューム スタックの上部に FS_BPIO_OP_VOLUME_STACK_PAUSE FSCTL_MANAGE_BYPASS_IO 操作を送信して、このボリュームのボリュームとストレージ スタックで BypassIO の実行を停止するようにファイル システムに通知する必要があります。 ファイル システムは、このボリュームからすべてのアクティブな BypassIO 操作をドレインした後で戻ります。 その後、ボリューム スタック ドライバーは外部の要求を処理できます。
BypassIO が有効になっているすべてのアクティブなファイルは、ストレージ スタック レベルの BypassIO 操作を停止します。 この操作要求は次のようになります。
- ボリューム ハンドルまたは特定のボリュームのファイル ハンドルに対して送信できます。
- 同じボリュームに複数回送信できます。
- ボリュームに BypassIO が有効なファイルがない場合に送信できます。
BypassIO は引き続きファイル システム スタックで動作します。
この操作を失敗させないでください。
ボリューム スタックの一時停止の例
BitLocker は、ボリュームで暗号化を有効にする必要がある場合にこの操作を使用するコンポーネントの例です。
もう 1 つの例は、次のようなシナリオです: アクティブなボリューム スナップショットがないボリュームで、Volsnap が BypassIO の有効化を許可されたとします。 その後、ボリューム スナップショットの作成要求が行われました。 Volsnap は、続行する前に次のアクションを実行します。
- FS_BPIO_OP_VOLUME_STACK_PAUSE 操作をスタックの先頭に送信し、システムがボリューム スタックに対する BypassIO を無効にすることを要求します。 これは、新しいスナップショットが作成されるたびに行われます。 正常で戻った場合、BypassIO は無効になっており、指定されたボリュームでドレインされます。
- スナップショット作成要求を処理します
その後、Volsnap は、それ以降のこのボリュームに対するすべての BPIO_OP_ENABLE と BPIO_OP_QUERY 要求を拒否する必要があります。
FS_BPIO_OP_VOLUME_STACK_RESUME 要求
ボリューム スタック ドライバーは、この FSCTL 操作をファイル システムに送信して、指定したボリュームに対する BypassIO 処理を再開します。 ドライバーが FS_BPIO_OP_VOLUME_STACK_PAUSE を送信する原因となったシナリオがアクティブでなくなったら、この操作を送信します。 この操作は、BypassIO が現在有効または一時停止になっていない場合でも送信できます。
この要求は、ユーザー モードまたはカーネル モードから送信される可能性があります。
この操作を失敗させないでください。
ボリューム スタックの再開の例
前に説明したボリューム スタックの一時停止のシナリオを使って、ボリュームにアクティブなスナップショットがなくなったとします。 Volsnap は、最後のスナップショットがなくなった後でのみ FS_BPIO_OP_VOLUME_STACK_RESUME を送信します。
FS_BPIO_OP_STREAM_PAUSE 要求
フィルターは、FS_BPIO_OP_STREAM_PAUSE 操作を送信して、ストリームに対する BypassIO を一時停止できます。 この要求は、ユーザー モードまたはカーネル モードから送信される可能性があります。 すべてのアクティブな BypassIO が有効なファイルで、BypassIO 操作が停止されます。
具体的には、フィルターが以前にストリームで BypassIO の有効化を許可していて、後で BypassIO を停止する必要がある場合 (ファイルまたはディレクトリを暗号化する要求などの外部要求により)、フィルター スタックから FS_BPIO_OP_STREAM_PAUSE ダウンを送信して 特定のストリームでの BypassIO の実行を停止するようにファイル システムに指示できます。 フィルターでこの操作をスタックの先頭に送信することはできません。
ファイル システムは、戻る前に、ストリームで開いているすべての BypassIO ハンドルを一時停止し、ストリームに対するすべてのアクティブな BypassIO 操作を完了します。 これらのアクションにより、戻ったら、フィルターは行う必要があるファイル操作を実行できるようになります。
この操作は、同じストリームに複数回送信できます。 現在 BypassIO が有効になっていないストリームに対して送信された場合、ファイル システムはそれを無視します。
フィルターがストリームの一時停止操作を行った場合、BypassIO はボリューム スタックとストレージ スタックで続行されます。
この操作を失敗させないでください。
ストリームの一時停止の例: 暗号化フィルター
暗号化フィルターが、その時点では暗号化されていないストリームで BypassIO の有効化を許可しましたが、後でこのストリームを暗号化する要求を受け取ったとします。
暗号化フィルターは、処理を続ける前に、FsRtlGetBypassIoOpenCount を呼び出して、このストリームで BypassIO がアクティブかどうかを判断する必要があります。 そうである場合、暗号化フィルターは、BypassIO の無効化をシステムに求める FS_BPIO_OP_STREAM_PAUSE 操作を送信します。 成功して戻ると、BypassIO は無効になり、ドレインされているため、フィルターは暗号化要求を安全に実行できます。 競合状態の可能性をなくすには、フィルターは、それ以降、この現在は暗号化されたストリームに対するすべての FS_BPIO_OP_ENABLE 要求と FS_BPIO_OP_QUERY 要求を拒否する必要があります。
FS_BPIO_OP_STREAM_RESUME 要求
フィルターが FS_BPIO_OP_STREAM_PAUSE 操作を送信する原因になったシナリオが存在しなくなった場合、フィルターは FS_BPIO_OP_STREAM_RESUME 操作をファイル システムに送信して、特定のストリームの BypassIO 処理を再開します。 この要求は、ユーザー モードまたはカーネル モードから送信される可能性があります。
BypassIO が現在有効または一時停止にされていないときにこの操作が送信された場合は、無視されます。
一時停止と再開は参照カウントされません。 そうではなく、再開時には、ファイル システムはファイル システム スタックの先頭に FS_BPIO_OP_QUERY 要求を発行して、残っているフィルターがまだブロックされているかどうかを判断します。 スタック内のすべてのフィルターが BypassIO をブロックしていない場合にのみ、ファイル システムは BypassIO を再開します。
この操作を失敗させないでください。
ストリーム再開の例: 暗号化フィルター
前に説明した FS_BPIO_OP_STREAM_PAUSE のシナリオを使って、FS_BPIO_OP_STREAM_PAUSE の呼び出しの後で以前は暗号化されていたファイルが暗号化されなくなったとします。 この場合、フィルターは FS_BPIO_OP_STREAM_RESUME 操作を送信して、そのストリームに対する BypassIO の再開を許可する必要があります。
FS_BPIO_OP_GET_INFO 要求
この要求は、ユーザー モードまたはカーネル モードから送信される可能性があります。 ファイル システムは、ボリュームに対する BypassIO に関する情報を FS_BPIO_INFO 構造体で返します。