﻿---
title: Linux File System Architecture Introduction
date: 2025-06-01
excerpt: 🤖 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.
tags:
  - Linux
  - fd
cover: https://assets.vluv.space/cover/Dev/Linux/file_system.webp
---

## 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](https://assets.vluv.space/linux_file_system_arch.webp)

> [!NOTE] File Systems 实现层
>
> | 文件系统 | 特点                                               |
> | -------- | -------------------------------------------------- |
> | ext4     | 稳定、支持大文件、多子目录、日志、延迟分配         |
> | XFS      | 高性能 64 位日志文件系统，适合大数据和并发写入场景 |

## Files In Disk & Kernel

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

### In Disk

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

![Linux File System](https://assets.vluv.space/linux_file_system.webp)

### In Kernel

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

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

![File Descriptor Architecture](https://assets.vluv.space/fd_architecture.webp)

### 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 语言更正统一点~~)

```python
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
