请求和授予 oplock
当网络重定向程序访问远程服务器上的文件时,它会从远程服务器请求 oplock。 仅当锁用于本地服务器上的文件时,客户端应用程序才直接请求 oplock。
Oplock 是通过 FSCL 请求的。 以下 FSCTL 用于用户模式应用程序和内核模式驱动程序可以颁发的不同 oplock 类型:
- 请求旧 oplock:
- 请求 Windows 7 oplock:
若要在用户模式下请求 Windows 7 oplock,请调用 DeviceIoControl:
- 将 dwIoControlCode 设置为 FSCTL_REQUEST_OPLOCK。
- 在 REQUEST_OPLOCK_INPUT_BUFFER 结构的Flags 成员中指定REQUEST_OPLOCK_INPUT_FLAG_REQUEST标志,该标志作为 lpInBuffer 参数传递。
以类似的方式,在内核模式下请求 Windows 7 oplock:
- 非文件系统微筛选器可以调用 ZwFsControlFile。
- 文件系统微筛选器必须使用 FltAllocateCallbackData 和 FltPerformAsynchronousIo。
若要指定需要四个 Windows 7 oplock 中的哪一个,请在 REQUEST_OPLOCK_INPUT_BUFFER 结构的 RequestedOplockLevel 成员中设置以下一个或多个标志:
- OPLOCK_LEVEL_CACHE_READ
- OPLOCK_LEVEL_CACHE_HANDLE
- OPLOCK_LEVEL_CACHE_WRITE
有关详细信息,请参阅 FSCTL_REQUEST_OPLOCK。
如果可以授予请求的 oplock,则文件系统将返回STATUS_PENDING。 因此,永远不会为同步 I/O 授予 oplock。 在破坏 oplock 之前,FSCTL IRP 不会完成。
如果无法授予 oplock,则文件系统将返回相应的错误代码。 最常返回的错误代码是STATUS_OPLOCK_NOT_GRANTED和STATUS_INVALID_PARAMETER (及其等效的用户模式模拟) 。
筛选器 oplock 允许应用程序在其他应用程序/客户端尝试访问同一流时“退出”。 此机制允许应用程序访问流,而不会导致流的其他访问器在尝试打开流时收到共享冲突。 为了避免共享冲突,应使用一个特殊的三步过程来请求 Filter oplock (FSCTL_REQUEST_FILTER_OPLOCK) :
以所需的FILE_READ_ATTRIBUTES访问权限和共享模式FILE_SHARE_READ打开文件 |FILE_SHARE_WRITE |FILE_SHARE_DELETE。
从步骤 1 请求句柄上的 Filter oplock。
再次打开文件以获取读取访问权限。
步骤 1 中打开的句柄不会导致其他应用程序收到共享冲突,因为它仅针对属性访问 (FILE_READ_ATTRIBUTES) 打开,而不针对数据访问 (FILE_READ_DATA) 。 此句柄适用于请求 Filter oplock,但不适用于对数据流执行实际 I/O。 步骤 3 中打开的句柄允许 oplock 的持有者对流执行 I/O;步骤 2 中授予的 oplock 允许 oplock 的持有者“退出”,而不会对尝试访问流的另一个应用程序造成共享冲突。
NTFS 文件系统通过FILE_RESERVE_OPFILTER create 选项标志为此过程提供优化。 如果在上一过程的步骤 1 中指定了此标志,则如果文件系统可以确定步骤 2 将失败,则允许文件系统通过STATUS_OPLOCK_NOT_GRANTED创建请求失败。 如果步骤 1 成功,则无法保证步骤 2 会成功,即使为创建请求指定了FILE_RESERVE_OPFILTER也是如此。
下表确定了授予 oplock 所需的条件。
请求类型 | 条件 |
---|---|
级别 1 筛选器 Batch |
仅当以下所有条件都为 true 时授予:
如果当前 oplock 状态为:
|
级别 2 |
仅当以下所有条件都为 true 时授予:
如果当前 oplock 状态为:
|
读取 |
仅当以下所有条件都为 true 时授予:
请注意,如果当前 oplock 状态为:
|
Read-Handle |
仅当以下所有条件都为 true 时授予:
如果当前 oplock 状态为:
|
读取/写入 |
仅当以下所有条件都为 true 时授予:
如果当前 oplock 状态为:
|
Read-Write-Handle |
仅当以下所有条件都为 true 时授予:
如果当前 oplock 状态为:
|
注意
读取和级别 2 oplock 可以共存于同一流中,Read 和 Read-Handle oplock 可以共存,但 Level 2 和 Read-Handle oplock 不能共存。