请求和授予 oplock

当网络重定向程序访问远程服务器上的文件时,它会从远程服务器请求 oplock。 仅当锁用于本地服务器上的文件时,客户端应用程序才直接请求 oplock。

Oplock 是通过 FSCL 请求的。 以下 FSCTL 用于用户模式应用程序和内核模式驱动程序可以颁发的不同 oplock 类型

若要在用户模式下请求 Windows 7 oplock,请调用 DeviceIoControl

以类似的方式,在内核模式下请求 Windows 7 oplock:

若要指定需要四个 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) :

  1. 以所需的FILE_READ_ATTRIBUTES访问权限和共享模式FILE_SHARE_READ打开文件 |FILE_SHARE_WRITE |FILE_SHARE_DELETE。

  2. 从步骤 1 请求句柄上的 Filter oplock。

  3. 再次打开文件以获取读取访问权限。

步骤 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 时授予:

  • 请求针对给定的文件流。
    • 如果为目录,则返回STATUS_INVALID_PARAMETER。
  • 为异步访问打开流。
    • 如果为同步访问打开,则返回STATUS_OPLOCK_NOT_GRANTED, (未为同步 I/O 请求授予 oplock) 。
  • 文件的任何流上都没有 TxF 事务。
    • 否则返回STATUS_OPLOCK_NOT_GRANTED。
  • 即使同一线程) ,流 (也没有其他打开。
    • 否则返回STATUS_OPLOCK_NOT_GRANTED。

如果当前 oplock 状态为:

  • 无 oplock:已授予请求。

  • 级别 2:原始级别 2 请求因FILE_OPLOCK_BROKEN_TO_NONE中断。 然后授予请求的独占 oplock。

  • 级别 1、Batch、Filter、Read、Read-Handle、Read-Write 或 Read-Write-Handle:返回STATUS_OPLOCK_NOT_GRANTED。

级别 2

仅当以下所有条件都为 true 时授予:

  • 请求针对给定的文件流。
    • 如果为目录,则返回STATUS_INVALID_PARAMETER。
  • 为异步访问打开流。
    • 如果为同步访问打开,则返回STATUS_OPLOCK_NOT_GRANTED。
  • 文件上没有 TxF 事务。
    • 否则返回STATUS_OPLOCK_NOT_GRANTED。
  • 流上没有当前字节范围锁。
    • 否则返回STATUS_OPLOCK_NOT_GRANTED。
    • 在 Windows 7 之前,操作系统会验证自上次打开流以来流上是否存在字节范围锁,如果存在,则请求失败。

如果当前 oplock 状态为:

  • 无 oplock:已授予请求。

  • 级别 2 和/或读取:请求已授予。 可以同时在同一流上授予多个级别 2/Read oplock。 多个级别 2 (但不是读取) oplock 甚至可以存在于同一句柄上。
    • 如果在已向其授予 Read oplock 的句柄上请求读取 oplock,则第一个 Read oplock 的 IRP 在授予第二个 Read oplock 之前,使用 STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE 完成。
  • 级别 1、Batch、Filter、Read-Handle、Read-Write、Read-Write、Read-Write-Handle:返回STATUS_OPLOCK_NOT_GRANTED。

读取

仅当以下所有条件都为 true 时授予:

  • 请求针对给定的文件流。
  • 为异步访问打开流。
    • 如果为同步访问打开,则返回STATUS_OPLOCK_NOT_GRANTED。
  • 文件上没有 TxF 事务。
    • 否则返回STATUS_OPLOCK_NOT_GRANTED。
  • 流上没有当前字节范围锁。
    • 否则返回STATUS_OPLOCK_NOT_GRANTED。

请注意,如果当前 oplock 状态为:

  • 无 oplock:已授予请求。

  • 级别 2 和/或读取:请求已授予。 可以同时在同一流上授予多个级别 2/Read oplock。
    • 此外,如果现有 oplock 具有与新请求相同的 oplock 密钥,则其 IRP 会STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE完成。
  • Read-Handle 和现有 oplock 具有与新请求不同的 oplock 密钥:请求已授予。 多个 Read 和 Read-Handle oplock 可以共存于同一流中, (请参阅下表后面的说明) 。
    • 否则, (oplock 键与返回) STATUS_OPLOCK_NOT_GRANTED 相同。
  • 级别 1、Batch、Filter、Read-Write、Read-Write、Read-Write-Handle:返回STATUS_OPLOCK_NOT_GRANTED。

Read-Handle

仅当以下所有条件都为 true 时授予:

  • 请求针对给定的文件流。
  • 为异步访问打开流。
    • 如果为同步访问打开,则返回STATUS_OPLOCK_NOT_GRANTED。
  • 文件上没有 TxF 事务。
    • 否则返回STATUS_OPLOCK_NOT_GRANTED。
  • 流上没有当前字节范围锁。
    • 否则返回STATUS_OPLOCK_NOT_GRANTED。

如果当前 oplock 状态为:

  • 无 oplock:请求已授予。

  • 读取:请求已授予。
    • 如果现有 Read oplock 与新请求具有相同的 oplock 密钥,则其 IRP 将完成STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE。 结果是将 oplock 从“读取”升级到“读取句柄”。
    • 任何与新请求没有相同 oplock 键的现有 Read oplock 将保持不变。
  • 级别 2、级别 1、Batch、筛选器、读写、读写句柄:返回STATUS_OPLOCK_NOT_GRANTED。

读取/写入

仅当以下所有条件都为 true 时授予:

  • 请求针对给定的文件流。
    • 如果为目录,则返回STATUS_INVALID_PARAMETER。
  • 为异步访问打开流。
    • 如果为同步访问打开,则返回STATUS_OPLOCK_NOT_GRANTED。
  • 文件上没有 TxF 事务。
    • 否则返回STATUS_OPLOCK_NOT_GRANTED。
  • 如果流上存在其他打开 ((即使由同一线程) 打开),则它们必须具有相同的 oplock 键。
    • 否则返回STATUS_OPLOCK_NOT_GRANTED。

如果当前 oplock 状态为:

  • 无 oplock:请求已授予。

  • 读取或 Read-Write,现有 oplock 具有与请求相同的 oplock 密钥:现有 oplock 的 IRP 通过STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE完成,请求授予。
    • 否则返回STATUS_OPLOCK_NOT_GRANTED。
  • 级别 2、级别 1、Batch、Filter、Read-Handle、Read-Write-Handle:返回STATUS_OPLOCK_NOT_GRANTED。

Read-Write-Handle

仅当以下所有条件都为 true 时授予:

  • 请求针对给定的文件流。
    • 如果为目录,则返回STATUS_INVALID_PARAMETER。
  • 为异步访问打开流。
    • 如果为同步访问打开,则返回STATUS_OPLOCK_NOT_GRANTED。
  • 文件上没有 TxF 事务。
    • 否则返回STATUS_OPLOCK_NOT_GRANTED。
  • 如果流上有其他打开的请求 (即使由同一线程) 它们必须具有相同的 oplock 密钥。
    • 否则返回STATUS_OPLOCK_NOT_GRANTED。

如果当前 oplock 状态为:

  • 无 oplock:请求已授予。

  • Read、Read-Handle、Read-Write 或 Read-Write-Handle 和现有的 oplock 具有与请求相同的 oplock 键:现有 oplock 的 IRP 是使用 STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE 完成的,请求授予。
    • 否则返回STATUS_OPLOCK_NOT_GRANTED。
  • 级别 2、级别 1、批处理、筛选器:返回STATUS_OPLOCK_NOT_GRANTED。

注意

读取和级别 2 oplock 可以共存于同一流中,Read 和 Read-Handle oplock 可以共存,但 Level 2 和 Read-Handle oplock 不能共存。