Share via


Oplock の破損

便宜的ロック要求して許可されると、その便宜的ロックの所有者は、要求した便宜的ロックの種類に基づいてストリームにアクセスできます。 現在の便宜的ロックと互換性がない操作を受け取った場合、システムはその便宜的ロックを解除します。

便宜的ロックが許可されると、システムは要求を行っている IRP を保留状態にします。 便宜的ロックが解除されると、保留されていた便宜的ロックの要求 IRP は STATUS_SUCCESS で完了します。 Level 1、Batch、Filter の各便宜的ロックでは、IRP の IoStatus.Information メンバーが、便宜的ロックの解除後のレベルを示すように設定されます。 これらのレベルは次のとおりです。

  • FILE_OPLOCK_BROKEN_TO_NONE - 便宜的ロックは解除されており、現在ストリームに便宜的ロックはありません。 このような便宜的ロックは、"None に解除" されていると言われます。

  • FILE_OPLOCK_BROKEN_TO_LEVEL_2 - 現在の便宜的ロック (Level 1 または Batch) は、Level 2 便宜的ロックに変換されました。 Filter 便宜的ロックは Level 2に解除されることはなく、常に None に解除されます。

Read-Handle、Read-Write、Read-Write-Handle の各便宜的ロックの場合、便宜的ロックの解除後のレベルは、DeviceIoControllpOutBuffer パラメーターとして渡される REQUEST_OPLOCK_OUTPUT_BUFFER 構造体の NewOplockLevel メンバーのフラグ OPLOCK_LEVEL_CACHE_READ、OPLOCK_LEVEL_CACHE_HANDLE、または OPLOCK_LEVEL_CACHE_WRITE の 0 個以上の組み合わせとして記述されます。 同様に、カーネル モードから Windows 7 の便宜的ロックを要求するには、FltFsControlFileZwFsControlFile を使用できます。 詳細については、FSCTL_REQUEST_OPLOCK に関する記事をご覧ください。

システムの便宜的ロック パッケージが、Level 1、Batch、Filter、Read-Write、Read-Write-Handle、または Read-Handle (特定の状況下) の各便宜的ロックを解除する場合:

  • 便宜的ロックパッケージは、保留されている便宜的ロック要求 IRP を完了します。
  • 便宜的ロックの解除の原因になった操作は、それ自体が保留されます。

操作が同期ハンドルに対して発行された場合、または常に同期的である IRP_MJ_CREATE の場合、I/O マネージャーは STATUS_PENDING を返すのではなく操作をブロックし、便宜的ロックの所有者から、処理が完了し、操作を続行しても安全であることを便宜的ロック パッケージに通知する受信確認を待ちます。 この遅延の目的は、現在の操作が続行される前に、便宜的ロックの所有者がストリームを一貫した状態に戻せるようにすることです。 タイムアウトはないため、システムは受信確認の受信を永久に待機します。 したがって、便宜的ロックの所有者は、タイムリーに解除に受信確認する必要があります。 保留されている操作の IRP はキャンセル可能な状態に設定されます。 待機を実行しているアプリケーションまたはドライバーが終了すると、便宜的ロック パッケージは直ちに STATUS_CANCELLED で IRP を完了します。

IRP_MJ_CREATE IRP では、便宜的ロック解除受信確認の一部としてブロックされないように、FILE_COMPLETE_IF_OPLOCKED 作成オプションを指定できます。 このオプションは、便宜的ロック解除受信確認が受信されるまで作成 IRP をブロックしないよう、便宜的ロック パッケージに指示します。 代わりに、作成の続行が許可されます。 作成成功の結果として便宜的ロックが解除された場合、戻りコードは STATUS_SUCCESS ではなく STATUS_OPLOCK_BREAK_IN_PROGRESS になります。 通常、FILE_COMPLETE_IF_OPLOCKED フラグはデッドロックを回避するために使われます。 たとえば、ストリームに対する便宜的ロックを所有しているクライアントが、後で同じストリームを開いた場合、そのクライアントは自分自身が便宜的ロック解除の受信確認を行うのを待って、ブロック状態になります。 このシナリオでは、FILE_COMPLETE_IF_OPLOCKED フラグを使うとデッドロックが回避されます。

NTFS ファイル システムは、共有違反をチェックする前に、バッチとフィルターの便宜的ロックに対する便宜的ロック解除を開始するため、FILE_COMPLETE_IF_OPLOCKED を指定した作成が STATUS_SHARING_VIOLATION で失敗しても、バッチまたはフィルターの便宜的ロックが解除される可能性があります。 この場合、IO_STATUS_BLOCK 構造体の情報メンバーは、呼び出し元がこのケースを検出できるように FILE_OPBATCH_BREAK_UNDERWAY に設定されます。

Read-Handle と Read-Write-Handle 便宜的ロックの場合、便宜的ロック解除は NTFS のチェックの後で開始され、共有違反を検出します。 これにより、これらの便宜的ロックの所有者はハンドルを閉じて回避する機会があるため、共有違反をユーザーに返さない可能性があります。 また、便宜的ロックでキャッシュされているハンドルが新しい作成と競合しない場合に、便宜的ロックが無条件に解除されることも防ぎます。

Level 2、Read、および Read-Handle (特定の状況下) の各便宜的ロックが解除されるとき、システムは受信確認を待機しません。 これは、他のクライアントにアクセスを許可する前にファイルに復元する必要があるキャッシュされた状態が、ストリームに存在しないためです。

便宜的ロックの現在の状態をチェックして、便宜的ロックを解除する必要があるかどうかを判断する、特定のファイル システム操作があります。 次の記事では、各操作の一覧が示され、便宜的ロックの解除がトリガーされる条件、便宜的ロックの解除後のレベルを決定する要因、解除の受信確認が必要かどうかが説明されています。

Windows 7 の便宜的ロックの解除では、DeviceIoControl(lpOutBuffer)、FltFsControlFile(OutBuffer)、または ZwFsControlFile(OutBuffer) の出力パラメーターとして渡される REQUEST_OPLOCK_OUTPUT_BUFFER 構造体の Flags メンバーで REQUEST_OPLOCK_OUTPUT_FLAG_ACK_REQUIRED フラグが設定されている場合、受信確認が必要です。 詳細については、FSCTL_REQUEST_OPLOCK に関する記事をご覧ください。

一覧の操作ごとの記事では、Read-Handle 便宜的ロックの解除によって、便宜的ロックを解除した操作が保留される場合の詳細が説明されています。 たとえば、IRP_MJ_CREATE の記事には、関連する Read-Handle の詳細が含まれます。