分类: LINUX
2015-06-14 00:00:03
1. 块设备分层
VFS作用:屏蔽下层文件系统的差异,为上层提供统一接口。正是由于VFS的存在,所以可以把设备、内存、信息等一切都抽象成文件。不管底层是flash还是磁盘,接口都是一样的。
具体文件系统:不同的文件系统有不同的格式,如FAT、EXT3等。每种文件系统都有自己的操作集合。
Page Cache:引入cache的目的是提高访问性能。上层的访问请求通常不会是对齐的,而下层的驱动都是对齐的,每次操作最小都是按Sector进行读写。cache的作用是,不论上层读写是否只是几个字节,都会按sector来取,并存入Page Cache。如果两次的请求在同一个sector上,则第二次不会再调用底层驱动,而是直接靠Page Cache中缓存的数据完成操作。
Generic Block Layer:接受上层发出的读写请求,并最终发送IO请求。
IO调度器:IO调度器不是必须的,作用是对IO请求进行重排,以提高磁盘访问效率。
Block Device Driver Layer:根据上层IO请求进行实际的设备读写。
Block Device Layer:具体的物理设备,定义了设备操作规范,如读写信号、时钟周期等。
2. 块设备读写原理
调用write或read时都会产生一个bio请求,bio中使用bvec表示buff,每个bvec指向一个page(4k)。
bio->bi_sector:起始扇区号
bio->bi_size:大小
bio->bi_rw:读写操作
从上述参数看,bio的操作粒度为一个sector(512Bytes),所以即使读写一个字节,也会读写一个sector。究其原因,块设备早期是为了操作磁盘设备,而磁盘设备最小粒度就是sector。同样道理,IO调度器的策略也是针对早期磁盘特性的,可以减少磁头的运动次数。现在的磁盘都支持线性读写,所以不适用IO调度器(或使用IO调度器中的NONE调度规则)效率更高一些。
bio的参数只要勇于块设备中的定位,用户buffer的信息则存储在bvec表中。
bvec->bv_page:buffer物理页号
bvec->bv_offset:业内偏移量
bvec->bv_len:数据长度
用户buffer来自用户空间,这块空间在用户空间是连续的,但在物理空间中不需要连续。内核用bvec数组表示一个bio请求中所需要buffer对应的物理page,每个bvec对应着一个物理page。这也决定了bv_offset加上bv_len不能超过一个page大小。
使用IO调度器时,为了方便,内核会申请一块连续的内核地址空间用于映射这块buffer,所以看起来buffer还是连续的,如果我们的块设备只是一块内存,则可以用memcpy直接实现数据传送。
如果我们不用IO调度器,则我们得到的只是一堆不连续的bvec,需要驱动来完成每个bvec的拷贝。每个bvec的处理过程如下: