既不使用缓冲 I/O,也不使用直接 I/O

如果驱动程序既不使用缓冲 I/O,也未使用直接 I/O,则 I/O 管理器会将其发送到驱动程序的 IRP 中传递原始用户空间虚拟地址。 若要安全地访问这些缓冲区,驱动程序必须在调用线程的上下文中执行。 因此,通常只有最高级别驱动程序(如 FSD)才能使用此方法访问缓冲区。

中间或最低级别驱动程序不能始终满足此条件。 例如,如果请求线程等待 I/O 请求完成,或者较高级别的驱动程序在中间或最低级别的驱动程序上分层,则不太可能在请求线程的上下文中调用较低级别的驱动程序的例程。

I/O 管理器确定 I/O 操作既不使用缓冲 I/O,也不使用直接 I/O,如下所示:

当驱动程序收到指定 I/O 操作的 IRP 时,既不使用缓冲 I/O,也不使用直接 I/O,它必须执行以下操作:

  1. 使用 ProbeForReadProbeForWrite 支持例程检查用户缓冲区地址范围的有效性,检查是否允许适当的读取或写入访问。 驱动程序必须将其对缓冲区地址范围的访问包含在驱动程序提供的异常处理程序中,以便用户线程无法在驱动程序访问内存时更改缓冲区的访问权限。 如果探测引发异常,驱动程序应返回错误。 驱动程序必须在发出 I/O 请求的线程上下文中调用这些例程;因此,只有更高级别的驱动程序才能执行此任务。

  2. 通过以下方式之一管理缓冲区和内存操作:

    • 执行自己的双重缓冲操作,就像 I/O 管理器对使用缓冲 I/O 的驱动程序执行的操作一样。 有关详细信息,请参阅 使用缓冲 I/O
    • 创建自己的 MDL 并通过调用内存管理器的支持例程来锁定缓冲区,就像 I/O 管理器对使用直接 I/O 的驱动程序所做的那样。 有关详细信息,请参阅 使用直接 I/O
    • 直接在调用线程的上下文中对用户缓冲区执行所有必要的操作。 驱动程序必须在驱动程序提供的异常处理程序中包装其对缓冲区的访问,以防用户线程在驱动程序访问内存时更改缓冲区的访问权限或缓冲区中的数据。 有关详细信息,请参阅 处理异常

实际上,驱动程序必须基于每个 IRP 选择是在调用线程的上下文中执行缓冲 I/O、直接 I/O 还是 I/O,并且它必须处理用户模式线程上下文中可能发生的任何异常。 驱动程序必须根据需要管理自己的用户缓冲区访问、双重缓冲操作和内存映射,而不是让 I/O 管理器处理驱动程序的这些操作。