编写简单的ramdisk(选择IO调度器)
前言
目前linux中包含anticipatory、cfq、deadline和noop这4个I/O调度器。2.6.18之前的linux默认使用anticipatory,而之后的默认使用cfq。我们在前面编写简单的ramdisk(有请求队列)中分配请求队列使用了blk_init_queue函数,该函数会默认该请求队列分配一个调度器,这里我们打算不使用该函数默认分配给请求队列的调度器,而是使用noop调度器。noop顾名思义,是一个基本上不干事的调度器。它基本不对请求进行什么附加的处理,仅仅假惺惺地告诉通用块设备层:我处理完了。但与吃空饷的公仆不同,noop的存在还是有不少进步意义的。至少我们现在就需要一个不要没事添乱的I/O调度器。
选择一个指定的IO调度器
可以用下面的函数来更换一个请求队列的调度器,该函数定义如下:
int elevator_change(struct request_queue *, const char *)
第一个参数是请求队列的指针,第二个参数是需要设定的I/O调度器名称。如果name为NULL,那么内核会首先尝试选择启动参数"elevator="中指定的调度器,不成功的话就去选择编译内核时指定的默认调度器,如果运气太背还是不成功,就去选择"noop"调度器。
对于我们的代码,就是在simp_blkdev_queue = blk_init_queue(simp_blkdev_do_request, NULL)后面加上elevator_change(simp_blkdev_queue, "noop");所以我们的代码应该是(颜色为红色的代码是选择调度器代码):
static int __init simp_blkdev_init(void)
{
int ret;
struct elevator_queue *elv_old; //分配一个请求队列
simp_blkdev_queue = blk_init_queue(simp_blkdev_do_request, NULL);
if(!simp_blkdev_queue)
{
ret = -ENOMEM;
goto blk_init_queue;
}
//更换IO调度器
if (IS_ERR_VALUE(elevator_change(simp_blkdev_queue, "noop")))
printk(KERN_WARNING "Switch elevator failed, using default\n"); //分配一个 gendisk 结构,有一个分区
simp_blkdev_disk = alloc_disk();
if(!simp_blkdev_disk)
{
ret = -ENOMEM;
goto err_alloc_disk;
} //填充 gendisk 主要结构成员
strcpy(simp_blkdev_disk->disk_name, SIMP_BLKDEV_DISKNAME);
simp_blkdev_disk->major = SIMP_BLKDEV_DEVICEMAJOR;
simp_blkdev_disk->first_minor = ;
simp_blkdev_disk->fops = &simp_blkdev_fops;
simp_blkdev_disk->queue = simp_blkdev_queue;
set_capacity(simp_blkdev_disk, SIMP_BLKDEV_BYTES >> ); //向内核注册块设备驱动
add_disk(simp_blkdev_disk); return ; err_alloc_disk:
blk_cleanup_queue(simp_blkdev_queue);
blk_init_queue:
return ret;
}
如果要用函数elevator_init来设置调度器,就必须先保存原来blk_init_queue()帮我们申请的默认调度器,然后设置队列中的指向调度器的elevator指针为NULL(注意:设置指针为NULL是必须的,要不然函数elevator_init会不做任何事情直接返回),最后才是调用elevator_init(simp_blkdev_queue, "noop")来设置,如果设置成功则调用elevator_exit来释放原来的调度器。具体代码如下(颜色为红色的代码是选择调度器代码):
static int __init simp_blkdev_init(void)
{
int ret;
struct elevator_queue *elv_old; //分配一个请求队列
simp_blkdev_queue = blk_init_queue(simp_blkdev_do_request, NULL);
if(!simp_blkdev_queue)
{
ret = -ENOMEM;
goto blk_init_queue;
} elv_old = simp_blkdev_queue->elevator;
simp_blkdev_queue->elevator = NULL;
//更换IO调度器
if (IS_ERR_VALUE(elevator_init(simp_blkdev_queue, "noop")))
printk(KERN_WARNING "Switch elevator failed, using default\n");
else
elevator_exit(elv_old);
//分配一个 gendisk 结构,有一个分区
simp_blkdev_disk = alloc_disk();
if(!simp_blkdev_disk)
{
ret = -ENOMEM;
goto err_alloc_disk;
} //填充 gendisk 主要结构成员
strcpy(simp_blkdev_disk->disk_name, SIMP_BLKDEV_DISKNAME);
simp_blkdev_disk->major = SIMP_BLKDEV_DEVICEMAJOR;
simp_blkdev_disk->first_minor = ;
simp_blkdev_disk->fops = &simp_blkdev_fops;
simp_blkdev_disk->queue = simp_blkdev_queue;
set_capacity(simp_blkdev_disk, SIMP_BLKDEV_BYTES >> ); //向内核注册块设备驱动
add_disk(simp_blkdev_disk); return ; err_alloc_disk:
blk_cleanup_queue(simp_blkdev_queue);
blk_init_queue:
return ret;
}
编写简单的ramdisk(选择IO调度器)的更多相关文章
- 如何选择IO调度器
概述 由于对multi-quque的IO调度算法不太熟悉,为了避免误人子弟,本文暂时只会介绍如何选择single-queue的IO调度算法.等将来对multi-queue有充分认识后再补充. 如果不清 ...
- 编写简单的ramdisk(无请求队列)
最近在研究块设备驱动的编写,看了赵磊大牛的<写一个块设备驱动>,受益匪浅,虽然能看懂里面说的,但动手写写代码还是能加深理解的,下面实现的ramdisk写的很简单,如果有错误,欢迎大牛们指正 ...
- Linux IO Scheduler(Linux IO 调度器)
每个块设备或者块设备的分区,都对应有自身的请求队列(request_queue),而每个请求队列都可以选择一个I/O调度器来协调所递交的request.I/O调度器的基本目的是将请求按照它们对应在块设 ...
- Linux IO调度器相关算法介绍(转)
IO调度器(IO Scheduler)是操作系统用来决定块设备上IO操作提交顺序的方法.存在的目的有两个,一是提高IO吞吐量,二是降低IO响应时间.然而IO吞吐量和IO响应时间往往是矛盾的,为了尽量平 ...
- Linux IO 调度器
Linux IO Scheduler(Linux IO 调度器) 每个块设备或者块设备的分区,都对应有自身的请求队列(request_queue),而每个请求队列都可以选择一个I/O调度器来协调所递交 ...
- IO调度器原理介绍
IO调度器(IO Scheduler)是操作系统用来决定块设备上IO操作提交顺序的方法.存在的目的有两个,一是提高IO吞吐量,二是降低IO响应时间.然而IO吞吐量和IO响应时间往往是矛盾的,为了尽量平 ...
- Linux IO Scheduler(Linux IO 调度器)【转】
每个块设备或者块设备的分区,都对应有自身的请求队列(request_queue),而每个请求队列都可以选择一个I/O调度器来协调所递交的request.I/O调度器的基本目的是将请求按照它们对应在块设 ...
- IO调度器
由于对blktrace的好奇,来到了block层.通过阅读block层的代码,自己的几个错误认知被纠正,比如 一) 同步操作时,进程是在驱动中睡觉真实情况是:进程在文件系统睡觉 二) 对同一个数据块的 ...
- 编写简单的ramdisk(有请求队列)
前言 前面用无请求队列实现的ramdisk的驱动程序虽然申请了请求队列,但实际上没用上,因为ramdisk不像实际的磁盘访问速度慢需要缓存,ramdisk之间使用内存空间,所以就没用请求队列了.本文将 ...
随机推荐
- oracle plsql 无法连接 报 ORA-12560: TNS:protocol adapter error
ORA-12560: TNS:protocol adapter error 添加一个环境变量,名为TNS_ADMIN,值为 tnsnames.ora 文件所在路径.比如我的本机为:D:/instant ...
- 在update语句中使用子查询
在update 中的 where 子句中使用子查询: UPDATE mg_page_log as a SET page_num=1 WHERE id in( SELECT id from mg_ ...
- sublime下安装ctags
sublime下安装ctags 标签: sublime 当我们阅读代码时, 会遇到很多不明确的函数名, 此时, 我们需要查看这个函数的定义的地方, 在sublime下我们需要安装一个插件, Cta ...
- 递归一题总结(OJ P1117倒牛奶)
题目: 农民约翰有三个容量分别是A,B,C升的桶,A,B,C分别是三个从1到20的整数,最初,A和B桶都是空的,而C桶是装满牛奶的.有时,约翰把牛奶从一个桶倒到另 ...
- Spring MVC 框架的架包分析,功能作用,优点
由于刚搭建完一个MVC框架,决定分享一下我搭建过程中学习到的一些东西.我觉得不管你是个初级程序员还是高级程序员抑或是软件架构师,在学习和了解一个框架的时候,首先都应该知道的是这个框架的原理和与其有关j ...
- touchstart、touchmove、touchend 实现移动端上的触屏拖拽
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- Sublime Text 3 配置和使用方法
下载: Sublime Text 3 官方下载地址 Sublime Text 3 汉化破解版 资料: Sublime Text 非官方文档 技巧 -用户或-User后缀的菜单项,其对应的配置文件都 ...
- 字节流与数据类型的相互转换---使用struct模块
字节流与数据类型的相互转换---使用struct模块 http://blog.csdn.net/Sunboy_2050/article/details/5974029 Python是一门非常简洁的语言 ...
- c++怎样让函数返回数组
这个问题属于非常初级的问题,但是对于初学不知道的人可能会比较头疼.C++中函数是不能直接返回一个数组的,但是数组其实就是指针,所以可以让函数返回指针来实现.比如一个矩阵相乘的函数,很容易地我们就写成: ...
- Asp.Net Core 发布和部署(Linux + Jexus )
前言 在上篇文章中,主要介绍了 Dotnet Core Run 命令,这篇文章主要是讲解如何在 asp.net core 中对我们的已经完成的程序进行发布和部署. 有关如何使用 Nginx 进行部署, ...