Linux中的文件系统

Linux文件系统的设计初衷

Linux操作系统中,有个很显著的特点就是:所有的IO对象都被抽象为文件,如果要进行IO操作,那么则通过调用Linux的虚拟文件系统提供的`open` 、`write `、`read`一系列接口,来到具体的IO块设备中使用设备驱动来实现。总而言之,就是Linux提供了一个内核层的软件,即虚拟文件系统,来提供所有的IO操作。

Linux虚拟文件系统支持的文件系统

磁盘文件系统

磁盘文件系统是用来管理本地磁盘的存储空间,或者其他可以起到磁盘作用的存储设备(U盘)。

Linux可以很好的支持对各种类型的文件系统的磁盘的访问,比如Linux使用的Ex4(第四拓展文件系统),Windows使用的NTFS以及 UNIX家族的各种操作系统

网络文件系统

网络文件系统是一种通过 VFS 把远程存储挂载到本地目录树的技术,本质是“文件系统驱动 + 网络协议”,它让应用像操作本地文件一样去读写远程数据。常见的RPC技术就是访问远程的网络文件系统的方式

特殊文件系统

特殊文件系统是 Linux 内核中不依赖磁盘的文件系统实现,它通过 VFS 提供统一的文件操作接口,但数据直接来自内存或内核数据结构,常用于系统信息、配置接口和临时存储。

常见的特殊文件系统介绍:

名称 挂载点 功能
procfs /proc 提供进程、内核状态信息(/proc/cpuinfo/proc/meminfo
sysfs /sys 反映内核对象(设备、驱动、总线等)的层次结构
tmpfs 任意挂载点(常见 /run/dev/shm 内存中的临时存储,可当 RAM Disk 用
devtmpfs /dev 自动创建设备节点
sockfs 内核内部使用 为 socket 提供 VFS 接口
pipefs 内核内部使用 管道/匿名管道实现
configfs /sys/kernel/config 允许用户空间创建和配置内核对象

虚拟文件系统中的数据结构

superblock

超级块是存放在磁盘上文件系统开头的一小块(通常在引导块之后),同时内存中也会有一份副本用于运行时访问。它是文件系统的“元信息(metadata)”,描述了整个文件系统的布局和关键参数。内核在挂载(mount)文件系统时,会读取超级块,将里面的参数加载到内存,用来指导后续的目录、inode、数据块的管理。

superblock 的主要内容:

  • 文件系统基本信息

    • 魔数(magic number):标识文件系统类型,防止挂载错误的分区。
    • 文件系统大小:总共有多少块(blocks)。
    • block 大小(一般 1KB、2KB、4KB)。
    • inode 总数。
  • 文件系统布局信息

    • inode 表起始位置、数量。
    • 数据块区域起始位置、数量。
    • 位图(block bitmap / inode bitmap)位置。
  • 一致性与日志相关信息

    • log 区域(用于 journaling 文件系统,比如 ext3/ext4 的 journal)。
    • 最近挂载时间、写入时间。
    • 是否被 cleanly unmount。
  • 运行时信息(仅内存态 superblock 保存)

    • 挂载点引用计数。
    • 指向 inode 缓存、dentry 缓存的指针。
    • 同步/锁机制。

简单地说,superblock 就是文件系统的“元信息控制中心”,它告诉操作系统如何解释磁盘上的数据,确保文件系统能被正确挂载、管理和维护。

索引节点对象(inode)

inode是文件系统中用来描述一个文件的 元数据结构 。每一个文件(普通文件、目录、符号链接、设备文件等)都有一个 inode。inode 不存储文件名 ,而是存储文件的属性和指向数据块的指针。

inode 中包含的主要信息

  • 文件属性(metadata)
  • 文件类型(普通文件、目录、符号链接、字符设备、块设备…)
  • 权限(rwx)
  • 所属用户 ID (UID)、组 ID (GID)
  • 文件大小(bytes)
  • 时间戳(atime/mtime/ctime)
  • 链接计数(多少个目录项指向该 inode)
  • 数据块位置
  • 直接块指针 (direct blocks):直接指向数据块。
  • 间接块指针 (indirect blocks):指向一个块,这个块里再存放更多数据块地址。
  • 二级/三级间接块指针 (large file 才需要)。

文件对象(file)

在 Linux 内核中,文件对象(file object) 就是 struct file 结构体。它并不是“磁盘上的实体”,而是 进程在打开文件时,内核为该打开实例创建的内存对象 。可以说,文件对象是站在进程的角度所设计出来的,它表示进程打开该文件的一次实例(动态的,运行时信息)

file中包含的主要信息

  • 路径 & inode

    • f_path:指向 dentry(目录项)和挂载点,用于路径解析
    • f_inode:快速访问 inode(文件的元数据)
  • 操作方法

    • f_op:指向一组函数指针(struct file_operations),定义了 read/write/ioctl/mmap 等操作的具体实现
    • 不同文件系统会注册自己的操作集,比如 ext4、procfs、sockfs
  • 运行时状态

    • f_flags:打开时传入的 flag(如 O_APPEND、O_NONBLOCK)
    • f_mode:读写模式(FMODE_READ, FMODE_WRITE)
    • f_pos:文件读写指针(当前偏移量)
  • 引用计数和同步

    • f_count:多少个 fd 指向这个 file 对象(dupfork 时会增加)
    • f_lock:保护并发访问
  • 缓存和私有数据

    • f_mapping:指向页缓存,用于文件和内存的映射
    • private_data:给具体文件系统或设备驱动使用(例如 socket 就会存 socket 的内部结构体)

有时候很容易混淆inode和file,简而言之,inode 描述文件是什么,file 描述“我这次打开它怎么用”

目录项对象(dentry)

dentry(directory entry,目录项对象) 是 VFS 用来表示 路径名的一部分(目录项) 的内存对象。它的作用是把 文件名inode 关联起来。需要注意的是:磁盘上存储目录项地方是目录文件的数据块,内存中对应的运行时抽象就是 dentry。

dentry中包含的主要信息

  • 名字信息

    • d_name:文件名(含长度和哈希值,便于快速查找)
    • d_parent:指向父目录的 dentry(形成目录树)
  • 层级关系

    • d_subdirs:子目录链表
    • 支持在内存里维护完整的目录树结构
  • 关联文件系统对象

    • d_inode:指向对应的 inode
    • d_sb:指向所属的超级块
  • 缓存与引用

    • d_hash:放入哈希表(dcache)中,用于快速查找路径
    • d_count:引用计数(多少个进程/内核对象正在用这个 dentry)
    • d_flags:标记 dentry 状态(是否有效、是否负向等)

目录项缓存(dentry cache ,简称 dcache)

dcache是 Linux VFS(虚拟文件系统)中非常重要的一部分。它的主要作用是: 加速路径名解析,避免重复的磁盘访问和 inode 查找

目录项缓存的作用

  • 路径名到 inode 的快速映射
    • dentry 保存了目录名(比如 docs)与其对应 inode 的关系。
    • 下次访问相同路径时可以直接从缓存获取 inode,而不用重新从磁盘读取。
  • 加速路径解析
    • 路径解析是逐级查找的,dcache 缓存了父目录到子目录/文件的映射,避免重复查找。
    • 例如多次访问 /home/user/docs/,后续只需查缓存。
  • 支持硬链接和别名
    • dentry 允许同一个 inode 被多个不同的目录项引用,帮助 VFS 处理硬链接。
  • 减少磁盘 I/O
    • 频繁打开、关闭文件时,通常 inode 和目录项都已经在缓存中,不需要再次读磁盘。
  • 配合 inode cache
    • dentry 只缓存 “路径 → inode 的映射”,而 inode cache 保存 “inode 号 → inode 对象”。
    • 两者结合起来,VFS 可以几乎不访问磁盘就完成大部分路径解析。

注意,这里dentry cache和inode cache都是保存在内存之中的

文件系统的路径名查找

这里以进程打开一个位于磁盘上的文件为例子 open(filename, flags, mode)

由于open要使用到系统的资源,因此需要使用SYS_OPEN, 陷入系统调用之后. 此时内核会去检查 dentrycache 查看有没有文件名对于的inode.如果找到了,那么根据该inode以及flags,mode,绑定对应inode中操作的函数指针,创建一个file类型,挂载在进程的file_struct中,同时,给该file对象分配一个fd,并且在fd_table中添加fd到file的映射,以根据文件描述符直接定位到制定的file. 如果没有找到,那么会依据目录名通过VFS中文件名解析的方式去查找,来返回对应文件名的inode,找到之后,在 dentrycache中添加这对映射关系,然后重复上面更新到进程的步骤.最后将对应的文件描述符返回.

作者

kosa-as

发布于

2025-08-29

更新于

2025-08-29

许可协议

评论