为较低级驱动程序创建 IRP

若要为异步请求分配 IRP(将由较低级驱动程序在任意线程上下文中处理), DispatchReadWrite 例程可以调用以下支持例程之一:

  • IoAllocateIrp,用于分配 IRP 和多个零初始化的 I/O 堆栈位置

    调度例程必须为新分配的 IRP 设置下一个较低驱动程序的 I/O 堆栈位置,通常是从原始 IRP 中自己的堆栈位置复制 (可能修改) 信息。 如果更高级别的驱动程序为新分配的 IRP 分配自己的 I/O 堆栈位置,则调度例程可以在其中设置每个请求的上下文信息,供 IoCompletion 例程使用。

  • IoBuildAsynchronousFsdRequest,根据调用方指定的参数为调用方设置下一个较低驱动程序的 I/O 堆栈位置

    更高级别的驱动程序可以调用此例程,为 IRP_MJ_READIRP_MJ_WRITEIRP_MJ_FLUSH_BUFFERS和IRP_MJ_SHUTDOWN请求分配 IRP

    为此类 IRP 调用 IoCompletion 例程时,它可以检查 I/O 状态块,并在必要时 (或可能) 再次在 IRP 中设置下一个较低驱动程序的 I/O 堆栈位置,然后重试请求或重复使用它。 但是, IoCompletion 例程在 IRP 中本身没有本地上下文存储,因此驱动程序必须在驻留内存中的其他位置维护有关原始请求的上下文。

  • IoMakeAssociatedIrp,用于分配 IRP 和多个零初始化的 I/O 堆栈位置,并将 IRP 与 IRP 相关联。

    中间驱动程序无法调用 IoMakeAssociatedIrp 来创建较低驱动程序的 IRP。

    调用 IoMakeAssociatedIrp 为较低驱动程序创建 IRP 的任何最高级别驱动程序,在发送其关联的 IRP 并为原始主 IRP 调用 IoMarkIrpPending 后,可以将控制权返回到 I/O 管理器。 当所有关联的 IRP 都由较低驱动程序完成时,最高级别的驱动程序可以依赖 I/O 管理器来完成主 IRP。

    驱动程序很少为关联的 IRP 设置 IoCompletion 例程。 如果最高级别驱动程序为其创建的关联 IRP 调用 IoSetCompletionRoutine ,则如果驱动程序从其 IoCompletion 例程返回STATUS_MORE_PROCESSING_REQUIRED,则 I/O 管理器不会完成主 IRP。 在这些情况下,驱动程序的 IoCompletion 例程必须使用 IoCompleteRequest 显式完成主 IRP。

如果驱动程序在新 IRP 中分配自己的 I/O 堆栈位置,则调度例程必须先调用 IoSetNextIrpStackLocation ,然后才能调用 IoGetCurrentIrpStackLocation ,以便在 IoCompletion 例程的自己的 I/O 堆栈位置中设置上下文。 有关详细信息,请参阅 处理Intermediate-Level驱动程序中的 IRP

调度例程必须使用原始 IRP 调用 IoMarkIrpPending ,但不能调用任何驱动程序分配的 IRP,因为 IoCompletion 例程将释放它们。

如果调度例程正在为部分传输分配 IRP,并且基础设备驱动程序可能控制可移动媒体设备,则调度例程必须从原始 IRP 中 Tail.Overlay.Thread 的值在其新分配的 IRP 中设置线程上下文。

可移动媒体设备的基础驱动程序可能会为驱动程序分配的 IRP 调用 IoSetHardErrorOrVerifyDevice,它引用 Irp-Tail.Overlay.Thread> 上的指针。 如果驱动程序调用此支持例程,则文件系统驱动程序可以向相应的用户线程发送一个对话框,提示用户取消、重试或失败驱动程序无法满足的操作。 有关详细信息 ,请参阅支持可移动媒体

将驱动程序分配的所有 IRP 发送到较低驱动程序后,调度例程必须返回STATUS_PENDING。

驱动程序的 IoCompletion 例程应在调用原始 IRP 的 IoCompleteRequest 之前,使用 IoFreeIrp 释放所有驱动程序分配的 IRP。 完成原始 IRP 后, IoCompletion 例程必须释放所有驱动程序分配的 IRP,然后才能返回控制权。

每个更高级别的驱动程序都为较低驱动程序设置分配的任何驱动程序 (和重用) IRP,这样,无论给定的请求来自中间驱动程序还是来自任何其他源(例如文件系统或用户模式应用程序),对基础设备驱动程序都无关紧要。

最高级别的驱动程序可以调用 IoMakeAssociatedIrp 来分配 IRP 并为较低级别的驱动程序链设置它们。 只要驱动程序不调用 IoSetCompletionRoutine 与原始 IRP 或其分配的任何关联 IRP,I/O 管理器会自动完成原始 IRP。 但是,最高级别的驱动程序不得为请求缓冲 I/O 操作的任何 IRP 分配关联的 IRP。

中间级别驱动程序无法通过调用 IoMakeAssociatedIrp 为低级别驱动程序分配 IRP。 中间驱动程序接收的任何 IRP 可能已经是关联的 IRP,并且驱动程序无法将另一个 IRP 与此类 IRP 相关联。

相反,如果中间驱动程序为较低驱动程序创建 IRP,它应调用 IoAllocateIrpIoBuildDeviceIoControlRequestIoBuildSynchronousFsdRequestIoBuildAsynchronousFsdRequest。 但是, IoBuildSynchronousFsdRequest 只能在以下情况下调用:

  • 由驱动程序创建的线程为读取或写入请求生成 IRP,因为此类线程可以在调度程序对象(如传递给 IoBuildSynchronousFsdRequest 的驱动程序初始化事件) (自己的) 的非比特线程上下文中等待

  • 在初始化期间或在卸载时在系统线程上下文中

  • 为固有同步操作(例如创建、刷新、关闭、关闭和设备控制请求)生成 IRP

但是,与 IoBuildSynchronousFsdRequest 相比,驱动程序更可能调用 IoBuildDeviceIoControlRequest 来分配设备控制 IRP。