Android核心技术—内核(Linux) 的IO栈

news2024/11/19 9:25:12

简述

Linux的IO路径可能是Linux系统中最纷繁复杂的模块了,而它又是如此的重要,直接决定了系统的性能。 接下来我们来看一张熟悉的老图:

由图可见,从系统调用的接口再往下,Linux下的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栈(读写流程)

linux IO 存储栈分为7层:

VFS 虚拟文件层: 在各个具体的文件系统上建立一个抽象层,屏蔽不同文件系统的差异。 PageCache 层: 为了缓解内核与磁盘速度的巨大差异。 映射层 Mapping Layer: 内核必须从块设备上读取数据,Mapping layer 要确定在物理设备上的位置。 通用块层: 通用块层处理来自系统其他组件发出的块设备请求。包含了块设备操作的一些通用函数和数据结构。 IO 调度层: IO 调度层主要是为了减少磁盘IO 的次数,增大磁盘整体的吞吐量,队列中多个bio 进行排序和合并。 块设备驱动层: 每一类设备都有其驱动程序,负责设备的读写。 物理设备层: 物理设备层有 HDD,SSD,Nvme 等磁盘设备。 PageCache 层: 两种策略: write back : 写入PageCache 便返回,不等数据落盘。 write through: 同步等待数据落盘。

读流程

  • (1)系统调用read()会触发相应的VFS(Virtual Filesystem Switch)函数,传递的参数 有文件描述符和文件偏移量。
  • (2)VFS确定请求的数据是否已经在内存缓冲区中;若数据不在内存中,确定如何执行读 操作。
  • (3)假设内核必须从块设备上读取数据,这样内核就必须确定数据在物理设备上的位置。 这由映射层(Mapping Layer)来完成。
  • (4)此时内核通过通用块设备层(Generic Block Layer)在块设备上执行读操作,启动I/O 操作,传输请求的数据。
  • (5)在通用块设备层之下是I/O调度层(I/O Scheduler Layer),根据内核的调度策略,对 等待的I/O等待队列排序。
  • (6)最后,块设备驱动(Block Device Driver)通过向磁盘控制器发送相应的命令,执行 真正的数据传输。

写流程

write()—>sys_write()—>vfs_write()—>通用块层—>IO调度层—>块设备驱动层—>块设备

块设备

系统中能够随机访问固定大小数据片(chunk)的设备称为块设备,这些数据片就称作 块。最常见的块设备是硬盘,除此之外,还有CD-ROM驱动器和SSD等。它们通常安装文 件系统的方式使用。

有关Android开发中的内核(Linux) 的IO栈学习,这里就做一部分浅析,如需深入了解,或者想进阶Android开发技术。大家可以参考《Android核心技术手册》这本电子书籍,里面分为很多知识板块。30个技术模块+笔记。点击查看免费方式。

总结

  1. IO 栈:VFS - 文件系统 - 块层 - SCSI 驱动层
  2. VFS 负责通用的文件抽象语义,管理并切换文件系统;
  3. 文件系统负责抽象出“文件的概念”,维护“文件”数据到块层的位置映射,怎么摆放数据,怎么抽象文件都是文件系统说了算;
  4. 块层对底层硬件设备做一层统一的抽象,最重要的是做一些IO 调度的策略。比如,尽可能收集批量 IO 聚合下发,让 IO 尽可能的顺序,合并 IO 请求减少 IO 次数等等;
  5. SCSI 层则是负责最后对硬件磁盘的对接,驱动层,本质就是个翻译器
  6. 文件的 buffer write 要实现 .write_begin,.write_page 等接口,前者用于分配 page 并绑定块层物理空间,后者用户异步回刷的时候调用(注意,非常规的优化在回刷的时候才去绑定物理空间);
  7. 文件系统 .write_begin 调用分配物理位置的时候依赖于get_block的实现,物理位置分配好之后,page 会对应到特定的 buffer head 结构,buffer head 结构则对应到具体的块设备位置;
  8. **direct IO 直接在用户路径上刷数据到磁盘,不走 PageCache 的逻辑,**但并不是所有文件系统都会实现它。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/11159.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Spring】——3、自定义TypeFilter指定@ComponentScan注解的过滤规则

📫作者简介:zhz小白 公众号:小白的Java进阶之路 专业技能: 1、Java基础,并精通多线程的开发,熟悉JVM原理 2、熟悉Java基础,并精通多线程的开发,熟悉JVM原理,具备⼀定的线…

Java中的IO流

Java中的IO流 Java中的4大IO抽象类 InputStream/OutputStream 为字节输入输出流 Reader/Writer 为字符输入输出流 InputStream OutputStream Reader Writer Java中流的概念细分 二进制文件(图片、影音)用字节流 文本信息用字符流 IO流的体系 练手案例…

HTML入门

目录1 HTML快速入门1.1 HTML 的介绍1.1.1 HTML 的组成标签属性1.2 入门案例1.2.1 案例效果1.2.2 实现步骤1.3 总结2 HTML 基本语法2.1 HTML 的注释2.2 HTML 标签2.3 HTML 的属性2.4 HTML 的特殊字符3 HTML 案例 新闻文本3.1 案例效果3.2 案例分析3.2.1 div 样式布局3.2.2 文本标…

软件测试面试真题 | Selenium 的工作原理是什么?

搜索微信公众号:TestingStudio 霍格沃兹的干货都很硬核 Selenium 通常被我们用做测试web的自动化测试工具,其实 Selenium 不仅仅是个API,它是一组工具集合,它是由三大组件组成 WebDriver: 可以模拟真正的用户去操作浏览器页面&am…

机械转码日记【24】继承

