Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1729731
  • 博文数量: 358
  • 博客积分: 2180
  • 博客等级: 大尉
  • 技术积分: 1810
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-17 13:47
文章分类

全部博文(358)

文章存档

2016年(17)

2015年(55)

2014年(9)

2013年(67)

2012年(181)

2011年(29)

分类:

2012-03-27 12:03:32

字符设备与块设备I/O操作的不同如下:
(1)块设备只能以块为单位接受输入和返回输出,而字符设备则以字节为单位。大多数设备是字符设备,因为他们不需要缓冲而且不以固定块大小进行操作。
(2)块设备对于I/O请求有对应的缓冲区,因此它们可以选择以什么顺序进行响应,字符设备无需缓冲且被直接读写。对于存存储设备而言调整读写的顺序作用巨大,因为在读写连续的扇区比分离扇区更快。
(3)字符设备只能被顺序读写,而块设备可以随机访问。虽然块设备可以随机访问,但对于磁盘这类机械设备而言,顺序地组织块设备的访问可以提高性能。

之所以引入块设备就是因为在操作机械设备如磁盘的时候,如果同一时间要去读和写不同的扇区(先读一个扇区,再写另一个扇区,再读另外的扇区),读写这个过程比较快,但是定位就要占很部分的时间,所以做一下调整,先读完了再去写,这样就可以减速少定位花去的时间,总体上让读写速度得到提高。

框架:

app:      open,read,write "1.txt"
---------------------------------------------  文件的读写
文件系统: vfat, ext2, ext3, yaffs2, jffs2      (把文件的读写转换为扇区的读写)
-----------------ll_rw_block-----------------  扇区的读写
                       1. 把"读写"放入队列
                       2. 调用队列的处理函数(优化/调顺序/合并)
            块设备驱动程序     
---------------------------------------------
硬件:        硬盘,flash

