Types of IO

IRP Buffer Management

首先区分一下page的内存与nonpaged的内存,内存如果用页管理,就难免面对被swap out的命运;但是如果用nonpaged管理,就会一直存在在物理内存中。

一般来说,内核以及驱动承担繁重的工作,因此常用nonpaged内存,以保证效率。

当application或者driver通过调用下列API/函数创建一个IRP请求数据包时,

  1. ReadFile/NtReadFile
  2. WriteFile/NtWriteFile
  3. DeviceIoControl/NtDeviceIoControl

IO manager会根据情况选用不同的buffer管理机制:

  • Buffered IO

由IO manager直接在nonpaged pool中分配内存,分配的buffer供driver使用,并且在适当的时机,将这块内存与用户态应用程序指定的内存进行同步。

  • Direct IO

将用户态应用程序传递进来的内存进行转化,由paged转化为nonpaged,转化的过程又称作lock。

转化之后的内存通过MDL(Memory Description List)进行维护,MDL描述的是物理内存。

如果driver不需要访问这段物理内存中的内容,比如DMA驱动,它不需要CPU的参与便可以在物理内存与IO设备之间进行传输数据,那么直接使用MDL就可以了;

但是如果driver需要访问这段物理内存中的内容,可以将物理内存map到system address space中的某段上,再进行访问。

  • Neither IO

即不同于以上两种方式的其他类型,就是不需要IO Manager的参与,由driver自己来管理缓存。

基本上意味着驱动直接访问用户态内存,这种情况下必须保证是访问用户态的缓存的驱动是同步驱动代码或者APC例程,即当前正在执行的线程就是请求IO操作的线程,可以访问该线程的页表描述的用户态地址空间,而不是ISR/DPC等异步例程。

具体选用什么类型的Buffer management方式,由driver在初始化时,指定在创建的device object对象里。

对于DeviceIoControl来说,buffer management的方式由相应的参数决定。

对于buffer management方式的选择,有以下规律:

1. 如果申请的是小于一页内存(4KB),选用Buffered IO,因为这时在用户态与内核态进行拷贝的代价还不是很大。

2. 如果申请的是大于一页内存,选用Direct IO。

一页内存可以看作是Buffered IO在用户态与内核态之间拷贝内存,与Direct IO锁定一块内存的开销的平衡点(trade-off)。

3. 文件系统驱动一般会使用Neither IO,因为该驱动只要保证对应用户态程序的进程被切换执行时,它将文件系统中的文件内容拷贝到用户态程序指定的内存中去就好了,因为这时的页表对于驱动来说是有效的(因为已经任务切换到该driver代表的用户态进程了);

4. 但是大多数的驱动不能使用Neither IO,比如driver如果需要在ISR/DPC routine中传递数据时,就没有办法保证当前状态下的页表对应的是正确的用户态应用程序。

当driver使用Neither IO(即意味着直接访问用户态内存)时,需要格外注意:

1. 用户态的地址是否valid,即是否已经映射,而不是内存区域间的间隙或者空洞,可以通过try/catch来捕获segmentation fault/access denied等待内存相关的异常;

2. 用户态的应用程序传递进来的地址是否包含内核空间地址,如果是的话,就可以从一个设备(比如文件、网络)中inject数据、代码到内核地址空间,这是非常危险的行为;driver可以使用ProbeForRead/ProbeForWrite来测试用户态应用程序传递进来的内存地址是否是单纯的用户态内存区域。

3. 用户态传递进来的内存是否可能被用户态应用程序作为其他用途,因此最好由内核态的缓存来捕获IO设备的输入;


IO Request to Single-Layered Driver

ISR DPC APC

  • ISR: Interrupt Servicing Rountine
  • DPC: Defered Procedure Call
  • APC: Asynchronous Procedure Call

驱动与IO设备交互的方式可以分为两种:同步和异步

同步很简单,直接调用HAL提供的API就可以向IO设备下达各种操作命令,或者读取IO设备的状态信息;

但是很多时候,驱动无法预知IO设备会何时发出请求或者完成IO操作,因此只有依赖于“中断机制”来通知驱动。

可以认为driver中正常的函数调用是同步的,而driver注册的ISR例程,以及ISR又注册的DPC例程,以及APC例程都是异步的。

异步的意思,就是无法确定它们的执行与driver中同步执行的一条指令之间的先后顺序。

中断服务

首先,驱动需要在IDT(Interrupt Dispatch Table)中注册相应的ISR例程;

当中断发生时,ISR被调用,ISR运行在相应的中断对应的特权级别,这是高于普通情况的特权级别,在ISR中通常需要尽可能地少做停留,只要获取到IO设备的状态,就应该退出ISR,剩余的操作由一个DPC例程来完成,DPC例程被queue到IO Manager中,当其他高于DPC特权级别的任务(ISR任务)都被完成了,IO Manager就会逐个处理DPC例程。

ISR与DPC例程在执行时,都与当前正在执行的线程Context没有关系,也就是说,它们不与具体的线程相关联,因此它们无法访问用户态地址空间;

Complete IO Request

当驱动完成了IRP的请求后,它需要调用IoCompleteRequest函数通知IO Manager,IO Manager需要把本次IRP的结果返回给用户态的应用程序。但是在异步操作中,此时正在执行的用户态应用程序很可以不是发起IRP请求的应用程序,那么IO Manager需要一种机制,在下一次用户态的应用程序被调度执行时,通知应用程序完成IO操作,并且将内核态中的结果拷贝回用户态内存地址空间中。

这种机制叫做APC。

APC可以分为用户态与内核态两种,都与具体的线程Context相关联。APC的运行级别低于DPC,但是高于正常的代码执行级别。

Synchronization

