编写简单的ramdisk(有请求队列)
前言
前面用无请求队列实现的ramdisk的驱动程序虽然申请了请求队列,但实际上没用上,因为ramdisk不像实际的磁盘访问速度慢需要缓存,ramdisk之间使用内存空间,所以就没用请求队列了。本文将介绍使用请求队列的ramdisk驱动,虽然对于ramdisk使用请求队列用处不大,但对于基于磁盘的块设备驱动来说却是必须要用的。
在LDD3书中,其中的有些块设备操作函数在当前的linux版本中有了很大的变动,需要自己重新根据新定义的一些函数进行适当的移植,以解决编译时报出的各种错误,主要是在请求处理函数中修改。
设置请求队列的请求处理函数
在前面用无请求队列实现的ramdisk的驱动程序中直接用blk_alloc_queue来分配请求队列,这样分配的请求队列是没有请求处理函数的,之所以可以这样是因为当时就没有使用请求队列,来自上层的请求都被自定义的请求提交函数处理了。现在如果要使用请求队列,那么就必须要对请求队列初始化其请求处理函数,内核提供了函数blk_init_queue,该函数以自定义的请求函数地址作为参数传来被调用,它既实现了blk_alloc_queue的功能,还初始化了队列的请求处理函数和请求提交函数,其中请求提交函数设置为通用函数blk_queue_bio。这样来自上层的请求通过请求队列被分发到我们自定义的请求处理函数来处理。
//分配一个请求队列
simp_blkdev_queue = blk_init_queue(simp_blkdev_do_request, NULL);
if(!simp_blkdev_queue)
{
ret = -ENOMEM;
goto blk_init_queue;
}
上面的simp_blkdev_do_request为自定义的请求处理函数。
实现请求处理函数
请求处理函数实现类似于在无请求队列ramdisk驱动中提交请求函数,说白了它们都是对上层请求的处理,只不过前者处理的是多个bio链表(每个请求时一个bio链表),后者仅仅处理一个bio而已。我们只需要遍历每个bio链表中的每个bio,并根据当前请求的类型来做相应的处理就可以了。值得注意的是自2.6.31内核开始,一些函数发生变化(见linux/include/blkdev.h)。在2.6.32内核中,
request -> sectors 变为 blk_rq_pos(request)
request -> nr_sectors 变为 blk_rq_nr_sectors(request)
elv_next_request(request) 变为 blk_fetch_request(request)
end_request(request, error) 变为 __blk_end_request_all(req, err))
static void simp_blkdev_do_request(struct request_queue *q)
{
struct request *req;
struct req_iterator ri;
struct bio_vec *bvec;
char *disk_mem;
char *buffer; //依次从队列中获取request
while ((req = blk_fetch_request(q)) != NULL) {
//判断当前request是否合法
if ((blk_rq_pos(req) << ) + blk_rq_cur_bytes(req)
> SIMP_BLKDEV_BYTES) {
printk(KERN_ERR SIMP_BLKDEV_DISKNAME
": bad request: block=%llu, count=%u\n",
(unsigned long long)blk_rq_pos(req),
blk_rq_cur_bytes(req));
blk_end_request_all(req, -EIO);
continue;
}
//获取需要操作的内存位置
disk_mem = simp_blkdev_data + (blk_rq_pos(req) << );
switch (rq_data_dir(req)) { //判断请求的类型
case READ:
rq_for_each_segment(bvec, req, ri)
{
buffer = kmap(bvec->bv_page) + bvec->bv_offset;
memcpy(buffer, disk_mem, bvec->bv_len);
kunmap(bvec->bv_page);
disk_mem += bvec->bv_len;
} /*memcpy(req->buffer,
simp_blkdev_data + (blk_rq_pos(req) << 9),
blk_rq_cur_bytes(req));*/
__blk_end_request_all(req, );
break;
case WRITE:
rq_for_each_segment(bvec, req, ri)
{
buffer = kmap(bvec->bv_page) + bvec->bv_offset;
memcpy(disk_mem, buffer, bvec->bv_len);
kunmap(bvec->bv_page);
disk_mem += bvec->bv_len;
}
/*memcpy(simp_blkdev_data + (blk_rq_pos(req) << 9),
req->buffer, blk_rq_cur_bytes(req));*/
__blk_end_request_all(req, );
break;
default:
/* No default because rq_data_dir(req) is 1 bit */
break;
}
}
}
需要注意的是结束请求需要用__blk_end_request_all函数,不能使用blk_end_request_all,这两个函数的唯一区别就是前者不会去获取队列锁,后者会尝试获取队列锁,用后者会导致系统死锁,并是系统崩溃(反正开始我是崩溃了几次)。上面代码中的rq_for_each_segment是用来遍历一个请求中的所有segment,和bio_for_each_segment类似。
编写简单的ramdisk(有请求队列)的更多相关文章
- 编写简单的ramdisk(无请求队列)
最近在研究块设备驱动的编写,看了赵磊大牛的<写一个块设备驱动>,受益匪浅,虽然能看懂里面说的,但动手写写代码还是能加深理解的,下面实现的ramdisk写的很简单,如果有错误,欢迎大牛们指正 ...
- 编写简单的ramdisk(选择IO调度器)
前言 目前linux中包含anticipatory.cfq.deadline和noop这4个I/O调度器.2.6.18之前的linux默认使用anticipatory,而之后的默认使用cfq.我们在前 ...
- SLAM+语音机器人DIY系列:(二)ROS入门——6.编写简单的service和client
摘要 ROS机器人操作系统在机器人应用领域很流行,依托代码开源和模块间协作等特性,给机器人开发者带来了很大的方便.我们的机器人“miiboo”中的大部分程序也采用ROS进行开发,所以本文就重点对ROS ...
- Python 利用Python编写简单网络爬虫实例3
利用Python编写简单网络爬虫实例3 by:授客 QQ:1033553122 实验环境 python版本:3.3.5(2.7下报错 实验目的 获取目标网站“http://bbs.51testing. ...
- Python 利用Python编写简单网络爬虫实例2
利用Python编写简单网络爬虫实例2 by:授客 QQ:1033553122 实验环境 python版本:3.3.5(2.7下报错 实验目的 获取目标网站“http://www.51testing. ...
- 学习 Linux,101: 自定义或编写简单脚本【转】
转自:http://www.ibm.com/developerworks/cn/linux/l-lpic1-105-2/index.html 学习如何使用标准的 shell 语法.循环和控制结构,以及 ...
- Flutter之Dio引入和简单的Get/Post请求
先在pubspec.yaml中引入Dio包如图所示 认识Dio库:dio是一个dart的 http请求通用库,目前也是大陆使用最广泛的库,国人开发,完全开源. flutter的插件包管理:学了引入di ...
- golang API 请求队列
概要 实现思路 使用方法 启动队列服务 使用队列服务 概要 在调用第三方 API 的时候, 基本都有访问限速的限制条件. 第三方的 API 有多个的时候, 就不太好控制访问速度, 常常会导致 HTTP ...
- 编写简单的Mapreduce程序并部署在Hadoop2.2.0上运行
今天主要来说说怎么在Hadoop2.2.0分布式上面运行写好的 Mapreduce 程序. 可以在eclipse写好程序,export或用fatjar打包成jar文件. 先给出这个程序所依赖的Mave ...
随机推荐
- Kafka设计解析(二)- Kafka High Availability (上)
本文转发自Jason’s Blog,原文链接 http://www.jasongj.com/2015/04/24/KafkaColumn2 摘要 Kafka在0.8以前的版本中,并不提供High Av ...
- c#动态编译并动态生成dll
/// <summary> /// 动态编译并执行代码 /// </summary> /// <param name="code">代码< ...
- USACO翻译:USACO 2014 FEB SILVER 三题
USACO 2014 FEB SILVER 一.题目概览 中文题目名称 自动打字 路障 神秘代码 英文题目名称 auto rblock scode 可执行文件名 auto rblock scode 输 ...
- .NET支持多平台后的一点拙见
我们目前对.NET的理解大部分可以归纳为:起初它是Java平台(注意是平台,不要跟Java语言搞混淆)的一个克隆品,后来慢慢演变,有了自己的特性.由于Java平台最显著的特点就是“平台独立性”(或者说 ...
- 在职场中混,"讲演稿"的重要性
背景: 在职场上工作的人,思维都像流水行云一样无拘无束.某时某刻说不定就会产生点“头脑风暴”. 但是在多数情总下,只是自己想想,跟朋友吹瞌子的时候随便说说,很少有用文字,图形把自己的思维给表现出来. ...
- Linux RAID卡优化
200 ? "200px" : this.width)!important;} --> 介绍 我们的生产服务器经常会做raid存储,但是单单做了raid就能保证性能高效和数据 ...
- 跨域获取json一些理解[腾讯电商数据的拉取方式]
如何跨域获取json数据源?我们都知道要有callback,具体callback是如何工作的呢?如果服务器端不接收callback,我们是不是就没有办法处理了呢?读完本文后相信你会有一个大体的了解. ...
- [ASP.NET MVC 小牛之路]05 - 使用 Ninject
在[ASP.NET MVC 小牛之路]系列上一篇文章(依赖注入(DI)和Ninject)的末尾提到了在ASP.NET MVC中使用Ninject要做的两件事情,续这篇文章之后,本文将用一个实际的示例来 ...
- js封装用户选项传递给Servlet之考试系统二
<%@ page language="java" import="java.util.*" contentType="text/html; ch ...
- spring事务管理器设计思想(二)
上文见<spring事务管理器设计思想(一)> 对于第二个问题,涉及到事务的传播级别,定义如下: PROPAGATION_REQUIRED-- 如果当前没有事务,就新建一个事务.这是最常见 ...