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_PNPIRP_MJ_READIRP_MJ_WRITEIRP_MJ_FLUSH_BUFFERSIRP_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。 由于异步请求与上下文无关,因此不会跟踪其他上下文信息。

较低级别的驱动程序可能会对提供给此例程的参数施加限制。 例如,磁盘驱动程序可能要求为 LengthStartingOffset 提供的值是设备扇区大小的整数倍。

中间或最高级别驱动程序还可以调用 IoBuildDeviceIoControlRequestIoAllocateIrpIoBuildSynchronousFsdRequest 来设置它发送给较低级别驱动程序的请求。 只有最高级别的驱动程序才能调用 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。 下面的代码示例演示此情况的 MmUnlockPagesIoFreeMdlIoFreeIrp 调用:

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)

另请参阅

IO_STACK_LOCATION

IRP

IoAllocateIrp

IoBuildDeviceIoControlRequest

IoBuildSynchronousFsdRequest

IoCallDriver

IoFreeIrp

IoFreeMdl

IoMakeAssociatedIrp

IoSetCompletionRoutine

IoSetHardErrorOrVerifyDevice

MmUnlockPages

ObDereferenceObjectWithTag

ObReferenceObjectByPointerWithTag

PsGetCurrentThread