IoBuildAsynchronousFsdRequest 函数 (wdm.h)
IoBuildAsynchronousFsdRequest 例程分配并设置要发送到较低级别的驱动程序的 IRP。
语法
__drv_aliasesMem PIRP IoBuildAsynchronousFsdRequest(
[in] ULONG MajorFunction,
[in] PDEVICE_OBJECT DeviceObject,
[in, out] PVOID Buffer,
[in, optional] ULONG Length,
[in, optional] PLARGE_INTEGER StartingOffset,
[in, optional] PIO_STATUS_BLOCK IoStatusBlock
);
参数
[in] MajorFunction
在 IRP 中设置的主要函数代码。 此代码可以是 IRP_MJ_PNP、IRP_MJ_READ、IRP_MJ_WRITE、IRP_MJ_FLUSH_BUFFERS或 IRP_MJ_SHUTDOWN。
[in] DeviceObject
指向下一个较低驱动程序的设备对象的指针。 此对象表示读取、写入、刷新或关闭作的目标设备。
[in, out] Buffer
指向从中读取数据或从中写入数据的缓冲区的指针。 此参数的值 NULL 刷新和关闭请求。
[in, optional] Length
Buffer指向的缓冲区的长度(以字节为单位)。 对于磁盘等设备,此值必须是扇区大小的整数倍数。 从 Windows 8 开始,扇区大小可以为 4,096 或 512 字节。 在早期版本的 Windows 中,扇区大小始终为 512 字节。 读取和写入请求需要此参数,但刷新和关闭请求必须为零。
[in, optional] StartingOffset
指向输入/输出媒体上起始偏移量的指针。 对于刷新和关闭请求,此参数的值为零。
[in, optional] IoStatusBlock
指向 I/O 状态块地址的指针,其中 to-be调用的驱动程序返回有关请求的作的最终状态。
返回值
IoBuildAsynchronousFsdRequest 返回指向 IRP 的指针;如果无法分配 IRP,则返回 NULL 指针。
言论
中间或最高级别驱动程序可以调用 IoBuildAsynchronousFsdRequest 为发送到较低级别的驱动程序的请求设置 IRP。 调用驱动程序必须为 IRP 提供 IoCompletion 例程,以便可以解除分配 IoFreeIrp。 有关 IRP 解除分配的详细信息,请参阅示例。
生成的 IRP 仅包含足够的信息来启动作并完成 IRP。 不会跟踪其他上下文信息,因为异步请求与上下文无关。
较低级别的驱动程序可能会对提供给此例程的参数施加限制。 例如,磁盘驱动程序可能需要为 长度 提供的值,StartingOffset 为设备的扇区大小的整数倍数。
中间或最高级别驱动程序还可以调用 IoBuildDeviceIoControlRequest、IoAllocateIrp或 IoBuildSynchronousFsdRequest 来设置发送到较低级别的驱动程序的请求。 只有最高级别的驱动程序才能调用 IoMakeAssociatedIrp。
在 IoBuildAsynchronousFsdRequest 调用期间,I/O 管理器将 Tail.Overlay.Thread 成员设置为指向调用方线程对象,但不会代表调用方对线程对象进行计数引用。 调用方将 IRP 发送到目标设备的驱动程序后,此驱动程序可能会使用 Tail.Overlay.Thread 成员访问线程对象。 例如,存储驱动程序可能会调用 IoSetHardErrorOrVerifyDevice 例程,并提供指向 IRP 的指针作为输入参数。 在此调用期间,IoSetHardErrorOrVerifyDevice 使用 Tail.Overlay.Thread 成员访问线程对象。 以这种方式访问线程对象时,调用 IoBuildAsynchronousFsdRequest 的驱动程序 分配 IRP 负责确保处理 IRP 时线程对象保持有效。
若要使线程对象保持有效,调用 IoBuildAsynchronousFsdRequest 的驱动程序 可以在发送 IRP 之前对线程对象执行计数引用。 例如,此驱动程序可以调用 ObReferenceObjectByPointerWithTag 例程并提供对象,作为 对象 参数,该对象指针来自 IRP 结构的 Tail.Overlay.Thread 成员。 稍后,此驱动程序的完成例程可以通过调用 ObDereferenceObjectWithTag等例程来取消引用对象。
驱动程序可以在一个线程中调用 IoBuildAsynchronousFsdRequest,并将此调用分配的 IRP 发送到另一个线程。 在发送 IRP 之前,此驱动程序应将 IRP Tail.Overlay.Thread 成员设置为指向发送线程的线程对象。 通常,驱动程序调用 PsGetCurrentThread 例程来获取线程对象指针。
调用 IoBuildAsynchronousFsdRequest 来分配 IRP 的驱动程序不一定需要在 Tail.Overlay.Thread 成员指向的线程对象上获取计数引用。 驱动程序可能会改用另一种方法来保证此线程对象在处理 IRP 时保持有效。 例如,如果驱动程序创建了线程,线程可以等待 IRP 完成以终止自身。
例子
在调用 IoFreeIrp之前,需要执行额外的步骤来释放由 IoBuildAsynchronousFsdRequest 生成的 IRP 的缓冲区(如果满足以下条件):
缓冲区是从系统内存池分配的。
在目标设备的设备对象中,DO_DIRECT_IO标志在 DeviceObject->标志 字段中设置。
Irp->MdlAddress 字段为非 NULL。
释放此 IRP 的缓冲区之前,请使用 Irp->MdlAddress 作为参数值调用 MmUnlockPages 例程。 此调用会减少 IoBuildAsynchronousFsdRequest 添加到 MDL 中的池页的额外引用计数。 否则,后续调用 IoFreeMdl 将进行 bug 检查,因为这些池页的引用计数将为 2,而不是 1。 以下代码示例演示 mmUnlockPages、IoFreeMdl,以及 IoFreeIrp 此情况的调用:
if (((DeviceObject->Flags & DO_DIRECT_IO) == DO_DIRECT_IO) &&
(Irp->MdlAddress != NULL))
{
MmUnlockPages(Irp->MdlAddress);
}
IoFreeMdl(Irp->MdlAddress);
IoFreeIrp(Irp);
要求
要求 | 价值 |
---|---|
目标平台 | 普遍 |
标头 | wdm.h (包括 Wdm.h、Ntddk.h、Ntifs.h) |
库 | NtosKrnl.lib |
DLL | NtosKrnl.exe |
IRQL | IRQL <= APC_LEVEL |
DDI 符合性规则 | ForwardedAtBadIrqlFsdAsync(wdm),HwStorPortProhibitedDDIs(storport),IoBuildFsdComplete(wdm),IoBuildFsdForward(wdm),IoBuildFsdFree(wdm) |