简单虚拟块设备驱动流程

 首先,创建我们的设备结构体,也就是把他包装起来,把gnedisk,request_queue,lock包含进来,具体的结构体是:
struct sbull_dev {
        int size;             // 给虚设备分配大小,等于分配给他的扇区个数乘于我们定义的扇区大小。                
        u8 *data;                                     
        short users;                  //记录用户,在open中用到,相当于计数
        short media_change;           //介质改变标记
        spinlock_t lock;              //锁,在进入请求处理的时候内核用它来实现互斥
        struct request_queue *queue;  //请求队列
        struct gendisk *gd;           //gendisk
        struct timer_list timer;      //定时器,用来定时,如果定时到,让一些操作失效
};

struct blk_operations 给他初始化,和字符设备的 file_operations一样。但是,块设备一般也就实现
open,release,他和字符设备不样,用户空间不能直接调用驱动,文件系统有多种,文件系统这一层已经实现了
读写等操作。

1,注册设备号,major = register_blk(major,"name");
  如果major传递的是0,那么,内核会分配一个主设备号给设备.和字符设备的注册不一样的是,
  块设备的次设备号是在gendisk中给出的。
 
2, 给虚设备分配空间,因为这里用的是RAM来虚拟的disk,所以给他分配空间。
3,初始化设备结构体得成员,主要的几个是lock,queue,gendisk.
  锁调用spin_lock_init,请求队列用 blk_init_queue(fun,&lock),在这个函数中绑定请求队列的后台fun,把锁也
  传递过去,返回值是请求队列。gendisk用alloc_disk()由内核分配,不能直接定义。
  设定扇区大小,调用 blk_queue_hardsect_size(queue,size),因为扇区是给请求队列知道的,所以参数中传递了队列和
  大小。
 
  初始化  gendisk,刚才只是分配了gendisk,主要的是gendisk的major,first_minor,fops,queue,private_data等成员赋值。 

4,注册设备,add_disk.这一步一定要在最后做,一旦add,内核就认为设备准备好了。

请求队列处理函数:
1,检查合法性,用CURRENT宏或者elv_next_request来从队列中获得请求队列上的第一个请求,只是获得,这里并没有把他从队列
  中干掉,只有当请求完成了才离开队列。用一个 request 结构体得到请求后,也就得到了从用户空间发过来的操作请求,对request
  的请求合法性进行检查。
 
2,数据传输,memcpy(), 操作buffer,也就是对文件系统这一层的buffer读写。这是和字符设备不用样的地方,所以字符设备在跨空间读写的时候
  要用copy_to_user,防止用户空间传递过来的东西不会破坏内核。

3,清除请求,end_request ,告知内核,处理完成,同时,这个函数也会使CURRENT宏或者elv_next_request指向请求队列的下一个request.
 
4,返回。

一般请求函数不会去做大量的工作,当收到请求后,创建一个内核线程去处理请求,也就是他只负责接收请求,唤醒线程。没有请求时让线程睡眠。 
 
 

 

 

 

你可能感兴趣的:(简单虚拟块设备驱动流程)