完成例程的约束

注意

为了获得最佳可靠性和性能,请使用支持筛选器管理器的 文件系统微筛选器驱动程序 ,而不是旧版文件系统筛选器驱动程序。 若要将旧驱动程序移植到微筛选器驱动程序,请参阅 移植旧筛选器驱动程序的指南

以下指南简要讨论了如何避免旧文件系统筛选器驱动程序完成例程中的常见编程错误。

由于可以在 IRQL DISPATCH_LEVEL调用完成例程,因此它们受以下约束:

  • 完成例程无法安全地调用需要较低 IRQL 的内核模式例程,例如 IoDeleteDeviceObQueryNameString

  • 必须在非分页池中分配完成例程中使用的任何数据结构。

  • 无法使完成例程可分页。

  • 完成例程无法获取资源、互斥或快速互斥。 但是,他们可以获取旋转锁。

检查 PendingReturned 标志

  • 除非完成例程发出事件信号,否则它必须检查 Irp-PendingReturned> 标志。 如果设置了此标志,则完成例程必须调用 IoMarkIrpPending 以将 IRP 标记为挂起。

  • 如果完成例程向事件发出信号,则它不应调用 IoMarkIrpPending

返回状态的约束

  • 文件系统筛选器驱动程序完成例程必须返回STATUS_SUCCESS或STATUS_MORE_PROCESSING_REQUIRED。 所有其他 NTSTATUS 值将重置为 I/O 管理器STATUS_SUCCESS。

返回STATUS_MORE_PROCESSING_REQUIRED的约束

完成例程应返回STATUS_MORE_PROCESSING_REQUIRED有三种情况:

  • 当相应的调度例程正在等待完成例程发出事件信号时。 在这种情况下,请务必返回STATUS_MORE_PROCESSING_REQUIRED,以防止 I/O 管理器在完成例程返回后过早完成 IRP。

  • 完成例程已将 IRP 发布到辅助角色队列,并且相应的调度例程已返回STATUS_PENDING。 在这种情况下,请务必返回STATUS_MORE_PROCESSING_REQUIRED,以防止 I/O 管理器在完成例程返回后过早完成 IRP。

  • 当同一驱动程序通过调用 IoAllocateIrpIoBuildAsynchronousFsdRequest 创建 IRP 时。 由于驱动程序未从更高级别的驱动程序接收此 IRP,因此它可以在完成例程中安全地释放 IRP。 完成例程调用 IoFreeIrp 后,它必须返回STATUS_MORE_PROCESSING_REQUIRED以指示不需要进一步的完成处理。

完成例程无法返回 oplock 操作的STATUS_MORE_PROCESSING_REQUIRED。 Oplock 操作不能 (发布到辅助角色队列) ,并且调度例程无法为其返回STATUS_PENDING。

将 IRP 发布到工作队列的约束

  • 如果完成例程将 IRP 发布到工作队列,则必须在将每个 IRP 发布到工作队列之前调用 IoMarkIrpPending 。 否则,在调用 IoMarkIrpPending 之前,IRP 可能会被另一个驱动程序例程取消排队、由系统释放,从而导致崩溃。