Linux 虚拟文件系统(一)--初识inode

1. 前言

文件系统是一个操作系统必备的功能之一。当你想运行一个应用时,你需要加载一个可执行文件。当你想编辑一段文本并保存时,你需要写入一个文本文件。当你想查看一个张图片时,你需要打开一个图片文件。可以想象,没有文件系统功能的操作系统也只剩下一套空壳。

一个成熟的操作系统至少支持一种文件系统。Linux 作为最主流的开源操作系统,只支持一种文件系统这么掉价的行为。肯定是不为 Linux 拥趸们接受的。

为了支持多个文件系统实现,以及访问其他操作系统的文件系统。Linux 在用户进程和文件系统实现之间加入了一个抽象层。这个抽象层被称为虚拟文件系统(Virtual File System,简称 VFS)。

计算机科学中的所有问题都可以通过增加一个间接层来解决 David Wheeler(剑桥大学计算机科学教授)

2. VFS 简介

VFS 屏蔽了底层文件系统实现的差异,为文件系统使用者提供了统一的文件系统视图。VFS 定义了一系列的通用接口和通用数据结构。支持加载和卸载文件系统,通用的文件操作等。

VFS 为了实现通用的文件视图,提供了一系列数据结构供用户进程和文件系统实现进行交互。这些对象包括 inode 结构体、超级块、目录项缓存、文件系统等。本文主要介绍 inode 结构体,以及其组织方式。

3. inode 结构体

ruby 复制代码
root@ubuntu:~# tree dir/
dir/
├── a.txt
└── subDir
    └── b.txt

1 directory, 2 files

一般而言,文件系统中文件的组织方式是有层次的。而实现这种层次结构的关键就是 inode 结构体。

在详细介绍 inode 结构体之前,我们先介绍一下 Linux 世界的一个重要法则:万物皆文件。在 Linux 的所有的 I/O 操作都可以通过 VFS 提供的读写 API 进行操作。

inode 存储的信息可以分成两大类

  • 描述文件状态的元数据。包括访问权限、创建时间、修改时间、文件长度等。
  • 保存实际文件内容的数据段(或指向数据的指针),数据段的具体格式取决于各个具体的文件系统实现

这里需要特别指出的是文件名并不存储在 inode 中。文件名存储在目录项(dentry)中,目录项存储在 inode 的数据段中,格式取决于具体的文件系统实现。

将文件名存储到目录项(dentry)而非 inode 中。可以很方便实现硬链接。

arduino 复制代码
struct inode {
	umode_t			i_mode; // 文件权限和文件类型的值
	kuid_t			i_uid; // 文件所属用户
	kgid_t			i_gid; // 文件所属组
	const struct inode_operations	*i_op; // inode 的操作函数
	struct super_block	*i_sb; // 文件系统的超级块
	unsigned long		i_ino; // inode 编号
	loff_t			i_size; // 文件长度
	struct timespec64	__i_atime; // 最后访问时间
	struct timespec64	__i_mtime; // 最后修改时间
	struct timespec64	__i_ctime; // inode 最后修改时间
	u8			i_blkbits; // 文件系统块的大小
	blkcnt_t		i_blocks; // 文件总共有多少块
	struct address_space	i_data; // 数据指针
	...
}

在 VFS 的世界观里是不区分目录和文件的,它们都统一使用了 inode 这个结构体进行表示。而目录和文件的 inode 区别在于数据段和 i_mode 字段。

文件的 i_data 数据指针指向的内存区域存储的是文件的内容。而目录的 i_data 数据指针指向的内存区域存储的是目录项,目录项的格式由各个文件系统自行定义, VFS 并没有做规范。

i_mode 是一个位掩码,用来标识文件类型和权限。Linux 内核中定义了如下的文件类型常量。

  • S_IFREG:常规文件
  • S_IFDIR:目录
  • S_IFCHR:字符设备
  • S_IFBLK:块设备
  • S_IFIFO:管道或FIFO
  • S_IFLNK:符号链接
  • S_IFSOCK:套接字

当一个 inode 结构表示目录的时候,i_mode 位掩码对应的位置会置为 S_IFDIR。内核代码可以轻易地判断出一个 inode 结构是属于文件还是一个目录。

上图是本小节 tree 命令的执行目录的 inode 结构示意图。其中圆形的表示 inode 结构,方形的表示数据段。每个 inode 都有一个文件系统内唯一的编号 i_no 和一个指向数据段的指针。数据段的内容因为文件类型而不同。如果是文件则为数据段的内容为文件内容。如果是目录则为目录项数据。目录项数据取决于具体的文件系统实现,但是至少应该包含文件名和 inode 编码。

4. inode 组织方式

内核中每个的文件系统的 inode 都以链表的形式组织在一起。每个 inode 结构都通过自身的 i_list 字段指向排在自己后面的 inode 结构。首尾相连,组成一个庞大的 inode 链表。

但是,链表的查找速度又太慢了。所以 VFS 又将所有的 inode 结构组织到一张哈希表中。通过溢出链的方式处理哈希冲突。inode 结构体中的 i_hash 字段用于关联溢出链的每个 inode 结构。

4. 参考

相关推荐
jessecyj19 分钟前
SpringBoot详解
java·spring boot·后端
爱吃的小肥羊27 分钟前
刚刚!Claude最强大模型泄露,Anthropic紧急封锁
后端
qqty121727 分钟前
Spring Boot管理用户数据
java·spring boot·后端
bearpping1 小时前
SpringBoot最佳实践之 - 使用AOP记录操作日志
java·spring boot·后端
一叶飘零_sweeeet1 小时前
线上故障零扩散:全链路监控、智能告警与应急响应 SOP 完整落地指南
java·后端·spring
开心就好20252 小时前
不同阶段的 iOS 应用混淆工具怎么组合使用,源码混淆、IPA混淆
后端·ios
架构师沉默3 小时前
程序员如何避免猝死?
java·后端·架构
椰奶燕麦3 小时前
Windows PackageManager (winget) 核心故障排错与通用修复指南
后端
zjjsctcdl3 小时前
springBoot发布https服务及调用
spring boot·后端·https
zdl6864 小时前
Spring Boot文件上传
java·spring boot·后端