IO的生命周期
● 将来自cache的数据封装成bio
submit_bh->submit_bh_wbc


此时IO还在fs层
● 进入block IO层
submit_bh_wbc->submit_io-> generic_make_request


上面获得的q是每个设备(block_device)的队列。block_device有一个成员queue,所有针对该设备的请求都会放入其中,该queue不是后面将要说到的三类queue。
make_queue_fn的注册在request queue初始化的时候:blk_init_queue->blk_init_allocated_queue
● 开始将bio合并到request:
generic_make_request->blk_queue_bio
blk_queue_bio实现了对bio的合并调度。它调用的函数elv_merge是关键函数,它寻找可以用来合并bio的request。

IO从块设备层(block IO layer),到发送到块设备驱动(device driver)整个过程经过三类队列:
1)unplug request queue 属于线程
2)elevator queue 调度队列,不同的调度器,队列不同
3)device request queue 派遣队列,dispatch queue。(例如,在deadline_dispatch_requests中实现)
plug和unplug:目的是让请求不马上被驱动程序处理。设备处于pluged状态,设备不会被激活。处于unplugged状态,被激活。
来自上层的请求,先尝试合并入unplug 队列,若不能合并,则调用elv_merge合并入调度队列elevator queue。若找不到可合并的请求,则获得一个空请求request,用该bio初始化该request,然后放到unplug队列中。

此时bio(request)还在unplug 队列中。

此时bio(request)在调度队列中。
● (若不能放入unplug队列)调用elv_merge,找到可以合并bio的request。
blk_queue_bio->elv_merge
elv_merge的作用主要是,找到可以将bio合并的request。




这一步,是调用特定的调度器找到可以合并bio的request
● 将unplug 队列中的request放到调度队列
blk_queue_bio:
通过blk_flush_plug_list(也可通过_elv_add_request)将unplug 请求队列中的请求发送到调度队列elevator queue。


add_acct_request->__elv_add_request
此时request在调度队列中。
● 将调度队列里的request发送到派遣队列:
返回blk_queue_bio,然后blk_queue_bio-> add_acct_request-> __elv_add_request

此时,request在device request queue(派遣队列)中。
这一步实现具体IO调度器对请求的派遣(发送到派遣队列):
__elv_add_request->elv_drain_elevator->elevator_dispatch_fn
elevator_dispatch_fn将被注册为具体调度器的派遣函数,例如deadline_dispatch_request

IO调度器的工作:合并,排序。
排序:使请求按扇区增长的方向有序排列。
CFQ:每个发起IO的进程都有一个队列。
Deadline:有4个队列,分为两类sort_list和fifo_list。每类都有读写两种队列。
sort_list 按请求起始扇区排序,fifo_list按请求生成的时间排序。
此时,请求在派遣队列(device request queue)中。
● 进入驱动程序,并获得一个request:
返回blk_queue_bio: blk_queue_bio-> __blk_run_queue-> __blk_run_queue_uncond->request_fn(scsi_request_fn)-> blk_peek_request->__elv_next_request
request_fn被注册为scsi_request_fn,该函数是驱动程序的入口。



从device request queue中获得一个请求,准备发送到scsi块设备驱动(中间层)
● 将request转化成scsi command:
在blk_peek_request中调用q->prep_rq_fn(注册为scsi_prep_fn),将request转化成scsi驱动能够识别scsi command。

● 发送scsi command到scsi host:
回到scsi_request_fn,调用scsi_dispatch_cmd将scsi command发送给scsi host

● DMA:
在scsi_dispatch_cmd中,调用queuecommand方法,将scsi command挂在自己的队列中,然后启动DMA,将scsi command发送到具体的磁盘。DMA完毕后,DMA控制器中断CPU,告诉CPU DMA结束。并且在中断上下文中,设置DMA结束的中断下半部。DMA中断处理程序返回之后,触发软中断,执行scsi中断下部。


驱动:scsi中间层(middle level driver) + scsi host driver。
scsi中间层抽象了scsi总线逻辑;scsi host driver控制scsi总线控制器,实现scsi数据的物理层传输。
queuecommand是这两层之间的桥梁。它将被注册为具体的物理块设备的函数,例如megaraid_queue。
● 执行中断下半部分,并返回:
在scsi中断下部,调用scsi command结束的回调函数scsi_done:scsi_dispatch_cmd->scsi_done。scsi_done调用blk_complete_request结束请求。


