zoukankan      html  css  js  c++  java
  • 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 ");  
    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 ");  
    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 ");      
    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 ");  
    131.       
    132. }  
    133.   
    134. module_init(disk_init);  
    135. module_exit(disk_exit);  
    136.   
    137. MODULE_LICENSE("Dual BSD/GPL");  
     
     
     
  • 相关阅读:
    左偏树
    论在Windows下远程连接Ubuntu
    ZOJ 3711 Give Me Your Hand
    SGU 495. Kids and Prizes
    POJ 2151 Check the difficulty of problems
    CodeForces 148D. Bag of mice
    HDU 3631 Shortest Path
    HDU 1869 六度分离
    HDU 2544 最短路
    HDU 3584 Cube
  • 原文地址:https://www.cnblogs.com/Ph-one/p/6436002.html
Copyright © 2011-2022 走看看