Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux 文件系統架構深度剖析:VFS、緩存與核心數據結構

編輯:Linux 教學

前言

Linux 支援數十種文件系統,透過 **虛擬文件系統 (VFS, Virtual File System Switch)** 統一抽象,實現「上層統一接口,下層多樣實現」。本文深入剖析 VFS 架構、核心數據結構、緩存機制、掛載流程與文件系統註冊,助你理解內核如何管理存儲資源。

一、整體架構分層

用戶空間
  ├── 應用程序 (read, write, open, stat...)
  ├── glibc (系統調用封裝)
內核空間
  ├── 系統調用入口 (sys_read, sys_write...)
  ├── VFS 虛擬文件系統 (核心抽象層)
  │     ├── 文件系統類型註冊表
  │     ├── 超級塊緩存
  │     ├── inode 緩存
  │     ├── 目錄項緩存
  │     └── 文件對象緩存
  ├── 具體文件系統驅動
  │     ├── ext4, xfs, btrfs, f2fs (磁碟)
  │     ├── nfs, cifs, fuse (網路/用戶態)
  │     ├── procfs, sysfs, debugfs (虛擬/內存)
  │     └── tmpfs, ramfs (純內存)
  ├── 緩衝區緩存 / 頁面緩存
  └── 塊設備驅動

二、VFS 核心數據結構

1. 超級塊對象 - 代表一個已掛載文件系統實例

struct super_block {
    struct list_head    s_list;         // 全局超級塊鏈表
    dev_t               s_dev;          // 設備號
    unsigned long       s_blocksize;    // 塊大小
    unsigned char       s_blocksize_bits;
    struct super_operations *s_op;      // 操作函數表
    struct export_operations *s_export_op;
    struct xattr_handler **s_xattr;
    struct list_head    s_inodes;       // 所有 inode 鏈表
    struct hlist_bl_head s_anon;        // 匿名 inode
    struct mutex        s_umount;       // 掛載/卸載鎖
    int                 s_count;        // 引用計數
    int                 s_active;       // 活躍引用
    void                *s_fs_info;     // 文件系統私有數據
    struct dentry       *s_root;        // 根目錄 dentry
    struct rw_semaphore s_umount;       // ...
};

**關鍵操作函數表** `super_operations`:`alloc_inode`、`destroy_inode`、`dirty_inode`、`write_inode`、`drop_inode`、`evict_inode`、`put_super`、`sync_fs`、`freeze_fs`、`unfreeze_fs`、`statfs`、`remount_fs`...

2. 索引節點對象 - 代表一個具體文件/目錄/設備

struct inode {
    umode_t             i_mode;         // 文件類型+權限
    uid_t               i_uid;
    gid_t               i_gid;
    loff_t              i_size;         // 文件大小 (位元組)
    struct timespec     i_atime, i_mtime, i_ctime;
    unsigned int        i_blkbits;      // 塊大小位數
    unsigned long       i_blocks;       // 佔用塊數
    struct inode_operations *i_op;      // inode 操作
    struct file_operations *i_fop;      // 默認文件操作
    struct super_block  *i_sb;          // 所屬超級塊
    struct address_space *i_mapping;    // 頁面緩存映射
    struct list_head    i_wb_list;      // 回寫列表
    union {
        struct pipe_inode_info *i_pipe;
        struct block_device *i_bdev;
        struct cdev *i_cdev;
    };
    spinlock_t          i_lock;
    unsigned int        i_flags;
    unsigned long       i_state;        // I_NEW, I_FREEING, I_CLEAR, I_SYNC, I_DIRTY...
    unsigned long       dirtied_when;
    unsigned long       dirtied_time_when;
    struct hlist_node   i_hash;         // inode 雜湊表
    struct list_head    i_lru;          // LRU 回收鏈表
    struct list_head    i_sb_list;      // 超級塊 inode 鏈表
    struct list_head    i_dentry;       // 關聯 dentry 列表
    spinlock_t          i_dentry_lock;
    atomic_t            i_count;        // 引用計數
    atomic_t            i_dio_count;
    atomic_t            i_writecount;
    void                *i_private;     // fs 私有
};

**inode_operations** 關鍵函數:`lookup`、`create`、`link`、`unlink`、`symlink`、`mkdir`、`rmdir`、`mknod`、`rename`、`setattr`、`getattr`、`listxattr`...

3. 目錄項對象 - 代表路徑分量,連接路徑名與 inode

struct dentry {
    unsigned int        d_flags;        // DCACHE_*
    struct dentry       *d_parent;      // 父目錄 dentry
    struct qstr         d_name;         // 目錄項名稱
    struct inode        *d_inode;       // 關聯 inode (NULL=負目錄項)
    struct hlist_bl_node d_hash;        // 雜湊表節點
    struct list_head    d_lru;          // LRU 列表
    struct list_head    d_child;        // 子目錄項鏈表
    struct list_head    d_subdirs;      // 子目錄列表
    struct list_head    d_alias;        // 別名 inode 鏈表
    struct dentry_operations *d_op;     // 目錄項操作
    struct super_block  *d_sb;          // 所屬超級塊
    void                *d_fsdata;      // fs 私有
};

