破坏 Oplock

请求并授予oplock 后,该 oplock 的所有者可以根据请求的 oplock 类型访问该流。 如果收到的操作与当前 oplock 不兼容,则系统会中断 oplock。

授予 oplock 后,系统将请求 IRP。 当 oplock 中断时,将用STATUS_SUCCESS完成吊坠 oplock 的请求 IRP。 对于级别 1、批处理和筛选器操作锁,IRP 的 IoStatus.Information 成员设置为指示 oplock 中断的级别。 这些级别包括:

  • FILE_OPLOCK_BROKEN_TO_NONE - oplock 已中断,流中没有当前 oplock。 据说,oplock已经“打破到无”。

  • FILE_OPLOCK_BROKEN_TO_LEVEL_2 - 当前 oplock (级别 1 或 Batch) 已转换为级别 2 oplock。 筛选器 oplock 从不中断到级别 2,它们始终中断到 None。

对于 Read-Handle、Read-Write 和 Read-Write-Handle oplock,将 oplock 中断的级别描述为作为 DeviceIoControllpOutBuffer 参数传递的 REQUEST_OPLOCK_OUTPUT_BUFFER 结构的 NewOplockLevel 成员中的零个或多个标志OPLOCK_LEVEL_CACHE_READ、OPLOCK_LEVEL_CACHE_HANDLE或OPLOCK_LEVEL_CACHE_WRITE的组合。 同样, FltFsControlFileZwFsControlFile 可用于从内核模式请求 Windows 7 操作锁。 有关详细信息,请参阅 FSCTL_REQUEST_OPLOCK

当系统的 oplock 包中断级别 1、Batch、Filter、Read-Write、Read-Write-Handle,或在某些情况下Read-Handle oplock:

  • oplock 包完成吊坠的 oplock 请求 IRP。
  • 导致 oplock 中断的操作本身是吊坠的。

如果操作是在同步句柄上发出的,或者它是始终同步的IRP_MJ_CREATE,则 I/O 管理器会导致操作被阻止,而不是返回STATUS_PENDING,等待 oplock 所有者的确认,以告知 oplock 包他们已完成处理,并且可以安全地继续执行该操作。 此延迟的目的是允许 oplock 的所有者在当前操作继续之前将流重新置于一致状态。 系统将永久等待接收确认,因为没有超时。 因此,oplock 的所有者有责任及时承认中断。 笔式操作的 IRP 设置为可取消状态。 如果执行等待的应用程序或驱动程序终止,oplock 包会立即完成 IRP 并STATUS_CANCELLED。

IRP_MJ_CREATE IRP 可以指定FILE_COMPLETE_IF_OPLOCKED创建选项,以避免在 oplock 中断确认过程中被阻止。 此选项告知 oplock 包在收到 oplock 中断确认之前不要阻止创建 IRP。 相反,允许继续创建。 如果成功创建导致 oplock 中断,则返回代码STATUS_OPLOCK_BREAK_IN_PROGRESS而不是STATUS_SUCCESS。 FILE_COMPLETE_IF_OPLOCKED 标志通常用于避免死锁。 例如,如果客户端在流上拥有 oplock,而同一客户端随后打开同一个流,则客户端将阻止等待自己确认 oplock 中断。 在这种情况下,使用 FILE_COMPLETE_IF_OPLOCKED 标志可避免死锁。

由于 NTFS 文件系统在检查共享冲突之前为 Batch 和 Filter oplock 启动 oplock 中断,因此指定的 FILE_COMPLETE_IF_OPLOCKED创建可能会失败并出现STATUS_SHARING_VIOLATION但仍导致 Batch 或 Filter oplock 中断。 在这种情况下, IO_STATUS_BLOCK 结构的信息成员设置为 FILE_OPBATCH_BREAK_UNDERWAY,以允许调用方检测此情况。

对于Read-Handle和读写处理操作锁,在 NTFS 检查并检测到共享冲突后启动 oplock 中断。 这让这些 oplock 的持有者有机会关闭其句柄并脱身,从而允许不向用户返回共享冲突的可能性。 它还避免在 oplock 缓存的句柄与新创建不冲突的情况下无条件中断 oplock。

当级别 2、读取以及在某些情况下Read-Handle oplock 中断时,系统不会等待确认。 这是因为在允许其他客户端访问该文件之前,流上不应存在需要还原到文件的缓存状态。

某些文件系统操作检查当前 oplock 状态,以确定是否需要中断 oplock。 以下文章列出了每个操作,并介绍了触发 oplock 中断的触发因素、确定 oplock 中断的级别以及是否需要确认中断:

如果在作为 DeviceIoControl (lpOutBuffer) 、FltFsControlFile (OutBuffer) 或 ZwFsControlFile (OutBuffer) 的输出参数传递的 REQUEST_OPLOCK_OUTPUT_BUFFER标志成员中设置了REQUEST_OPLOCK_OUTPUT_FLAG_ACK_REQUIRED标志,则 Windows 7 oplock 的中断需要确认。 有关详细信息,请参阅 FSCTL_REQUEST_OPLOCK

列出的每操作文章详细介绍了何时中断Read-Handle oplock 导致中断操作的操作挂起。 例如, IRP_MJ_CREATE 文章包含关联的Read-Handle详细信息。