您的位置:首页 > 运维架构 > 网站架构

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

2017-08-15 09:08 288 查看
1.块设备概念

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

2.快速体验

insmod simple-blk.ko

ls /dev/simp_blkdev0

mkfs.ext3 /dev/simp_blk0

mkdir –p /mnt/blk

mount /dev/simp_blk0 /mnt/blk

cp /etc/init.d/* /mnt/blk

ls /mnt/blk

umount /mnt/blk

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.块设备驱动实例分析

#include <linux/module.h>

#include <linux/moduleparam.h>

#include <linux/init.h>

#include <linux/sched.h>

#include <linux/kernel.h> /* printk() */

#include <linux/slab.h> /* kmalloc() */

#include <linux/fs.h> /* everything... */

#include <linux/errno.h> /* error codes */

#include <linux/timer.h>

#include <linux/types.h> /* size_t */

#include <linux/fcntl.h> /* O_ACCMODE */

#include <linux/hdreg.h> /* HDIO_GETGEO */

#include <linux/kdev_t.h>

#include <linux/vmalloc.h>

#include <linux/genhd.h>

#include <linux/blkdev.h>

#include <linux/buffer_head.h> /* invalidate_bdev */

#include <linux/bio.h>

MODULE_LICENSE("Dual BSD/GPL");

static int major = 0;

static int sect_size = 512;

static int nsectors = 1024;

/*

* The internal representation of our device.

*/

struct blk_dev{

         int size; /* Device size in sectors */

         u8 *data; /* The data array */

         struct request_queue *queue; /* The device request queue */

         struct gendisk *gd; /* The gendisk structure */

};

struct blk_dev *dev;

/*

* Handle an I/O request, in sectors.

*/

static void blk_transfer(struct blk_dev *dev, unsigned long sector,

   unsigned long nsect, char *buffer, int write)                                                                                    //扇区访问函数

{

unsigned long offset = sector*sect_size;

unsigned long nbytes = nsect*sect_size;

if ((offset + nbytes) > dev->size) {

   printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);

   return;

}

if (write)

   memcpy(dev->data + offset, buffer, nbytes);                                                                                       //对内存读写

else

   memcpy(buffer, dev->data + offset, nbytes);

}

/*

* The simple form of the request function.

*/

static void blk_request(struct request_queue *q)                                                                                      //实现读写请求处理函数

{

struct request *req;

req = blk_fetch_request(q);                                                                                                           //从队列中取出一个请求

while (req != NULL) {

   struct blk_dev *dev = req->rq_disk->private_data;

   blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));

   

   if(!__blk_end_request_cur(req, 0))                                                                                                 //判断请求队列是否为空

   {

    req = blk_fetch_request(q);                                                                                                       //嵌套处理

   }

}

}

/*

* The device operations structure.

*/

static struct block_device_operations blk_ops = {

.owner = THIS_MODULE,

};

/*

* Set up our internal device.

*/

static void setup_device()

{

/*

* Get some memory.

*/

dev->size = nsectors*sect_size;                                                                                  //获取设备大小

dev->data = vmalloc(dev->size);                                                                                  //获取数据指针

if (dev->data == NULL) {

   printk (KERN_NOTICE "vmalloc failure.\n");

   return;

}

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

   if (dev->queue == NULL)

    goto out_vfree;

blk_queue_logical_block_size(dev->queue, sect_size);                                                             //指明扇区大小

dev->queue->queuedata = dev;

/*

* And the gendisk structure.

*/

dev->gd = alloc_disk(1);                                                                                         //为块设备分配gendisk结构,并初始化

if (! dev->gd) {

   printk (KERN_NOTICE "alloc_disk failure\n");

   goto out_vfree;

}

dev->gd->major = major;

dev->gd->first_minor = 0;

dev->gd->fops = &blk_ops;

dev->gd->queue = dev->queue;

dev->gd->private_data = dev;

sprintf (dev->gd->disk_name, "simp_blk%d", 0);

set_capacity(dev->gd, nsectors*(sect_size/sect_size));

add_disk(dev->gd);                                                                                               //注册块设备

return;

out_vfree:

if (dev->data)

   vfree(dev->data);

}

static int __init blk_init(void)

{

/*

* Get registered.

*/

major = register_blkdev(major, "blk");                                                                  //注册块设备驱动,major若为0会自动分配

if (major <= 0) {

   printk(KERN_WARNING "blk: unable to get major number\n");

   return -EBUSY;

}

dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL);                                                      //分配一个blk_dev空间

if (dev == NULL)

   goto out_unregister;

   setup_device();                                                                                      //调用函数

     

return 0;

out_unregister:

unregister_blkdev(major, "sbd");

return -ENOMEM;

}