**dentry 狀態**:正向 (d_inode != NULL)、負向 (d_inode == NULL,加速「文件不存在」查詢)、未連接 (d_parent == d_self)。

4. 文件對象 - 代表進程打開的文件實例

struct file {
    struct path         f_path;         // dentry + vfsmount
    struct inode        *f_inode;       // 便捷指針
    const struct file_operations *f_op; // 文件操作函數表
    atomic_long_t       f_count;        // 引用計數
    unsigned int        f_flags;        // O_RDONLY, O_NONBLOCK, O_APPEND...
    fmode_t             f_mode;         // FMODE_READ/WRITE/LSEEK...
    loff_t              f_pos;          // 文件讀寫偏移量
    struct fown_struct  f_owner;        // 信號驅動 I/O 擁有者
    struct file_ra_state f_ra;          // 預讀狀態
    void                *private_data;  // 驅動私有數據
    struct list_head    f_ep_links;     // epoll 關聯
    spinlock_t          f_lock;
};

**file_operations** 關鍵函數:`open`、`read`/`read_iter`、`write`/`write_iter`、`llseek`、`mmap`、`fsync`、`ioctl`/`unlocked_ioctl`、`poll`、`release`、`flock`、`fallocate`...

三、緩存機制

1. 目錄項緩存

  • 將路徑名解析結果缓存,避免重複遍歷目錄 inode。
  • LRU 列表回收,`d_count` 引用計數為 0 時移入 LRU。
  • 負目錄項緩存「不存在」結果,大幅加速 `open("not_exist")` 失敗路徑。

2. inode 緩存

  • 雜湊表 (`inode_hashtable`) + LRU 列表 (`inode_lru_list`)。
  • `I_DIRTY` 狀態標記需回寫磁碟,`writeback_inodes_sb()` 定期回寫。
  • `drop_caches` 可手動清理:`echo 2 > /proc/sys/vm/drop_caches` (僅回收 inode/dentry)。

3. 頁面緩存

  • 文件內容按頁面 (4KB) 緩存於 `address_space` (掛載在 inode->i_mapping)。
  • `read()` → `page_cache_read()` → 檢查頁面緩存 → 缺頁 → `mapping->a_ops->readpage()` → 塊設備 I/O。
  • `write()` → `page_cache_write()` → 標記頁面 `PageDirty` → `writeback` 異步回寫。

四、掛載流程詳解

mount -t ext4 /dev/sda1 /mnt/data

1. 系統調用 mount() → sys_mount()
2. 解析設備路徑 /dev/sda1 → 獲取 block_device
3. 文件系統類型 "ext4" → 查找 file_system_type 註冊表
4. fs_type->mount() → ext4_mount()
   a. 讀取超級塊 (bread)
   b. 驗證魔數、特徵標誌
   c. 分配 struct super_block,填充 s_op、s_root
   d. 讀取根目錄 inode → 分配 dentry ("/") → 關聯
5. 將 super_block 掛入全局列表,建立 vfsmount 結構
6. 將 vfsmount 掛入命名空間 mount 树 (namespace->mnt_root)
7. 返回用戶空間

五、文件系統註冊與模塊加載

// 文件系統驅動入口
static struct file_system_type ext4_fs_type = {
    .owner      = THIS_MODULE,
    .name       = "ext4",
    .mount      = ext4_mount,
    .kill_sb    = kill_block_super,
    .fs_flags   = FS_REQUIRES_DEV,
};
MODULE_ALIAS_FS("ext4");
MODULE_ALIAS("ext4");

// 模塊初始化
static int __init ext4_init_fs(void) {
    return register_filesystem(&ext4_fs_type);
}
static void __exit ext4_exit_fs(void) {
    unregister_filesystem(&ext4_fs_type);
}

掛載時內核自動 `request_module("fs-ext4")` 加載模塊。

六、特殊文件系統類型

類型代表特點
磁碟文件系統ext4, xfs, btrfs, f2fs塊設備、持久化、日志/COW
網路文件系統nfs, cifs, cephfs遠程協議、頁面緩存一致性挑戰
用戶態文件系統fuse (fuseblk, fuse.fuse)VFS → fuse 驅動 → 用戶態 daemon → 任意後端
虛擬/內存文件系統procfs, sysfs, debugfs, tmpfs, ramfs無底層設備、動態生成內容、tmpfs 可交換
偽文件系統pipefs, sockfs, bdev, mqueue內核內部對象命名空間

七、關鍵內核線程

  • `kworker/uX:X`:工作隊列執行異步 I/O、回寫。
  • `flush-X:Y` / `writeback`:髒頁回寫磁碟。
  • `jbd2/sdX-Y`:ext4 日志提交線程。
  • `kcopyd`:裝置映射器複製 (LVM 快照、鏡像)。
  • `kthrotld`:I/O 限流 (cgroups blkio)。

結語

VFS 以四大對象為核心,將「命名空間操作」(dentry)、「文件元數據」(inode)、「文件系統整體」(super_block)、「打開文件上下文」(file) 清晰分離,並透過緩存層 (dcache、icache、page cache) 橋接高速 CPU 與慢速存儲。理解這套架構,是分析文件系統性能瓶頸、開發新型文件系統、排查掛載/權限/一致性故障的必經之路。

Copyright © Windows教程網 All Rights Reserved