前面, 我们已经讨论了内核所作的在队列中优化请求顺序的工作; 这个工作包括排列请求和, 或许, 甚至延迟队列来允许一个预期的请求到达. 这些技术在处理一个真正的旋转的磁盘驱动器时有助于系统的性能. 但是, 许多面向块的设备, 例如闪存阵列, 用于数字相机的存储卡的读取器、u盘等, 并且 RAM 盘真正地有随机存取的性能, 包含从高级的请求队列逻辑中获益. 其他设备, 例如软件 RAID 阵列或者被逻辑卷管理者创建的虚拟磁盘, 没有这个块层的请求队列被优化的性能特征. 对于这类设备, 它最好直接从块层接收请求, 并且根本不去烦请求队列.

这时候我们就不用内核提供的IO调度器来优化排列和合并请求,不用内核的__make_request 帮我们处理bio,而是我们自己处理bio

数据流程

当我们初始化一个请求队列

struct request_queue *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)
{
return blk_init_queue_node(rfn, lock, -);
}

把请求队列和这个内核已经实现好的函数绑定起来,__make_request就是负责制造请求request 的

blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
{
struct request_queue *q = blk_alloc_queue_node(GFP_KERNEL, node_id);
......
blk_queue_make_request(q, __make_request);
......
}
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 函数有这个原型:

typedef int (make_request_fn) (request_queue_t *q, struct bio *bio);  

参考代码:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/vmalloc.h>
#include <linux/hdreg.h>
#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <asm/uaccess.h> #define BLK_NAME "ram_blk"
#define BLK_MAJOR 222
#define DISK_SECTOR_SIZE 512 //每扇区大小
#define DISK_SECTOR 1024 //总扇区数,
#define DISK_SIZE (DISK_SECTOR_SIZE*DISK_SECTOR)//总大小,共0.5M typedef struct//设备结构体
{
unsigned char *data;
struct request_queue *queue;
struct gendisk *gd;
} disk_dev; disk_dev device;//定义设备结构体 //--------------------------------------------------------------------------
//在硬盘等带柱面扇区等的设备上使用request,可以整理队列。但是ramdisk等可以
//使用make_request
static int disk_make_request(struct request_queue *q,struct bio *bio)
{
int i;
char *mem_pbuf;
char *disk_pbuf;
disk_dev *pdevice;
struct bio_vec *pbvec;
/*在遍历段之前先判断要传输数据的总长度大小是否超过范围*/
i=bio->bi_sector*DISK_SECTOR_SIZE+bio->bi_size;
if(i>DISK_SIZE)//判断是否超出范围
goto fail; pdevice=(disk_dev*)bio->bi_bdev->bd_disk->private_data;//得到设备结构体
disk_pbuf=pdevice->data+bio->bi_sector*DISK_SECTOR_SIZE;//得到要读写的起始位置 /*开始遍历这个bio中的每个bio_vec*/
bio_for_each_segment(pbvec,bio,i)//循环分散的内存segment
{
mem_pbuf=kmap(pbvec->bv_page)+pbvec->bv_offset;//获得实际内存地址
switch(bio_data_dir(bio))
{//读写
case READA:
case READ:
memcpy(mem_pbuf,disk_pbuf,pbvec->bv_len);
break;
case WRITE:
memcpy(disk_pbuf,mem_pbuf,pbvec->bv_len);
break;
default:
kunmap(pbvec->bv_page);
goto fail;
}
kunmap(pbvec->bv_page);//清除映射
disk_pbuf+=pbvec->bv_len;
}
bio_endio(bio,);//这个函数2.6.25和2.6.4是不一样的,
return ;
fail:
bio_io_error(bio);//这个函数2.6.25和2.6.4是不一样的,
return ;
} int blk_open(struct block_device *dev, fmode_t no)
{
return ;
} int blk_release(struct gendisk *gd, fmode_t no)
{
return ;
} int blk_ioctl(struct block_device *dev, fmode_t no, unsigned cmd, unsigned long arg)
{
return -ENOTTY;
} static struct block_device_operations blk_fops=
{
.owner=THIS_MODULE,
.open=blk_open,//
.release=blk_release,//
.ioctl=blk_ioctl,//
}; int disk_init(void)
{
if(!register_blkdev(BLK_MAJOR,BLK_NAME));//注册驱动
{
printk("register blk_dev succeed\n");
} device.data=vmalloc(DISK_SIZE);
device.queue=blk_alloc_queue(GFP_KERNEL);//生成队列
blk_queue_make_request(device.queue,disk_make_request);/*注册make_request 绑定请求制造函数*/ printk("make_request succeed\n"); device.gd=alloc_disk();//生成gendisk
device.gd->major=BLK_MAJOR;//主设备号
device.gd->first_minor=;//此设备号
device.gd->fops=&blk_fops;//块文件结构体变量
device.gd->queue=device.queue;//请求队列
device.gd->private_data=&device;
sprintf(device.gd->disk_name,"disk%c",'a');//名字
set_capacity(device.gd,DISK_SECTOR);//设置大小
add_disk(device.gd);//注册块设备信息
printk("gendisk succeed\n");
return ;
} void disk_exit(void)
{ del_gendisk(device.gd);
put_disk(device.gd);
unregister_blkdev(BLK_MAJOR,BLK_NAME);
vfree(device.data);
printk("free succeed\n"); } module_init(disk_init);
module_exit(disk_exit); MODULE_LICENSE("Dual BSD/GPL");

http://blog.csdn.net/jianchi88/article/details/7213290

最新文章

  1. java 给指定时间加上天数or给当前日期加天数
  2. 利用CSS制作三角形
  3. jQuery in action 3rd - Working with properties, attributes, and data
  4. css3:盒模型以及box-sizing属性
  5. 0517Scrum项目4.0
  6. 解决:jquery-1.11.1.min.js红叉问题
  7. python--str的几个方法
  8. shell 流程控制
  9. Shell 脚本编程
  10. 如何解决C#编译中&quot;csc不是内部或外部命令&quot;的问题
  11. 零基础学习云计算及大数据DBA集群架构师【Linux Bash Shell编程及系统自动化2015年1月21日周四】
  12. Interpolator(插值器)的种类
  13. POJ 2217 Secretary (后缀数组)
  14. 高通平台的bootloader过程【转】
  15. PythonStudy——Pycharm 小技巧
  16. 关于JS的一些东西
  17. 获取VirtualBox COM对象失败,Unable to start the virtual device
  18. 常见的移动端Web页面问题
  19. React Native发布APP之打包iOS应用
  20. C#_正则表达式

热门文章

  1. spring-logback
  2. Android-黑科技-微信抢红包必备软件
  3. iOS不同版本号适配问题(#ifdef __IPHONE_7_0)
  4. Web端即时通讯、消息推送的实现
  5. oc17--点语法
  6. 搜索分析(DFS、BFS、递归、记忆化搜索)
  7. nyoj--105--九的余数(水题)
  8. Python 生成requirement 使用requirements.txt
  9. MySql数据库中乱码问题解决方案
  10. Hadoop MapReduce编程 API入门系列之wordcount版本1(五)