linux flush 文件,Linux文件系统学习:io的plug过程-blk_flush_plug_list的情况
在上篇文章中我们看到
if (plug) {
if (!request_count)
trace_block_plug(q);
else {
if (request_count >= BLK_MAX_REQUEST_COUNT) {//如果这个队列的个数太多了,就通过下面的blk_flush_plug_list进行泄洪
blk_flush_plug_list(plug, false);
trace_block_plug(q);
}
}
这个是在blk_queue_bio 中,也就是在提交请求的情况下,会调用blk_flush_plug_list 来unplug操作。
今天看看另外一种unplug操作,
调度时进行unplug(异步方式),
当发生内核调度时,当前进程sleep前,先将当前task的plug列表中的请求flush到派发队列中,并进行unplug。
主要代码流程如下:
schedule->
sched_submit_work ->
blk_schedule_flush_plug()->
blk_flush_plug_list(plug, true) ->注意:这里传入的from_schedule参数为true,表示将触发异步unplug,即唤醒kblockd工作队列来进行unplug操作。后续的kblockd的唤醒周期在块设备驱动中设置,比如scsi中设置为3ms。
queue_unplugged-> blk_run_queue_async
queue_unplugged():
void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule)
{
struct request_queue *q;
unsigned long flags;
struct request *rq;
LIST_HEAD(list);
unsigned int depth;
flush_plug_callbacks(plug, from_schedule);
if (!list_empty(&plug->mq_list))
blk_mq_flush_plug_list(plug, from_schedule);
if (list_empty(&plug->list))
return;
list_splice_init(&plug->list, &list);
list_sort(NULL, &list, plug_rq_cmp);
q = NULL;
depth = 0;
local_irq_save(flags);
while (!list_empty(&list)) {
rq = list_entry_rq(list.next);list 里面存放的就是要执行的rq,每一个遍历出来。这个
list_del_init(&rq->queuelist);
BUG_ON(!rq->q);
if (rq->q != q) {
/*
* This drops the queue lock
*/
if (q)
queue_unplugged(q, depth, from_schedule);
q = rq->q;
depth = 0;
spin_lock(q->queue_lock);
}
/*
* Short-circuit if @q is dead
*/
if (unlikely(blk_queue_dying(q))) {
__blk_end_request_all(rq, -ENODEV);
continue;
}
/*
* rq is already accounted, so use raw insert
*/
if (rq->cmd_flags & (REQ_FLUSH | REQ_FUA))
__elv_add_request(q, rq, ELEVATOR_INSERT_FLUSH);
else
__elv_add_request(q, rq, ELEVATOR_INSERT_SORT_MERGE);
depth++;
}
static void queue_unplugged(struct request_queue *q, unsigned int depth,
bool from_schedule)
__releases(q->queue_lock)
{
if (from_schedule)
blk_run_queue_async(q);
else
__blk_run_queue(q);
spin_unlock(q->queue_lock);
}
根据from_schedule 进行同步操作或者异步
void blk_run_queue_async(struct request_queue *q)
{
if (likely(!blk_queue_stopped(q) && !blk_queue_dead(q)))
mod_delayed_work(kblockd_workqueue, &q->delay_work, 0);
}
这里面就调入一个异步时钟,到见了它还是会调用到__blk_run_queue,进行request的操作的。
这里面异步时钟的逻辑,它里面有一套,大概可以比喻成handle 的消息处理机制,这一套我们先不讨论。
我们先看下这个异步时钟是在哪里设置的,
blk_init_queue--》blk_init_queue_node--》blk_alloc_queue_node
就是在初始化的时候做的,
struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
{
struct request_queue *q;
int err;
.....
setup_timer(&q->backing_dev_info.laptop_mode_wb_timer,
laptop_mode_timer_fn, (unsigned long) q);
setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
INIT_DELAYED_WORK(&q->delay_work, blk_delay_work);
}
中间的时钟消息逻辑我们先不看,我们知道,到时间以后,它会执行blk_delay_work
static void blk_delay_work(struct work_struct *work)
{
struct request_queue *q;
q = container_of(work, struct request_queue, delay_work.work);
spin_lock_irq(q->queue_lock);
__blk_run_queue(q);
spin_unlock_irq(q->queue_lock);
}
OK,最终还是到__blk_run_queue,在进行下一步分析前我们先处理下逻辑。
就是一个list里面,有很多个bio请求,这些bio请求转换成驱动能认识的就是rq,什么时候对这个rq进行遍历,
一个就是实际请求的时候,同步策略,另外一个就是schedule的时候异步。
达到的条件是要达到MAX,我就开始遍历。每个rq。
rq的--->q,是由驱动设置进来的,q有可能有很多个驱动,如磁盘,usb或者其他block驱动
所以这里可以细化的,就是可以做一个list分类,每个驱动达到MAX,再来清理
那么我们作为学习,假设就是一个q来说,最终由__blk_run_queue,送入到那个地方进行运行,而驱动就使用elv_next_request,
拿取,rq。这里似乎还有点差距。我们在来看看__blk_run_queue,应该就没什么缝隙了。
void __blk_run_queue(struct request_queue *q)
{
if (unlikely(blk_queue_stopped(q)))
return;
__blk_run_queue_uncond(q);
}
inline void __blk_run_queue_uncond(struct request_queue *q)
{
if (unlikely(blk_queue_dead(q)))
return;
q->request_fn_active++;
q->request_fn(q);
q->request_fn_active--;
}
OK,最终调用的是request_fn,就是在
这边设置进来的东西,上面是我们的demo代码。
ok,调用到了驱动的代码,没有问题了,最终的这个elv_next_request,进行那q里面,电梯排好的请求。
这就意味着,电梯算法处理的是rq,它是怎么进入的,
进入也是没有问题的,
初始化也应该没有问题,这样的话,我大概就是可以去看,elv的代码了。
--- Linux文件系统学习系列笔记 ---
(原创笔记,转载请联系博主授权)
linux flush 文件,Linux文件系统学习:io的plug过程-blk_flush_plug_list的情况相关推荐
- linux flush 文件,Linux 写文件时 何时 flush buffer
遇到了一个很奇怪的问题,读文件失败.尤其是想要读取特别小的文件的时候. 流程是: 数据流 -> 存入文件 -> 读出文件数据 -> 操作 开始怀疑文件没有保存下来. 仔细查看了log ...
- linux stat文件,Linux stat命令:显示文件或文件系统的详细信息
在 Linux 中,文件有访问时间.数据修改时间.状态修改时间这三个时间,而没有创建时间.stat 是査看文件详细信息的命令,而且可以看到文件的这三个时间,其基本信息如下. 命令名称:stat. 英文 ...
- linux设备文件,Linux 文件系统与设备文件
1 Linux 文件系统 1.1 Linux 文件系统与设备驱动关系 下图表明了 Linux 中虚拟文件系统.磁盘/Flash文件系统以及一般的设备文件与设备驱动程序之间的关系. 文件系统与设备驱动之 ...
- linux 编码文件,linux文件编码
linux下新建一个文件,或采用fopen新建,那么文件的编码是什么? 怎么查看文件编码格式: 查看文件编码file命令 file ip.txt ip.txt: UTF-8 Unicode text, ...
- 分析 linux 日志文件,linux精讲|操作系统常见日志文件分析
linux运维,离不开对系统日志的分析,除syslog外,还有常用的dmesg.wtmp.btmp.bash_history等系统日志文件以及应用程序相关的日志. 一.dmesg日志:记录内核日志信息 ...
- linux 移动 文件,linux移动文件命令
linux移动文件命令 mv命令 功能:为文件或目录改名或将文件由一个目录移入另一个目录中.该命令如同DOS下的ren和move的组合. 语法:mv [选项] 源文件或目录 目标文件或目录 说明: 视 ...
- linux php文件,Linux php文件安装目录在哪
php文件安装目录一般默认在"/var/www"里面,如果是自定义安装,则可以用Linux的命令进行查找,查找的命令是"find / -name "*www*& ...
- 怎么解压linux镜像文件,linux 怎么解压文件
linux怎么解压文件 Linux提供了一个很简单的功能,用来解压*.zip 文件. 解压命令:unzip filename.zip Linux系统中还有一类后缀为*.tar的文件. 解压命令为: t ...
- linux flush 磁盘,linux 磁盘IO栈和优化思路
首先来看一下整个的IO栈,大概分为7层,每一层都有其特殊的功能和意义. IO Layer 1.VFS层 即虚拟文件系统,这是linux内核为了应对不同的文件系统(ext3\ext4)抽象出来的,直接与 ...
最新文章
- 【转】MYSQL入门学习之十:视图的基本操作
- 《响应式Web设计全流程解析》一1.2 静态设计稿舒适区
- 2015人脸检测研究进展
- UART0串口编程(三):中断方式的串口编程;用中断编写发送函数
- baidu+app+per+android,百度移动统计|移动应用APP统计|android统计分析|iOS统计分析
- 使用@functools.wraps的理由
- 关于IOCP完成端口的文章
- django-oscar相关的模块调研信息汇总
- mysql的唯一索引UNIQUE
- html宽度满屏,宽度满屏的代码怎么样写?
- [POJ2104] 区间第k大数 [区间第k大数,可持久化线段树模板题]
- 游戏开发:Html5 虚拟摇杆控制人物移动
- kitti点云地图拼接
- idea运行sql文件
- 已知一点经纬度及与另一点距离和航向,求另一点经纬度
- 不懂就问,苹果电脑格式化了能恢复数据吗?
- VR光学设计的关键参数
- English Learning NetSource
- 仿腾讯QQ竖直滑动导航菜单
- Spring中的静态工厂与实例工厂
热门文章
- html图片滚动浏览,ul结合CSS制作网页相册滑动浏览效果
- 计算机软考可以直接高级吗,计算机软考没有中级能考高级吗
- 一年级下册数学计算机应用题,一年级数学下册期中检测试题
- 错误: 无法生成项目输出组“内容文件来自WebApplication1(活动)”
- 【洛谷】普及练习场 深度优先搜索【易】
- [Swift]LeetCode478. 在圆内随机生成点 | Generate Random Point in a Circle
- mysql 8.0.11安装教程
- 新浪sae平台进行数据库的连接
- 【循序渐进学Python】9.异常处理
- python类的属性和对象属性_Python打印对象的全部属性