placeholderLinux File System Architecture Introduction

Linux File System Architecture Introduction

🤖 Explores Linux file system architecture built on Unix's "everything is a file" philosophy, covering VFS layer, popular file systems (ext2/3/4, XFS), and how files exist differently in disk vs kernel through superblocks, inodes, and file descriptors. Learn practical file descriptor usage with hands-on examples.

Intro

Linux 文件系统架构遵循 Unix 的设计理念,其核心哲学之一就是“一切皆文件”(Everything is a file)。这意味着无论是普通的文本文件、目录、设备(如打印机、磁盘)、管道、套接字还是其他系统资源,都被抽象成文件的形式进行操作,从而提供了一致的接口和简单的编程模型。

Linux File System Architecture

VFS 是内核中的一个抽象层,屏蔽了各种底层文件系统之间的差异,向用户和上层应用提供统一接口,定义了一些标准的文件系统对象(如 inode、dentry、super_block、file etc.),开发应用时无需关心底层是 ext4、XFS 还是 Btrfs

具体的 file system 差异这里先不作说明,涉及到知识盲区了

Linux File System Architecture
Linux File System Architecture

File Systems 实现层

文件系统 特点
ext4 稳定、支持大文件、多子目录、日志、延迟分配
XFS 高性能 64 位日志文件系统,适合大数据和并发写入场景

Files In Disk & Kernel

Linux 文件系统的设计使得文件在磁盘和内核中有不同的表现形式。文件在磁盘上以数据块的形式存储,而在内核中则通过文件描述符、索引节点等结构进行管理。

In Disk

Terms

Superblock: 文件系统的控制信息数据结构,包含文件系统的状态、类型、大小等信息
Inode: 存储文件元数据的数据结构,包含文件大小、拥有者、创建时间、数据块位置等信息, 使用ls -i可查看文件对应的 inode 号

Linux File System
Linux File System

In Kernel

内核使用的三个表来表示进程使用的文件

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

File Descriptor Architecture
File Descriptor Architecture

File Descriptor

上面三个 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 语言更正统一点)

import osimport sysfd = 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.txtprint("Hello, test.txt!")os.close(fd)

常见的例子还有socket编程,当创建一个 socket 时,系统会返回一个文件描述符,比如int sockfd = socket(AF_INET, SOCK_STREAM, 0);创建一个 socket,返回值sockfd就是一个文件描述符。这个文件描述符可以用来进行读写操作,就像对待普通文件一样。比如,你可以使用write(sockfd, data, len)来发送数据到这个 socket

CompactRelaxed
Normal1.70