I/O 管理器为分层驱动程序链中的每个驱动程序提供其设置的每个 IRP 的 I/O 堆栈位置。 每个 I/O 堆栈位置都由 IO_STACK_LOCATION 结构组成。
I/O 管理器为每个 IRP 创建一个 I/O 堆栈位置数组,该数组元素对应于分层驱动程序链中的每个驱动程序。 每个驱动程序在数据包中拥有一个堆栈位置,并调用 IoGetCurrentIrpStackLocation 以获取有关 I/O 操作的特定于驱动程序的信息。
此类链中的每个驱动程序都负责调用 IoGetNextIrpStackLocation,然后设置下一个较低驱动程序的 I/O 堆栈位置。 任何更高级别驱动程序的 I/O 堆栈位置也可用于存储有关作的上下文,以便驱动程序的 IoCompletion 例程可以执行其清理作。
分层驱动程序中的处理 IRP 图显示了原始 IRP 中的两个 I/O 堆栈位置,因为它显示两个驱动程序、一个文件系统驱动程序和一个大容量存储设备驱动程序。 分层驱动程序图中处理 IRP 中由驱动程序分配的 IRP,并没有为创建它们的 FSD(文件系统驱动程序)提供堆栈位置。 根据下一个较低驱动程序的设备对象的 StackSize 值,为较低级别的驱动程序分配 IRP 的任何更高级别的驱动程序也会确定新 IRP 应具有多少 I/O 堆栈位置。
下图更详细地显示了 IRP 的内容。
如图所示,IRP 中的每个特定于驱动程序的 I/O 堆栈位置包含以下常规信息:
主要函数代码(IRP_MJ_XXX),指示驱动程序应执行的基本作
对于一些由 FSD、更高级别的 SCSI 驱动程序以及所有 PnP 驱动程序处理的主要功能代码,存在一个次级功能代码(IRP_MN_XXX),用于指明驱动程序应执行的基本操作的子案例。
一组特定于操作的参数,例如用于驱动程序传入或传出数据的缓冲区的长度和起始位置。
指向驱动程序创建的设备对象的指针,表示请求操作的目标(物理、逻辑或虚拟)设备
指向文件对象的指针,该对象表示已打开的文件、设备、目录或卷。
文件系统驱动程序通过其 I/O 堆栈位置在 IRP 中访问文件对象。 其他驱动程序通常忽略文件对象。
特定驱动程序处理的 IRP 的主要和次要功能代码集合可能因设备类型而异。 但是,最低级别的驱动程序和中间驱动程序(包括 PnP 函数和筛选器驱动程序)通常处理以下一组基本请求:
IRP_MJ_CREATE: 打开目标设备对象,指示它存在且可用于 I/O操作
IRP_MJ_READ — 从设备传输数据
IRP_MJ_WRITE - 将数据传输到设备
IRP_MJ_DEVICE_CONTROL - 根据系统定义的特定于设备的 I/O 控制代码(IOCTL)设置(或重置)设备
IRP_MJ_CLOSE — 关闭目标设备对象
IRP_MJ_PNP — 在设备上执行即插即用操作。 PnP 管理器通过 I/O 管理器发送 IRP_MJ_PNP 请求。
IRP_MJ_POWER — 对设备执行电源操作。 电源管理器通过 I/O 管理器发送 IRP_MJ_POWER 请求。
有关驱动程序需要处理的主要 IRP 函数代码的详细信息,请参阅 IRP 主要函数代码。
通常,I/O 管理器会将至少有两个 I/O 堆栈位置的 IRP 发送到大容量存储驱动程序,因为文件系统叠加在其他大容量存储驱动程序之上。 I/O 管理器将具有单个堆栈位置的 IRP 发送到没有其他驱动程序层在其上的任何驱动程序。
但是,I/O 管理器支持向系统中的任何现有驱动程序链添加新驱动程序。 例如,可以插入一个中间层 镜像驱动程序 来备份给定磁盘分区上的数据,该驱动程序介于在 分层驱动程序与 IRP 处理 图中所示的文件系统驱动程序和最低级别驱动程序之间。 当此新驱动程序将自身附加到设备堆栈时,I/O 管理器会调整它发送到文件系统、镜像和最低级别驱动程序的所有 IRP 中的 I/O 堆栈位置数。 文件系统在 分层驱动程序中处理 IRP 图中分配的每个 IRP 还将包含此类新镜像驱动程序的另一个 I/O 堆栈位置。
请注意,对向现有链添加新驱动程序的支持意味着对任何特定驱动程序访问 IRP 中 I/O 堆栈位置的某些限制:
分层驱动程序链中的更高级别驱动程序只能安全地访问其自己的和下一级驱动程序的 I/O 堆栈位置(在任何 IRP 中)。 此类驱动程序必须在 IRP 中为下一级驱动程序设置 I/O 堆栈位置。 但是,在设计此类更高级别的驱动程序时,无法预测何时(或是否)将新驱动程序添加到驱动程序正下方的现有链中。
因此,应假定任何后续添加的驱动程序都将处理与下一级别驱动程序所取代的下一级驱动程序相同的 IRP 主要函数代码(IRP_MJ_XXX)。
分层驱动程序链中的最低级别驱动程序只能在任何 IRP 中安全地访问自己的 I/O 堆栈位置。 设计此类驱动程序时,无法预测何时(或是否)将新驱动程序添加到设备驱动程序上方的现有链中。
在设计最低级别的驱动程序时,假设驱动程序可以使用在其自己的 I/O 堆栈位置传递的信息继续处理 IRP,无论给定 IRP 的发起源是什么,以及上面分层了多少个驱动程序。