Linux设备驱动

 

前面, 我们已经研究了水源所作的在队列中优化请求顺序的劳作;
这么些工作包括排列请求和, 或许, 甚至延迟队列来允许一个预料的央浼到达.
这一个技术在拍卖一个真正的转动的磁盘驱动器时有助于系统的性能. 不过,
许多面向块的设施, 例如闪存阵列, 用于数字相机的存储卡的读取器、u盘等,
并且 RAM 盘真正地有随机存取的习性, 包含从高级的乞请队列逻辑中收益.
其他装备, 例如软件 RAID 阵列或者被逻辑卷管理者制造的虚拟磁盘,
没有这一个块层的请求队列被优化的性质特征. 对于这类设备,
它最好直接从块层接收请求, 并且根本不去烦请求队列.

这时候我们就不用内核提供的IO调度器来优化排列和归并请求,不用内核的__make_request 帮大家处理bio,而是大家协调处理bio

多少流程

当我们初阶化一个呼吁队列

[cpp] view
plain
 copy

 

 print?

  1. struct request_queue *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)  
  2. {  
  3.     return blk_init_queue_node(rfn, lock, -1);  
  4. }  

把请求队列和那个根本已经实现好的函数绑定起来,__make_request就是承担创建请求request

[cpp] view
plain
 copy

 

 print?

  1. blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)  
  2. {  
  3.     struct request_queue *q = blk_alloc_queue_node(GFP_KERNEL, node_id);  
  4.     ……  
  5.     blk_queue_make_request(q, __make_request);  
  6.     ……  
  7. }  

 

[cpp] view
plain
 copy

 

 print?

  1. static int __make_request(struct request_queue *q, struct bio *bio)  

其一bio就是最基本的读写不同扇区的伸手,经过__make_request处理后,经过优化重回request

而是,在此地早已不需要了,我们要一向处理bio,来一个处理一个。

分配“请求队列” request_queue_t *blk_alloc_queue(int gfp_mask);
对于FLASH、RAM盘等统统自由走访的非机械设备,并不需要举办复杂的I/O调度,这多少个时候,应该运用上述函数分配1个“请求队列”,并使用如下函数来绑定“请求队列”和“创立请求”函数。
void blk_queue_make_request(request_queue_t * q, make_request_fn
* mfn);

void blk_queue_hardsect_size(request_queue_t *queue, unsigned
short max); 
该函数用于告知内核块设备硬件扇区的大小,所有由基础发生的呼吁都是其一分寸的倍数并且被科学对界。可是,内核块设备层和驱动之间的通信仍然以512字节扇区为单位举办。

绑定请求队列和“创建请求”函数

void blk_queue_make_request(struct request_queue *q,
make_request_fn *mfn)

一个”创制请求”函数来处理bio, make_request 函数有其一原型:

[cpp] view
plain
 copy

 

 print?

  1. typedef int (make_request_fn) (request_queue_t *q, struct bio *bio);   

参照代码:

[cpp] view
plain
 copy

 

 print?

  1. #include <linux/init.h>  
  2. #include <linux/module.h>  
  3. #include <linux/kernel.h>  
  4. #include <linux/fs.h>  
  5. #include <linux/errno.h>  
  6. #include <linux/types.h>  
  7. #include <linux/fcntl.h>  
  8. #include <linux/vmalloc.h>  
  9. #include <linux/hdreg.h>  
  10. #include <linux/blkdev.h>  
  11. #include <linux/blkpg.h>  
  12. #include <asm/uaccess.h>  
  13.   
  14. #define BLK_NAME “ram_blk”  
  15. #define BLK_MAJOR 222  
  16. #define DISK_SECTOR_SIZE 512 //每扇区大小  
  17. #define DISK_SECTOR 1024  //总扇区数,  
  18. #define DISK_SIZE (DISK_SECTOR_SIZE*DISK_SECTOR)//总大小,共0.5M  
  19.   
  20. typedef struct//设备结构体  
  21. {  
  22.        unsigned char          *data;  
  23.        struct request_queue   *queue;  
  24.        struct gendisk         *gd;  
  25. } disk_dev;  
  26.   
  27. disk_dev device;//定义设备结构体  
  28.   
  29. //————————————————————————–  
  30. //在硬盘等带柱面扇区等的设施上选取request,可以整理队列。不过ramdisk等能够  
  31. //使用make_request  
  32. static int disk_make_request(struct request_queue *q,struct bio *bio)  
  33. {  
  34.        int i;  
  35.        char *mem_pbuf;  
  36.        char *disk_pbuf;  
  37.        disk_dev *pdevice;  
  38.        struct bio_vec *pbvec;  
  39.        /*在遍历段在此以前先判断要传输数据的总长度大小是否超过限制*/  
  40.        i=bio->bi_sector*DISK_SECTOR_SIZE+bio->bi_size;  
  41.        if(i>DISK_SIZE)//判断是否超出范围  
  42.               goto fail;  
  43.          
  44.        pdevice=(disk_dev*)bio->bi_bdev->bd_disk->private_data;//得到设备结构体  
  45.        disk_pbuf=pdevice->data+bio->bi_sector*DISK_SECTOR_SIZE;//得到要读写的开场地点  
  46.          
  47.        /*开始遍历这些bio中的每个bio_vec*/  
  48.        bio_for_each_segment(pbvec,bio,i)//循环分散的内存segment  
  49.        {  
  50.               mem_pbuf=kmap(pbvec->bv_page)+pbvec->bv_offset;//得到实际内存地址  
  51.               switch(bio_data_dir(bio))  
  52.               {//读写  
  53.                      case READA:  
  54.                      case READ:  
  55.                             memcpy(mem_pbuf,disk_pbuf,pbvec->bv_len);  
  56.                             break;  
  57.                      case WRITE:  
  58.                             memcpy(disk_pbuf,mem_pbuf,pbvec->bv_len);  
  59.                             break;  
  60.                      default:  
  61.                             kunmap(pbvec->bv_page);  
  62.                             goto fail;  
  63.               }  
  64.               kunmap(pbvec->bv_page);//清除映射  
  65.               disk_pbuf+=pbvec->bv_len;  
  66.        }  
  67.        bio_endio(bio,0);//这多少个函数2.6.25和2.6.4是不相同的,  
  68.        return 0;  
  69. fail:  
  70.        bio_io_error(bio);//这几个函数2.6.25和2.6.4是不一致的,  
  71.        return 0;  
  72. }  
  73.   
  74. int blk_open(struct block_device *dev, fmode_t no)   
  75. {  
  76.        return 0;  
  77. }  
  78.   
  79. int blk_release(struct gendisk *gd, fmode_t no)  
  80. {  
  81.        return 0;  
  82. }  
  83.   
  84. int blk_ioctl(struct block_device *dev, fmode_t no, unsigned cmd, unsigned long arg)  
  85. {  
  86.        return -ENOTTY;  
  87. }  
  88.   
  89. static struct block_device_operations blk_fops=  
  90. {  
  91.        .owner=THIS_MODULE,  
  92.        .open=blk_open,//  
  93.        .release=blk_release,//  
  94.        .ioctl=blk_ioctl,//   
  95. };  
  96.   
  97. int disk_init(void)  
  98. {  
  99.         if(!register_blkdev(BLK_MAJOR,BLK_NAME));//注册驱动  
  100.     {  
  101.          printk(“register blk_dev succeed\n”);  
  102.     }  
  103.       
  104.        device.data=vmalloc(DISK_SIZE);  
  105.        device.queue=blk_alloc_queue(GFP_KERNEL);//生成队列  
  106.        blk_queue_make_request(device.queue,disk_make_request);/*注册make_request  绑定请求创立函数*/  
  107.   
  108.     printk(“make_request succeed\n”);  
  109.   
  110.        device.gd=alloc_disk(1);//生成gendisk  
  111.        device.gd->major=BLK_MAJOR;//主设备号  
  112.        device.gd->first_minor=0;//此设施号  
  113.        device.gd->fops=&blk_fops;//块文件结构体变量  
  114.        device.gd->queue=device.queue;//请求队列  
  115.        device.gd->private_data=&device;  
  116.        sprintf(device.gd->disk_name,”disk%c”,’a’);//名字  
  117.        set_capacity(device.gd,DISK_SECTOR);//设置大小  
  118.        add_disk(device.gd);//注册块设备音信  
  119.     printk(“gendisk succeed\n”);      
  120.        return 0;  
  121. }  
  122.   
  123. void disk_exit(void)  
  124. {  
  125.       
  126.        del_gendisk(device.gd);  
  127.        put_disk(device.gd);  
  128.        unregister_blkdev(BLK_MAJOR,BLK_NAME);  
  129.        vfree(device.data);  
  130.         printk(“free succeed\n”);  
  131.       
  132. }  
  133.   
  134. module_init(disk_init);  
  135. module_exit(disk_exit);  
  136.   
  137. MODULE_LICENSE(“Dual BSD/GPL”);     

相关文章