前言

  前面用无请求队列实现的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(有请求队列)的更多相关文章

  1. 编写简单的ramdisk(无请求队列)

    最近在研究块设备驱动的编写,看了赵磊大牛的<写一个块设备驱动>,受益匪浅,虽然能看懂里面说的,但动手写写代码还是能加深理解的,下面实现的ramdisk写的很简单,如果有错误,欢迎大牛们指正 ...

  2. 编写简单的ramdisk(选择IO调度器)

    前言 目前linux中包含anticipatory.cfq.deadline和noop这4个I/O调度器.2.6.18之前的linux默认使用anticipatory,而之后的默认使用cfq.我们在前 ...

  3. SLAM+语音机器人DIY系列:(二)ROS入门——6.编写简单的service和client

    摘要 ROS机器人操作系统在机器人应用领域很流行,依托代码开源和模块间协作等特性,给机器人开发者带来了很大的方便.我们的机器人“miiboo”中的大部分程序也采用ROS进行开发,所以本文就重点对ROS ...

  4. Python 利用Python编写简单网络爬虫实例3

    利用Python编写简单网络爬虫实例3 by:授客 QQ:1033553122 实验环境 python版本:3.3.5(2.7下报错 实验目的 获取目标网站“http://bbs.51testing. ...

  5. Python 利用Python编写简单网络爬虫实例2

    利用Python编写简单网络爬虫实例2 by:授客 QQ:1033553122 实验环境 python版本:3.3.5(2.7下报错 实验目的 获取目标网站“http://www.51testing. ...

  6. 学习 Linux,101: 自定义或编写简单脚本【转】

    转自:http://www.ibm.com/developerworks/cn/linux/l-lpic1-105-2/index.html 学习如何使用标准的 shell 语法.循环和控制结构,以及 ...

  7. Flutter之Dio引入和简单的Get/Post请求

    先在pubspec.yaml中引入Dio包如图所示 认识Dio库:dio是一个dart的 http请求通用库,目前也是大陆使用最广泛的库,国人开发,完全开源. flutter的插件包管理:学了引入di ...

  8. golang API 请求队列

    概要 实现思路 使用方法 启动队列服务 使用队列服务 概要 在调用第三方 API 的时候, 基本都有访问限速的限制条件. 第三方的 API 有多个的时候, 就不太好控制访问速度, 常常会导致 HTTP ...

  9. 编写简单的Mapreduce程序并部署在Hadoop2.2.0上运行

    今天主要来说说怎么在Hadoop2.2.0分布式上面运行写好的 Mapreduce 程序. 可以在eclipse写好程序,export或用fatjar打包成jar文件. 先给出这个程序所依赖的Mave ...

随机推荐

  1. SubVersion Ubuntu

    UbuntuサーバにSubversionを入れる Linux, 開発ツール |    Ubuntuサーバが無事に動いたので.続いてSubversionを入れてみる. こんな感じの環境を考える. Apa ...

  2. jquery中focus()失效怎么解决

    又学到一个新的知识! 今天在写表单验证的时候遇到一个关于获取焦点的focus()问题. 场景说明:在验证密码输入格式不对之后,弹出alert()提示框,提示密码不对,请重新输入.同时清空密码框并获得焦 ...

  3. 【转】关于FLASH中图文混排聊天框的小结

    原文链接 图文混排也是FLASH里一个很古老的话题了,我们不像美国佬那样游戏里面聊天框就是聊天框,全是文字干干净净,也不像日本人发明了并且频繁地使用颜文字.不管是做论坛.做游戏,必定要实现的一点就是带 ...

  4. JavaIO 将数据写入到文件中去

    package com.Practice_FileWriter; import java.io.FileWriter; import java.io.IOException; public class ...

  5. >hibernate的四种状态

    hibernate的四种状态 1.临时状态 与数据库中没有相对应的数据,也不在session的管理之中,一般是新new出来的对象 2.持久化状态 对象在session的管理中,最后会在事务提交后,在数 ...

  6. 原来scanf读入字符串还能这样..

    (本文针对于NOIP Day1 玩具迷题) (这是弱鸡写的)(字符串用char二维,本质一样的) 在NOIP成功AC了这道题,结果OJ上被string卡了时间,没办法只能用scanf了.....百度看 ...

  7. chrome浏览器js 导出excel

    <table id="table"> <tr> <th>ID</th> <th>姓名</th> <th ...

  8. python读取文本文件

    1. 读取文本文件 代码: f = open('test.txt', 'r') print f.read() f.seek(0) print f.read(14) f.seek(0) print f. ...

  9. SQL Server的镜像是基于物理块变化的复制 镜像Failover之后数据的预热问题

    SQL Server的镜像是基于物理块变化的复制 镜像Failover之后数据的预热问题 基于物理块变化的复制,没有并行也是很快的. 逻辑复制的日志是按事务结束的时间排序的,而物理复制是与事务无关的, ...

  10. Visual Studio 2013 Web开发

    cnbeta新闻:微软正式发布Visual Studio 2013 RTM版,微软还发布了Visual Studio 2013的最终版本..NET 4.5.1以及Team Foundation Ser ...