Linux 的IO栈【转】

转自:https://zhuanlan.zhihu.com/p/39721251

说明


Linux的IO路径可能是Linux系统中最纷繁复杂的模块了,而它又是如此的重要,直接决定了系统的性能。之前在看Linux IO模块源码时,就对IO模块的层次比较模糊,在对IO路径上的各个模块进行了较深入的理解后,将自己的理解写出来,希望对入门者能有所帮助。

整体架构

应用程序:

这没什么好说的,通过相关系统调用(如open/read/write)发起IO请求,属于IO请求的源头;

文件系统:

应用程序的请求直接到达文件系统层。文件系统又分为VFS和具体文件系统(ext3、ext4等),VFS对应用层提供统一的访问接口,而ext3等文件系统则具体实现了这些接口。另外,为了提供IO性能,在该层还实现了诸如page cache等功能。同时,用户也可以选择绕过page cache,而是直接使用direct模式进行IO(如数据库)。

块设备层:

文件系统将IO请求打包提交给块设备层,该层会对这些IO请求作合并、排序、调度等,然后以新的格式发往更底层。在该层次上实现了多种电梯调度算法,如cfq、deadline等。

SCSI层:

块设备层将请求发往SCSI层,SCSI就开始真实处理这些IO请求,但是SCSI层又对其内部按照功能划分了不同层次:

* SCSI高层:高层驱动负责管理disk,接收块设备层发出的IO请求,打包成SCSI层可识别的命令格式,继续往下发;

* SCSI中层:中层负责通用功能,如错误处理,超时重试等;

* SCSI低层:底层负责识别物理设备,将其抽象提供给高层,同时接收高层派发的scsi命令,交给物理设备处理。


各层接口


清晰的接口能让复杂的系统变得容易理解和维护。

应用程序 => 文件系统


做开发的人可能都应该了解,通过诸如open/read/pread/write/writev等POSIX接口来调用文件系统各种功能。由于其普遍性,在这里就不一一描述接口形式了。


文件系统 => 块设备层


这里我们将文件系统当成一个整体,并不区分VFS和具体文件系统。块设备层对文件系统提供的接口为submit_bio(),接口形式如下:

void submit_bio(int rw, struct bio *bio)


文件系统向块设备提交的每个bio请求都设置了完成回调函数,记录在bio->bi_end_io。bio请求完成后,通过该字段通知文件系统。


块设备层 => SCSI上层


scsi_reuqest_fn()和struct request_queue。
老实来说,块设备层和SCSI上层之间分的没有那么清楚,耦合的稍微紧密,块设备层看到的IO请求结构是request。而SCSI层看到的IO命令则是scsi_cmnd

每个scsi设备(如scsi disk)均维护了一个请求队列request_queue,而每个scsi设备对上层呈现的其实是一个块设备。因此,块设备和scsi设备有着天然的联系,request_queue则是连接块设备层和SCSI层的纽带。块设备层对request请求最终会派发至request_queue中。而在特定条件下通过泄流机制将request_queue中积攒的request派发至SCSI层处理。而泄流的实际处理过程就是scsi_request_fn()函数,因此说它是块设备层和SCSI上层的接口也不为过,虽然不是特别准确。在scsi_reuqest_fn内会进行request至scsi_cmnd的转换。

SCSI上层 => SCSI中间层


SCSI上层在收到块设备层发起的scsi命令后马不停蹄又将其转发至SCSI中间层。SCSI上层至SCSI中间层的接口是 scsi_dispatch_cmd

static void scsi_request_fn(struct request_queue *q) {
    ......
    // 设置scsi命令完成回调函数
    cmd->scsi_done = scsi_done;
    rtn = scsi_dispatch_cmd(cmd);
    ......
}


SCSI中间层 => SCSI低层


SCSI中间层收到块设备层发下来的scsi_cmnd命令后,中间层作自己处理后,然后再将该命令继续往下传递,接下来该命令到了scsi底层,而传递的接口是 queuecommand()

static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) {
    ......
    rtn = host->hostt->queuecommand(host, cmd);
    ......
}


host为该设备所属的主机适配器结构。任何一个SCSI主机适配器都需要实现queuecommand接口。注意这个提交过程是异步的,无需等待该命令完成便直接返回。
scsi 命令完成后,会通过记录在命令内的完成函数回调上层处理,具体是cmd->scsi_done

总结


参考资料

Linux IO协议栈框图​blog.yufeng.info图标scsi块设备驱动层处理 - CSDN博客​blog.csdn.net图标
发布于 2018-07-14
【作者】张昺华
【大饼教你学系列】https://edu.csdn.net/course/detail/10393
【新浪微博】 张昺华--sky
【twitter】 @sky2030_
【微信公众号】 张昺华
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
原文地址:https://www.cnblogs.com/sky-heaven/p/14844894.html