分析ll_rw_block
        for (i = 0; i < nr; i++) {   /* nr 请求个数 */
            struct buffer_head *bh = bhs[i];
            submit_bh(rw, bh);
                struct bio *bio; // 使用bh来构造bio (block input/output)
                submit_bio(rw, bio);
                    // 通用的构造请求: 使用bio来构造请求(request)
                    generic_make_request(bio);
                        __generic_make_request(bio);
                            request_queue_t *q = bdev_get_queue(bio->bi_bdev); // 找到队列  
                            
                            // 调用队列的"构造请求函数"
                            ret = q->make_request_fn(q, bio);
                                    // 默认的函数是__make_request
                                    __make_request
                                        // 先尝试合并
                                        elv_merge(q, &req, bio);
                                        
                                        // 如果合并不成,使用bio构造请求
                                        init_request_from_bio(req, bio);
                                        
                                        // 把请求放入队列
                                        add_request(q, req);
                                        
                                        // 执行队列
                                        __generic_unplug_device(q);
                                                // 调用队列的"处理函数"
                                                q->request_fn(q);
            
怎么写块设备驱动程序呢?
1. 分配gendisk: alloc_disk
2. 设置
2.1 分配/设置队列: request_queue_t  // 它提供读写能力
    blk_init_queue
2.2 设置gendisk其他信息             // 它提供属性: 比如容量
3. 注册: add_disk


点击(此处)折叠或打开

  1. /* 参考xd.c z2ram.c这两个文件 */
  2. #include <linux/module.h>
  3. #include <linux/errno.h>
  4. #include <linux/interrupt.h>
  5. #include <linux/mm.h>
  6. #include <linux/fs.h>
  7. #include <linux/kernel.h>
  8. #include <linux/timer.h>
  9. #include <linux/genhd.h>
  10. #include <linux/hdreg.h>
  11. #include <linux/ioport.h>
  12. #include <linux/init.h>
  13. #include <linux/wait.h>
  14. #include <linux/blkdev.h>
  15. #include <linux/blkpg.h>
  16. #include <linux/delay.h>
  17. #include <linux/io.h>

  18. #include <asm/system.h>
  19. #include <asm/uaccess.h>
  20. #include <asm/dma.h>

  21. static struct gendisk *ramblock_disk;
  22. static request_queue *ramblock_queue;
  23. static int major;
  24. #define RAMBLOCK_SIZE (1024*1024)     /* 分配大小1MB */
  25. static unsigned char *ramblock_buf;   /* 缓冲区 */


  26. static DEFINE_SPINLOCK(ramblock_lock);  /* 定义一个自旋锁 */

  27. static int ramblock_getgeo(ramblock_disk, struct hd_geometry *geo)
  28. {/* 容量 = heads*cylinders*sectors*512 最后512是一个扇区有512个字节 */
  29.  // geo->heads = unit[drive].type->heads; /* 磁头数 */
  30.     geo->heads = 2;
  31.  // geo->cylinders = unit[drive].type->tracks; /* cyllinders 柱面数 */
  32.     geo->cylinders = 32;
  33.  // geo->sectors = unit[drive].dtype->sects * unit[drive].type->sect_mult; /* 扇区数 */
  34.     geo->sectors = RAMBLOCK_SIZE/2/32/512 /* 单位为字节 */
  35.     return 0;
  36. }

  37. static struct block_device_operations ramblock_fops = {
  38.     .owner    = THIS_MODULE,
  39.     //.ioctl    = ramblock_ioctl,
  40.     .getgeo = ramblock_getgeo, /* geo geometry几何 getgeo获得几何属性 */
  41. };

  42. static void do_ramblock_request(request_queue_t *q)
  43. {
  44.     static int r_cnt = 0;
  45.     static int w_cnt = 0;
  46.     struct request *req;
  47.    // printk("do_ramblock_request %d\n", ++cnt);
  48.     /* 以电梯调度算法(elv)取出下一个请求 */
  49.     while ((req = elv_next_request(q)) != NULL) {
  50.         /* 数据传输三要素:源、目的、长度 */
  51.         /*/目的 */
  52.         unsigned long offset = req->sector << 9; /* 左移9位相当于乘以512(一个扇区的大小) */
  53.         /* 目的/*/
  54.         // req->buffer
  55.         /* 长度 */
  56.         unsigned long len = req->current_nr_sectors << 9;
  57.         if (rq_data_dir(req) == READ)
  58.         {
  59.         
  60.            // printk("do_ramblock_request read%d\n", ++r_cnt);
  61.             memcpy(req->buffer, ramblock_buf + offset, len); /* 这里是直接从内存拷,如果                                                     是实际的设备则要涉及相关的硬件操作 */
  62.         }
  63.         else
  64.         {
  65.             //printk("do_ramblock_request write%d\n", ++w_cnt);
  66.             memcpy(ramblock_buf + offset, req->buffer, len);
  67.         }
  68.         end_request(req,1); /* 1表示成功,0表失败 */
  69.     }
  70. }

  71. static int ramblock_init(void)
  72. {
  73.     /* 1.分配一个gendisk结构体 */
  74.     ramblock_disk = alloc_disk(16); /* minors是指次设备号个数即分区个数 + 1
  75.   当minors为0时,表示整个磁盘,minors为1时表示只有一个磁盘分区且不可再分区 */
  76.     /* 2.设置gendisk结构体 */
  77.     /* 2.1 分配/设置一个队列 提供读写能力 */
  78.     ramblock_queue = blk_init_queue(do_ramblock_request, ramblock_lock);
  79.     ramblock_disk ->queue = ramblock_queue;
  80.     
  81.     /* 2.2 设置其他属性:比如容量等 */
  82.     major = register_blkdev(0,"ramblock"); /* cat /proc/devices */
  83.     ramblock_disk->major = major;
  84.     ramblock_disk->first_minor = 0;
  85.     sprintf(ramblock_disk->disk_name, "ramblock");
  86.     ramblock_disk->fops = &ramblock_fops;
  87.    // ramblock_disk->private_data = p;
  88.    // ramblock_disk->quese = ramdisk_queue;
  89.     set_capacity(ramblock_disk, RAMBLOCK_SIZE/512); /* 容量是以扇区为单位 */
  90.     /* 3.硬件相关操作 分配内存 */
  91.     ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);
  92.     /* 4.注册 */
  93.     add_disk(ramblock_disk)
  94.     return 0;
  95. }

  96. static void ramblock_exit(void)
  97. {
  98.     unregister_blkdev( major, "ramblock");
  99.     del_gendisk(ramblock_disk);
  100.     put_disk(ramblock_disk);
  101.     blk_cleanup_queue(ramblock_queue);
  102.     kfree(ramblock_buf);
  103. }

  104. module_init(ramblock_init);
  105. module_exit(ramblock_exit);


  106. MODULE_DESCRIPTION("block driver test for the s3c2440");
  107. MODULE_LICENSE("GPL");

阅读(717) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~