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. LeetCode 数组中两个数的最大异或值

    题目链接:https://leetcode-cn.com/problems/maximum-xor-of-two-numbers-in-an-array/ 题目大意: 略. 分析: 字典树 + 贪心. ...

  2. java--二叉树解析及基本实现

    一.二叉树的结构 在进行链表结构开发的过程之中,会发现所有的数据按照首尾相连的状态进行保存,那么 在进行数据查询时为了判断数据是否存在,这种情况下它所面对的时间复杂度就是"O(n)" ...

  3. Python快速设置Excel表格边框

    import xlwings as xw #打开存好的excel app = xw.App() #设置应用 wb = xw.Book("E:/Data/小蜜蜂超市销售报表.xlsx" ...

  4. cygwin的用途

    cgywin简介 打开cygwin的官方网站(www.cygwin.com),一行英文非常醒目:Get that Linux feeling – on Windows! 简而言之,cygwin是一个在 ...

  5. 配置进程外Session 同时解决一个奇怪的BUG 因为SQLserver 服务器名不是默认的.或者localhost而引发的一系列问题

    用公司的电脑学习如鹏网的视频,开发一个项目,用到了进程外session,因为公司电脑SQLServer 是2008 服务器名称是.  然后参考这篇文章进行设置进程外session 很顺利 完成了设置. ...

  6. 如何优雅地在React中处理事件响应&&React绑定onClick为什么要用箭头函数?

    React绑定onClick为什么要用箭头函数? https://segmentfault.com/q/1010000010918131 如何优雅地在React中处理事件响应 https://segm ...

  7. Android No static field XXX of type I in class Lcom/XXX/R$id错

    问题复现: 问题原因: 出现这样的情况,你先检查你的依赖工程(module)的对应布局layout/xxx.xml是否跟主项目的layout重名,你点开R文件的时候,你会发现你的布局发生了错乱,导致你 ...

  8. 关于Django路由层简单笔记

    Django—路由层 URL配置(URLconf)就像Django 所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表:你就是以这种方式告诉Django,对于客户端发来的某个U ...

  9. go语言从例子开始之Example13.函数多返回值

    Go 内建多返回值 支持.这个特性在 Go 语言中经常被用到,例如用来同时返回一个函数的结果和错误信息. Example: package main import "fmt" // ...

  10. SSM框架搭建过程

    引入依赖的jar包(pom.xml) a. <!--Spring SpringMVC相关-->  spring-webmvc b. <!--Spring事务-->  sprin ...