目录 前言 1.继承的概念及定义 1.1继承的概念 1.2 继承定义 1.2.1定义格式 1.2.2继承关系和访问限定符 1.2.3继承基类成员访问方式的变化 2.基类和派生类对象赋值转换 3.继承中的作用域 4.派生类的默认成员函数 4.1构造函数 5.设计一个不能被继承的类 6.继承与…

瑞吉外卖(三) 分类管理

瑞吉外卖 分类管理瑞吉外卖 分类管理 需求分析自动填充 代码思想ThreadLocal 的 引入瑞吉外卖 分类管理 需求分析 对于当前的多个Model,存在了多个相同的字段 比如说:更新时间,创建时间, 更新人等 这些重复的业务可以通过统一的接…

已有项目eclipse开发配置步骤

已有项目eclipse开发配置步骤 前提:jdk8安装、tomcat8安装 1、eclipse打开已有项目 File->import->Existing Projects into Workspace 说明:我这里已经打开项目了 2、配置Properties 项目根目录右击->点击Properties Java Build Path -&…

【僵尸进程和文件系统调用】

目录虚拟空间物理空间僵尸进程僵尸进程产生僵尸进程的解决孤儿进程文件系统调用虚拟空间物理空间 内存与磁盘的运行速度1:20 x86 32位 4G–> 物理内存:寻址能力4G 4G供内核1G,用户态的3G, 虚拟空间4G,虚拟空间可以…

周阳老师JUC并发编程

1. 序章 1)JUC是什么? java.util.concurrent在并发编程中使用的工具包 对JUC知识的高阶内容讲解和实战增强 2)为什么学习并用好多线程极其重要? 硬件方面: 摩尔定律: 它是由英特尔创始人之一Gordon Moore(戈登摩尔…

Linux 下编译实现C/Fortran调用动态库

目录 FORTRAN语言 生成动态库Demo 查看动态库中的函数 Fortran语言 FORTRAN语言是Formula Translation的缩写,意为“公式翻译”。它是为科学、工程问题或企事业管理中的那些能够用数学公式表达的问题而设计的,其数值计算的功能较强。 FORTRAN语言是…

样式补充(精灵图、背景图片、阴影),项目前置认知、结构搭建

一、网页制作 根目录 图片文件夹&#xff1a;images 样式文件夹&#xff1a;CSS 首页&#xff1a;index.html <link rel"stylesheet" href"./CSS/index.css"> 二、项目样式补充 1. 精灵图 场景&#xff1a;项目中将多张小图片&#xff0c;合并…

基于粒子群算法训练常规自动编码器附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

docker安装mysql,tomcat,redis,nginx

docker安装常用应用安装mysql解决docker mysql5.7中文乱码的问题开启防火墙指定端口docker MySQL容器被删除后数据恢复docker 配置MySQL主从创建master创建slave配置主从测试安装tomcat安装redis安装nginx安装mysql docker安装之前&#xff0c;需要查看宿主机上是否已安装&…

基于matlab仿真多普勒效应及其影响(附源码)

目录 一、介绍 二、估计直升机的叶片速度 三、直升机回声模拟 四、叶片返回微多普勒分析 五、汽车雷达中的行人识别 六、行人微多普勒提取 七、总结 八、程序 本例介绍了由于目标旋转而对目标进行雷达回波时微多普勒效应的基本概念。可以使用微多普勒特征来帮助识别目标…

UE4 回合游戏项目 16- 控制玩家

在上一节&#xff08;UE4 回合游戏项目 15- 生成玩家、控制玩家&#xff09;基础上&#xff0c;继续完善控制玩家的步骤 步骤&#xff1a; 1.打开1lantu&#xff0c;将Alpha的值设为1&#xff0c;这样玩家控制的角色会随着鼠标的移动而产生一个偏头的效果 2.接下来给角色添加…

java设计模式之原型模式

一&#xff1a;原型模式 1.什么是原型模式? 用一个已经创建的实例作为原型&#xff0c;通过复制该原型对象来创建一个和原型对象相同的新对象。 基本介绍 1.原型模式(Prototype模式)是指&#xff1a;用原型实例指定创建对象的种类&#xff0c;并且通过拷贝这些原型&#xff0…

STM32CubeMX学习笔记(47)——USB接口使用(MSC基于内部Flash模拟U盘)

一、USB简介 USB&#xff08;Universal Serial BUS&#xff09;通用串行总线&#xff0c;是一个外部总线标准&#xff0c;用于规范电脑与外部设备的连接和通讯。是应用在 PC 领域的接口技术。USB 接口支持设备的即插即用和热插拔功能。USB 是在 1994 年底由英特尔、康柏、IBM、…

数据库知识之图的创建以及各种遍历、生成树的形成

利用邻接矩阵创建图并打印输出利用递归完成dfs算法遍历利用非递归完成bfs算法遍历利用prim算法得出最小生成树利用kruskal算法得出最小生成树 #include <iostream> #include <cstdlib>//包含一些特定函数 #include <string> //邻接矩阵结构存储图 #defin…

量子计算(六):量子计算软件介绍

文章目录 量子计算软件介绍 一、量子语言 二、量子软件开发包 三、量子云平台 量子计算软件介绍 一、量子语言 由于当前量子计算机的通用体系架构未得到统一&#xff0c;在硬件层面上的技术路线也未最终确定&#xff0c;所以目前还无法确定哪种量子机器指令集相对更科学、…

2010年408大题总结

2010年408大题第41题第42题第43题第44题第45题第46题第47题第41题 这个考的是散列表&#xff08;巧了&#xff0c;我没复习&#xff0c;这就去看&#xff09; 第一个要记住的是装填因子&#xff0c;关键字个数/装填因子 数组长度 第二个是线性探测再散列&#xff0c;表示如果当…