当driver中的同步代码与ISR/DPC/APC中异步代码同时访问一些全局数据时,需要在二者之间进行同步协调操作,以免使全局数据发生不一致现象。

driver可以调用KeSynchronizeExecution,该函数会在driver同步代码访问全局数据时,阻止ISR等异步例程被执行。

除此之外,在多核系统中,driver同步代码也可能在多个processor上运行,因此只要driver访问到全局数据时,就需要使用SpinLock,以防止全局数据发生不一致现象。

IO Request to Layered Drivers

多层驱动模型与单层驱动模型在本质上是一样的,唯一的区别在于,需要多层的驱动之间需要互动和通信,那么它们之间通信的媒介也还是IRP,区别在于IRP是复用驱动收到的IRP,还是新生成一个新的IRP。

对于新生成的IRP,那么与单层驱动模型就更加相似了,就是一个过程重复了几次而已;

而对于复用IRP,这里关键的是复用机制。

复用IRP

IRP在创建的时候,可以有几种方法,或者说可以创建不同大小的IRP,IRP由定长的header和不定长的几个stack locations组成,但是对于一个具体的IRP来说,在header中会保存整个IRP的长度。

简单来说,每个stack location是为一层driver而保留的,因为虽然是同一个IRP,但是对于不同的driver,IRP中包含的消息是不同的,最显而易见的是MAJOR_CODE就不可能一样,举例来说,读文件操作的IRP,在文件系统驱动这一层,是读取几个的cluster操作,而在磁盘驱动这一层,就是读取几个sector的操作,也就是说在应用程序看来相同的IO操作,分解到不同层次的驱动上,就是完成不同的操作。

IO Cancellatio

IO Completion Ports

IO Priority

IO Processing的更多相关文章

  1. Linux BPF/bcc for Oracle Tracing

    Luca Canali on 26 May 2016 Topic: In this post you will find a short discussion and pointers to the ...

  2. Windows完成端口编程

    Windows完成端口编程目录一 基本概念二 OVERLAPPED数据结构三 完成端口的内部机制创建完成端口完成端口线程的工作原理线程间数据传递线程的安全退出 一 基本概念       设备---wi ...

  3. VS2015编译GEOS

    下载链接:http://trac.osgeo.org/geos/ 1. 打开cmake,加载geos源码和定位geos的工程存放位置: 2.点击configure,会报错,首先设置CMAKE_INST ...

  4. 解决hiveserver2报错:java.io.IOException: Job status not available - Error while processing statement: FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask

    用户使用的sql: select count( distinct patient_id ) from argus.table_aa000612_641cd8ce_ceff_4ea0_9b27_0a3a ...

  5. Python(七)Socket编程、IO多路复用、SocketServer

    本章内容: Socket IO多路复用(select) SocketServer 模块(ThreadingTCPServer源码剖析) Socket socket通常也称作"套接字" ...

  6. Day11-协程/异步IO/RabbitMQ

    协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候 ...

  7. 《Scalable IO in Java》笔记

    Scalable IO in Java http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf 基本上所有的网络处理程序都有以下基本的处理过程:Read reque ...

  8. python之协程与IO操作

    协程 协程,又称微线程,纤程.英文名Coroutine. 协程的概念很早就提出来了,但直到最近几年才在某些语言(如Lua)中得到广泛应用. 子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B ...

  9. 统计和分析系统性能【IO CPU 内存】的工具集合

    统计和分析系统性能[IO CPU 内存]的工具集合 blktrace http://www.oschina.net/p/blktrace 获取磁盘写入的信息 root@demo:~/install/p ...

随机推荐

  1. SSH服务搭建、账号密码登录远程Linux虚拟机、基于密钥的安全验证(Windows_Xshell,Linux)

    问题1:如果是两台虚拟机ping不同且其中一个虚拟机是克隆的另一个,需要更改一下MAC地址,关机状态下 一> "编辑虚拟机设置" 一>" 网络适配器" ...

  2. C++学习书籍推荐

    列出几本侯捷老师推荐的书1. C++程序员必备的书a) <C++ Programming Language> Bjarne Stroustrupb) <C++ Primer> ...

  3. leetcode.双指针.88合并两个有序数组-Java

    1. 具体题目 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组. 说明: 初始化 nums1 和 nums2 的元素数量分别 ...

  4. cnblogs博客主题原来可以弄得这么美观

    参考了网友 https://www.cnblogs.com/maybreath/p/5253824.html的做法,没想到真的可以耶. 总想弄个方便的.简洁的.可以被搜索引擎搜到的博客.以前用过wor ...

  5. 2018-2-13-win10-UWP-应用设置

    title author date CreateTime categories win10 UWP 应用设置 lindexi 2018-2-13 17:23:3 +0800 2018-2-13 17: ...

  6. shell input value from console

    echo "Please enter some input: " read input_variable echo "You entered: $input_variab ...

  7. 力扣——Partition List(分隔链表) python实现

    题目描述: 中文: 给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前. 你应当保留两个分区中每个节点的初始相对位置. 示例: 输入: head = ...

  8. config.properties

    # 数据库配置db.host=10.100.2.50db.port=3306db.database=paycoredb.username=rootdb.password=mysql@123db.ini ...

  9. Java线程的优先级设置遵循什么原则?

    Java线程的优先级设置遵从下述原则: (1) 线程创建时,子线程继承父线程的优先级 (2) 线程创建后,可在程序中通过调用setPriority( )方法改变线程的优先级 (3) 线程的优先级是1~ ...

  10. 修改TOMCAT服务的端口

    1.进入tomcat配置文件的目录 [root@db200 conf]# cd /usr/local/tocat8/conf/ 2.打开配置文件 vim server.xml 找到Connector ...