● 将来自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的生命周期的更多相关文章

  1. uni-app 生命周期

    生命周期分为:页面生命周期和应用生命周期 生命周期可参考:uni-app官方API 注意平台支持,仅某个平台支持会显示,5+App是超HTML5+的App方案. 例如分享:只有小程序支持.这时我们就要 ...

  2. "过期不候"--具备生命周期的数据的技术实现方案

    "过期不候"--具备生命周期的数据的技术实现方案 1   引言 本文可以作为之前的一个 原理性文章 对应的 技术实现部分 . 此处给出其上文的直达电梯: http://www.cn ...

  3. PHP扩展-生命周期和内存管理

    1. PHP源码结构 PHP的内核子系统有两个,ZE(Zend Engine)和PHP Core.ZE负责将PHP脚本解析成机器码(也成为token符)后,在进程空间执行这些机器码:ZE还负责内存管理 ...

  4. Servlet的生命周期

    Servlet的生命周期 Servlet的生命周期是由tomcat服务器来控制的. 1 构造方法: 创建servlet对象的时候调用.默认情况下,第一访问servlet就会创建servlet对象只创建 ...

  5. Java多线程 2 线程的生命周期和状态控制

    一.线程的生命周期 线程状态转换图: 1.新建状态 用new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态.处于新生状态的线程有自己的内存空间,通过调用start方法进入就 ...

  6. Java并发1——线程创建、启动、生命周期与线程控制

    内容提要: 线程与进程 为什么要使用多线程/进程?线程与进程的区别?线程对比进程的优势?Java中有多进程吗? 线程的创建与启动 线程的创建有哪几种方式?它们之间有什么区别? 线程的生命周期与线程控制 ...

  7. Servlet的生命周期+实现方式

    1.Servlet的生命周期:        (1)被创建:            默认情况下,Servlet第一次被访问时,被服务器创建.会调用init()方法.                一个 ...

  8. react学习小结(生命周期- 实例化时期 - 存在期- 销毁时期)

    react学习小结   本文是我学习react的阶段性小结,如果看官你是react资深玩家,那么还请就此打住移步他处,如果你想给一些建议和指导,那么还请轻拍~ 目前团队内对react的使用非常普遍,之 ...

  9. Java多线程开发系列之三:线程这一辈子(线程的生命周期)

    前文中已经提到了,关于多线程的基础知识和多线程的创建.但是如果想要很好的管理多线程,一定要对线程的生命周期有一个整体概念.本节即对线程的一生进行介绍,让大家对线程的各个时段的状态有一定了解. 线程的一 ...

随机推荐

  1. How to Optimize Battery Health?

    1. click on the battery icon from taskbar next to the date and time. 2. click "More power optio ...

  2. kindEditort图片自动上传

    参考:http://www.cnblogs.com/jaxu/p/3824583.html (赞一个)

  3. PHP CI框架学习笔记-分页实现程序

    视图html  <div id="body"> <form action="/index.php/search/index/" method= ...

  4. x264_param_t结构体参数分析

    转自:http://blog.chinaunix.net/uid-17053077-id-1987955.html 参考网上的一些资料,结合个人的理解,对x264中x264_param_t结构体作了初 ...

  5. JSP Servlet 路径解析 路径设置

    转自:http://ethen.iteye.com/blog/800415 在用JSP和Servlet编写Web应用时,经常遇到的问题就是找不到.do路径,或者.do路径不能解析,其实归根到底就是Se ...

  6. jquery优化02

    缓存变量:DOM遍历是昂贵的,所以尽量将会重用的元素缓存. $element = $('#element'); h = $element.height(); //缓存 $element.css('he ...

  7. DFS POJ 2362 Square

    题目传送门 /* DFS:问能否用小棍子组成一个正方形 剪枝有3:长的不灵活,先考虑:若根本构不成正方形,直接no:若第一根比边长长,no 这题是POJ_1011的精简版:) */ #include ...

  8. BZOJ1397 : Ural 1486 Equal squares

    二分答案mid,然后检验是否存在两个相同的mid*mid的正方形 检验方法: 首先对于每个位置,求出它开始长度为mid的横行的hash值 然后对于hash值再求一次竖列的hash值 将第二次求出的ha ...

  9. Java IO操作

    转自:http://www.cnblogs.com/jyan/articles/2505791.html Johnny Yan的博客 1 InputStream类型 InputStream的作用是标志 ...

  10. topcoder SRM 593 DIV2 WolfDelaymaster

    #include <iostream> #include <string> #include <algorithm> using namespace std; cl ...