location) 在固定部分(或头)中,I/0管理器维护与原始请求有关的信息,例如调用者的线程 ID和参数,还有在其上被打开文件的设备对象的地址,等等。固定部分也包含一个 I/0状态块,驱动程序在其中设置请求的I/0操作的状态信息。 在最高层驱动程序的Ⅰ/0栈位置中,I/0管理器、即插即用管理器、或电源管理器设 置驱动程序特定的参数,例如由相应驱动程序请求的特定操作(描述成一个函数代 码)和它使用的环境,以确定的它将要做些什么。如果需要的话,按照顺序,每一个 较高层的驱动程序创建相邻的较低层驱动程序的I/0栈位置 因为给定的IRP通过每个驱动程序的标准例程集被处理,每一个标准例程能在IRP中访问 那个驱动程序的I/0栈位置,从而在驱动程序操作的每个阶段重用IRP。另外,更高层的 驱动程序能创建(或重用)IRP以发送请求到低层的驱动程序 参见第2章,“分层的1/0、IRP、和1/0对象”可以得到IRP通过分层的驱动程序的处理 过程的介绍。如果希望得到关于IRP设备类型特定的信息,参看《 Windows2000驱动程序 开发参考》的卷2:对于PnP和电源管理IRP,参看《即插即用、电源管理和安装设计指 南》和《 Windows2000驱动程序开发参考》的卷1。 1.3.7支持异步I/0 Ⅰ/0管理器提供异步Ⅰ/0支持,从而使得I/0请求的发出者(通常是用户模式应用程序, 但有些时候是另一个驱动程序)可以继续执行,而不用等待它的I/0请求完成。提供异步 Ⅰ/0支持提高了系统整体的吞吐量,同样也提高了任何作出Ⅰ/0请求的代码的性能。 结果之一是,内核模式驱动程序不必按照Ⅰ/0请求被送往I/0管理器的顺序来处理它们。 Ⅰ/管理器或更高层驱动程序能依据Ⅰ/0请求被接受的顺序重新编程它们,或者能将一个 大的数据传输请求拆分成几个较小的传输请求。此外,驱动程序能重叠I/0请求处理,特 别是在对称多处理器平台中,就像1.3.4,“多处理器安全”一节中提到的那样。 还有,对内核模式驱动程序的单独1/0请求的处理不必要序列化。这就是说,在驱动程序 开始处理下一个进来的I/0请求之前,它不必处理完每个IRP,就像在单处理器机器中, 驱动程序在被写成支持同步I/0的单任务操作系统所作的那样。 IRP被传递给驱动程序的标准例程,通过完成任何例程指定的操作以最终满足当前请求 驱动程序响应当前的IRP。当然,最低层的驱动程序被要求帮助I/0管理器和任何高层的 驱动程序处理同样的IRP,并通过设置IRP中的I/0状态块来跟踪每个请求的状态 驱动程序也能在其设备对象的特定部分维护当前I/0操作的信息,这个部分被称为设备扩 展 若想得到IRP处理和设备对象如何表示驱动程序的物理和逻辑设备的概述,可以参看第2 章“分层的I/0、IRP和I/0对象”。关于设备对象和设备扩展更详细的信息,参见第 章,“针对驱动程序系统定义的对象和支持”。 11
11 location): ▪ 在固定部分(或头)中,I/O 管理器维护与原始请求有关的信息,例如调用者的线程 ID 和参数,还有在其上被打开文件的设备对象的地址,等等。固定部分也包含一个 I/O 状态块,驱动程序在其中设置请求的 I/O 操作的状态信息。 ▪ 在最高层驱动程序的 I/O 栈位置中,I/O 管理器、即插即用管理器、或电源管理器设 置驱动程序特定的参数,例如由相应驱动程序请求的特定操作(描述成一个函数代 码)和它使用的环境,以确定的它将要做些什么。如果需要的话,按照顺序,每一个 较高层的驱动程序创建相邻的较低层驱动程序的 I/O 栈位置。 因为给定的 IRP 通过每个驱动程序的标准例程集被处理,每一个标准例程能在 IRP 中访问 那个驱动程序的 I/O 栈位置,从而在驱动程序操作的每个阶段重用 IRP。另外,更高层的 驱动程序能创建(或重用)IRP 以发送请求到低层的驱动程序。 参见第 2 章,“分层的 I/O、IRP、和 I/O 对象”可以得到 IRP 通过分层的驱动程序的处理 过程的介绍。如果希望得到关于 IRP 设备类型特定的信息,参看《Windows 2000 驱动程序 开发参考》的卷 2;对于 PnP 和电源管理 IRP,参看《即插即用、电源管理和安装设计指 南》和《Windows 2000 驱动程序开发参考》的卷 1。 1.3.7 支持异步 I/O I/O 管理器提供异步 I/O 支持,从而使得 I/O 请求的发出者(通常是用户模式应用程序, 但有些时候是另一个驱动程序)可以继续执行,而不用等待它的 I/O 请求完成。提供异步 I/O 支持提高了系统整体的吞吐量,同样也提高了任何作出 I/O 请求的代码的性能。 结果之一是,内核模式驱动程序不必按照 I/O 请求被送往 I/O 管理器的顺序来处理它们。 I/O 管理器或更高层驱动程序能依据 I/O 请求被接受的顺序重新编程它们,或者能将一个 大的数据传输请求拆分成几个较小的传输请求。此外,驱动程序能重叠 I/O 请求处理,特 别是在对称多处理器平台中,就像 1.3.4,“多处理器安全”一节中提到的那样。 还有,对内核模式驱动程序的单独 I/O 请求的处理不必要序列化。这就是说,在驱动程序 开始处理下一个进来的 I/O 请求之前,它不必处理完每个 IRP,就像在单处理器机器中, 驱动程序在被写成支持同步 I/O 的单任务操作系统所作的那样。 IRP 被传递给驱动程序的标准例程,通过完成任何例程指定的操作以最终满足当前请求, 驱动程序响应当前的 IRP。当然,最低层的驱动程序被要求帮助 I/O 管理器和任何高层的 驱动程序处理同样的 IRP,并通过设置 IRP 中的 I/O 状态块来跟踪每个请求的状态。 驱动程序也能在其设备对象的特定部分维护当前 I/O 操作的信息,这个部分被称为设备扩 展。 若想得到 IRP 处理和设备对象如何表示驱动程序的物理和逻辑设备的概述,可以参看第 2 章“分层的 I/O、IRP 和 I/O 对象”。关于设备对象和设备扩展更详细的信息,参见第 3 章,“针对驱动程序系统定义的对象和支持
第2章分层的I/0、IRP和I/0对象 本章介绍 Microsoft windows2000的I/0模型,内容包括:内核模式驱动程序如何适合系 统,驱动程序如何处理IRP,系统定义的标准驱动程序例程,通用设备配置和相应的分层 驱动程序,以及描述设备和驱动程序的对象 本章的组织如下: 2.1 Windows20001/0模型概述 2.2终端用户I/0请求和 Windows2000文件对象 2.2.1用户I/0请求的注意事项 2.3IRP和驱动程序特定I/0栈位置 2.3.1处理IRP的注意事项 2.4驱动程序对象和标准驱动程序例程 2.4.1对象不透明性 2.4.2标准驱动程序对象入口点 2.4.3其他的标准驱动程序例程 2.4.4标准驱动程序例程的注意事项 2.5设备配置和分层驱动程序 2.5.1简单设备和驱动程序配置 2.5.2添加驱动程序的注意事项 2.6设备对象和分层的驱动程序 2.6.1针对简单配置的设备对象 2.6.2设备对象的注意事项 注意除了第一节,每节都包含了一个“注意事项”列表。这些小节总结对驱动程序的基本 要求和限制,就像本节从整体上介绍一样 21 Windows2000o模型概述 每一个操作系统都有一个隐含的或明确的I/0模型,以处理与外围设备之间的数据流。 Microsoft Windows2000I/o模型的最大不同之处是它支持异步I/0,就如第1章中描述 的那样。另外,I/0模型有下列特性: I/0管理器提供一致的接口给所有的内核模式驱动程序,包括最低层、中间层和文件 驱动程序。所有的对驱动程序的1/0请求被作为I/O请求包(IRP)发送 I/0操作是分层的。I/0管理器输出I/0系统服务,用户模式保护子系统代表它们的应 用程序和/或终端用户,调用它们完成I/0操作。I/0管理器解释这些调用,创建一个 或多个IRP,并且通过可能的分层驱动程序发送它们到物理设备。 I/0管理器定义一组驱动程序支持的标准例程,一些是必需的,一些是可选的。所有 的驱动程序遵从一个相对一致的实现模型,允许外围设备之间的差别,并且总线、功 能、过滤器和文件系统驱动程序被要求的不同功能。 就如操作系统本身,驱动程序是基于对象的。驱动程序、它们的设备和系统硬件被表 示为对象。Ⅰ/0管理器和其他操作系统组件输出内核模式支持例程,驱动程序通过操 纵合适的对象调用这些例程来完成工作 除了使用IRP传送传统的I/0请求之外,I0管理器与PnP和电源管理器一起工作发送包
12 第2章 分层的 I/O、IRP 和 I/O 对象 本章介绍 Microsoft Windows 2000 的 I/O 模型,内容包括:内核模式驱动程序如何适合系 统,驱动程序如何处理 IRP,系统定义的标准驱动程序例程,通用设备配置和相应的分层 驱动程序,以及描述设备和驱动程序的对象。 本章的组织如下: 2.1 Windows 2000 I/O 模型概述 2.2 终端用户 I/O 请求和 Windows 2000 文件对象 2.2.1 用户 I/O 请求的注意事项 2.3 IRP 和驱动程序特定 I/O 栈位置 2.3.1 处理 IRP 的注意事项 2.4 驱动程序对象和标准驱动程序例程 2.4.1 对象不透明性 2.4.2 标准驱动程序对象入口点 2.4.3 其他的标准驱动程序例程 2.4.4 标准驱动程序例程的注意事项 2.5 设备配置和分层驱动程序 2.5.1 简单设备和驱动程序配置 2.5.2 添加驱动程序的注意事项 2.6 设备对象和分层的驱动程序 2.6.1 针对简单配置的设备对象 2.6.2 设备对象的注意事项 注意除了第一节,每节都包含了一个“注意事项”列表。这些小节总结对驱动程序的基本 要求和限制,就像本节从整体上介绍一样。 2.1 Windows 2000 I/O 模型概述 每一个操作系统都有一个隐含的或明确的 I/O 模型,以处理与外围设备之间的数据流。 Microsoft Windows 2000 I/O 模型的最大不同之处是它支持异步 I/O,就如第 1 章中描述 的那样。另外,I/O 模型有下列特性: ▪ I/O 管理器提供一致的接口给所有的内核模式驱动程序,包括最低层、中间层和文件 驱动程序。所有的对驱动程序的 I/O 请求被作为 I/O 请求包(IRP)发送。 ▪ I/O 操作是分层的。I/O 管理器输出 I/O 系统服务,用户模式保护子系统代表它们的应 用程序和/或终端用户,调用它们完成 I/O 操作。I/O 管理器解释这些调用,创建一个 或多个 IRP,并且通过可能的分层驱动程序发送它们到物理设备。 ▪ I/O 管理器定义一组驱动程序支持的标准例程,一些是必需的,一些是可选的。所有 的驱动程序遵从一个相对一致的实现模型,允许外围设备之间的差别,并且总线、功 能、过滤器和文件系统驱动程序被要求的不同功能。 ▪ 就如操作系统本身,驱动程序是基于对象的。驱动程序、它们的设备和系统硬件被表 示为对象。I/O 管理器和其他操作系统组件输出内核模式支持例程,驱动程序通过操 纵合适的对象调用这些例程来完成工作。 除了使用 IRP 传送传统的 I/O 请求之外,I/O 管理器与 PnP 和电源管理器一起工作发送包
含PnP和电源管理请求的IRP。如果希望了解驱动程序是如何操纵这些ⅠRP的,可参看 《安装、即插即用和电源管理设计指南》。 22终端用户l/o请求和 Windows2000文件对象 内核模式驱动程序被 Microsoft Windows2000保护子系统向终端用户隐藏,这个子系统实 现一个已经很友善的编程接口,例如 Windows或 POSIX。设备对用户模式代码是可见的 它包括保护子系统,仅仅作为命名的文件对象被I/0管理器控制。 图2.1说明了终端用户和I/0管理器之间的这种关系。 图2.1代表文件、卷和设备的文件对象 Windows2000保护子系统,例如Win32子系统,通过I/0系统服务传送I/0请求到合适的 内核模式驱动程序。图2.1中显示的子系统依赖于显示、视频适配器、键盘和鼠标设备驱 动程序的支持。 保护子系统隔离它的终端用户和应用程序,使得它们不必知道关于内核模式组件(包括驱 动程序)的任何细节。同样,I/0管理器隔离保护子系统,使得它们不必知道关于机器特 定的设备配置或驱动程序实现的任何细节 I/0管理器的分层方法也使得大多数驱动程序不必知道任何下列的细节: 是否一个I/0请求在任何特定的保护子系统中被生成,如Win32或 POSIX 是否一个给定的保护子系统拥有特定种类的用户模式驱动程序 什么是保护子系统的I/0模型和什么是对驱动程序的接口 Ⅰ/O管理器提供给驱动程序一个单独的I/O模型、一组驱动程序能用来完成I/0操作的内 核模式支持例程,和I/0请求发出者与响应这个请求的驱动程序之间的一个一致接口 如图2.1所示,子系统和它的本地应用程序仅仅通过I/0管理器提供的文件对象句柄,能 访问驱动程序设备或海量存储设备上的文件。为了打开这样一个文件对象或获得一个句柄 以实现与设备或数据文件的I/0,文件子系统使用一个请求调用I/0系统服务以打开一个 命名的文件。这个命名的文件可以拥有一个子系统指定的别名(符号连接),以将文件对 象联系到内核模式名字。 Ⅰ/0管理器,输出这些系统服务,负责寻找或创建文件对象,这个文件对象用来描述设备 或数据文件;I/0管理器还要寻找合适的驱动程序。图2.2描述了当子系统代表应用程序 打开描述数据文件的文件对象时发生的事情 1.子系统调用一个I/0系统服务以打开一个命名文件。 2.I/0管理器调用对象管理器以寻找命名的文件,并帮助它决定到文件对象的符号连接 它也调用安全引用监视器以检查子系统是否拥有正确的权限打开那个文件对象。 3.如果卷还没有被安装( mount),I/0管理器暂停打开请求,并且调用一个或多个 Windows2000文件系统,直到它们中间之一认可这个文件对象存储在文件系统使用的 海量存储设备之一上面。当文件系统已经安装了卷,I/0管理器继续处理这个请求 4.I/0管理器为这个打开请求分配内存并初始化一个IRP。对于驱动程序来说,打开等同 于一个“创建”请求 5.I/0管理器调用文件系统驱动程序,传递它给IRP。文件系统驱动程序访问它的在IRP 中的I/0栈位置,以确定什么操作必须被完成、检查参数、确定是否请求的文件在缓存 中,并且如果没有的话,在IRP中设置相邻的较低层的驱动程序的I/O栈位置
13 含 PnP 和电源管理请求的 IRP。如果希望了解驱动程序是如何操纵这些 IRP 的,可参看 《安装、即插即用和电源管理设计指南》。 2.2 终端用户 I/O 请求和 Windows 2000 文件对象 内核模式驱动程序被 Microsoft Windows 2000 保护子系统向终端用户隐藏,这个子系统实 现一个已经很友善的编程接口,例如 Windows 或 POSIX。设备对用户模式代码是可见的, 它包括保护子系统,仅仅作为命名的文件对象被 I/O 管理器控制。 图 2.1 说明了终端用户和 I/O 管理器之间的这种关系。 图 2.1 代表文件、卷和设备的文件对象 Windows 2000 保护子系统,例如 Win32 子系统,通过 I/O 系统服务传送 I/O 请求到合适的 内核模式驱动程序。图 2.1 中显示的子系统依赖于显示、视频适配器、键盘和鼠标设备驱 动程序的支持。 保护子系统隔离它的终端用户和应用程序,使得它们不必知道关于内核模式组件(包括驱 动程序)的任何细节。同样,I/O 管理器隔离保护子系统,使得它们不必知道关于机器特 定的设备配置或驱动程序实现的任何细节。 I/O 管理器的分层方法也使得大多数驱动程序不必知道任何下列的细节: ▪ 是否一个 I/O 请求在任何特定的保护子系统中被生成,如 Win32 或 POSIX ▪ 是否一个给定的保护子系统拥有特定种类的用户模式驱动程序 ▪ 什么是保护子系统的 I/O 模型和什么是对驱动程序的接口 I/O 管理器提供给驱动程序一个单独的 I/O 模型、一组驱动程序能用来完成 I/O 操作的内 核模式支持例程,和 I/O 请求发出者与响应这个请求的驱动程序之间的一个一致接口。 如图 2.1 所示,子系统和它的本地应用程序仅仅通过 I/O 管理器提供的文件对象句柄,能 访问驱动程序设备或海量存储设备上的文件。为了打开这样一个文件对象或获得一个句柄 以实现与设备或数据文件的 I/O,文件子系统使用一个请求调用 I/O 系统服务以打开一个 命名的文件。这个命名的文件可以拥有一个子系统指定的别名(符号连接),以将文件对 象联系到内核模式名字。 I/O 管理器,输出这些系统服务,负责寻找或创建文件对象,这个文件对象用来描述设备 或数据文件;I/O 管理器还要寻找合适的驱动程序。图 2.2 描述了当子系统代表应用程序 打开描述数据文件的文件对象时发生的事情。 1. 子系统调用一个 I/O 系统服务以打开一个命名文件。 2. I/O 管理器调用对象管理器以寻找命名的文件,并帮助它决定到文件对象的符号连接。 它也调用安全引用监视器以检查子系统是否拥有正确的权限打开那个文件对象。 3. 如果卷还没有被安装(mount),I/O 管理器暂停打开请求,并且调用一个或多个 Windows 2000 文件系统,直到它们中间之一认可这个文件对象存储在文件系统使用的 海量存储设备之一上面。当文件系统已经安装了卷,I/O 管理器继续处理这个请求。 4. I/O 管理器为这个打开请求分配内存并初始化一个 IRP。对于驱动程序来说,打开等同 于一个“创建”请求。 5. I/O 管理器调用文件系统驱动程序,传递它给 IRP。文件系统驱动程序访问它的在 IRP 中的 I/O 栈位置,以确定什么操作必须被完成、检查参数、确定是否请求的文件在缓存 中,并且如果没有的话,在 IRP 中设置相邻的较低层的驱动程序的 I/O 栈位置
6.驱动程序处理IRP,并完成请求的I/0操作,调用I/0管理器和其他系统组件(图2.2 种没有显示)提供的内核模式支持例程 7.驱动程序将IRP连同I/0状态块集返回到I/0管理器,以指明请求的操作是成功被执行 了,还是失败了。 8.I/o管理器从IRP获得I/0状态,所以它能通过保护子系统返回状态信息到原始调用 9.I/0管理器释放完成的IRP 如果打开操作成功,I/0管理器返回文件对象的句柄到子系统。如果出现错误,它 返回合适的状态到子系统 子系统成功打开一个描述数据文件、设备或卷的文件对象后,它使用返回的句柄为设备 Ⅰ/O操作(通常是读、写、或设备I/0控制请求)在后续的请求中指明文件对象。为了创 建这样的请求,子系统调用I/0系统设备。I/0管理器将这些请求作为IRP,发送它们到合 适的驱动程序。 2.2.1用户I/0请求的注意事项 当设计一个内核模式的驱动程序时,切记以下几点 驱动程序可以被分层,并且多个驱动程序能处理单独的I/0请求(IRP)。 驱动程序不能做任何有关其他驱动程序将会在设备栈位置中的假设。因此,每个驱动 程序应该被准备用于接收来自任何其他驱动程序的请求,并能处理所有潜在的错误 驱动程序在IRP的I/0状态块中获得请求的I/O操作成功或失败的消息。I/0管理器 将请求的I/0操作成功或失败的消息发送给用户模式的请求者。 驱动程序不必,也不应该被设计成能提供应用程序特定的支持。保护子系统或它的子 系统特定的用户模式驱动程序提供这种支持。对这条规则有一个例外:依赖于一个应 用专用设备的MS-D0S应用程序能请求 Windows2000驱动程序以控制这个设备,还能 请求一个紧密结合的Wind32用户模式的虚拟设备驱动程序(VDD)。有关VDD的详细 信息参看在线DDK中的“ Virtual device drivers”(虚拟设备驱动程序)文档 23IRP和驱动程序指定的WO栈位置 图2.2带有两个I/0栈位置的IRP,但实际上一个IRP可以拥有任意多个I/0栈位置,这 依赖于有多少分层的驱动程序处理给定的请求。 图2.3在分层的驱动程序中处理IRP 图2.3更详细的说明了图2.2中的驱动程序是怎样使用I/0支持例程(IoXx)为一个读/ 写请求处理IRP 1.I/O管理器用一个IRP调用文件系统驱动程序(FSD),这个IRP是为子系统读/写请求 分配的。FSD访问IRP中它的I/0栈位置,以决定它完成什么操作。 2.FSD能将原始请求分成更小的请求(可能是针对几个设备驱动程序),这项工作是通过 调用一个I/0支持例程( loAllocateIrp)一次或多次以分配额外的IRP。这些额外的 IRP连同为更低层驱动程序创建的I/⑩0栈位置(被填充为全零)被返回给FSD。由它随 意决定,FSD能在原始IRP中安装相邻的较低层驱动程序的I/0栈位置,并传递它给更 14
14 6. 驱动程序处理 IRP,并完成请求的 I/O 操作,调用 I/O 管理器和其他系统组件(图 2.2 种没有显示)提供的内核模式支持例程。 7. 驱动程序将 IRP 连同 I/O 状态块集返回到 I/O 管理器,以指明请求的操作是成功被执行 了,还是失败了。 8. I/O 管理器从 IRP 获得 I/O 状态,所以它能通过保护子系统返回状态信息到原始调用 者。 9. I/O 管理器释放完成的 IRP。 10. 如果打开操作成功,I/O 管理器返回文件对象的句柄到子系统。如果出现错误,它 返回合适的状态到子系统。 子系统成功打开一个描述数据文件、设备或卷的文件对象后,它使用返回的句柄为设备 I/O 操作(通常是读、写、或设备 I/O 控制请求)在后续的请求中指明文件对象。为了创 建这样的请求,子系统调用 I/O 系统设备。I/O 管理器将这些请求作为 IRP,发送它们到合 适的驱动程序。 2.2.1 用户 I/O 请求的注意事项 当设计一个内核模式的驱动程序时,切记以下几点: ▪ 驱动程序可以被分层,并且多个驱动程序能处理单独的 I/O 请求(IRP)。 ▪ 驱动程序不能做任何有关其他驱动程序将会在设备栈位置中的假设。因此,每个驱动 程序应该被准备用于接收来自任何其他驱动程序的请求,并能处理所有潜在的错误。 ▪ 驱动程序在 IRP 的 I/O 状态块中获得请求的 I/O 操作成功或失败的消息。I/O 管理器 将请求的 I/O 操作成功或失败的消息发送给用户模式的请求者。 ▪ 驱动程序不必,也不应该被设计成能提供应用程序特定的支持。保护子系统或它的子 系统特定的用户模式驱动程序提供这种支持。对这条规则有一个例外:依赖于一个应 用专用设备的 MS-DOS 应用程序能请求 Windows 2000 驱动程序以控制这个设备,还能 请求一个紧密结合的 Wind32 用户模式的虚拟设备驱动程序(VDD)。有关 VDD 的详细 信息参看在线 DDK 中的“Virtual Device Drivers”(虚拟设备驱动程序)文档。 2.3 IRP 和驱动程序指定的 I/O 栈位置 图 2.2 带有两个 I/O 栈位置的 IRP,但实际上一个 IRP 可以拥有任意多个 I/O 栈位置,这 依赖于有多少分层的驱动程序处理给定的请求。 图 2.3 在分层的驱动程序中处理 IRP 图 2.3 更详细的说明了图 2.2 中的驱动程序是怎样使用 I/O 支持例程(IoXxx)为一个读/ 写请求处理 IRP。 1. I/O 管理器用一个 IRP 调用文件系统驱动程序(FSD),这个 IRP 是为子系统读/写请求 分配的。FSD 访问 IRP 中它的 I/O 栈位置,以决定它完成什么操作。 2. FSD 能将原始请求分成更小的请求(可能是针对几个设备驱动程序),这项工作是通过 调用一个 I/O 支持例程(IoAllocateIrp)一次或多次以分配额外的 IRP。这些额外的 IRP 连同为更低层驱动程序创建的 I/O 栈位置(被填充为全零)被返回给 FSD。由它随 意决定,FSD 能在原始 IRP 中安装相邻的较低层驱动程序的 I/O 栈位置,并传递它给更
低层的驱动程序,通过这种方法FSD能重用原来的IRP,而不是象图2.3种所示的那样 分配额外的IRP。 3.对于每个驱动程序分配的IRP,图2.3中的FSD调用一个I/0支持例程以注册一个FSD 支持的完成例程。在这个完成例程中,FSD能确定低层驱动程序是否满足请求,并能在 低层驱动程序完成任务后释放每个驱动程序分配的IRP。不论每个驱动程序分配的IRP 是被成功完成,还是返回一个错误状态,或者是被放弃,I/0管理器都将调用FSD支持 的完成例程。更高层驱动程序负责释放IRP,这个IRP是它根据自己的需求为较低层驱 动程序分配并安装的。I/0管理器在所有驱动程序完成任务后释放它分配的IRP。 下一步,FSD调用一个I/0支持例程( IoGetIrpStackLocation)访问相邻的较低层的驱 动程序的I/0栈位置,从而为临近低层驱动程序设置请求。(图2.3种,相邻的较低层 驱动程序碰巧是最低层的驱动程序。)FSD然后调用I/0支持例程( loCalldriver)将 那个IRP传递给相邻的较低层驱动程序。 4.当最低层驱动程序被使用IRP调用时,它检查它的I/0栈位置以确定它将在目标设备上 完成什么操作(通过 IRP MJ XXX函数代码指定)。目标设备在它的被指定的I/0栈位 置中被设备对象表示,并且连带IRP被传送给驱动程序。最低层驱动程序假定I/O管理 器已经发送IRP到一个入口点,这个入口点是驱动程序为 IRP MJ XXX(这里是 IRP MJ READ或 IRP MJ WRITE)操作定义的,并且假定高层驱动程序已经为请求检查过 其他参数的有效性 如果没有较高层驱动程序,最低层驱动程序将检査 IRP MJ XXX的输入参数是否是有效 的。如果它们是有效的,驱动程序通常调用I/0支持例程以通知Ⅰ/0管理器设备操作正 在IRP上等待决定,并且要么将IRP放入队列,要么传递它给另一个驱动程序提供的例 程,这些例程可以访问目标设备(这里是物理设备或逻辑设备:磁盘或磁盘上的一个分 5.Ⅰ/0管理器确定目标设备的驱动程序是否正在处理另一个IRP,如果是这样的话,将IRP 放入队列,并返回。否则,I/0管理器发送IRP到驱动程序提供的例程,这个例程在它 的设备上开始Ⅰ/0操作。(在这个阶段,图2.3中的驱动程序和I/0管理器返回控 制。) 6.当设备中断时,驱动程序的中断服务例程(ISR)所作的仅仅是阻止设备中断,并保存 必要的操作环境。然后,ISR用IRP调用I/0支持例程( IoRequestDpc),等待一个驱 动程序提供的DPC(延迟过程调用)例程以在比ISR更低的硬件优先级上完成请求的操 作 7.当驱动程序的DPC获得控制,它使用环境(在ISR的调用中被传递给 IoRequestDpc)以 完成I/O操作。DPC调用支持例程将下一个IRP(如果有)取出队列,然后传递这个IRP 到驱动程序提供的例程上,这个例程在设备上开始I/0操作(见第5步)。DPC然后在 IRP的I/0状态块中设置刚刚完成的操作的状态,并使用 IoCompleteRequest将它返回 给I/0管理器 8.I/0管理器将IRP中最低层的驱动程序的I/0栈位置赋零,并用FSD分配的IRP调用文 件系统的已注册的完成例程(见第3步)。这个完成例程检查1/0状态块,以确定是否 重试请求或更新任何保存原始请求的内部状态,以及是否释放它的驱动程序分配的 IRP。文件系统能收集所有驱动程序分配的发送给低层驱动程序的IRP的状态信息,所 以它能设置I/0状态,并能完成原始IRP。当文件系统完成原始IRP,I/0管理器返回 Windows nt状态给I/0操作的原始请求者(子系统的本地函数) 图2.3也显示了原始IRP中的两个I/0栈位置,因为它显示了两个驱动程序,一个文件系 驱动程序和一个海量存储设备驱动程序。I/0管理器给分层的驱动程序链中的每个驱动
15 低层的驱动程序,通过这种方法 FSD 能重用原来的 IRP,而不是象图 2.3 种所示的那样 分配额外的 IRP。 3. 对于每个驱动程序分配的 IRP,图 2.3 中的 FSD 调用一个 I/O 支持例程以注册一个 FSD 支持的完成例程。在这个完成例程中,FSD 能确定低层驱动程序是否满足请求,并能在 低层驱动程序完成任务后释放每个驱动程序分配的 IRP。不论每个驱动程序分配的 IRP 是被成功完成,还是返回一个错误状态,或者是被放弃,I/O 管理器都将调用 FSD 支持 的完成例程。更高层驱动程序负责释放 IRP,这个 IRP 是它根据自己的需求为较低层驱 动程序分配并安装的。I/O 管理器在所有驱动程序完成任务后释放它分配的 IRP。 下一步,FSD 调用一个 I/O 支持例程(IoGetIrpStackLocation)访问相邻的较低层的驱 动程序的 I/O 栈位置,从而为临近低层驱动程序设置请求。(图 2.3 种,相邻的较低层 驱动程序碰巧是最低层的驱动程序。)FSD 然后调用 I/O 支持例程(IoCallDriver)将 那个 IRP 传递给相邻的较低层驱动程序。 4. 当最低层驱动程序被使用 IRP 调用时,它检查它的 I/O 栈位置以确定它将在目标设备上 完成什么操作(通过 IRP_MJ_XXX 函数代码指定)。目标设备在它的被指定的 I/O 栈位 置中被设备对象表示,并且连带 IRP 被传送给驱动程序。最低层驱动程序假定 I/O 管理 器已经发送 IRP 到一个入口点,这个入口点是驱动程序为 IRP_MJ_XXX(这里是 IRP_MJ_READ 或 IRP_MJ_WRITE)操作定义的,并且假定高层驱动程序已经为请求检查过 其他参数的有效性。 如果没有较高层驱动程序,最低层驱动程序将检查 IRP_MJ_XXX 的输入参数是否是有效 的。如果它们是有效的,驱动程序通常调用 I/O 支持例程以通知 I/O 管理器设备操作正 在 IRP 上等待决定,并且要么将 IRP 放入队列,要么传递它给另一个驱动程序提供的例 程,这些例程可以访问目标设备(这里是物理设备或逻辑设备:磁盘或磁盘上的一个分 区)。 5. I/O 管理器确定目标设备的驱动程序是否正在处理另一个 IRP,如果是这样的话,将 IRP 放入队列,并返回。否则,I/O 管理器发送 IRP 到驱动程序提供的例程,这个例程在它 的设备上开始 I/O 操作。(在这个阶段,图 2.3 中的驱动程序和 I/O 管理器返回控 制。) 6. 当设备中断时,驱动程序的中断服务例程(ISR)所作的仅仅是阻止设备中断,并保存 必要的操作环境。然后,ISR 用 IRP 调用 I/O 支持例程(IoRequestDpc),等待一个驱 动程序提供的 DPC(延迟过程调用)例程以在比 ISR 更低的硬件优先级上完成请求的操 作。 7. 当驱动程序的 DPC 获得控制,它使用环境(在 ISR 的调用中被传递给 IoRequestDpc)以 完成 I/O 操作。DPC 调用支持例程将下一个 IRP(如果有)取出队列,然后传递这个 IRP 到驱动程序提供的例程上,这个例程在设备上开始 I/O 操作(见第 5 步)。DPC 然后在 IRP 的 I/O 状态块中设置刚刚完成的操作的状态,并使用 IoCompleteRequest 将它返回 给 I/O 管理器。 8. I/O 管理器将 IRP 中最低层的驱动程序的 I/O 栈位置赋零,并用 FSD 分配的 IRP 调用文 件系统的已注册的完成例程(见第 3 步)。这个完成例程检查 I/O 状态块,以确定是否 重试请求或更新任何保存原始请求的内部状态,以及是否释放它的驱动程序分配的 IRP。文件系统能收集所有驱动程序分配的发送给低层驱动程序的 IRP 的状态信息,所 以它能设置 I/O 状态,并能完成原始 IRP。当文件系统完成原始 IRP,I/O 管理器返回 Windows NT 状态给 I/O 操作的原始请求者(子系统的本地函数)。 图 2.3 也显示了原始 IRP 中的两个 I/O 栈位置,因为它显示了两个驱动程序,一个文件系 统驱动程序和一个海量存储设备驱动程序。I/O 管理器给分层的驱动程序链中的每个驱动