1.4 通用块层的处理
在前面普通文件和块设备文件的readpage方法中介绍到,对于一个普通文件,要读取相对于文件头的ppos处开始size个连续的字节,就必须计算成对应的页面缓存在内存中;如果存在不连续的情况,如“文件的洞”,就调用块设备的readpage方法建立块设备页高速缓存存放不来连续的块。
不管怎样,最终都将封装一个bio结构,并把请求传递给函数 generic_make_request ,并由 generic_make_request 函数将请求提交给通用块层处理。在进入通用块层之前,先把块设备的一些预备知识清理了。
1.4.1 块设备的基础知识
块设备主要是指那些磁盘、U盘等一些用来存储的设备,他们的主要特点是,CPU和总线读写数据所花时间与磁盘硬件的速度不匹配。块设备的平均访问时间很长。每个操作都需要几个毫秒才能完成,主要是因为磁盘控制器必须在磁盘表面将磁头移动到记录数据的确切位置。但是,当磁头到达正确位置时,数据传送就可以稳定在每秒几十MB的速率。
块设备驱动程序上的每个操作都涉及很多内核组件,我们来看ULK-3的一幅经典的图:
我们前面所有的内容都在讲一个进程在某个磁盘文件上发出一个read()系统调用——其实write请求本质上采用同样的方式。下面咱们就站在设备管理的高度对通用块层之前的步骤进行一下总结和回顾:
1. read()系统调用的服务例程调用一个适当的VFS函数,也就是前面的generic_file_read,将文件描述符和文件内的偏移量传递给它。
2. generic_file_read函数确定所请求的数据是否已经存在于页高速缓存中(address_space对应的基树中)。有时候没有必要访问磁盘上的数据,因为内核将大多数最近从块设备读出或写人其中的数据保存在页高速缓存中。
3. 我们假设内核需要从块设备读数据,那么它就必须确定数据的物理位置。为了做到这点,内核依赖映射层(mapping layer<