I/O 堆栈位置
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 (文件系统驱动程序) 没有堆栈位置。 为较低级别的驱动程序分配 IRP 的任何较高级别的驱动程序也会根据下一个较低级别的驱动程序的设备对象的 StackSize 值确定新 I/O 堆栈位置的数量。
下图更详细地显示了 IRP 的内容。
如图所示,IRP 中每个特定于驱动程序的 I/O 堆栈位置包含以下常规信息:
主要函数代码 (IRP_MJ_XXX) ,指示驱动程序应执行的基本操作
对于由 FSD、更高级别的 SCSI 驱动程序和所有 PnP 驱动程序处理的某些主要函数代码, (IRP_MN_XXX) ,指示驱动程序应执行基本操作的子用例
一组特定于操作的参数,例如驱动程序将数据传输到的缓冲区的长度和起始位置
指向驱动程序创建的设备对象的指针,表示所请求操作 (物理、逻辑或虚拟) 设备的目标
指向文件对象的指针,表示打开的文件、设备、目录或卷
文件系统驱动程序通过 IRP 中的 I/O 堆栈位置访问文件对象。 其他驱动程序通常忽略文件对象。
特定驱动程序处理的 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 — 在设备上执行即插即用操作。 IRP_MJ_PNP请求由 PnP 管理器通过 I/O 管理器发送。
IRP_MJ_POWER - 在设备上执行电源操作。 IRP_MJ_POWER请求由电源管理器通过 I/O 管理器发送。
有关驱动程序需要处理的主要 IRP 函数代码的详细信息,请参阅 IRP 主要函数代码。
一般情况下,I/O 管理器将至少具有两个 I/O 堆栈位置的 IRP 发送到大容量存储设备驱动程序,因为文件系统分层于大容量存储设备的其他驱动程序上。 I/O 管理器将具有单个堆栈位置的 IRP 发送到上面没有其他驱动程序分层的任何驱动程序。
但是,I/O 管理器支持将新驱动程序添加到系统中的任何现有驱动程序链。 例如,备份给定磁盘分区上的数据的中间 镜像驱动程序 可能会在一对驱动程序之间插入,例如文件系统驱动程序和分层驱动程序中的 处理 IRP 图中显示的最低级别驱动程序。 当此新驱动程序自行附加到设备堆栈时,I/O 管理器会调整它发送到文件系统、镜像和最低级别驱动程序的所有 IRP 中的 I/O 堆栈位置数。 分配 的分层驱动程序中处理 IRP 中的文件系统的每个 IRP 也将包含此类新镜像驱动程序的另一个 I/O 堆栈位置。
请注意,这种对将新驱动程序添加到现有链的支持意味着对任何特定驱动程序对 I/O 堆栈位置在 IRP 中的访问存在某些限制:
分层驱动程序链中的较高级别驱动程序只能在任何 IRP 中安全地访问其自身和下一级别驱动程序的 I/O 堆栈位置。 此类驱动程序必须为 IRP 中的下一个较低级别驱动程序设置 I/O 堆栈位置。 但是,在设计此类更高级别的驱动程序时,无法预测何时 (或) 新驱动程序是否会添加到驱动程序正下方的现有链中。
因此,应假定任何后续添加的驱动程序都将处理与置换的下一低级别驱动程序相同的 IRP 主要函数代码 (IRP_MJ_XXX) 。
分层驱动程序链中的最低级别驱动程序只能安全访问任何 IRP 中自己的 I/O 堆栈位置。 设计此类驱动程序时,无法预测何时 (或) 新驱动程序是否会添加到设备驱动程序上方的现有链中。
在设计最低级别的驱动程序时,假设驱动程序可以使用其自己的 I/O 堆栈位置中传递的信息继续处理 IRP,无论给定 IRP 的起源源如何,也不管其上方有多少驱动程序。