编写简单的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之间使用内存空间,所以就没用请求队列了.本文将 ...
随机推荐
- IOS UIWebView 下拉刷新功能的简单实现
1.运行效果图 2.swift 代码的实现 import UIKit class RefreshWebViewController: UIViewController,UIScrollViewDele ...
- sparkR读取csv文件
sparkR读取csv文件 The general method for creating SparkDataFrames from data sources is read.df. This met ...
- Torch Problems: require some packages doesn't work
I've recently got a problem. require 'cutorch' doesn't work. But it was ok yesterday, although I hav ...
- Codeforces Round #361 (Div. 2) B
B - Mike and Shortcuts Description Recently, Mike was very busy with studying for exams and contests ...
- css3 filter的十种特效
filter默认值是none,他不具备继承性,其中filter-function具有一下属性: grayscale灰度 sepia褐色(求专业指点翻译) saturate饱和度 hue-rotate色 ...
- PHP基础知识之foreach
定义: foreach (array_expression as $value)------------循环时传递key foreach (array_expression as $key => ...
- IIS 8:IIS 入门
深埋在您的 Microsoft 服务器 (2008年. 2008 R2 和 2012年的版本) 的范围内是最强大的 Web 服务器可用. 它只等待你来发挥其全部潜力. 您的目标是要从家里运行一个 Wo ...
- Android提权漏洞CVE-2014-7920&CVE-2014-7921分析
没羽@阿里移动安全,更多安全类技术干货,请访问阿里聚安全博客 这是Android mediaserver的提权漏洞,利用CVE-2014-7920和CVE-2014-7921实现提权,从0权限提到me ...
- WPF+通过配置文件生成菜单(Menu)+源码
这个月做项目,遇到过一个通过配置文件来生成菜单的解决方案,感觉挺优雅的,特地放到博客园来,以飨读者. 说来惭愧,以前做的项目都没有这样用过,都是固定死了.如果后续有需要加入菜单,还得在重新修改UI,然 ...
- R in Action 读书笔记(4)
MindMapper 原文件