Linux 系统编程:文件系统的底层逻辑 - inode

《Linux 程序设计》的第三章讲文件操作。在提到 目录 时有这么一段文字:

文件,除了本身包含的 内容 以外,它还会有一个 名字 和一些 属性,即"管理信息",包括文件的创建 / 修改日期和它的访问权限。这些属性被保存在文件的 inode 中,它是文件系统中的一个特殊数据库,它同时还包含文件的长度和文件在磁盘上存放的位置。系统使用的是文件的 inode 编号,目录结构为文件命名仅仅是为了便于人们使用。

目录 是用于保存其他文件的 节点号名字 的文件。目录文件中的每个数据项都是指向某个文件节点的链接,删除文件名就等于删除与之对应的链接。你可以通过使用 ln 命令在不同的目录中创建指向同一个文件的链接。

刚开始,我不能清晰的理解这两段内容,特别是 inode 。所以我查找了 inode 的资料,发现它是一个重要的基础概念。当我深入了解了 inode 之后,我甚至觉得它是学好 Linux 文件系统的关键。

什么是 inode

当 Linux 创建文件时,会完成两件事情。第一,Linux 在存储设备上保留一块空间用来存储数据。第二,Linux 创建一个称为 索引节点 (index node,简称 inode) 的接口,用来存放文件的属性信息。每一个文件都有对应的 inode ,具体有以下内容:

  • 文件大小,以字节为单位
  • 包含该文件的设备名称
  • 属主的用户标识(Uid)
  • 组标识(Gid)
  • 文件的权限
  • 文件时间戳,共 3 个:inode 上一次修改时间(ctime)、文件上一次修改时间(mtime)、文件上一次访问时间(atime)
  • 指向该文件的链接数
  • 文件类型(普通、目录、特殊、符合连接等)
  • 分配给该文件的块数

需要解释下最后一条:"分配给文件的块数"。文件都存储在 中:文件存储的物理介质,比如硬盘,最小存储单位叫做 扇区(sector),每个扇区存储 512 字节。操作系统读取硬盘时,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即读取一个 (block)。文件存取的最小单位就是块,最常见一个块是 4KB 。

文件系统将所有的 inode 存放在一个大表中,这个表称为 inode 表。在 inode 表中,每个 inode 由唯一编号表示。使用命令 stat 可以查看文件的 inode 信息,比如:

其中红圈中的数字就是 inode 的编号。

inode 也会消耗硬盘空间,所以硬盘格式化的时候,操作系统自动将硬盘分成两个区域。一个是数据区,存放文件数据;另一个是 inode 区,存放 inode 所包含的信息。在我的 Ubuntu 20.4 系统中,一个 inode 占用 256 字节。inode 节点的总数,在格式化时就给定,一般是每 1KB 或每 2KB 就设置一个 inode。因此有可能发生 inode 已经用光,但是硬盘还未存满的情况。这时,就无法在硬盘上创建新文件。

查看每个硬盘分区的 inode 总数和已经使用的数量,可以使用 df -i 命令。df 是 disk free-space (磁盘可用空间) 的简称。

需要注意的是,inode 信息中并没有文件的文件名。下面解释为什么会这样。

当处理目录时,就好像目录实际包含文件一样。例如 home 目录中有 tmp.txt 文件。但是,该目录中并不包含文件。实际上,该目录只包含有文件的名称和文件的 inode 编号。因此,目录的大小相当小。

下面举例说明。当在 home 目录中创建文件 tmp.txt 文件时,首先,系统在硬盘上保留存放该文件的存储空间。接下来,系统查看 inode 表,查找一个空闲的 inode。假设系统查找到的 inode 编号是 #1000,系统会将 tmp.txt 文件的属性信息填到这个 inode 中。最后,系统在 home 目录中存放一个条目。该条目包含名称 tmp.txt ,以及一个编号为 1000 的inode 号。

每当程序需要使用文件时,表面上通过文件名,打开文件。实际上,系统内部这个过程分成三步:首先,系统找到这个文件名对应的 inode 编号;其次,通过 inode 编号,获取 inode 信息;最后,根据 inode 信息访问文件即可。

文件名和 inode 之间的连接称为链接。从概念上讲,链接将文件名和文件本身连接起来。系统使用的是文件的 inode 编号,目录结构为文件命名仅仅是为了便于人们使用。这就是为什么 inode 不包含文件名的原因。

