【Tiny6410 And Linux】—(5.1)—RamDisk 驱动实现(内核缺省的处理函数 __make_request())——原理

相信看过我写的文章的会大吃一惊!

为什么突然由 2 到了 5,这也跨度太大了点吧,呵呵,不是的,因为前面的国嵌的几天的课程真的看不懂!你懂得!现在水平的确有限!

DM9000 和 PCI 串口,这两天的内容只能暂时放下了,没有很好地教程,自己看了两天“瓶颈”又很多,所以~~

 

好了,从今天开始就是块设备的驱动了

努力!

哼哼!

 

1、块设备简介

块设备将数据存储在固定大小的块中,每个块的大小通常在 512 字节到 32768 字节之间。磁盘、SD 卡都是常见的块设备。
块设备和字符设备的区别:
①、块设备和字符设备最大的区别在于读写数据的基本单元不同。块设备读写数据的基本单元为块,例如磁盘通常为一个扇区,而字符设备饿基本单元为字节。
②、块设备能够随机访问,而字符设备则只能顺序访问。

2、块设备结构

如图:


①、虚拟文件系统 VFS:
VFS 是对各种具体文件系统的一种封装,为用户程序访问文件提供统一的接口。

②、Disk Cache:
说白了就是一个缓存!
当用户发起文件访问请求的时候,首先回到 Disk Cache 中寻找文件是否被缓存了,如果在 Cache 中,则直接从 Cache 中读取。如果数据不再缓存中,就必须要到具体的文件系统中读取数据了。

③、Mapping Layer:
首先确定文件系统的大小,然后计算所请求的数据包含多少个块,然后调用具体文件函数来访问文件的 inode,确定所请求的数据在磁盘上的逻辑块地址。

④、Generic Block Layer:
Linux 内核为块设备抽象了统一的模型,把块设备看作是由若干个扇区组成的数据空间。上层的读写请求在通用块层(Generic Block Layer)被构造成一个或者多个 bio 结构。

⑤、I/O Sxheduler Layer:
I/O 调度层负责将 I/O 操作进行排序,采用某种算法(主要是:电梯调度算法)来高效地处理操作(如果对于 ramdisk、U 盘等自己分配就哦了)。

⑥、Block Device Driver:
块设备驱动程序通过发送命令给磁盘控制器实现真正的数据传输。

3、块设备驱动

①、设备描述:
Linux 内核使用 struct gendisk(定义与 <linux/genhd.h>)来描述块设备。

struct gendisk 
{
 	Int major; 			/* 主设备号 */
 	Int fistr_minor; 		/* 次设备号 */
	Int minors; 			/* 次设备数 */
 	Char disk_name[DISK_NAME_LEN];  /* 驱动名 */
 	Struct block_device_operations *fops; 	/* 块设备操作集合 */
 	Struct request_queue *queue;		/* 请求队列 */
	…
 	Int node_id;
};


②、设备注册
Linux 内核使用 add_disk 函数向内核注册块设备驱动。

void add_disk(struct gendisk *gd);


③、设备操作
字符设备通过 file-operations 结构来定义使它所支持的操作,块设备使用一个类似的结构:
Struct block_device_operations。

Struct block_device_operations
{
 	Int (*open)(struct block_device *,fmode_t);
 	Int (*release)(struct gendisk *,fmode_t);
 	Int (*ioctl)(struct block_device *,fmode_t,ussigned,unsigned long);
 	…
};


④、IO 请求

在 Linux 内核中,使用 struct request 来表示等待处理的块设备 I/O 请求。

struct request
{
    struct list_head questlist;  /* 链表结构 */
    sector_t sector;   /* 要操作的首个扇区 */
    unsigned long nr_sectors; /* 要操作的扇区数目 */
    struct bio *bio;    /* 请求的 bio 结构体的链表 */
    struct bio *biotail;  /* 请求的 bio 结构体的链表尾 */
    ....
};

简单的说,请求队列就是 IO 请求 request 所形成的队列,在 LInux 内核中 struct request_queue 描述。

⑤、请求队列
内核提供了一系列函数用来操作请求队列:

▲:struct request_queue *blk_init_queue(request_fn_proc *rfn,spinlock_t *lock)

初始化请求队列,一般在块设备驱动的模块加载函数中调用。
其中 rfn 是个函数指针。当有数据请求来的时候就会调用 rfn 这个函数。

注意:

使用 blk_init_queue() 函数来初始化一个请求队列,默认会将请求队列的 make_request_fn 方法设置为内核缺省的处理函数 __make_request()。

该函数会使用 IO 调度器将多个 bio 的访问书序进行优化,调整,合并为一个请求放入请求队列,但是对于 ramdisk、U 盘、记忆棒之类的设备,并不存在磁盘所面临的寻到时间。

因此对这样的“块设备”而言,一个 I/O 调度器不但发挥不了作用,反而其本省将白白耗掉不少内存和 CPU。因此对于此类块设备的驱动,需要实现自己的 make_request_fn 函数,通过函数 blk_alloc_queue() 我们可以分配一个请求队列结构而不将 make_request_fn 方法设置为默认的处理函数 __make_request()。


▲:void blk_cleanup_queue(request_queue_t *q)

清除请求队列,这个函数完成将请求队列返回给系统的任务,一般在块设备驱动模块卸载函数中调用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值