static void blk_exit(void)

{

   if (dev->gd) {

    del_gendisk(dev->gd);

    put_disk(dev->gd);

   }

   if (dev->queue)

    blk_cleanup_queue(dev->queue);

   if (dev->data)

    vfree(dev->data);

   unregister_blkdev(major, "blk");

kfree(dev);

}

module_init(blk_init);

module_exit(blk_exit);



11、简单块设备驱动设计

#include <linux/module.h>

#include <linux/init.h>

#include <linux/errno.h>

#include <linux/blkdev.h>

#include <linux/bio.h>

#include <linux/string.h>

#include <asm/uaccess.h>

#include <linux/kernel.h>

#include <linux/types.h>

#include <linux/genhd.h>

MODULE_LICENSE("GPL");

static int major = 0;

static int sect_size = 512;

static int nsectors = 1024;

struct blk_dev {

    int size;

    u8 *data;

    struct request_queue *queue;

    struct gendisk *gd;

};

struct blk_dev *dev;

static void blk_transfer(struct blk_dev *dev, unsigned long sector, unsigned long nsect,char *buffer, int write)

{

    unsigned long offset = sector * sect_size;

    unsigned long nbyte = nsect * sect_size;

    

    if((offset + nbyte) > dev->size)

    {

        printk(KERN_NOTICE"Beyond-end write (%ld %ld)\n", offset, nbyte);

    return;

    }

    if(write)

    {

        memcpy(dev->data + offset, buffer, nbyte);

    }

    else

    {

        memcpy(buffer, dev->data + offset, nbyte);

    }

}

void blk_request(struct request_queue *q)

{

    struct request *req;

    req = blk_fetch_request(q);

    while(req != NULL)

    {

        struct blk_dev *dev = req->rq_disk->private_data;

        //处理该请求

    blk_transfer(dev, blk_rq_pos(req), blk_rq_cur_sectors(req), req->buffer, rq_data_dir(req));

    

    if(!__blk_end_request_cur(req, 0))

     req = blk_fetch_request(q);

    }

}

static struct block_device_operations blk_ops = {

    .owner = THIS_MODULE,

};

static void setup_device(void)

{

    dev->size = nsectors * sect_size;

    dev->data = vmalloc(dev->size);

    if(dev->data == NULL) {

        printk(KERN_NOTICE "vmalloc failure.\n");

    return;

    }

    

    dev->queue = blk_init_queue(blk_request, NULL);

    if(dev->queue == NULL)

    {

        goto out_vfree;

    }

    

    blk_queue_logical_block_size(dev->queue, sect_size);

    dev->queue->queuedata = dev;

    dev->gd = alloc_disk(1);

    if(!dev->gd)

    {

        printk(KERN_NOTICE "alloc_disk failure\n");

    goto out_vfree;

    }

    dev->gd->major = major;

    dev->gd->first_minor = 0;

    dev->gd->fops = &blk_ops;

    dev->gd->queue = dev->queue;

    dev->gd->private_data = dev;

    sprintf(dev->gd->disk_name, "simp_blk%d", 0);

    set_capacity(dev->gd, nsectors);

    add_disk(dev->gd);

    return;

out_vfree:

    if(dev->data)

        vfree(dev->data);

}

static int __init blk_init(void)

{

    major = register_blkdev(0, "blk");

    if(major <= 0)

    {

        printk(KERN_WARNING "register blk dev fail!\n");

    return -EBUSY;

    }

    dev = kmalloc(sizeof(struct blk_dev), GFP_KERNEL);

    if(dev == NULL)

        goto out_unregister;

    setup_device();

    return 0;

out_unregister:

    unregister_blkdev(major, "sbd");

    return -ENOMEM;

}

static void blk_exit(void)

{

    del_gendisk(dev->gd);

    blk_cleanup_queue(dev->queue);

    vfree(dev->data);

    unregister_blkdev(major, "blk");

    kfree(dev);

}

module_init(blk_init);

module_exit(blk_exit);

错误总结:一开始写的时候,编译完加载进内核。直接死机,因为代码有点长。就从逻辑处一点一点注释掉来分析,果然有好多错误。

第一次遇到的问题,内核中常用goto跳转处理错误情况。如果跳转处前面没有return就坑爹了,第一次遇到找了好久


<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>

阅读(68) | 评论(0) | 转发(0) |

0
上一篇:LCD驱动程序架构和分析

下一篇:MTD系统架构和yaffs2使用、Nandflash驱动设计

相关热门文章
SHTML是什么_SSI有什么用...

查看linux中某个端口(port)...

卡尔曼滤波的原理说明...

shell中字符串操作

关于java中的“错误:找不到或...

给主人留下些什么吧!~~

评论热议
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: