【Tiny6410 And Linux】—(5.1)—RamDisk 驱动实现(内核缺省

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

为什么突然由 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)清除请求队列,这个函数完成将请求队列返回给系统的任务,一般在块设备驱动模块卸载函数中调用。

世上并没有用来鼓励工作努力的赏赐,

【Tiny6410 And Linux】—(5.1)—RamDisk 驱动实现(内核缺省

相关文章:

你感兴趣的文章:

标签云: