I/O管理器
I/O 管理器定义了有序的结构,或者说是模型,在这个模型里将I/O请求发送给设备驱动程序。I/O系统是包驱动的,大部分I/O请求用I/O请求包(IRP)代表,从一个I/O系统组件传送到另一个组件。(注意:快速I/O不是IRP。)这种设计允许一个应用程序线程可以同时管理多个I/O请求。一个IRP是一个数据结构,包含了完整地描述一个I/O请求的信息。(可以通过Windbg内核调试扩展命令lkd> dt nt!_irp来查看IRP数据结构)
I/O管理器创建一个IRP代表一个I/O操作,将指向IRP的指针传递给正确的驱动程序,并且当I/O操作完成时删除IRP。相反,驱动程序收到一个IRP,执行IRP指定的操作,不管是完成操作还是要将IRP传递给另外一个驱动程序进行更进一步的处理,驱动程序都将IRP传回给I/O管理器。
除了创建和删除IRP,I/O管理器还为不同的驱动程序提供公共的代码,驱动程序可以调用这些公共代码进行I/O处理。将I/O管理器中公共的任务合并,可以使驱动程序变得更简单轻便。例如,I/O管理器提供一个函数,允许驱动程序调用其它驱动程序。I/O管理器还管理为I/O请求而设立的缓冲区,为驱动程序提供超时支持,记录操作系统装载了哪个可安装的文件系统。I/O管理器中有将近100个不同的例程可以被设备驱动程序调用。
I/O管理器还提供了灵活的I/O服务,允许环境子系统,如Win32和POSIX,实现它们各自的I/O函数。这些服务包括了用于异步I/O的复杂的服务,用于开发者构造可升级的、高性能的服务器应用程序。
驱动程序提供统一的、模块化的接口,允许I/O管理器可以调用任何驱动程序,而不需要知道驱动程序内部的结构或者是细节的任何信息。前面已经提到,操作系统将所有的I/O请求当作向一个文件发出的请求,驱动程序将发送给虚拟文件的请求转换成硬件特有的请求。驱动程序通过I/O管理器可以互相调用,从而完成对一个I/O请求分层的、各自独立的处理。
除了通常的打开、关闭、读和写函数,Windows 2000 I/O 系统还提供了几个高级特性,如异步,直接,缓冲和分散/集中 I/O。
I/O管理器还负责管理I/O请求缓冲区。
IRP缓冲区管理
当应用程序或者是设备驱动程序通过使用 NtReadFile, NtWriteFile, 或是 NtDeviceIoControlFile 的系统服务(与这些系统服务对应的Win32 API 函数分别是 ReadFile, WriteFile, 和 DeviceIoControl )间接地创建一个IRP,I/O管理器决定是否需要参与管理调用者的输入或输出缓冲区。I/O管理器进行以下三种类型的缓冲区管理:
· 缓冲I/O(Buffered I/O)
I/O管理器在非分页池分配一个缓冲区,大小与调用者的缓冲区相同。写操作:当创建IRP时,I/O管理器将调用者的缓冲区数据拷贝到分配的缓冲区;读操作:当IRP完成时,I/O管理器将分配的缓冲区的数据拷贝到调用者的缓冲区。然后释放分配的缓冲区。
· 直接I/O(Direct I/O)
当I/O管理器创建IRP时,它锁住了用户的缓冲区到内存(非分页),当I/O管理器完成IRP时,它将缓冲区解锁。I/O管理器用内存描述子列表(MDL)的形式保存了一个内存描述,一个MDL指定了缓冲区占用的物理内存。进行直接内存访问(DMA)的设备只要求有缓冲区的物理描述,因此对于操作这种类型的设备,MDL就足够了。(支持DMA的设备在设备和计算机的内存之间直接传输数据,不使用CPU。)如果驱动程序必须访问缓冲区的内容,它可以将缓冲区映射到系统的地址空间。
· 无关I/O(Neither I/O)
I/O管理并不进行任何的缓冲区管理,缓冲区管理交由设备驱动程序自行判断,它可以选择手工进行I/O管理器对其他缓冲区管理类型进行的操作步骤。
对每种类型的缓冲区管理,I/O管理器都在IRP中放入合适的的输入和输出缓冲区的引用地址。I/O管理进行缓冲区管理的类型,取决于驱动程序每个类型的操作所请求的缓冲区管理的类型。驱动程序登记对代表设备的设备对象进行读和写操作时,希望获得的缓冲区管理类型。设备I/O控制操作(通过 NtDeviceIoControlFile 进行的操作)由驱动程序定义的I/O控制码指定缓冲区管理类型,一个控制码包含了当发送IRP时,I/O管理器使用的缓冲区管理的描述,发送的IRP中包含了该控制码。
当调用者的传输请求小于1页(4KB)时,驱动程序通常使用缓冲I/O,当大请求时,使用直接I/O。1页大约是缓冲区的大小,是缓冲I/O的拷贝操作开销和直接I/O锁内存的开销两者之间的一种平衡。文件系统驱动程序通常使用无关I/O,因为数据可以从文件系统缓冲拷贝到调用者的缓冲区,因此没有缓冲区管理开销。大部分驱动程序不使用无关I/O的原因是因为指向调用者的缓冲区的指针,只有当线程所属的调用者的进程执行时才有效。如果驱动程序必须在 ISR 或者是 DPC 例程中传输数据(从设备或是到设备),它必须确保进程的任何上下文环境,调用者的数据都是可以访问的,这意味着缓冲区必须有一个系统虚拟地址。
说明:
本文摘自《 Windows Internals》第9章 《I/O系统 》9.1和9.3节