块设备驱动系统架构和简单设计

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就坑爹了,第一次遇到找了好久

无欲速,无见小利。欲速,则不达;见小利,则大事不成。
原文地址:https://www.cnblogs.com/ch122633/p/7363297.html