zoukankan      html  css  js  c++  java
  • 块设备驱动系统架构和简单设计

    1.块设备概念
    块设备是指只能以块(512Byte)为单位进行访问的设备,块大小一般是512个字节的整数倍。常见的块设备包括硬件,SD卡,光盘等。

    2.快速体验
    1. insmod simple-blk.ko
    2. ls /dev/simp_blkdev0
    3. mkfs.ext3 /dev/simp_blk0
    4. mkdir –p /mnt/blk
    5. mount /dev/simp_blk0 /mnt/blk
    6. cp /etc/init.d/* /mnt/blk
    7. ls /mnt/blk
    8. umount /mnt/blk
    9. ls /mnt/blk

    3.块设备驱动系统架构 

    VFS是对各种具体文件系统的一种封装 ,为用户程序访问文件提供统一的接口

    4.系统架构-Cache
    当用户发起文件访问请求的时候,首先会到Disk Cache中寻找文件是否被缓存了,如果在cache中,则直接从cache中读取。
    如果数据不在缓存中,就必须要到具体的文件系统中读取数据了。

    5.Mapping Layer(映射层、FS文件系统)
    1. 首先确定文件系统的block size,然后计算所请求的数据包含多少个block。
    2. 调用具体文件系统的函数来访问文件的inode结构,确定所请求的数据在磁盘上的地址。

    6. Generic Block Layer
    Linux内核把把块设备看作是由若干个扇区组成的数据空间。上层的读写请求在通用块层被构造成一个或多个bio结构。

    7. I/O Scheduler Layer
    I/O调度层负责采用某种算法(如:电梯调度算法)将I/O操作进行排序。


    8. I/O Scheduler Layer
    电梯调度算法的基本原则:如果电梯现在朝上运动,如果当前楼层的上方和下方都有请求,则先响应所有上方的请求,然后才向下响应下方的请求;如果电梯向下运动,则刚好相反。

    9.
    块设备驱动
    在块系统架构的最底层,由块设备驱动根据排序好的请求,对硬件进行数据访问。

    10.块设备驱动实例分析

    1. #include <linux/module.h>
    2. #include <linux/moduleparam.h>
    3. #include <linux/init.h>

    4. #include <linux/sched.h>
    5. #include <linux/kernel.h> /* printk() */
    6. #include <linux/slab.h> /* kmalloc() */
    7. #include <linux/fs.h> /* everything... */
    8. #include <linux/errno.h> /* error codes */
    9. #include <linux/timer.h>
    10. #include <linux/types.h> /* size_t */
    11. #include <linux/fcntl.h> /* O_ACCMODE */
    12. #include <linux/hdreg.h> /* HDIO_GETGEO */
    13. #include <linux/kdev_t.h>
    14. #include <linux/vmalloc.h>
    15. #include <linux/genhd.h>
    16. #include <linux/blkdev.h>
    17. #include <linux/buffer_head.h> /* invalidate_bdev */
    18. #include <linux/bio.h>

    19. MODULE_LICENSE("Dual BSD/GPL");

    20. static int major = 0;

    21. static int sect_size = 512;

    22. static int nsectors = 1024;

    23. /*
    24. * The internal representation of our device.
    25. */
    26. struct blk_dev{
    27.          int size; /* Device size in sectors */
    28.          u8 *data; /* The data array */
    29.          struct request_queue *queue; /* The device request queue */
    30.          struct gendisk *gd; /* The gendisk structure */
    31. };

    32. struct blk_dev *dev;


    33. /*
    34. * Handle an I/O request, in sectors.
    35. */
    36. static void blk_transfer(struct blk_dev *dev, unsigned long sector,
    37.    unsigned long nsect, char *buffer, int write)                                                                                    //扇区访问函数
    38. {
    39. unsigned long offset = sector*sect_size;
    40. unsigned long nbytes = nsect*sect_size;

    41. if ((offset + nbytes) > dev->size) {
    42.    printk (KERN_NOTICE "Beyond-end write (%ld %ld) ", offset, nbytes);
    43.    return;
    44. }
    45. if (write)
    46.    memcpy(dev->data + offset, buffer, nbytes);                                                                                       //对内存读写
    47. else
    48.    memcpy(buffer, dev->data + offset, nbytes);
    49. }

    50. /*
    51. * The simple form of the request function.
    52. */
    53. static void blk_request(struct request_queue *q)                                                                                      //实现读写请求处理函数
    54. {
    55. struct request *req;

    56. req = blk_fetch_request(q);                                                                                                           //从队列中取出一个请求
    57. while (req != NULL) {
    58.    struct blk_dev *dev = req->rq_disk->private_data;

    59.    blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));
    60.    
    61.    if(!__blk_end_request_cur(req, 0))                                                                                                 //判断请求队列是否为空
    62.    {
    63.     req = blk_fetch_request(q);                                                                                                       //嵌套处理
    64.    }
    65. }
    66. }

    67. /*
    68. * The device operations structure.
    69. */
    70. static struct block_device_operations blk_ops = {
    71. .owner = THIS_MODULE,
    72. };


    73. /*
    74. * Set up our internal device.
    75. */
    76. static void setup_device()
    77. {
    78. /*
    79. * Get some memory.
    80. */
    81. dev->size = nsectors*sect_size;                                                                                  //获取设备大小
    82. dev->data = vmalloc(dev->size);                                                                                  //获取数据指针
    83. if (dev->data == NULL) {
    84.    printk (KERN_NOTICE "vmalloc failure. ");
    85.    return;
    86. }

    87.    dev->queue = blk_init_queue(blk_request, NULL);                                                               //请求队列初始化,blk_request是处理上层传下来的请求的
    88.    if (dev->queue == NULL)
    89.     goto out_vfree;

    90. blk_queue_logical_block_size(dev->queue, sect_size);                                                             //指明扇区大小
    91. dev->queue->queuedata = dev;
    92. /*
    93. * And the gendisk structure.
    94. */
    95. dev->gd = alloc_disk(1);                                                                                         //为块设备分配gendisk结构,并初始化
    96. if (! dev->gd) {
    97.    printk (KERN_NOTICE "alloc_disk failure ");
    98.    goto out_vfree;
    99. }
    100. dev->gd->major = major;
    101. dev->gd->first_minor = 0;
    102. dev->gd->fops = &blk_ops;
    103. dev->gd->queue = dev->queue;
    104. dev->gd->private_data = dev;
    105. sprintf (dev->gd->disk_name, "simp_blk%d", 0);
    106. set_capacity(dev->gd, nsectors*(sect_size/sect_size));
    107. add_disk(dev->gd);                                                                                               //注册块设备
    108. return;

    109. out_vfree:
    110. if (dev->data)
    111.    vfree(dev->data);
    112. }

    113. static int __init blk_init(void)
    114. {
    115. /*
    116. * Get registered.
    117. */
    118. major = register_blkdev(major, "blk");                                                                  //注册块设备驱动,major若为0会自动分配
    119. if (major <= 0) {
    120.    printk(KERN_WARNING "blk: unable to get major number ");
    121.    return -EBUSY;
    122. }

    123. dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL);                                                      //分配一个blk_dev空间
    124. if (dev == NULL)
    125.    goto out_unregister;

    126.    setup_device();                                                                                      //调用函数
    127.      
    128. return 0;

    129. out_unregister:
    130. unregister_blkdev(major, "sbd");
    131. return -ENOMEM;
    132. }

    133. static void blk_exit(void)
    134. {

    135.    if (dev->gd) {
    136.     del_gendisk(dev->gd);
    137.     put_disk(dev->gd);
    138.    }
    139.    if (dev->queue)
    140.     blk_cleanup_queue(dev->queue);
    141.    if (dev->data)
    142.     vfree(dev->data);

    143.    unregister_blkdev(major, "blk");
    144. kfree(dev);
    145. }

    146. module_init(blk_init);
    147. module_exit(blk_exit);


    11、简单块设备驱动设计

    1. #include <linux/module.h>
    2. #include <linux/init.h>
    3. #include <linux/errno.h>
    4. #include <linux/blkdev.h>
    5. #include <linux/bio.h>
    6. #include <linux/string.h>
    7. #include <asm/uaccess.h>
    8. #include <linux/kernel.h>
    9. #include <linux/types.h>
    10. #include <linux/genhd.h>

    11. MODULE_LICENSE("GPL");

    12. static int major = 0;

    13. static int sect_size = 512;
    14. static int nsectors = 1024;

    15. struct blk_dev {
    16.     int size;
    17.     u8 *data;
    18.     struct request_queue *queue;
    19.     struct gendisk *gd;
    20. };

    21. struct blk_dev *dev;

    22. static void blk_transfer(struct blk_dev *dev, unsigned long sector, unsigned long nsect,char *buffer, int write)
    23. {
    24.     unsigned long offset = sector * sect_size;
    25.     unsigned long nbyte = nsect * sect_size;
    26.     
    27.     if((offset + nbyte) > dev->size)
    28.     {
    29.         printk(KERN_NOTICE"Beyond-end write (%ld %ld) ", offset, nbyte);
    30.     return;
    31.     }

    32.     if(write)
    33.     {
    34.         memcpy(dev->data + offset, buffer, nbyte);
    35.     }
    36.     else
    37.     {
    38.         memcpy(buffer, dev->data + offset, nbyte);
    39.     }
    40. }

    41. void blk_request(struct request_queue *q)
    42. {
    43.     struct request *req;
    44.     req = blk_fetch_request(q);

    45.     while(req != NULL)
    46.     {
    47.         struct blk_dev *dev = req->rq_disk->private_data;
    48.         //处理该请求
    49.     blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));
    50.     
    51.     if(!__blk_end_request_cur(req, 0))
    52.      req = blk_fetch_request(q);
    53.     }

    54. }

    55. static struct block_device_operations blk_ops = {
    56.     .owner = THIS_MODULE,
    57. };

    58. static void setup_device(void)
    59. {
    60.     dev->size = nsectors * sect_size;
    61.     dev->data = vmalloc(dev->size);
    62.     if(dev->data == NULL) {
    63.         printk(KERN_NOTICE "vmalloc failure. ");
    64.     return;
    65.     }
    66.     
    67.     dev->queue = blk_init_queue(blk_request, NULL);
    68.     if(dev->queue == NULL)
    69.     {
    70.         goto out_vfree;
    71.     }
    72.     
    73.     blk_queue_logical_block_size(dev->queue, sect_size);
    74.     dev->queue->queuedata = dev;

    75.     dev->gd = alloc_disk(1);
    76.     if(!dev->gd)
    77.     {
    78.         printk(KERN_NOTICE "alloc_disk failure ");
    79.     goto out_vfree;
    80.     }

    81.     dev->gd->major = major;
    82.     dev->gd->first_minor = 0;
    83.     dev->gd->fops = &blk_ops;
    84.     dev->gd->queue = dev->queue;
    85.     dev->gd->private_data = dev;
    86.     sprintf(dev->gd->disk_name, "simp_blk%d", 0);

    87.     set_capacity(dev->gd, nsectors);
    88.     add_disk(dev->gd);
    89.     return;

    90. out_vfree:
    91.     if(dev->data)
    92.         vfree(dev->data);
    93. }

    94. static int __init blk_init(void)
    95. {
    96.     major = register_blkdev(0, "blk");
    97.     if(major <= 0)
    98.     {
    99.         printk(KERN_WARNING "register blk dev fail! ");
    100.     return -EBUSY;
    101.     }

    102.     dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL);
    103.     if(dev == NULL)
    104.         goto out_unregister;

    105.     setup_device();

    106.     return 0;
    107. out_unregister:
    108.     unregister_blkdev(major, "sbd");
    109.     return -ENOMEM;
    110. }

    111. static void blk_exit(void)
    112. {
    113.     del_gendisk(dev->gd);
    114.     blk_cleanup_queue(dev->queue);
    115.     vfree(dev->data);
    116.     unregister_blkdev(major, "blk");
    117.     kfree(dev);
    118. }

    119. module_init(blk_init);
    120. module_exit(blk_exit);

    错误总结:一开始写的时候,编译完加载进内核。直接死机,因为代码有点长。就从逻辑处一点一点注释掉来分析,果然有好多错误。
    第一次遇到的问题,内核中常用goto跳转处理错误情况。如果跳转处前面没有return就坑爹了,第一次遇到找了好久

    无欲速,无见小利。欲速,则不达;见小利,则大事不成。
  • 相关阅读:
    每日英语:AntiJapan Protests Flare in China
    opencv CvMat矩阵学习
    warning C4018有符号无符号不匹配
    每日英语:Relationship Repair: 10 Tips for Thinking Like a Therapist
    结构体数组定义和引用
    每日英语:China's Conflicted Consumers
    一个托盘程序, 简化notifyicon的使用.
    nunit notes from TDD in .net
    一款能拖拉的winform树形控件
    vss 2005 internet visit
  • 原文地址:https://www.cnblogs.com/ch122633/p/7363297.html
Copyright © 2011-2022 走看看