LDD之块设备驱动程序

一,Linux块设备子系统:

        图一,来自深入理解Linux内核架构

                                                

            图二,是本人通过阅读内核源代码总结的分层结构:

                                        

                       Linux块设备驱动程序的主要任务:

                               1,注册设备(获取主设备号) 

                               2,块设备驱动上层通路:

                                              调用IO子系统提供的接口分配并初始化请求队列,绑定队列请求处理函数;

                                              设置请求能够处理的最大硬件扇区数;

                                              设置硬件数据块大小;

                               3,块设备驱动底层通路:

                                             分配块设备结构实例;

                                             初始化块设备结构实例(名字,主设备号,第一个次设备号,块设备操作,设备容量——以512字节为单位的扇区数量);

                                             添加块设备结构实例到内核;

                                              

二,Linux块设备驱动程序实现:

        1,设备相关数据结构:

                 <linux/genhd.h>

                  struct gendisk{

                          int major;

                          int first_minor;

                          int minors;

                          char disk_name[DISK_NAME_LEN];

                          struct block_device_operations ops;

                          void *private_data;

                          struct request_queue *queue;

                          ...   ...   

                  };

  

                <linux/fs.h>

                 struct block_device_operations {

                           int (*open)(struct block_device *dev,fmode_t mode);

                           void (*release)(struct gendisk *gdisk);

                           int   (*rw_page)(struct gendisk *gdisk,fmode_t mode);

                           ...   ...   

                 };

              2,读写操作请求相关的数据结构:

                <linux/bio.h>

                  struct bio {//设备扇区与缓存的内存段的映射管理;

                       struct bio *bi_next;

                       struct bvec_iter bi_iter;  //设备扇区索引;

                       struct bio_vec  *bi_io_vec;  //扇区数据对应的缓存段;

                       ...   ...  

                 };


               <linux/blkdev.h>

                struct request {

                       struct bio *bio;

                       ...  ... 

                };


              上述请求相关数据结构之间的关系如下图:

                                             

                      数据结构相关的操作api函数:

                           注册设备:                          int register_blkdev(int major,char *name);//如果major为0则动态分配并返回主设备号;

                           请求队列处理函数:          void (*request_fn_proc)(struct request_queue *queue);

                           请求获取函数:                  struct request *blk_peek_request(struct request_queue *queue);

                           从请求队列删除请求:      void blk_start_request(struct request *request);

                           结束请求:                          void blk_end_request_all(struct request *request);// void __blk_end_request_all(struct request *request);

                           请求队列分配并初始化:  struct request_queue *blk_init_queue(void (*request)(struct request_queue *queue));

                           遍历请求的bio:                    rq_for_each_bio(bio,rq);

                           遍历bio的每个段:             bio_for_each_segment(bvec,bio,iter);

                           获取数据船速方向:           rq_data_dir(rq);

                           获取bio当前段的字节数: bio_cur_bytes(bio,iter);

                           释放请求队列:                   blk_cleanup_queue(struct request_queue *queue);

                           分配设备:                           struct gendisk *alloc_disk(int minors);

                           设置设备capacity:            void set_capacity(struct gendisk *disk,sector_t size);//size是以512为单位的扇区数量;

                            添加设备:                          void add_disk(struct gendisk *disk);

                            删除设备:                          void del_disk(struct gendisk *disk);

                 3,块设备驱动示例主要逻辑代码(simple_ramdisk):

                       1,自定义块设备数据结构:

                          struct simple_ramdisk {

                                      int size;

                                      u8 *data;

                                      short user;

                                      spinlock_t spin_lock;

                                      struct gendisk *disk;

                                      struct request_queue *queue;

                          };

                            

                          struct simple_ramdisk *sramdisk;

                      1,设备初始化:

                            int setup_simple_ramdisk(){

                                        int major=register_blkdev(0,"simple_ramdisk");

                                        sramdisk=kmalloc(sizeof(struct simple_ramdisk),GFP_KERNEL);

                                        memset(sramdisk,0,sizeof(struct simple_ramdisk));

                                        sramdisk->size=SECTORS*SECTOR_SIZE;

                                        sramdisk->data=vmalloc(SECTORS*SECTOR_SIZE);

                                        memset(sramdisk->data,0,SECTORS*SECTOR_SIZE);

                                        if(!sramdisk->data) 

                                                        return -ENOMEM;

                                        spin_lock_init(&sramdisk->spin_lock);

                                         

                                         /* 1,上行通道;  */

                                         sramdisk->queue=blk_init_queue(request_fn_proc , &spin_lock);

                                         if(!sramdisk->queue)

                                                         return -ENODEV;

                                         blk_queue_physical_block_size(sramdisk->queue,SECTOR_SIZE);

                                         blk_queue_max_hw_sectors(sramdisk->queue,1024);

                                         

                                         /* 2,底层通道;  */

                                         sramdisk->disk=alloc_disk(1);//此处一定要是1,否则在insmod模块的时候需要check_partions就会挂起;

                                         sramdisk->disk->major=major;

                                         sramdisk->disk->first_minor=0;

                                         sramdisk->disk->ops=block_ops;

                                         sramdisk->disk->queue=sramdisk->queue;

                                         sramdisk->disk->private_data=sramdisk;

                                         snprintf(sramdisk->disk->disk_name,DISK_NAME_LEN,"simple_ramdisk%c",'a');

                                         set_capacity(sramdisk->disk,SECTORS*SECTOR_SIZE/512);

                                         add_disk(sramdisk->disk);

                            }


                      2,请求处理函数:

                           void transfer(struct simple_ramdisk *rd,sector_t sector,int sectors,u8 *buffer,bool iswrite){

                                        unsigned long offset=sector_t<<9;

                                        unsigned long len=sectors<<9;

                                        if(offset+len>rd->size)

                                                      return;


                                        if(iswrite){//向块设备写入数据;

                                                       memcpy(rd->data+offset,buffer,len); 

                                       } else {//从块设备读取数据到页缓存;

                                                       memcpy(buffer,rd->data+offset,len);

                                       }

                            }


                            void request_fn_proc(struct request_queue *queue){

                                           struct bio *bio;

                                           struct bio_vec *b_vec;

                                           struct bvec_iter bi_iter;

                                           struct request *rq;

                                           sector_t  sector;

                                           struct simple_ramdisk *sramdisk;

                                           while((rq=blk_queue_peek_request())!=NULL){

                                                 sramdisk=rq->rq_disk->private_data;

                                                 if(! blk_account_rq(rq)){

                                                           blk_start_request(rq);

                                                           blk_end_request_all(rq,-EIO);

                                                   continue; 

  }

                                                

                                                blk_start_request(rq);

                                                rq_for_each_bio(bio,rq){

                                                            sector=bio->bi_iter.sector

                                                           bio_for_each_segment(bvec,bio,bi_iter){

                                                                        u8 *buffer=__bio_kmap_atomic(bio,iter);

                                                                        transfer(sramdisk,sector,bio_cur_bytes(bio)>>9,buffer,rq_data_dir(rq)==WRITE);

                                                                        sector+=bio_cur_bytes(bio)>>9;

                                                                        __bio_kunmap_atomic(buffer);

                                                           }

                                               }

                                           }

                            }


                     3,块设备操作相关函数:

                           int simple_ramdisk_open(struct block_device *device,fmode_t mode){

                                          struct simple_ramdisk *srd=device->bd_disk->private_data;

                                          spin_lock_irqsave(flags);

                                           srd->user++;

                                          spin_unlock_irqrestore(flags);

                                           return 0;

                           }

 

                          void simple_ramdisk_release(struct gendisk *disk,fmode_t mode){

                                          struct simple_ramdisk *srd=device->bd_disk->private_data;

                                          spin_lock_irqsave(flags);

                                           srd->user--;

                                          spin_unlock_irqrestore(flags);


                          }


                          int   simple_ramdisk_rw_page(struct block_device *device , sector_t sector , struct page *page , bool iswrite){

                                            return endpage(page);

                          }

                            

                        struct block_device_operations block_ops={

                                                                                                               .open=simple_ramdisk_open,

                                                                                                               .release=simple_ramdisk_release,

                                                                                                               .rw_page=simple_ramdisk_rw_page

                                                                                                      };

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值