Ext系列文件系统
引言
Ext系列文件系统是Linux系统中使用最为广泛的文件系统之一,包括Ext2、Ext3、Ext4等
1. Ext2文件系统 - 简介:即第二代扩展文件系统(Extended File System 2),是Linux系统中早期常用的文件系统,它是在Ext文件系统基础上改进而来。
磁盘结构:
- 超级块(Super Block):包含了文件系统的整体信息,如文件系统的大小、块大小、inode数量等,是文件系统的关键元数据。
- 块组(Block Group):将磁盘空间划分为多个块组,每个块组包含inode表、数据块等。这样的设计有利于提高文件系统的可靠性和性能,比如在部分块组损坏时,不会影响整个文件系统的使用。
- inode:用于存储文件的元数据,如文件的权限、所有者、大小、创建时间等。每个文件都有一个对应的inode,inode中还包含了指向文件数据块的指针。
- 数据块(Data Block):用于实际存储文件的数据。数据块的大小通常为4KB等,根据文件系统的配置而定。
- 特点:没有日志功能,因此在系统崩溃或突然断电等情况下,可能会导致文件系统不一致,需要进行较长时间的磁盘检查和修复。但它具有简单高效的特点,适用于对数据安全性要求不高,且需要快速访问的场景。
2. Ext3文件系统 - 简介:即第三代扩展文件系统(Extended File System 3),是在Ext2基础上发展而来,它在Ext2的基础上增加了日志功能,提高了文件系统的可靠性和稳定性。
- 磁盘结构:在Ext2的基础上,增加了日志块组。日志块组用于记录文件系统的更改操作,包括文件的创建、删除、修改等。
- 特点:通过日志功能,在系统崩溃后可以快速恢复文件系统到一致状态,减少了磁盘检查和修复的时间。它采用了预分配技术,对于顺序写入的文件能够提高写入性能。但由于需要记录日志,相对Ext2来说,会有一定的性能开销。
3. Ext4文件系统 - 简介:即第四代扩展文件系统(Extended File System 4),是目前Linux系统中广泛使用的文件系统,它在Ext3的基础上进行了多项改进和优化,提供了更好的性能、可靠性和扩展性。
- 磁盘结构:支持更大的文件系统和文件大小,理论上支持的文件系统大小可达1EB,文件大小可达16TB。引入了延迟分配技术,在文件写入时并不立即分配磁盘空间,而是等到文件数据真正需要写入磁盘时才分配,这样可以更有效地利用磁盘空间,提高文件系统的性能。
- 特点:支持更多的inode数量,能够更好地应对大量小文件的存储。采用了多块分配技术,一次可以分配多个连续的数据块,提高了文件的写入性能。同时,它还支持日志校验和等功能,进一步提高了文件系统的可靠性。 总体而言,Ext系列文件系统在Linux系统中发挥着重要作用,随着版本的不断更新,它们在磁盘管理和使用方面的性能、可靠性和功能都得到了不断的提升和完善,以适应不同应用场景和需求。
1. 硬件
磁盘是计算机系统中用于存储数据的重要硬件设备,磁头、柱面、扇区是磁盘的重要组成部分。
磁头
磁头是磁盘驱动器中用于读取和写入数据的部件。它通过电磁感应原理,将电信号转换为磁信号记录在磁盘表面,或者将磁盘表面的磁信号转换为电信号读取出来,从而实现数据的存储和访问。
柱面
柱面是由一组位于不同盘片上、具有相同半径的磁道所组成的圆柱面结构。在一个多盘片的磁盘中,每个盘片都有自己的磁道,所有盘片上相同编号的磁道就构成了一个柱面。例如,假设磁盘有 3 个盘片,每个盘片上的第 5 个磁道就共同组成了柱面 5。
扇区
扇区是磁盘上数据存储的基本单位,是对磁道进一步划分得到的区域。通常情况下,每个磁道会被划分为若干个大小相等的扇区,常见的扇区大小为 512 字节或 4096 字节。扇区的划分是通过在磁盘格式化时确定的,格式化过程会在磁盘表面创建一系列的磁道和扇区,并为每个扇区分配一个唯一的编号。
1.1 磁盘的存储结构
扇区:是磁盘存储数据的基本单位,512字节,块设备
如何定位⼀个扇区呢?
• 可以先定位磁头(header)
• 确定磁头要访问哪⼀个柱面(磁道)(cylinder
• 定位⼀个扇区(sector)
CHS地址定位
• 扇区是从磁盘读出和写入信息的最小单位,通常大小为 512 字节。
• 磁头(head)数:每个盘片⼀般有上下两面,分别对应1个磁头,共2个磁头
• 磁道(track)数:磁道是从盘片外圈往内圈编号0磁道,1磁道...,靠近主轴的同心圆用于停靠磁头,不存储数据
• 柱面(cylinder)数:磁道构成柱面,数量上等同于磁道个数
• 扇区(sector)数:每个磁道都被切分成很多扇形区域,每道的扇区数量相同
• 圆盘(platter)数:就是盘片的数量
• 磁盘容量=磁头数×磁道(柱面)数×每道扇区数×每扇区字节数
柱面(cylinder),磁头(head),扇区(sector),显然可以定位数据了,这就是数据定位(寻址)方式之⼀,CHS寻址方式。
1.2 磁盘的逻辑结构
那么磁盘本质上虽然是硬质的,但是逻辑上我们可以把磁盘想象成为卷在⼀起的磁带,那么磁盘的逻辑存储结构我们也可以类似于:
这样每⼀个扇区,就有了⼀个线性地址(其实就是数组下标),这种地址叫做LBA 。
柱面是⼀个逻辑上的概念,其实就是每⼀面上,相同半径的磁道逻辑上构成柱面。
所以,磁盘物理上分了很多面,但是在我们看来,逻辑上,磁盘整体是由“柱面”卷起来的。
所以,磁盘的真实情况是:
磁道:一维数组
某⼀盘面的某⼀个磁道展开:
柱面:二维数组
整个磁盘所有盘面的同⼀个磁道,即柱面展开:
整盘:由多个柱面组成,即三维数组
所有,寻址⼀个扇区:先找到哪⼀个柱面(Cylinder),在确定柱面内哪⼀个磁道(其实就是磁头位置,Head),在确定扇区(Sector),所以就有了CHS。
1.3 CHS && LBS地址
CHS 转换为 LBA:
磁头数 × 每磁道扇区数 = 单个柱面的扇区总数。
LBA = 柱面号 C × 单个柱面的扇区总数 + 磁头号 H × 每磁道扇区数 + 扇区号 S - 1。
即 LBA = 柱面号 C × (磁头数 × 每磁道扇区数) + 磁头号 H × 每磁道扇区数 + 扇区号 S - 1。
扇区号通常从 1 开始计数,而在 LBA 中,地址从 0 开始。
柱面和磁道的编号均从 0 开始。
总柱面数、磁道个数、扇区总数等信息由磁盘内部自动维护,系统上层在开机时会获取这些参数。
LBA 转换为 CHS:
柱面号 C = LBA // (磁头数 × 每磁道扇区数),其中磁头数 × 每磁道扇区数 = 单个柱面的扇区总数。
磁头号 H = (LBA % (磁头数 × 每磁道扇区数)) // 每磁道扇区数。
扇区号 S = (LBA % 每磁道扇区数) + 1。
"//" 表示除法取整。
因此,对于磁盘使用者而言,无需关心 CHS 地址,而是直接使用 LBA 地址,磁盘内部会自动进行转换。换句话说,磁盘可以被视为一个由扇区组成的一维数组,数组下标即为每个扇区的 LBA 地址。操作系统使用磁盘时,仅需通过一个数字即可访问磁盘扇区。
2. 文件系统
2.1 块
块是文件系统中最小的数据存储单位,通常由多个扇区组成。
硬盘是典型的“块”设备,操作系统读取硬盘数据的时候,不会一个一个扇区地读取,因为这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个“块”(block)。
硬盘的每个分区都被划分为一个个的“块”。一个“块”的大小是在格式化的时候确定的,并且不可以更改,最常见的是4KB,也就是连续八个扇区组成一个“块”。“块”是文件存取的最小单位。
磁盘就是⼀个三维数组,我们把它看待成为⼀个"⼀维数组",数组下标就是LBA,每个元素都是扇
区。
• 每个扇区都有LBA,那么8个扇区⼀个块,每⼀个块的地址我们也能算出来。
• 知道LBA:块号=LBA/8
• 知道块号:LAB=块号*8+n(n是块内第几个扇区)
2.2 分区
分区是磁盘上的逻辑划分,一个磁盘可以被划分为多个分区,每个分区可以使用不同的文件系统。
以Windows观点来看,你可能会有⼀块磁盘并且将它分区成C,D,E盘。那个C,D,E就是分区。分区从实质上说就是对硬盘的⼀种格式化。但是Linux的设备都是以⽂件形式存在,那是怎么分区的呢?
柱面是分区的最小单位,我们可以利用参考柱面号码的方式来进行分区,其本质就是设置每个区的起始柱面和结束柱面号码。此时我们可以将硬盘上的柱面(分区)进行平铺,将其想象成⼀个大的平面,如下图所示:
块和柱面的关系
- 块由扇区组成,而柱面由磁道组成。
- 一个柱面可以存储多个块。 在传统的 CHS 寻址方式下,一个柱面包含多个磁道,每个磁道包含多个扇区,而多个扇区可以组合成一个块。因此,一个柱面可以存储多个块。
- 块的分布可能跨柱面。 由于文件系统的逻辑组织方式,块的分配不一定严格按照柱面进行,而是由文件系统的分配策略决定。
总之,柱面是磁盘物理存储结构的一部分,而块是文件系统的逻辑存储单位。磁盘的物理组织方式(如柱面、磁道、扇区)决定了数据的存储方式,而文件系统则通过块来管理和访问数据,以提高存取效率。
2.3 inode
文件=数据+属性 ,我们使用 ls -l 的时候看到的除了看到文件名,还能看到文件元数据(属性)。
每行包含7列:
• 模式
• 硬链接数
• 文件所有者
• 组
• 大小
• 最后修改时间
• 文件名
ls -l读取存储在磁盘上的文件信息,然后显示出来。
到这我们要思考一个问题,文件数据都储存在“块”中,那么很显然,我们还必须找到一个地方储存文件的元信息(属性信息),比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode,中文译名为“索引节点”。
- Linux下文件的存储是属性和内容分离存储的。
- Linux下,保存文件属性的集合叫做inode,⼀个文件有⼀个inode,inode内有⼀个唯⼀的标识符,叫做inode号。
下面时inode的源码
struct ext2_inode {
__le16 i_mode; // File mode
__le16 i_uid; // Low 16 bits of Owner Uid
__le32 i_size; // Size in bytes
__le32 i_atime; // Access time
__le32 i_ctime; // Creation time
__le32 i_mtime; // Modification time
__le32 i_dtime; // Deletion Time
__le16 i_gid; // Low 16 bits of Group Id
__le16 i_links_count; // Links count
__le32 i_blocks; // Blocks count
__le32 i_flags; // File flags
union {
struct {
__le32 l_i_reserved1;
} linux1;
struct {
__le32 h_i_translator;
} hurd1;
struct {
__le32 m_i_reserved1;
} masix1;
} osd1; // OS dependent 1
__le32 i_block[15]; // 根据备注中 EXT2_N_BLOCKS = 15,这里直接写 15 作为数组大小
__le32 i_generation; // File version (for NFS)
__le32 i_file_acl; // File ACL
__le32 i_dir_acl; // Directory ACL
__le32 i_faddr; // Fragment address
union {
struct {
__u8 l_i_frag; // Fragment number
__u8 l_i_fsize; // Fragment size
__u16 i_pad1;
__le16 l_i_uid_high; // these 2 fields
__le16 l_i_gid_high; // were reserved2[0]
__u32 l_i_reserved2;
} linux2;
struct {
__u8 h_i_frag; // Fragment number
__u8 h_i_fsize; // Fragment size
__le16 h_i_mode_high;
__le16 h_i_uid_high;
__le16 h_i_gid_high;
__le32 h_i_author;
} hurd2;
struct {
__u8 m_i_frag; // Fragment number
__u8 m_i_fsize; // Fragment size
__u16 m_pad1;
__u32 m_i_reserved2[2];
} masix2;
} osd2; // OS dependent 2
};
// 定义与数据块相关的常量
#define EXT2_NDIR_BLOCKS 12
#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
备注:EXT2_N_BLOCKS = 15
通过上面的代码,我们可以发现:
文件名属性并未纳⼊到inode数据结构内部。
inode的大小⼀般是128字节或者256,我们后面统⼀128字节。
任何文件的内容大小可以不同,但是属性大小⼀定是相同的。
inode 号(Inode Number):唯一标识一个 inode,在整个文件系统内唯一。
文件类型(File Type):表示该 inode 对应的文件类型,如普通文件(-)、目录(d)、符号链接(l)。
权限(Permission):文件的访问权限,例如 644、755,分别表示所有者、用户组、其他用户的读写执行权限。
链接数(Link Count):指向该 inode 的硬链接数量,当硬链接数降为 0 时,inode 及其数据块将被释放。
用户 ID(UID)和组 ID(GID):文件的所有者和所属组信息。
文件大小(Size):文件的字节数,决定了需要多少个数据块来存储文件内容。
时间戳(Timestamps):包括
ctime(Change Time):inode 上一次被修改的时间。
mtime(Modify Time):文件内容上一次被修改的时间。
atime(Access Time):文件上一次被访问的时间。
指针(Pointer):inode 通过指针来管理文件数据存储的位置。
我们已经知道硬盘是典型的“块”设备,操作系统读取硬盘数据的时候,读取的基本单位
是”块”。“块”有是硬盘的每个分区下的结构,难道“块”是随意的在分区上排布的吗?那要怎么找到“块”呢?
2. 还有就是上面提到的存储文件属性的inode,又是如何放置的呢?文件系统就是为了组织管理这些的!!
3. ext2 文件系统
我们想要在硬盘上存储文件,必须先把硬盘格式化为某种格式的文件系统,才能存储文件。文件系统的目的就是组织和管理硬盘中的文件。在Linux系统中,最常见的是ext2系列的文件系统。其早期版本为ext2,后来又发展出ext3和ext4。ext3和ext4虽然对ext2进行了增强,但是其核心设计并没有发生变化,我们仍是以较老的ext2作为演示对象。
3.1 文件系统
ext2文件系统将整个分区划分成若干个同样大小的块组(Block Group),而每个Block Group都有着相同的结构组成。如下图所示。只要能管理⼀个分区就能管理所有分区,也就能管理所有磁盘文件。
上图中启动块(Boot Block/Sector)的大小是确定的,为1KB,由PC标准规定,用来存储磁盘分区信息和启动信息,任何文件系统都不能修改启动块。启动块之后才是ext2文件系统的开始。
-
磁盘(Disk)
- 磁盘包含主引导记录(MBR)和多个分区(Partition 1、Partition 2 等)。
- MBR 负责存储分区表和引导加载程序,管理磁盘上的分区信息。
-
分区(Partition)
- 每个分区可以包含不同的文件系统,例如 EXT2、EXT3、NTFS 等。
- EXT2 分区包含引导扇区(Boot Sector)和文件系统数据。
-
文件系统(File System)
- EXT2 文件系统被划分为多个 块组(Block Group),这样可以减少碎片化并提高访问效率。
-
块组(Block Group)
-
inode 表(inode Table)
- EXT2 文件系统采用 块组 结构,每个块组都包含 inode 表、数据块等信息。
- 超级块 记录文件系统的元数据,例如总块数、总 inode 数等。
- inode 负责管理文件的元数据,而数据块存储文件内容。
- 块位图和 inode 位图用于追踪块和 inode 的使用情况,提高文件系统管理效率。
3.2 块内部组成
超级块(Super Block)
超级块存储整个文件系统的重要元数据,包括:
- 文件系统大小:文件系统的总块数、总 inode 数量。
- 块大小:决定每个数据块的大小,常见的大小为 1KB、2KB、4KB。
- 可用块数和已用块数:用于管理文件系统的空间分配。
- inode 计数:整个文件系统包含的 inode 总数。
- 文件系统标识符:用于唯一标识文件系统。
- 挂载信息:包括上次挂载时间、上次写入时间、挂载次数等。
- 日志信息(如果有):用于恢复文件系统状态(EXT3 及以后版本)。
超级块通常存放在磁盘的起始位置,并在后续的块组中进行备份,以防损坏时仍能恢复文件系统。
组描述符表(GDT,Group Descriptor Table)
- 记录每个块组的元数据位置,例如 超级块、块位图、inode 位图、inode 表、数据块 的位置。
- 方便文件系统管理块组,使得文件系统可以分块管理,提高磁盘 I/O 性能。
块位图(Block Bitmap)
- 记录该块组中 哪些数据块已被使用,哪些是空闲的。
- 每个位对应一个数据块,值为 1 表示该块已被占用,值为 0 表示该块是空闲的。
- 这个位图帮助文件系统快速分配和回收数据块,避免碎片化。
inode 位图(inode Bitmap)
- 记录该块组中 哪些 inode 已被使用,哪些是空闲的。
- 方式与块位图相同,每个位代表一个 inode。
- 这个位图用于 inode 分配管理,确保 inode 不会重复分配。
inode 表(inode Table)
- 记录了该块组中的所有 inode 结构,每个 inode 占据固定大小的空间(一般是 128 字节或 256 字节)。
- inode 负责存储文件的元数据,如权限、大小、链接数等(具体内容见 3.3)。
数据块(Data Blocks)
- 用于存储文件的实际内容,也是用户数据的存放区域。
- 文件系统会通过 inode 结构来管理数据块,并根据 inode 指针找到数据块的位置。
注意:
- 并不是每个块都存储超级块、块位图、inode 位图等结构,而是每个块组按照固定布局存储这些结构。
- 超级块和组描述符表仅在块组 0 及部分备份块组中存储,其他块组不包含这些数据。
- 块位图、inode 位图、inode 表和数据块是每个块组都有的,用于文件系统管理和数据存储。
- 数据块占据块组的主要空间,用于存储实际的文件内容。
3.3 inode指针 和 数据块映射
一个 inode 结构包含多个指针字段(一般 12 个直接指针 + 1 个间接指针 + 1 个二级间接指针 + 1 个三级间接指针),这些指针指向数据块,文件系统根据这些指针找到数据块存放的实际位置。
- 直接指针(Direct Pointers)(12 个):每个指针指向一个数据块,适用于存储小文件(文件大小 <= 12 个数据块)。
- 一级间接指针(Single Indirect Pointer):指向一个块,该块存储的是数据块地址的列表。
- 二级间接指针(Double Indirect Pointer):指向一个块,该块存储的是一级间接指针块的地址。
- 三级间接指针(Triple Indirect Pointer):指向一个块,该块存储的是二级间接指针块的地址。
示例:文件大小对 inode 指针使用的影响
- 小文件(小于 12 个数据块):仅使用直接指针,inode 直接指向数据块。
- 中等大小文件(大于 12 个数据块,但小于 12 + 256 个数据块):使用直接指针 + 一级间接指针。
- 较大文件(大于 12 + 256 个数据块,但小于 12 + 256 + 256² 个数据块):使用直接指针 + 一级间接指针 + 二级间接指针。
- 超大文件(大于 12 + 256 + 256² 个数据块):使用直接指针 + 一级间接指针 + 二级间接指针 + 三级间接指针。
inode 与数据块映射示例
假设一个文件使用 inode 结构存储如下数据:
- inode 号:100
- 文件大小:5 KB(块大小 1 KB)
- 指针映射情况:
Direct Pointer[0]
→ 指向 数据块 500Direct Pointer[1]
→ 指向 数据块 501Direct Pointer[2]
→ 指向 数据块 502Direct Pointer[3]
→ 指向 数据块 503Direct Pointer[4]
→ 指向 数据块 504
此文件仅使用直接指针,inode 直接存储 5 个指向数据块的地址。若文件大小增大到 13KB,就需要使用 间接指针 来存储更多数据块地址。
3.4 文件与目录名
创建一个新文件主要有以下4个操作:
1. 存储属性:内核先找到一个空闲的inode节点(这里是263466)。内核把文件信息记录到其中。
2. 存储数据:该文件需要存储在三个磁盘块,内核找到了三个空闲块:300,500,800。将内核缓冲区的第一块数据复制到300,下一块复制到500,以此类推。
3. 记录分配情况:文件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。
4. 添加文件名到目录:新的文件名abc。linux如何在当前的目录中记录这个文件?内核将入口(263466,abc)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起来。
访问文件,必须打开当前目录,根据文件名,获得对应的inode号,然后进行文件访问
访问文件必须要知道当前工作目录,本质是必须能打开当前工作目录⽂件,查看目录文件的内容!
3.5 路径缓存
问题1:Linux磁盘中,存在真正的目录吗?
答案:不存在,只有文件。只保存文件属性+文件内容
问题2:访问任何文件,都要从/目录开始进行路径解析?
答案:原则上是,但是这样太慢,所以Linux会缓存历史路径结构
问题3:Linux目录的概念,怎么产生的?
答案:打开的文件是目录的话,由OS自己在内存中进行路径维护
Linux中,在内核中维护树状路径结构的内核结构体叫做: struct_dentry
struct dentry {
atomic_t d_count;
unsigned int d_flags;
/* protected by d_lock */
spinlock_t d_lock;
/* per dentry lock */
struct inode *d_inode;
/* Where the name belongs to - NULL is
* negative */
/*
* The next three fields are touched by __d_lookup. Place them here
* so they all fit in a cache line.
*/
struct hlist_node d_hash; /* lookup hash list */
struct dentry *d_parent; /* parent directory */struct qstr d_name;
struct list_head d_lru; /* LRU list */
/*
* d_child and d_rcu can share memory
*/
union {
struct list_head d_child; /* child of parent list */struct rcu_head d_rcu;
} d_u;
struct list_head d_subdirs; /* our children */struct list_head d_alias; /* inode alias list */
unsigned long d_time;
/* used by d_revalidate */
struct dentry_operations *d_op;struct super_block *d_sb; /* The root of the dentry tree */
void *d_fsdata;
/* fs-specific data */
#ifdef CONFIG_PROFILING
struct dcookie_struct *d_cookie; /* cookie, if any */
#endif
int d_mounted;
unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
};
每个文件其实都要有对应的dentry结构,包括普通文件。这样所有被打开的文件,就可以在内存中形成整个树形结构。
• 整个树形节点也同时会隶属于LRU(Least Recently Used,最近最少使用)结构中,进行节点淘汰。
• 整个树形节点也同时会隶属于Hash,方便快速查找。
• 更重要的是,这个树形结构,整体构成了Linux的路径缓存结构,打开访问任何文件,都在先在这棵树下根据路径进行查找,找到就返回属性inode和内容,没找到就从磁盘加载路径,添加dentry结构,缓存新路径。
4. 软硬链接
4.1 硬连接
真正找到磁盘上文件的并不是文件名,⽽是inode。其实在linux中可以让多个文件名对应
于同⼀个inode。
abc和def的链接状态完全相同,他们被称为指向文件的硬链接。内核记录了这个连接数,inode(666321)的硬连接数为2。
• 我们在删除文件时干了两件事情:1.在目录中将对应的记录删除,2.将硬连接数-1,如果为0,则将对应的磁盘释放。
特点:
- 多个文件名指向同一个 inode,即多个硬链接共享同一个 inode 号和数据块。
- 删除任意一个硬链接,不影响其他硬链接,只有当所有硬链接被删除后,文件数据才会被释放。
- 不能跨文件系统(因为 inode 号在不同的文件系统中不通用)。
- 不能对目录创建硬链接(防止文件系统出现循环结构)。
. 和 .. 就是硬链接,除此之外linux系统不支持给目录创建硬链接。
4.2 软链接
硬链接是通过inode引用另外⼀个文件,软链接是通过名字引用另外⼀个文件,但实际上,新的文件和被引用的文件的inode不同,应用常见上可以想象成⼀个快捷方式。
特点:
- 软链接是一个独立的文件,存储指向原文件路径的地址(类似 Windows 的快捷方式)。
- 软链接的 inode 号与原文件不同,它只是一个指向目标文件路径的特殊文件。
- 可以跨文件系统,因为它存储的是文件路径而不是 inode。
- 可以指向目录,不像硬链接只能用于普通文件。
- 如果原文件被删除,软链接会变成“悬空链接”(Broken Link),因为它指向的路径已经不存在
4.3 硬链接 vs 软链接
特性 | 硬链接(Hard Link) | 软链接(Soft Link) |
---|---|---|
inode 号 | 相同(共享 inode) | 不同(独立 inode) |
作用方式 | 直接指向数据块 | 存储路径指向目标文件 |
是否跨文件系统 | 否 | 是 |
是否可指向目录 | 否 | 是 |
原文件删除影响 | 不影响其他硬链接 | 变成悬空链接 |