Linux File System Architecture Introduction
Intro
Linux 文件系统架构遵循 Unix 的设计理念,其核心哲学之一就是“一切皆文件”(Everything is a file
)。这意味着无论是普通的文本文件、目录、设备(如打印机、磁盘)、管道、套接字还是其他系统资源,都被抽象成文件的形式进行操作,从而提供了一致的接口和简单的编程模型。
Linux File System Architecture
VFS 是内核中的一个抽象层,屏蔽了各种底层文件系统之间的差异,向用户和上层应用提供统一接口,定义了一些标准的文件系统对象(如 inode、dentry、super_block、file
etc.),开发应用时无需关心底层是 ext4、XFS 还是 Btrfs
具体的file system差异这里先不作说明,涉及到知识盲区了

文件系统 | 特点 |
---|---|
ext4 | 稳定、支持大文件、多子目录、日志、延迟分配 |
XFS | 高性能 64 位日志文件系统,适合大数据和并发写入场景 |
Files In Disk & Kernel
Linux 文件系统的设计使得文件在磁盘和内核中有不同的表现形式。文件在磁盘上以数据块的形式存储,而在内核中则通过文件描述符、索引节点等结构进行管理。
In Disk
Superblock: 文件系统的控制信息数据结构,包含文件系统的状态、类型、大小等信息
Inode: 存储文件元数据的数据结构,包含文件大小、拥有者、创建时间、数据块位置等信息, 使用ls -i
可查看文件对应的 inode 号

In Kernel
内核使用的三个表来表示进程使用的文件
层级名称 | 是否私有 | Description |
---|---|---|
fd table | 每个进程私有 | 存储在PCB的指针数组。下标被称作fd ,fa_table[fd] 为一个指向file table 的entry |
file table | 可被多个进程共享 | 存放文件状态,如文件偏移量、打开模式、引用计数,指向 inode table 的entry |
inode table | 所有进程共享 | 文件的元信息:权限、类型、大小、时间戳、磁盘块位置等,是真实文件的抽象描述 |

上面三个table中,日常开发最常接触的应该是进程的文件描述符表fd table
。当你使用 API 操作诸如 socket、pipe、open 等资源时,系统会返回一个文件描述符(fd),你后续需要使用这个 fd 来读写、关闭或传递资源。
在进程间通信(IPC)中,fd 也常作为资源句柄传递,实现资源共享。
文件描述符本质上是进程控制块(PCB)中的 fd table
的索引值。每个进程在创建时,默认会打开三个特殊的文件描述符,它们在所有进程中编号固定,用于标准输入输出:
文件描述符 | 名称 | 说明 |
---|---|---|
fd 0 | Standard Input (stdin) | 标准输入,通常是键盘 |
fd 1 | Standard Output (stdout) | 标准输出,通常是终端屏幕 |
fd 2 | Standard Error (stderr) | 标准错误输出,通常是终端屏幕 |
用一个简单的python script演示如何使用文件描述符重定向标准输出到一个文件(可能这里用C语言更正统一点)
1
2
3
4
5
6
7
8
9
10
11
12
13
import os
import sys
fd = os.open("test.txt", os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o644)
# 将标准输出重定向到a.txt在进程中的fd, 为了可读性,这里用`sys.stdout.fileno()`而非数字`1`
os.dup2(fd, sys.stdout.fileno())
# 现在所有 print 都输出到 a.txt
print("Hello, test.txt!")
os.close(fd)
常见的例子还有socket
编程,当创建一个 socket 时,系统会返回一个文件描述符,比如int sockfd = socket(AF_INET, SOCK_STREAM, 0);
创建一个socket,返回值sockfd
就是一个文件描述符。这个文件描述符可以用来进行读写操作,就像对待普通文件一样。比如,你可以使用write(sockfd, data, len)
来发送数据到这个 socket。
Linux File System Architecture Introduction