當網路重導程式存取遠端伺服器上的檔案時,它會向遠端伺服器請求 oplock。 只有當鎖定適用於本地伺服器上的檔案時,用戶端應用程式才會直接請求 oplock。
Oplocks 是透過 FSCTLs要求的。 下列 FSCTL 用於不同的 oplock 類型,兩者均可由使用者模式應用程式和核心模式驅動程式發出。
- 若要請求 Windows 7 oplocks:
- 若要要求舊版檔案鎖定 (oplocks):
在使用者模式中要求 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 中斷之前不會完成。 作業完成之後,REQUEST_OPLOCK_OUTPUT_BUFFER 會包含 oplock 中斷的相關資訊。
如果無法獲得 oplock,檔案系統會傳回適當的錯誤碼。 最常傳回的錯誤碼是ERROR_OPLOCK_NOT_GRANTED和ERROR_INVALID_PARAMETER。
核心模式中申請 oplock
若要在核心模式中要求 Windows 7 的 oplocks:
文件系統迷你篩選程式
文件系統迷你篩選器必須使用 FltAllocateCallbackData,並填寫配置的 FLT_CALLBACK_DATA,如下所示:
- 將 Iopb->MajorFunction 字段設定為 IRP_MJ_FILE_SYSETM_CONTROL。
- 將其 Iopb->MinorFunction 欄位設定為 IRP_MN_USER_FS_REQUEST。
- 將其 Iopb->參數的 FileSystemControl.Buffered.FsControlCode 成員設定為 FSCTL_REQUEST_OPLOCK。
- 配置大小等於大於 REQUEST_OPLOCK_INPUT_BUFFER 或 REQUEST_OPLOCK_OUTPUT_BUFFER的緩衝區。
- 將配置的 FLT_CALLBACK_DATAIopb->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 中斷之前不會完成。 作業完成之後,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 中斷之前不會完成。 作業完成之後,REQUEST_OPLOCK_OUTPUT_BUFFER 會包含 oplock 中斷的相關資訊。
如果無法獲得 oplock,檔案系統會傳回適當的錯誤碼。 最常傳回的錯誤碼是STATUS_OPLOCK_NOT_GRANTED和STATUS_INVALID_PARAMETER。
在請求Oplocks時避免共用違規
使用 Atomic Create-With-Oplock 方法
原子 create-with-oplock 不是一種 oplock 類型。 相反地,這是一種程序,可讓開啟作業避免在開啟檔案與接收 oplock 之間的時間範圍內引發共享模式違規。 使用舊版 oplocks 時,需要篩選 oplocks 和開啟兩個句柄。 透過 Windows 7 oplocks,應用程式或驅動程式可以使用此程式提出任何類型的 oplock 要求,而且只需開啟一個句柄。
若要執行原子性 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 類型。 這樣,您可以允許其他呼叫者進行最大程度的並行存取,同時在需要關閉控制代碼以避免產生共用衝突時得到通知。
使用舊版過濾器 Oplock
舊版 Filter oplock 也可讓應用程式在其他應用程式/用戶端嘗試存取相同數據流時「退出」,但靈活性不如使用 oplock 的原子創建方法。 此機制可讓應用程式存取串流,而不會造成其他存取者在嘗試開啟串流時發生共用衝突。 若要避免共用違規,應該使用下列三個步驟的程序來申請 Filter oplock:
以需要的存取模式 FILE_READ_ATTRIBUTES 和 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE 的共用模式開啟檔案。 在此步驟中開啟的句柄不會造成其他應用程式收到共用違規,因為此句柄只會針對屬性存取 (FILE_READ_ATTRIBUTES) 而非數據存取 (FILE_READ_DATA) 開啟。 此句柄適用於要求篩選操作鎖定,但不適合在數據流上執行實際的 I/O。
在步驟 1 的控制代碼上請求 Filter oplock (FSCTL_REQUEST_FILTER_OPLOCK)。 此步驟中授與的oplock可讓oplock持有者「走出去」,而不會造成嘗試存取數據流的另一個應用程式發生共享違規。
再次開啟檔案以進行讀取存取。 在此步驟中開啟的控制柄可讓 oplock 持有人在數據流上執行 I/O。
NTFS 檔案系統透過 FILE_RESERVE_OPFILTER 建立選項旗標,為這個過程提供優化。 如果在上一個程序的步驟 1 中指定此標誌,並且文件系統能夠判定步驟 2 將失敗,則文件系統允許建立請求失敗,並返回 STATUS_OPLOCK_NOT_GRANTED。 如果步驟 1 成功,則不保證步驟 2 會成功,即使已為建立要求指定FILE_RESERVE_OPFILTER也一樣。
授予Oplocks的條件
下表列出授予 oplock 所需的必要條件。
| 要求類型 | 條件 |
|---|---|
層級 1 過濾器 批 |
只有在下列所有條件都成立時才授與:
如果目前的 oplock 狀態為:
|
層級 2 |
只有在下列所有條件都成立時才授與:
如果目前的 oplock 狀態為:
|
讀 |
只有在下列所有條件都成立時才授與:
如果目前的 oplock 狀態為:
|
Read-Handle |
只有在下列所有條件都成立時才授與:
如果目前的 oplock 狀態為:
|
讀寫 |
只有在下列所有條件都成立時才授與:
如果目前的 oplock 狀態為:
|
讀取:Write-Handle |
只有在下列所有條件都成立時才授與:
如果目前的 oplock 狀態為:
|
注意
讀取和Level 2 oplock可以共存於相同的數據流,而讀取和Read-Handle oplocks可以共存,但Level 2和Read-Handle oplocks無法共存。