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 状态块地址的指针,其中要调用的驱动程序返回有关所请求操作的最终状态。
返回值
IoBuildAsynchronousFsdRequest 返回指向 IRP 的指针;如果无法分配 IRP,则返回 NULL 指针。
注解
中间或最高级别驱动程序可以调用 IoBuildAsynchronousFsdRequest ,为发送到较低级别驱动程序的请求设置 IRP。 调用驱动程序必须为 IRP 提供 IoCompletion 例程,以便可以使用 IoFreeIrp 解除分配 IRP。 有关 IRP 解除分配的详细信息,请参阅示例。
生成的 IRP 仅包含足够的信息来启动操作和完成 IRP。 由于异步请求与上下文无关,因此不会跟踪其他上下文信息。
较低级别的驱动程序可能会对提供给此例程的参数施加限制。 例如,磁盘驱动程序可能要求为 Length 和 StartingOffset 提供的值是设备扇区大小的整数倍。
中间或最高级别驱动程序还可以调用 IoBuildDeviceIoControlRequest、 IoAllocateIrp 或 IoBuildSynchronousFsdRequest 来设置它发送给较低级别驱动程序的请求。 只有最高级别的驱动程序才能调用 IoMakeAssociatedIrp。
在 IoBuildAsynchronousFsdRequest 调用期间,I/O 管理器将 IRP 结构的 Tail.Overlay.Thread 成员设置为指向调用方线程对象,但不代表调用方对线程对象的计数引用。 调用方将 IRP 发送到目标设备的驱动程序后,此驱动程序可能会使用 Tail.Overlay.Thread 成员访问线程对象。 例如,存储驱动程序可能会调用 IoSetHardErrorOrVerifyDevice 例程,并提供指向 IRP 的指针作为输入参数。 在此调用期间, IoSetHardErrorOrVerifyDevice 使用 Tail.Overlay.Thread 成员访问线程对象。 以这种方式访问线程对象时,调用 IoBuildAsynchronousFsdRequest 来分配 IRP 的驱动程序负责确保在处理 IRP 时线程对象保持有效。
若要使线程对象保持有效,调用 IoBuildAsynchronousFsdRequest 的 驱动程序可以在发送 IRP 之前对线程对象进行计数引用。 例如,此驱动程序可以调用 ObReferenceObjectByPointerWithTag 例程,并提供来自 IRP 结构的 Tail.Overlay.Thread 成员的对象指针作为 Object 参数。 稍后,此驱动程序的完成例程可以通过调用 ObDereferenceObjectWithTag 等例程来取消引用对象。
驱动程序可能会在一个线程中调用 IoBuildAsynchronousFsdRequest ,并在另一个线程中发送此调用分配的 IRP。 在发送 IRP 之前,此驱动程序应将 IRP 的 Tail.Overlay.Thread 成员设置为指向发送线程的线程对象。 通常,驱动程序调用 PsGetCurrentThread 例程来获取线程对象指针。
调用 IoBuildAsynchronousFsdRequest 来分配 IRP 的驱动程序不一定需要对 IRP 的 Tail.Overlay.Thread 成员指向的线程对象进行计数引用。 驱动程序可能会改用另一种方法来保证此线程对象在处理 IRP 时保持有效。 例如,如果驱动程序创建了线程,则线程可以等待 IRP 完成以终止自身。
示例
在调用 IoFreeIrp 之前,如果满足以下所有条件,则需要执行额外的步骤来释放 由 IoBuildAsynchronousFsdRequest 生成的 IRP 的缓冲区:
缓冲区是从系统内存池分配的。
在目标设备的设备对象中,DO_DIRECT_IO标志在 DeviceObject-Flags> 字段中设置。
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) |
Library | NtosKrnl.lib |
DLL | NtosKrnl.exe |
IRQL | IRQL <= APC_LEVEL |
DDI 符合性规则 | ForwardedAtBadIrqlFsdAsync (wdm) 、 HwStorPortProhibitedDDI (storport) 、 IoBuildFsdComplete (wdm) 、 IoBuildFsdForward (wdm) 、 IoBuildFsdFree (wdm) |