博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
编写简单的ramdisk(有请求队列)
阅读量:5086 次
发布时间:2019-06-13

本文共 3498 字,大约阅读时间需要 11 分钟。

前言

  前面用虽然申请了请求队列,但实际上没用上,因为ramdisk不像实际的磁盘访问速度慢需要缓存,ramdisk之间使用内存空间,所以就没用请求队列了。本文将介绍使用请求队列的ramdisk驱动,虽然对于ramdisk使用请求队列用处不大,但对于基于磁盘的块设备驱动来说却是必须要用的。

  在LDD3书中,其中的有些块设备操作函数在当前的linux版本中有了很大的变动,需要自己重新根据新定义的一些函数进行适当的移植,以解决编译时报出的各种错误,主要是在请求处理函数中修改。

设置请求队列的请求处理函数

  在前面用无请求队列实现的ramdisk的驱动程序中直接用blk_alloc_queue来分配请求队列,这样分配的请求队列是没有请求处理函数的,之所以可以这样是因为当时就没有使用请求队列,来自上层的请求都被自定义的请求提交函数处理了。现在如果要使用请求队列,那么就必须要对请求队列初始化其请求处理函数,内核提供了函数blk_init_queue,该函数以自定义的请求函数地址作为参数传来被调用,它既实现了blk_alloc_queue的功能,还初始化了队列的请求处理函数和请求提交函数,其中请求提交函数设置为通用函数blk_queue_bio。这样来自上层的请求通过请求队列被分发到我们自定义的请求处理函数来处理。

 

1         //分配一个请求队列2         simp_blkdev_queue = blk_init_queue(simp_blkdev_do_request, NULL);3         if(!simp_blkdev_queue) 4         {5             ret = -ENOMEM;6             goto blk_init_queue;7         }

 上面的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))

1 static void simp_blkdev_do_request(struct request_queue *q) 2 { 3     struct request *req; 4     struct req_iterator ri; 5     struct bio_vec *bvec; 6     char *disk_mem; 7     char *buffer; 8          9     //依次从队列中获取request10     while ((req = blk_fetch_request(q)) != NULL) {11        //判断当前request是否合法12         if ((blk_rq_pos(req) << 9) + blk_rq_cur_bytes(req)13             > SIMP_BLKDEV_BYTES) {14             printk(KERN_ERR SIMP_BLKDEV_DISKNAME15                 ": bad request: block=%llu, count=%u\n",16                 (unsigned long long)blk_rq_pos(req),17                 blk_rq_cur_bytes(req));18                 blk_end_request_all(req, -EIO);19             continue;20         }21         //获取需要操作的内存位置22         disk_mem = simp_blkdev_data + (blk_rq_pos(req) << 9);23         switch (rq_data_dir(req)) {  //判断请求的类型24         case READ:    25             rq_for_each_segment(bvec, req, ri)26             {27                 buffer = kmap(bvec->bv_page) + bvec->bv_offset;28                 memcpy(buffer, disk_mem, bvec->bv_len);29                 kunmap(bvec->bv_page);30                 disk_mem += bvec->bv_len;31             }32             33             /*memcpy(req->buffer,34             simp_blkdev_data + (blk_rq_pos(req) << 9),35             blk_rq_cur_bytes(req));*/36             __blk_end_request_all(req, 0);37             break;38         case WRITE:        39             rq_for_each_segment(bvec, req, ri)40             {41                 buffer = kmap(bvec->bv_page) + bvec->bv_offset;42                 memcpy(disk_mem, buffer, bvec->bv_len);43                 kunmap(bvec->bv_page);44                 disk_mem += bvec->bv_len;45             }46             /*memcpy(simp_blkdev_data + (blk_rq_pos(req) << 9),47             req->buffer, blk_rq_cur_bytes(req));*/48             __blk_end_request_all(req, 0);49             break;50         default:51             /* No default because rq_data_dir(req) is 1 bit */52             break;53         }54     }55 }

  需要注意的是结束请求需要用__blk_end_request_all函数,不能使用blk_end_request_all,这两个函数的唯一区别就是前者不会去获取队列锁,后者会尝试获取队列锁,用后者会导致系统死锁,并是系统崩溃(反正开始我是崩溃了几次)。上面代码中的rq_for_each_segment是用来遍历一个请求中的所有segment,和bio_for_each_segment类似。

转载于:https://www.cnblogs.com/chengxuyuancc/p/3550047.html

你可能感兴趣的文章
Python 3 学习笔记(三)----数据运算、集合操作和文件操作
查看>>
jQuery $.ajax方法
查看>>
PAT 1025. 反转链表 (25)
查看>>
基于Metronic的Bootstrap开发框架经验总结(6)--对话框及提示框的处理和优化
查看>>
Java的compare比较
查看>>
HTML5中createPattern()
查看>>
Git分支实战入门详细图解
查看>>
mac地址静态捆绑,防止arp欺骗
查看>>
SQL脚本-变量--转
查看>>
[转]Greenplum 执行计划之广播与重分布
查看>>
Js的执行
查看>>
【转】查看 Linux 发行版名称和版本号的 8 种方法
查看>>
STM32配置GPIO前须先打开其时钟,否则配置失败
查看>>
Android:控件的隐藏显示
查看>>
TabBottomFragmentLayout【自定义底部选项卡区域(搭配Fragment)】
查看>>
webpack自带的跨域代理配置
查看>>
设置Windows Azure Linux虚拟机中的root账户
查看>>
websocket使用ssl 证书,开启加密服务
查看>>
Chapter13
查看>>
POJ 3579 Median
查看>>