实际上,一个 inode 可以由不止一个文件名引用,换句话说,就是一个文件可以有不止一个名称。这称为 多重链接

创建新链接 :ln

硬链接

一般情况下,文件名和 inode 编码是"一一对应"关系,每个 inode 编码对应一个文件名。但是,Unix/Linux系统允许多个文件名指向同一个 inode 编码。

这意味着,可以用不同的文件名访问同样的内容;对文件内容进行修改,会影响到所有文件名;但是,删除一个文件名,不影响另一个文件名的访问。这种情况就被称为"硬链接"(hard link)。

每当创建文件时,文件系统都会自动在文件名和文件之间创建一个链接。如果希望为已有文件创建一个新链接,使用 ln 命令。以下命令都是创建硬链接:

  • ln tmp.txt new_name.txt:本来只有 tmp.txt 文件,现在 new_name.txt 和 tmp.txt 指向同一个文件。
  • ln /home/desktop/tmp.txt /etc:目录 etc 中也会有 tmp.txt,修改 etc 目录中的 tmp.txt 文件的内容,在 home/desktop 目录下的 tmp.txt 文件内容也会跟着修改。

软连接

硬链接允许为同一个文件指定不止一个名称。但是这样的链接有两个限制:

  1. 不能为目录创建链接。
  2. 不能为不同文件系统中的文件创建链接

为了实现不同文件系统中的目录或文件链接时,需要创建 符号连接 (symbol link)。使用带 -s 选项的 ln 命令。符号链接包含的不是文件的 inode 编号,而是原文件的路径名。每当访问符号链接时,系统借助该路径名查找文件(类似于 Windows 中的快捷方式)。

当使用 ls -l 显示符号链接文件时,需要注意:

  1. 文件类型指示符(最左边的字符) 是小写的 l,表示 link,链接。
  2. 实际的符号链接在输出行的右边显示 (下图红框内)

    注意符号链接文件的大小是 10 字节,这恰好是存储路径名占用的大小。如果要查看文件本身的长列表,必须指定实际的路径名:ls -l ../tmp.txt

这种链接方式称为软连接。文件 A 和文件 B 的 inode 编码虽然不一样,但是文件 A 的内容是文件 B 的路径。读取文件 A 时,系统会自动将访问者导向文件 B。因此,无论打开哪一个文件,最终读取的都是文件B。这时,文件 A 就称为文件 B 的"软链接"(soft link)或者"符号链接(symbolic link)。

这意味着,文件 A 依赖于文件 B 而存在,如果删除了文件 B,打开文件 A 就会报错:"No such file or directory"。这是软链接与硬链接最大的不同:文件 A 指向文件 B 的文件名,而不是文件 B 的 inode 编码,文件 B 的 inode "链接数"不会因此发生变化。


参考资料:

  1. 《UNIX & Linux 大学 教程》

  2. 《Linux 程序设计》

  3. 《理解inode》 - 阮一峰


读后有收获,资助博主养娃 - 千金难买知识,但可以买好多奶粉 (〃'▽'〃)

相关推荐
维尔切37 分钟前
Linux中基于Centos7使用lamp架构搭建个人论坛(wordpress)
linux·运维·架构
tan77º1 小时前
【项目】分布式Json-RPC框架 - 项目介绍与前置知识准备
linux·网络·分布式·网络协议·tcp/ip·rpc·json
正在努力的小河4 小时前
Linux设备树简介
linux·运维·服务器
荣光波比4 小时前
Linux(十一)——LVM磁盘配额整理
linux·运维·云计算
LLLLYYYRRRRRTT5 小时前
WordPress (LNMP 架构) 一键部署 Playbook
linux·架构·ansible·mariadb
轻松Ai享生活5 小时前
crash 进程分析流程图
linux
大路谈数字化6 小时前
Centos中内存CPU硬盘的查询
linux·运维·centos
luoqice7 小时前
linux下查看 UDP Server 端口的启用情况
linux
倔强的石头_8 小时前
【Linux指南】动静态库与链接机制:从原理到实践
linux
赏点剩饭7789 小时前
linux中的hostpath卷、nfs卷以及静态持久卷的区别
linux·运维·服务器