ネットワーク リダイレクターは、リモート サーバー上のファイルにアクセスすると、リモート サーバーから oplock を要求します。 クライアント アプリケーションは、ロックがローカル サーバー上のファイルを対象としている場合にのみ、oplock を直接要求します。
Oplocks は FSCTLs.を通じてリクエストされます。 次の FSCTLは、ユーザーモードアプリケーションとカーネルモードドライバーの両方から発行できる、さまざまな 型のオプトロックに使用されます。
- Windows 7 の oplock を要求するには:
- 従来の oplock をリクエストするには:
ユーザーモードでのオプロックの要求
ユーザーモードで Windows 7 の oplock を要求するには、DeviceIoControlを呼び出します。
- dwIoControlCode を FSCTL_REQUEST_OPLOCK に設定します。
- lpInBuffer パラメーターで REQUEST_OPLOCK_INPUT_BUFFER 構造体へのポインターを渡します。
- oplock 要求の書式を設定する方法については、その構造体のドキュメントを参照してください。
- lpOutBuffer パラメーターで REQUEST_OPLOCK_OUTPUT_BUFFER 構造体へのポインターを渡します。
詳細については、FSCTL_REQUEST_OPLOCK を参照してください。
要求された oplock を許可できる場合、DeviceIoControl は FALSE を返し、GetLastErrorは ERROR_IO_PENDING を返します。 このため、同期 I/O に対して oplock が付与されることはありません。 重複する操作は、oplock が壊れるまで完了しません。 操作が完了すると、REQUEST_OPLOCK_OUTPUT_BUFFER には oplock の解除に関する情報が含まれます。
oplock を許可できない場合、ファイル システムは適切なエラー コードを返します。 最も一般的に返されるエラー コードは、ERROR_OPLOCK_NOT_GRANTED と ERROR_INVALID_PARAMETER です。
カーネル モードでの oplock の要求
カーネルモードでWindows 7のオプノロックを要求するには、
ファイル システム ミニフィルター
ファイル システムミニフィルターでは、FltAllocateCallbackData を使用して、次のように割り当てられた FLT_CALLBACK_DATA を入力する必要があります。
- Iopb->MajorFunction フィールドを IRP_MJ_FILE_SYSTEM_CONTROL に設定します。
- Iopb->MinorFunction フィールドを IRP_MN_USER_FS_REQUEST に設定します。
- Iopb->Parameters.FileSystemControl.Buffered.FsControlCode メンバーを FSCTL_REQUEST_OPLOCK に設定します。
- サイズが大きい REQUEST_OPLOCK_INPUT_BUFFER または REQUEST_OPLOCK_OUTPUT_BUFFER に等しいバッファーを割り当てます。
- 割り当てられた FLT_CALLBACK_DATA の Iopb->Parameters.FileSystemControl.Buffered.SystemBuffer メンバーをそのバッファーを指すよう設定します。
- 割り当てられた FLT_CALLBACK_DATA の Iopb->Parameters.FileSystemControl.Buffered.InputBufferLength と Iopb->Parameters.FileSystemControl.Buffered.OutputBufferLength の各フィールドを、そのバッファーのサイズに設定します。
oplock 要求の書式を設定する方法については、REQUEST_OPLOCK_INPUT_BUFFER 構造体のドキュメントを参照してください。
その後、ファイル システムミニフィルターは FltPerformAsynchronousIo を呼び出し、割り当てられた FLT_CALLBACK_DATA を CallbackData パラメーターとして渡す必要があります。
要求された oplock を許可できる場合、FltPerformAsynchronousIo 呼び出しは STATUS_PENDING を返します。 このため、同期 I/O に対して oplock が付与されることはありません。 操作は、oplock が壊れるまで完了しません。 操作が完了すると、REQUEST_OPLOCK_OUTPUT_BUFFER には oplock の解除に関する情報が含まれます。
oplock を許可できない場合、ファイル システムは適切なエラー コードを返します。 最も一般的に返されるエラー コードは、STATUS_OPLOCK_NOT_GRANTED と STATUS_INVALID_PARAMETER です。
その他の種類のドライバー
他の種類のドライバーは、ZwFsControlFile呼び出すことができます。
- FsControlCode を FSCTL_REQUEST_OPLOCKに設定します。
- InputBuffer パラメーター内の REQUEST_OPLOCK_INPUT_BUFFER 構造体へのポインターを渡し、InputBufferLength パラメーターをそのバッファーのサイズに設定します。
- OutputBuffer パラメーター内の REQUEST_OPLOCK_OUTPUT_BUFFER 構造体へのポインターを渡し、OutputBufferLength パラメーターをそのバッファーのサイズに設定します。
oplock 要求の書式を設定する方法については、REQUEST_OPLOCK_INPUT_BUFFER 構造体のドキュメントを参照してください。
要求された oplock を許可できる場合、ZwFsControlFile 呼び出しは STATUS_PENDING を返します。 このため、同期 I/O に対して oplock が付与されることはありません。 操作は、oplock が壊れるまで完了しません。 操作が完了すると、REQUEST_OPLOCK_OUTPUT_BUFFER には oplock の解除に関する情報が含まれます。
oplock を許可できない場合、ファイル システムは適切なエラー コードを返します。 最も一般的に返されるエラー コードは、STATUS_OPLOCK_NOT_GRANTED と STATUS_INVALID_PARAMETER です。
Oplock を要求するときの共有違反の回避
Atomic Create-With-Oplock メソッドを使用する
アトミック create-with-oplock は oplock 型ではありません。 むしろ、オープン操作は、ファイルを開いてから oplock を受け取るまでの間に、共有モード違反を引き起こさないようにする手順です。 従来の oplock では、Filter oplock と 2 つのハンドルを開く必要があります。 Windows 7 oplock を使用すると、アプリケーションまたはドライバーは、この手順を使用して任意の種類の oplock を要求でき、1 つのハンドルのみを開く必要があります。
アトミックな create-with-oplock プロシージャを実行するには、次の手順を実行する必要があります。
- ファイルを開くには、適宜 FltCreateFileEx2または ZwCreateFileを使用します。 CreateOptions パラメーターで、フラグを FILE_OPEN_REQUIRING_OPLOCK渡します。 DesiredAccess パラメーターと ShareAccess パラメーターは、必要に応じて設定できます。 たとえば、DesiredAccess パラメーターセット GENERIC_READ でファイルを読み取ることができるようにし、ShareAccess パラメーターで FILE_SHARE_READ |FILE_SHARE_DELETE フラグを使用して、ファイルを開いている間に他のユーザーがファイルの読み取り、名前変更、および/または削除のマークを付けることができるようにします。
- FSCTL_REQUEST_OPLOCK 制御コードを使用して、カーネル モードでの oplock の要求 に関するページで説明されているように、結果のファイル オブジェクトまたはハンドルに対して oplock を要求します。
手順 1 から 2 の間、ファイル に対してファイル システム操作を実行しないでください。 これを行うと、デッドロックが発生する可能性があります。
このプロシージャを使用して要求する最も一般的な oplock は、Read-Handle 型です。 これにより、他の呼び出し元に可能な限り多くの同時アクセスを許可しながら、競合するオープンに共有違反が発生しないようにハンドルを閉じる必要がある場合に通知を受け取ることができます。
レガシーフィルターオプロックの使用
従来の Filter oplock では、他のアプリケーション/クライアントが同じストリームにアクセスしようとしたときにアプリケーションを "バックアウト" することもできます。しかし、アトミックな create-with-oplock メソッドよりも柔軟性が低くなります。 このメカニズムにより、ストリームを開こうとしたときに、ストリームの他のアクセサーが共有違反を受け取ることなく、アプリケーションがストリームにアクセスできるようになります。 共有違反を回避するには、次の 3 つの手順を使用してフィルター操作を要求する必要があります。
FILE_READ_ATTRIBUTESのアクセス権と、FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETEの共有モードでファイルを開く。 この手順で開いたハンドルは、データ アクセス (FILE_READ_DATA) ではなく属性アクセス (FILE_READ_ATTRIBUTES) に対してのみ開かれているため、他のアプリケーションが共有違反を受け取ることはありません。 このハンドルは、フィルター操作ロックを要求するのに適していますが、データ ストリームで実際の I/O を実行する場合には適していません。
手順 1 のハンドルでフィルターの oplock (FSCTL_REQUEST_FILTER_OPLOCK) を要求します。 この手順で付与された oplock により、oplock 所有者はストリームへのアクセスを試みる他のアプリケーションに対して共有違反を引き起こすことなく、"邪魔にならないようにする" ことができます。
読み取りアクセス用にファイルを再度開きます。 この手順で開いたハンドルを使用すると、oplock ホルダーはストリームで I/O を実行できます。
NTFS ファイル システムは、FILE_RESERVE_OPFILTER 作成オプション フラグを使用して、この手順の最適化を提供します。 前の手順のステップ 1 でこのフラグが指定されている場合、ファイル システムは手順 2 が失敗すると判断できる場合、STATUS_OPLOCK_NOT_GRANTED で作成要求を失敗させることができます。 手順 1 が成功した場合、作成要求に FILE_RESERVE_OPFILTER が指定されている場合でも、手順 2 が成功するという保証はありません。
Oplocks を付与するための条件
次の表は、oplock を許可するために必要な条件を示しています。
| 要求の種類 | 条件 |
|---|---|
レベル 1 フィルター バッチ |
これは、次の条件がすべて満たされている場合にのみ当てはまります。
現在の oplock 状態が次の場合:
|
[レベル 2] |
これは、次の条件がすべて満たされている場合にのみ当てはまります。
現在の oplock 状態が次の場合:
|
既読 |
これは、次の条件がすべて満たされている場合にのみ当てはまります。
現在の oplock 状態が次の場合:
|
読み取りハンドル |
これは、次の条件がすべて満たされている場合にのみ当てはまります。
現在の oplock 状態が次の場合:
|
読み取り/書き込み |
これは、次の条件がすべて満たされている場合にのみ当てはまります。
現在の oplock 状態が次の場合:
|
読み取り/書き込みハンドル |
次のすべてが当てはまる場合にのみ許可されます。
現在の oplock 状態が次の場合:
|
メモ
読み取りとレベル 2 の oplock は同じストリーム上で共存でき、読み取りと Read-Handle の oplock は共存できますが、レベル 2 と Read-Handle の oplock は共存できません。