%%
# 纲要
> 主干纲要、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] 符号链接
>
> 
<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`。
>
> 
>
<br>
## 日志文件系统
日志文件系统放弃了之前先**将数据直接写入存储设备再更新 i 节点表**的做法,而是:
1. 先**将文件变更(创建/删除/修改内容)写入临时文件**(称作日志),当其**被成功记录到日志**后,**文件系统才实际执行数据更改操作**;
2. 当**数据更改被成功执行后**(写入到存储设备和 i 节点表),**再删除对应的日志条目**。
优点:
- **日志文件系统可以确保文件系统在系统崩溃后保持一致性,因为所有更改都先在日志中记录:**
- 如果系统在数据被写入存储设备之前崩溃或断电,则日志文件系统会读取日志文件,尚未完成的操作可以被正确地识别并处理。
- **提升效率**:将更改先写入**连续的日志区域**,可以减少磁盘寻道时间和提高写入效率。
- **加快恢复速度**:在系统崩溃后,恢复过程更快,因为只需要查看并应用或回滚日志中的记录,而不需要检查整个文件系统。
Linux 中有三种广泛使用的**日志方法**,每种的保护等级都不同:

通常,文件系统默认采用 "**有序模式**" 的日志方法,即**只有 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