●
IO的生命周期的更多相关文章
- uni-app 生命周期
生命周期分为:页面生命周期和应用生命周期 生命周期可参考:uni-app官方API 注意平台支持,仅某个平台支持会显示,5+App是超HTML5+的App方案. 例如分享:只有小程序支持.这时我们就要 ...
- "过期不候"--具备生命周期的数据的技术实现方案
"过期不候"--具备生命周期的数据的技术实现方案 1 引言 本文可以作为之前的一个 原理性文章 对应的 技术实现部分 . 此处给出其上文的直达电梯: http://www.cn ...
- PHP扩展-生命周期和内存管理
1. PHP源码结构 PHP的内核子系统有两个,ZE(Zend Engine)和PHP Core.ZE负责将PHP脚本解析成机器码(也成为token符)后,在进程空间执行这些机器码:ZE还负责内存管理 ...
- Servlet的生命周期
Servlet的生命周期 Servlet的生命周期是由tomcat服务器来控制的. 1 构造方法: 创建servlet对象的时候调用.默认情况下,第一访问servlet就会创建servlet对象只创建 ...
- Java多线程 2 线程的生命周期和状态控制
一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就 ...
- Java并发1——线程创建、启动、生命周期与线程控制
内容提要: 线程与进程 为什么要使用多线程/进程?线程与进程的区别?线程对比进程的优势?Java中有多进程吗? 线程的创建与启动 线程的创建有哪几种方式?它们之间有什么区别? 线程的生命周期与线程控制 ...
- Servlet的生命周期+实现方式
1.Servlet的生命周期: (1)被创建: 默认情况下,Servlet第一次被访问时,被服务器创建.会调用init()方法. 一个 ...
- react学习小结(生命周期- 实例化时期 - 存在期- 销毁时期)
react学习小结 本文是我学习react的阶段性小结,如果看官你是react资深玩家,那么还请就此打住移步他处,如果你想给一些建议和指导,那么还请轻拍~ 目前团队内对react的使用非常普遍,之 ...
- Java多线程开发系列之三:线程这一辈子(线程的生命周期)
前文中已经提到了,关于多线程的基础知识和多线程的创建.但是如果想要很好的管理多线程,一定要对线程的生命周期有一个整体概念.本节即对线程的一生进行介绍,让大家对线程的各个时段的状态有一定了解. 线程的一 ...
随机推荐
- Balance(poj 1837)
题意:一个天平上有C个挂钩,第i个挂钩的位置为C[i],C[i] < 0表示该挂钩在原点的左边,C[i] > 0表示该挂钩在原点的右边:然后给出G个钩码的重量,问有多少种挂法使得天平保持平 ...
- Servlet获取参数
package action; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.Servlet ...
- kvm NET 和 BRIDGE
net: <interface type='network'> <mac address='52:54:00:e1:ac:43'/> <source network='d ...
- 【Ubuntu日常技巧】【解决】Ubuntu 16 右上角的音量调节通知框不停地闪烁问题
一. 先上干货 解决问题 1.1 安装工具alsa-tools-gui sudo apt-get install alsa-tools-gui 1.2 通过hdajackretask设置 直接执行命令 ...
- VBScript [ 译 ]
VBScript ( Visual Basic Scripting Edition) 使用COM 来和宿主环境交互.从Microsoft Windows 98 开始的所有的微软桌面操作系统的relea ...
- 能加载文件或程序集“System.Data.SQLite”或它的某一个依赖项。试图加载格式不正确的程序。
现象: 能加载文件或程序集“System.Data.SQLite”或它的某一个依赖项.试图加载格式不正确的程序.
- uva 10972(边双连通分量)
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=33804. 思路:和poj的一道题有点像,不过这道题图可能不连通,因 ...
- 在mysql数据库中制作千万级测试表
在mysql数据库中制作千万级测试表 前言: 最近准备深入的学一下mysql,包括各种引擎的特性.性能优化.分表分库等.为了方便测试性能.分表等工作,就需要先建立一张比较大的数据表.我这里准备先建一张 ...
- spring实战二之Bean的自动装配(非注解方式)
Bean的自动装配 自动装配(autowiring)有助于减少甚至消除配置<property>元素和<constructor-arg>元素,让Spring自动识别如何装配Bea ...
- BZOJ3831 : [Poi2014]Little Bird
设f[i]表示到i最少休息次数,f[i]=min(f[j]+(h[j]<=a[i])),i-k<=j<i,单调队列优化DP #include<cstdio> #defin ...