硬盘里面有很多磁头,每个磁头有很多环,类似跑道。称为柱面:0柱面 1柱面;跑道里面有很多块称为扇区:扇区0 扇区1。硬盘操作的耗时主要在磁盘转换的时候,如果我们一会读1磁头,一会写2磁头,然后又读1磁头,如果来回这么跳转,会导致效率十分低。
(2)Flash
Flash有很多块,每个块里面有很多扇区。
Flash以块为单位进行操作。操作扇区时也需要读取整个块到内存中。如果读1块中的1扇区,又去写2块的1扇区,然后又读1块的2扇区,如果不优化效率将很低。
因此,基于以上硬件的特点,及效率问题,内核采用了电梯调度算法进行命令的优化。也就是收到一个命令时不会立刻执行,而是放入队列,当存在多个命令时,经过电梯调度算法来进行优化后执行,这样就提升了读写的效率,这个是块设备驱动程序要考虑的问题。
应用程序文件读写—》扇区读写,文件系统来做转换之后调用ll_rw_block函数操作块设备。
那么扇区读写函数是?
ll_rw_block:low_level read write block
ll_rw_block作用:把读写放入队列并优化,之后调用队列的处理函数。即优化后执行。
int submit_bh(int rw, struct buffer_head *bh)
函数作用:用buffer_head来构造bio,最后提交bio--》submit_bio
void submit_bio(int rw, struct bio *bio)
--generic_make_request
函数作用:使用bio来构造请求,把请求放入队列。
elv_merge(q, &req, bio); 电梯调度算法,来尝试把bio合并到队列里面去。如果合并不成,使用bio构造请求init_request_from_bio(req, bio); 把请求放入队列add_request(q,req); 执行队列__generic_unplug_device(q); 调用队列的"处理函数" q->request_fn(q);
这里强调:块设备的读写并不会立刻执行,而是先放入队列进行优化。
常规思路,分配结构体,设置结构体,注册到某个地方。
(1)分配gendisk:alloc_disk
(2)设置
分配/设置队列: request_queue_t // 它提供读写能力
blk_init_queue //设备队列
设置gendisk其他信息 // 它提供属性: 比如容量
(3) 注册: add_disk
4、内存模拟块设备
参考:driversblockxd.c
driversblockz2ram.c
(1)拷贝头文件,搭出框架
(2)明确需要做的任务
(3)实现
ramblock_disk = alloc_disk(16);
ramblock_buf= kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);//分配内存模拟
while ((req = elv_next_request(q)) != NULL)//电梯调度算法
(4)实验
没有立刻写,等一会才出现write
要么都是读要么都是写 不会一读一写。效率高
测试5th:
1. insmod ramblock.ko
2. ls /dev/ramblock*
3. fdisk /dev/ramblock
分别操作分区。