%% # 纲要 > 主干纲要、Hint/线索/路标 # Q&A #### 已明确 #### 待明确 > 当下仍存有的疑惑 **❓<font color="#c0504d"> 有什么问题?</font>** # Buffer ## 闪念 > sudden idea ## 候选资料 > Read it later %% # Linux 文件系统布局 下图参见 [^1] ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-9FAAF35E8A598B4962DF1431B8DB8673.png|830]] > [!info] Linux ext2 文件系统的结构示意 > > > ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-36239628CE46EF179DF826ADA2CA8D5D.png|700]] > > ext 系文件系统中,按 "**块组**" 进行划分。 > > ```text > 磁盘分区 > └── 文件系统结构 > ├── 引导块(Boot Block) > ├── 块组0 > | ├── 超级块(Superblock) > | ├── 块组描述符表(Block Group Descriptor) > | ├── 数据块位图 (标记数据块使用情况) > | ├── inode 位图(标记inode使用情况) > | ├── inode 列表(块组中所有inode) > | └── 数据块(Data Blocks, 存放实际数据) > | > |── 块组1 > |── 块组... > ``` > <br> ## 引导块 引导块位于**主分区的第一个扇区**(0 号扇区,称之为 "**主引导记录**",Master Boot Record,**==MBR==**)[^2] 引导块中存放着**引导程序**,其在 BIOS/UEFI 固件启动时被加载,用于**装载操作系统**。 > [!NOTE] OS 启动过程 > > **BIOS/UEFI 固件启动** => **读取 MBR(引导块)** => 执行**引导程序**(bootloader)=> 加载 OS 内核至内存,**交由内核接管** > > 1. **BIOS/UEFI 固件启动**——按下电源键后,主板上的该固件启动; > 2. **加载 MBR 引导块**——BIOS 加载硬盘中的 "**第一个扇区**"(MBR,**==引导块==**)到内存 > - 引导块中存储的是 "**引导程序**"(bootloader),例如具体的 `GRUB` 或 `LILO` 程序。 > 3. **执行引导代码**——引导程序将 "**==操作系统内核==**" 加载至内存中 > - OS 内核及相关组件存放**在文件系统的 `/boot` 或 `/` 路径**中; > - 引导程序首先读取其**配置文件**(例如 `grub.cfg`),由此获知 **内核文件路径** 等信息。 > - 引导程序从文件系统中 **加载内核** 到内存,完整内核参数配置,跳转至内核运行。 > 4. **内核接管运行**——挂载根文件系统,**启动首个用户进程**(如 `inti` 或 `systemd`) > ## 超级块 超级块中存储着 **整个文件系统的全局元信息**: - 文件系统总大小 - inode 总数 - 数据块 总数 - 每个**块组**的 inode 个数(上限) - 每个**块组**的数据块个数(上限) - inode 区、数据区起始位置 - ... ## 块组描述符表 ext 系文件系统中,按 "**块组**" 进行划分,块组描述符中记录了 "**各个块组的状态**",例如**块组中空闲块与 inode 数量**。 > [!NOTE] "超级块" 与 "块组描述符表" 是全局信息 > > ext2 中 **每个块组中** 都保存了一份上述冗余副本: > > - 一方面可用于意外时恢复; > - 另一方面可使**块组数据**与**文件系统元信息**排列接近,减少磁盘寻道时间。 > > 在 ext 系后续文件系统中,采用了更优的稀疏技术,不再是每个块组都保存冗余副本。 > <br> ## "inode 位图" 与 "数据位图" 利用二进制位来表示 "磁盘上的**数据块**" 以及 "**inode**" 使用情况,0 空闲,1 已分配。 <br> ## inode 表 inode 表在磁盘上是**一块连续的空间**,每个 **inode 占据固定的大小**,**紧邻排列,编号由 1 起递增**。 inode 表由文件系统初始化时创建,决定了文件系统可支持的 "**最大文件数量**",若 inode 耗尽,即使磁盘还有剩余空间,也无法创建新文件。 inode 位图标记即是 **inode 表中各个 inode 的分配情况**。 ## 数据块 硬盘是以 "**扇区**" 或 "**页**" 作为**物理存取单位**的(机械硬盘按 "扇区",典型为 512B;固态硬盘按 "页",典型为 4KB), 但 OS 文件系统以 "**数据块**(block)" 作为**最小存取单位**(即 **==I/O 块==大小**),意味着**文件系统请求一个数据块时,在 HHD 上会至少访问 8 个扇区**。 > [!NOTE] 查看文件系统的**数据块大小** > > 方式一:`stat <file>` > > ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-BA1518F7CC9785AC81D3186ECB990493.png|613]] > > 方式二: > > - `df -hT` 获取文件系统的**设备名**; > - `sudo tune2fs -l /dev/sda3 | grep "Block size"` 查看文件系统的**块大小** > > ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-6B8417DE51955540454714A9F450FB46.png|536]] > > <br><br><br> # inode (i 节点) inode 是存储着 “**文件元信息**” 的数据结构,占固定大小(例如 128 字节或 ext4 默认的 256 字节),存储有以下信息: - **文件类型**: 普通文件、目录或链接等 - **文件访问权限**:可读、可写、可执行; - **所有者**:用户 id、组 id; - **文件大小**:文件大小,以字节为单位 - **时间戳**:inode 修改时间、文件最近修改时间 mtime、最近访问时间 atime - **链接计数**:指向该 inode 的 "**硬链接**" 数量(即 **目录项数量**) - **块数量**:共占用了多少 “**数据块**”。 - **标志位** - **==数据块指针==**(数组):指向 "**索引数据块**" or "**数据块**" - 索引数据块存的是**指向下一级数据块的指针**,构成 **==多级索引==**,由此实现大文件存储。 每个文件创建时,内核 **通过 inode 位图找到==空闲的 inode==** 进行分配, 由此为每个文件关联 "**==唯一的 inode==**" 以及 "**inode 号**"。此后,文件系统通过 **inode 号** 来识别和访问文件。 > [!info] inode 中不存储 "**inode 号**"、"**文件名**" 与 "**文件数据内容**" > > - **文件名 & inode 号**:仅存储于文件所在目录的 "**目录条目**"中——即**目录项**,存储了 "**文件名 -> 对应的 ==inode 号==**" 。 > - **文件数据内容**:inode 存储了指向 "**数据块**" 的指针,文件数据内容存储在数据块中。 ![[02-开发笔记/11-Linux/Linux 命令行/Linux-文件与目录相关命令#^nzcq1t]] > [!note] ext2 文件系统中 inode 保存的数据块指针 [^3] > > inode 里的 `i_block` 大小为 15: > > - `[0, 11]`:直接指向 "**存放文件数据内容的数据块**"。 > - `[12]`:指向一个 "一级索引块"——块中存储的每个指针指向一个 "**存放文件数据内容的数据块**"。 > - `[13]`:指向一个 "二级索引块"——块中存储的每个指针分别指向一个 "**一级索引块**"; > - `[14]`:指向一个 "三级索引块"。 > > 由此,支持 TB 级大文件存储,缺点是对于大文件的访问需要多次间接查询,为此 ext4 中采取了一定的修改优化。 > > > ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-A32FF5D7B18512125BF9EFF6B14B3762.png|581]] > > > [!info] ext4 中 inode 定义[^4] > > ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-F1141AFC502CDC7B23AF460D78484802.png|477]] <br><br><br> # 目录 & 目录项 Linux 中**目录**本质上也是文件,其 "**数据块**" 中保存的是 "**目录条目**",称为 "**==目录项==**"(directory entry)。 目录项中存储了每个文件的 "**文件名**" & "**inode 号**",以 ext4 文件系统为例,具体包含: - **文件 inode 号** - **文件名** - **文件类型** - **文件名长度** - **目录项长度**(各个目录项不是固定长度,但会存在 **字节对齐**) > [!info] ext4 中的目录项结构体[^4] > > ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-7B2A146D976ECEFE7F14D33CBCD030A6.png]] > [!INFO] Linux 下文件名(basename)**最长为 255 字节**,完整路径名 **最长为 4095 字节**。 > [!info] ext3/4 文件系统中的目录数据块(引入了哈希目录结构) > > 由 "**文件名**" 计算哈希值,从而快速确认该文件对应的 "**目录项**" 具体在该目录的哪一个 "**数据块**" 中。 > > ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-168F7BF5BE1083A540DC41B0307F448A.png|789]] > <br><br><br> # "软链接" 与 "硬链接" - **硬链接**(Hard Link):多个 "**目录项**" 指向 **==同一个 inode==**, - **软链接 | 符号链接**(Symbol Link):一个**实际文件**,有独立的 inode 与数据块,其文件内容是 "**==被链接文件的路径==**",文件大小即该 "**路径名**" 的**实际字节数**。 > [!NOTE] 硬链接、软链接示意图[^3] > > ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-541D5C2886D24AD3CB5EC0310CFB6530.png|585]] > > [!NOTE] 一个目录的硬链接数量 = "**2 + 直接子目录数量**" > > 以 `/foo/bar/` 为例 > > - bar 的父目录 foo 中有一个目录项指向 bar 的 inode,计数 1; > - bar 自身的目录项中有一个 `.` 指向其自身 inode,也计数 1。 > > 因此,目录的硬链接数量至少为 2。 <br> ## 区别对比 - **生存期与删除**: - **硬链接**:即使原始文件被删除,**硬链接仍然保留并指向相同的数据**。只有删除**所有的硬链接和原始文件**,文件数据才被真正删除。 - **符号链接**:若原始文件被删除或移动,则将成为"**死链接**",**指向无效位置**。 - **空间占用上**: - **硬链接**:仅占用 "**一个目录项**" 的硬盘空间; - **符号链接**:占用极小的硬盘空间,仅存储所指向文件的路径信息。 - **显示上**: - **硬链接**: `ls` 查看时,其与原始文件看起来相同,包括所显示的文件大小。 - **符号链接**: `ls` 查看时,符号链接会显示为一个链接路径,例如 `source -> target`。 - **链接到目录**: - 硬链接:通常不允许链接到目录(root 用户除外) - 符号链接:可以链接到目录 - **跨文件系统方面**: - 硬链接:不能跨文件系统,只能对处于同一存储设备的文件创建硬链接。 - 符号链接:可以跨文件系统,可在不同存储设备的文件之间创建符号链接。 > [!info] > 硬链接在文件系统中**显示占用的空间与原始文件相同**,但 **==实际上不占用额外的磁盘空间==**,而是**与原始文件共享相同的数据块**; > [!example] 符号链接 > > ![image-20230922185611649](_attachment/02-开发笔记/11-Linux/Linux%20文件系统基本概念.assets/IMG-Linux%20文件系统基本概念-2400A96D5CBF17FD8F6BDE23FD50B83A.png) <br><br><br> # Linux 文件类型 > `ls` 查看文件,首字母标记文件类型 **Linux 系统中,一切都是文件**——数据、程序、物理硬件设备、内核对象等都**抽象为文件**。 共七种文件类型[^5]: - `-` **普通文件** (包含某种形式的数据,文本 or 二进制数据, **UNIX 内核对文本数据和二进制数据并不加以区分**) - 文本文件:由 **纯文本数据(字符)** 构成的文件 - 二进制文件:由**二进制数据**构成,**只在被执行或由其他程序解释时才有意义**,包括可执行程序、图片、音视频、电子表格等等。 - `d` **目录文件**:用于组织文件和子目录,形成层次结构 - 目录中不存放实际文件,只包含定位文件所需的信息——**一个目录条目**仅包含**一个文件名**,以及**一个指向该文件的指针**。 - `l` **符号链接文件**:指向另一个文件或目录的**引用**。 - `c` **字符设备文件**:用于访问提供 **"串行数据流"** 的设备(如终端、键盘、鼠标),**==不带缓冲,每次访问长度可变==**,例如 `/dev/tty`。 - `b` **块设备文件**:用于访问提供 "**块数据存储**" 的设备(如硬盘),**==带缓冲,每次访问以块为单位进行==**,例如 `/dev/sda` 等。 - `p` **命名管道**(FIFO): 用于**进程间通信**的**命名管道**,通过 FIFO 的方式传递数据。 - `s` **套接字文件**:用于**进程间通信**的**套接字**,可在网络或同一台机器上的不同进程之间传递数据,最常见于`/run` 或 `/tmp` 目录 > [!NOTE] 设备文件、套接字、管道并不是真正在磁盘上 "存储数据" 的文件,而是一种 "设备访问接口" 或 "通信机制"。 > [!NOTE] "字符设备" 与 "块设备" > > Unix 系统区分这两种类型的设备: > > - 每次**处理单个字节数据**的设备(如终端)称之为 "**字符设备**"; > - 每次**处理固定数量字节数据**的设备(如磁盘)称之为 "**块设备**"。 > <br> %% ## 命名管道 ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-A1B47C333E6E2EC1DA161B13706F357D.png|521]] %% <br> %% # 文件读取过程 对于文件路径 `/a/b/c.txt`,例如调用 `open()` 打开时,文件系统需要**从根目录起遍历各级目录**: - 读取 **根目录的 inode**,访问其指向的数据块,即遍历 "**根目录的目录项**",**获取 `a` 条目对应的 inode 号** - 读取 **`a` 目录的 inode**,获取 #TODO # 文件打开过程 - 内存中打开的文件数据结构 #TODO %% <br><br><br> # Linux 虚拟文件系统 VFS > **虚拟文件系统**(Virtual File System, VFS) VFS 是 Linux 系统**对文件系统的抽象**,其提供了一组 **访问文件系统的标准 API**,而对应用程序**隐藏了底层不同文件系统间的差异**(包括本地 or 网络文件系统、伪文件系统)。 得益于这层抽象,**程序无需考虑数据实际所位于的文件系统类型**,而只需要向**虚拟文件系统 VFS** 发起请求,由 VFS 来**定位具体的文件系统**并**通知设备驱动程序执行 I/O** 与之进行通信。 VFS 这层抽象体现了 "**一切皆为文件**" 的设计理念,包括 `/dev` 下设备文件、对于 `/proc` 伪文件系统的访问,均通过这层统一接口进行访问。 ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-011925AD07003596276E40DF2B11EFFB.png|505]] <br><br> # 伪文件系统(pseudo-filesystem) Linux 中特定路径下挂载的文件系统是 "**==伪文件系统==**"(pseudo-filesystem),其中的文件是 "**==伪文件==**",数据并非存储于磁盘,而是**来自==内存==** 。 VFS 虚拟文件系统这层抽象使得 **"可以像查看/修改文件内容一样"** 来操作这些来自内存的数据。 | 伪文件系统 | 挂载路径 | 说明 | | ----- | ----------------- | --------------------- | | proc | `/proc` | 提供了查看/修改**内核数据**的接口 | | sysfs | `/sys` | 提供了查看/管理**内核设备信息**的接口 | > [!info] `man 5 proc`、`man 5 sysfs` 说明 > > ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-19381B2EACD8D1BD222582713BFB76A2.png|802]] > > ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-06D42318DBB7429F0F0D5990EFF7D9B4.png|798]] <br> ### proc 虚拟文件系统 `/proc` **由内核在内存中维护**,用于向用户空间**暴露内核状态和进程信息**。 系统中 **每个进程** 在 `/proc` 中都对应一个子目录,**目录名为进程 PID**(例如 `/proc/619` 是 PID 为 619 的进程对应的目录)。 该目录下的 "**伪文件**" 存储了**进程相关信息**,包括进程的命令行、环境变量和信号掩码等。 > [!info] `ps` 程序正是通过读取 `proc` 文件来收集所需数据 > [!quote] > ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-D16FBE6DFF8E8F6896966F25F6AD2D04.png|596]] > [!example] 使用示例 > > - 查看 CPU 信息:`cat /proc/cpuinfo` > - 查看进程状态:`cat /proc/<pid>/status`(包括 UIP、线程数、内存占用等) > > 参见 [[02-开发笔记/11-Linux/Linux 命令行/Linux-系统信息相关命令#查看进程相关信息(`/proc//`)|Linux-系统信息相关命令]] <br> ### sysfs 虚拟文件系统 sysfs 文件系统挂载于 `/sys` 路径,主要用于**查看和管理内核导出的对象模型(设备、驱动、总线、内核子系统)**。 ##### `/proc/sys` 与 `/sys` 的区别 | | `/proc/sys` | `/sys` | | ------- | -------------------------- | ----------------------------------------------- | | 管理内容 | 内核参数 | 内核对象模型(设备/驱动/模块) <br>如硬件设备、驱动、总线、block、CPU、电源等 | | 持久化配置方式 | 通过 `/etc/sysctl.conf` 配置文件 | 通过 udev、systemd、udevadm 等工具 | <br><br><br> # Linux 支持的文件系统类型 Linux 支持的文件系统类型包括 - 传统文件系统:ext2 / minix / MS-DOS / FAT (用 vfat 模块) / iso9660 (光盘) 等等; - 日志式文件系统: ext3 /**ext4** / ReiserFS / Windows' NTFS / IBM's JFS / SGI's **XFS** / ZFS - 网络文件系统: NFS / SMBFS 最早的 Linux 操作系统使用 MINIX 文件系统,随后被第一代**扩展文件系统**ext 取代,后者又被 ext2 取代。 ext2 是早期一段时间内 Linux 最流行的文件系统。 当下 Linux 发行版默认采用的是**日志文件系统 EXT4 或者 XFS**。 > [!info] > - RHEL 7、CentOS 7 起,**预设的文件系统已经由 EXT4 变成了 XFS 文件系统**;(centos6 是 ext4,centos5 是 ext3) > - Ubuntu 22.04.3 LTS 的预设文件系统仍然是 **EXT4**。 > [!NOTE] > - vaft 即 Windows 下的 fat32 文件系统,在 Linux 中识别为 vfat。支持最大 32GB 的分区和**最大 4GB 的文件**。通常,U 盘中的默认文件系统格式即 `fat32`。 > > ![image-20230922115748991|633](_attachment/02-开发笔记/11-Linux/Linux%20文件系统基本概念.assets/IMG-Linux%20文件系统基本概念-7BA6F0A66A77AEC0EAB1ED454374262E.png) > <br> ## 日志文件系统 日志文件系统放弃了之前先**将数据直接写入存储设备再更新 i 节点表**的做法,而是: 1. 先**将文件变更(创建/删除/修改内容)写入临时文件**(称作日志),当其**被成功记录到日志**后,**文件系统才实际执行数据更改操作**; 2. 当**数据更改被成功执行后**(写入到存储设备和 i 节点表),**再删除对应的日志条目**。 优点: - **日志文件系统可以确保文件系统在系统崩溃后保持一致性,因为所有更改都先在日志中记录:** - 如果系统在数据被写入存储设备之前崩溃或断电,则日志文件系统会读取日志文件,尚未完成的操作可以被正确地识别并处理。 - **提升效率**:将更改先写入**连续的日志区域**,可以减少磁盘寻道时间和提高写入效率。 - **加快恢复速度**:在系统崩溃后,恢复过程更快,因为只需要查看并应用或回滚日志中的记录,而不需要检查整个文件系统。 Linux 中有三种广泛使用的**日志方法**,每种的保护等级都不同: ![image-20231107102157930|683](_attachment/02-开发笔记/11-Linux/Linux%20文件系统基本概念.assets/IMG-Linux%20文件系统基本概念-260DD9B75AD9F492F5859CF50B25C83E.png) 通常,文件系统默认采用 "**有序模式**" 的日志方法,即**只有 i 节点数据会被写入日志**,例如 ext3/4。 ##### 常见的日志文件系统 - **Ext3 和 Ext4**:这是 Linux 中广泛使用的日志文件系统,提供了向前兼容性(即可以从 Ext2 升级到 Ext3/Ext4 而无需格式化)。 - **XFS**:这是一个高性能的日志文件系统,常用于大型文件系统和高性能计算环境。 > [!info] ext4 文件系统 > > 第四代扩展文件系统(Fourth EXtended filesystem,ext4) > > Ext4 是 Ext3 文件系统的升级版,ext4 改变了 ext3 所采用的**块寻址方案**,在性能、伸缩性和可靠性方面进行了大量改进: > > - 向下兼容 Ext3; > - 支持最大 1EB 文件系统和 16TB 文件; > - 理论上支持无限数量子目录; > - Extents 连续数据块概念; > - 多块分配、延迟分配、持久预分配; > - 快速 FSCK、日志校验、无日志模式、在线碎片整理、inode 增强、默认启用 barrier 等; > > ext4 的主要改动在于使用了 "**盘区**",盘区代表 "连续的存储块",例如 128MB 的连续 4KB 的块。 > <br><br><br> # Buffer 块缓冲 Linux 中的 Buffer 是用于**缓冲 "==块设备==" 的元数据** 的内存,即 "**文件系统元信息**",例如: - **inode 表** - **超级块**; - inode 位图、数据块位图(block bitmap) - **目录项** - ...... > [!info] 参见 `man 5 proc` 中的说明——"原始磁盘块的相对临时存储" > > ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-54EE3B6EC60938A673A8D6695793CA1C.png|749]] > <br><br><br> # Page Cache 页缓存 "**页**"(page)是内存管理的基本单位(通常 4KB),Page Cache 即是 Linux 内核用于 **缓存==磁盘文件内容==** 的内存页。 内核 **将文件的数据读入到内存的 Page Cache 中**,**旨在减少磁盘 I/O**,有两方面作用: 1. **读缓存**:下次请求读取该文件数据时,若命中 Page Cache 时则无需访问磁盘; 2. **写缓存**:即 write-back 回写机制——对文件内容的修改**先写入 Page Cache 并标记==脏页==**,再**由内核后台线程异步刷入磁盘**。 > [!NOTE] Linux 文件系统 I/O:Page Cache[^6] > ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-48F7F512113BBC5D309094E2FCEED9E1.png|611]] > [!NOTE] 可通过 `cat /proc/meminfo` 查看系统的 PageCache ### 读缓存 当进程通过 read 请求读取一个文件时,**内核会先检查 Page Cache 是否已缓存该数据**: - 若命中 cache,则直接从内存中读取,无需访问磁盘; - 若未命中,则从磁盘读取数据,同时存入 Page Cache 中。 ### 写缓存 即 "write-back" 回写机制。 <br> # Linux 中的回写策略(write-back) 1. 进程调用 `write()` 写文件; 2. 数据修改会先写到 **==Page Cache 页缓存==** 中,并标记为 "**==脏页==**",加入到内核中 "**脏页链表**"。 3. Linux **后台回写线程** 在特定条件触发时执行 "**回写**"(后台线程调用 `sync()`),将脏页实际地写入磁盘,实现持久化。 4. 进程也可主动调用 `sync()`,`fsync(fd)`,**强制将脏页刷入磁盘**[^7]。 > [!INFO] "脏页" 的含义是内存与磁盘上数据不一致——磁盘上旧数据已过时 > [!NOTE] 内核后台线程执行 "脏页回写" 的部分触发条件 > > - 周期性触发回写 > - 脏页数超过阈值; > - 脏页存在时间超过阈值; > - 内存不够用,内核进行**缓存回收**,从而腾出更多干净页时; > [!NOTE] 关于 `sync()` 与 `fsync(fd)` 系统调用 > > - `sync()`:将所有脏页刷入磁盘。**Linux 下==保证会阻塞==直至完整刷入磁盘**(不同于 POSIX 标准要求[^8]) > - `fsync(fd)`:只将文件描述符 fd 指定的 **单个文件** 的脏页刷入磁盘,**==阻塞==直至刷入磁盘后返回**。 > > 参见 `man 2 sync` 说明: > > ![[_attachment/02-开发笔记/11-Linux/Linux 文件系统基本概念.assets/IMG-Linux 文件系统基本概念-A5D678AC2D2EDD87209ABE25493B9B7E.png|830]] > > 注:Linux 命令 `sync` 背后即是简单调用 `sync()` 系统调用。 ### 回写相关的内核参数 | 内核参数 | 说明 | | ---------------------------------------- | --------------------------------------------------- | | `/proc/sys/vm/dirty_writeback_centisecs` | 周期性回写的时间间隔(单位:1/100 秒),默认值 500,表示 5 秒触发一次 | | `/proc/sys/vm/dirty_expire_centisecs` | 脏页过期时间(单位:1/100 秒),超时后被强制刷入磁盘,默认值 3000,即 30 秒。 | | `/proc/sys/vm/dirty_ratio` | 内存中脏页占比(%)**上限**。超过该值时,**==阻塞进程的写操作==**,**强制回写脏页**。 | | `/proc/sys/vm/dirty_background_ratio` | 内存中脏页占比(%)超过该值时,内核后台线程开始 **异步回写脏页**。 | <br><br> # 参考资料 # Footnotes [^1]: 《UNIX 环境高级编程》P91 [^2]: 《现代操作系统》(P157) [^3]: [7.1 文件系统全家桶 \| 小林coding](https://xiaolincoding.com/os/6_file_system/file_system.html#unix-%E6%96%87%E4%BB%B6%E7%9A%84%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F) [^4]: [linux/fs/ext4/ext4.h at master · torvalds/linux · GitHub](https://github.com/torvalds/linux/blob/master/fs/ext4/ext4.h#L776) [^5]: 《UNIX 环境高级编程》P75 [^6]: [7.2 进程写文件时,进程发生了崩溃,已写入的数据会丢失吗? \| 小林coding](https://xiaolincoding.com/os/6_file_system/pagecache.html) [^7]: 《操作系统导论 OSTEP》P368 [^8]: 《UNIX 环境高级编程》P65