破坏 Oplock
请求并授予 oplock 后,该 oplock 的所有者将基于所请求的 oplock 类型访问流。 如果收到的操作与当前 oplock 不兼容,则系统会中断 oplock。
授予 oplock 后,系统将请求的 IRP 挂起。 当 oplock 被断开时,挂起的 oplock 请求 IRP 将以 STATUS_SUCCESS 完成。 对于级别 1、批处理和筛选器 oplock,IRP 的 IoStatus.Information 成员被设置为指示 oplock 中断的级别。 这些级别包括:
FILE_OPLOCK_BROKEN_TO_NONE:oplock 已中断,流上没有当前的 oplock。 oplock 被称为“中断为无”。
FILE_OPLOCK_BROKEN_TO_LEVEL_2:当前 oplock(级别 1 或批处理)已转换为级别 2 oplock。 筛选器 oplock 永远不会中断到级别 2,它们始终中断为无。
对于 Read-Handle、Read-Write 和 Read-Write-Handle oplock,oplock 被中断的级别描述为传递作为 DeviceIoControl 的 lpOutBuffer 参数传递的 REQUEST_OPLOCK_OUTPUT_BUFFER 结构的 NewOplockLevel 成员中零个或多个标志 OPLOCK_LEVEL_CACHE_READ、OPLOCK_LEVEL_CACHE_HANDLE 或 OPLOCK_LEVEL_CACHE_WRITE 的组合。 以类似的方式,可以使用 FltFsControlFile 和 ZwFsControlFile 从内核模式请求 Windows 7 oplock。 有关详细信息,请参阅 FSCTL_REQUEST_OPLOCK。
当系统的 oplock 包中断级别 1、批处理、筛选器、Read-Write、Read-Write-Handle 或在某些情况下 Read-Handle oplock 时:
- oplock 包完成挂起的 oplock 请求 IRP。
- 导致 oplock 中断的操作本身已挂起。
I/O 管理器会导致操作被阻止,而不是返回 STATUS_PENDING,如果操作满足以下条件:
- 在同步句柄上发出。
- 是一个总是同步的 IRP_MJ_CREATE。
I/O 管理器等待 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 文件系统会为批处理和筛选器 oplock 启动 oplock 中断。 因此,指定了 FILE_COMPLETE_IF_OPLOCKED 的创建可能会失败,并出现 STATUS_SHARING_VIOLATION,但仍会导致批处理或筛选器 oplock 中断。 在这种情况下,IO_STATUS_BLOCK 结构的信息成员被设置为 FILE_OPBATCH_BREAK_UNDERWAY,从而使调用方能够检测到这种情况。
对于 Read-Handle 和 Read-Write-Handle oplock,NTFS 在检查并检测到共享冲突后,将启动 oplock 中断。 此序列使 oplock 持有者有机会关闭其句柄并退出操作,从而允许不将共享违例返回给用户。 它还避免在 oplock 缓存的句柄与新创建的句柄不冲突的情况下无条件地中断 oplock。
当级别 2、读取和在某些情况下 Read-Handle oplock 中断时,系统不会等待确认。 原因是,因为在允许其他客户端访问该流之前,不应在流上存在需要还原到文件的缓存状态。
某些文件系统操作检查当前的 oplock 状态,以确定是否需要中断 oplock。 以下与操作相关的文章描述了触发机会锁中断的因素、确定机会锁中断级别的标准,以及是否需要对中断进行确认:
- IRP_MJ_CREATE
- IRP_MJ_READ
- IRP_MJ_WRITE
- IRP_MJ_CLEANUP
- IRP_MJ_LOCK_CONTROL
- IRP_MJ_SET_INFORMATION
- IRP_MJ_FILE_SYSTEM_CONTROL
- FS_FILTER_ACQUIRE_FOR_SECTION_SYNCHRONIZATION
如果在作为 DeviceIoControl(lpOutBuffer)、FltFsControlFile(OutBuffer) 或 ZwFsControlFile(OutBuffer) 的输出参数传递的 REQUEST_OPLOCK_OUTPUT_BUFFER 结构的 Flags 成员中设置了 REQUEST_OPLOCK_OUTPUT_FLAG_ACK_REQUIRED 标志,则 Windows 7 oplock 的中断需要确认。 有关详细信息,请参阅 FSCTL_REQUEST_OPLOCK。
列出的按操作文章详细描述了 Read-Handle oplock 的中断何时导致中断 oplock 的操作挂起。 例如,IRP_MJ_CREATE 文章包含关联的 Read-Handle 详细信息。