文件读写,从请求到IO启动
在Linux中,块设备的读写是一个比较复杂的过程。如果再加上VFS的话,层次就更多了。实际上VFS和块设备驱动联系的不是非常密切。在VFS中,我们会看到当发生读写请求的时候,会调用ll_rw_block函数或者submit_bh函数,其中ll_rw_block是对submit_bh的封装。这个函数,实际上就是从VFS到实际设备读写的必经之路。关于这一点,有很多用systemtap来观测io的脚本就是在submit_bh函数安装一个stub(有关io检测的相关的文章,可以参看淘宝的大牛诸霸的博客)。 在这里,我们不再谈论VFS的东西,而是从submit_bh开始看起,然后到数据被读出,进程又继续执行的流程。 submit_bh的功能正如其函数的名字那样–“提交buffer head”。那么,具体提交给谁呢?由谁来提交呢?其实块设备的读写似乎是一个C/S架构的服务器。客户端是各个进行io操作的进程,服务器端就是设备的请求队列。进程把请求的信息包装成一个request的数据结构,然后,挂载在服务端,即块设备的请求队列中。我前面说的那句话“似乎是一个C/S架构的”,而不是真正C/S架构的。因为,C/S架构来源于网络程序,客户端进程把数据发往正在监听的服务端,然后服务端的进程从网络缓冲区中经过网络协议的层层解压“剥皮”,拿到数据。而我们谈论这个文件数据的读写并不真正是C/S架构的,原因就是,客户端的发送和服务端的接收请求全由一个进程,即用户进程来完成的。这一点应该很好理解,因为在OS中,除了中断以及异常处理没有上下文外,其他的都有进程上下文,因此,从submit读写请求到接收读写请求,当然就是进程自己的事情了,当然,如果你要是抬杠“在内核中完全可以由一个专门的线程用来处理服务端的事情”,我也无话可说。原理上,你这个抬杠当然是行得通的。说到这里,我想起了微内核的MINIX,就此打住,继续回到他们的处理过程中。 当用户进程提交请求,并挂载到块设备队列的过程中,还涉及一个IO调度的问题,即是,用户进程在提交一个请求时,遇到了调度算法,这个调度算法做的事情很简单,它检查这个请求和正在排队的请求能否合二为一。如果不能合二为一,那就直接挂上去。至此,一个进程所要做的工作基本上...