磁盘存储
基础IO讲了进程与被打开的文件的关系,这里讲一讲在磁盘上的文件。
文件被存在磁盘上,通过定位磁盘,柱面,磁道,扇区,可以定位任意一个文件所在的位置。,采用CHS硬件定位法。可以将存储结构其抽象成数组:

系统给出LBA地址,通过LBA地址找到在哪个扇区,如果给一个LBA地址为123,如何根据其找到在哪个扇区呢?下面看一看,给出了每个单位内存储的内容:
这样通过LBA地址与CHS搜索的方法寻找文件,解耦合了软件层面和硬件层面。
操作系统如何管理磁盘
先组织,再描述,文件系统 被格式化为一个块组(block group)的集合,每个块组都有自己的 inode 表 和 数据块。这些 inode 和数据块都属于同一个文件系统,文件系统管理着它们的分配和使用。将200GB的磁盘采用分治的思想管理,也就是常见的C,D,E盘:

每个分区又被分成了n组。
Superblock(超级块)
存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block的信息被破坏,可以说整个文件系统结构就被破坏了。所以其被不规则地分散在group中。
-
Group Descriptor Table(组描述表)
告诉系统每个组中重要结构的位置(位图、inode 表)
-
Block Bitmap / Inode Bitmap
哪些块/哪些 inode 已被使用
而inode也类似,不过inode一般为128个字节的结构体,所以一块block可以包含2KB➗128B个inode。
-
Inode Table
每个文件的属性(大小、权限、时间戳、数据块地址等),注意,没有文件名字
-
Data Blocks
文件实际内容存放处
每个块组都是一个"小文件系统单元",设计上有助于局部性访问和减少磁盘寻道。一个block的大小是由格式化的时候确定的,并且不可以更改。例如mke2fs的-b选项可以设定block大小为1024、2048或4096字节。一般为2048。

查看文件的inode:

目录文件
目录其实也是文件,那么它在上述系统中是怎么存储的呢?首先他肯定也有一个inode存储属性,其次,文件内容存储目录中文件名字与其对应的inode的映射,因此文件名字一般不能重名。
从磁盘中找到文件内容的过程:给定一个/usr/file/text.txt,首先会找到根目录的inode 2,再在其data block中找到对应file的inode,直到找到text.txt的inode为止,再查看对应的inodebitmap,看看是否为1,为1找到对应的数据块内容读出;删除一个文件,先查看inode的引用计数是否为1,为1的话可以将其对应的数据块bitmap置空,inode bitmap置空,删除对应目录中的目录项,从目录中移除文件信息,否则inode引用计数减一。
软硬链接
在 Linux 中,软链接 和硬链接是两种常见的文件链接方式,它们的创建和使用通过不同的命令来实现。我们分别来详细讲解它们的创建方式,以及它们的特点。
硬链接(Hard Link)
硬链接是指 多个文件名 指向 同一个 inode (即同一个文件的数据块)。
硬链接和原文件没有区别,它们指向相同的 inode,所以对任何一个硬链接进行修改(包括删除)都会影响到所有硬链接。
特点:
硬链接不能跨越文件系统。
删除任何一个硬链接不会影响其他链接指向的文件,直到所有硬链接都被删除,文件的数据块才会被释放。
创建硬链接的命令:
ln <原文件> <硬链接文件>
-
<原文件>:你想要创建硬链接的文件。 -
<硬链接文件>:硬链接的名称。
示例: 
发现test与hard_file的inode一样。其中.表示当前文件夹,为什么会有两个硬链接数呢?因为test_11_6这个文件名与.对应的文件名都硬链接到一个inode!..也是一个道理,上层文件夹。inode结构体中引用计数与硬链接数一致。
注意
硬链接不能链接目录文件,否则会出现死循环,比如/usr/test 引用/usr,都指向同一inode,在/usr下find test,inode中找data block,test对应inode,然后又找到test对应同一个inode,又在该inode中找test......
软链接(Symbolic Link)
软链接(又称符号链接)是一种特殊的文件,它包含了一个指向其他文件的路径。软链接和原文件是不同的文件,软链接只是一个指向目标文件路径的文本文件。
特点:
软链接可以跨文件系统(即可以链接到不同的分区或者磁盘)。
删除软链接不会影响原文件,但删除原文件会使软链接失效。
软链接的 inode 号与原文件不同,因为它本身是一个独立的文件。
与windows桌面下的快捷方式类似
创建软链接的命令:
ln -s <原文件> <软链接文件>
-
-s:指定创建软链接。 -
<原文件>:你想要创建软链接的文件。 -
<软链接文件>:软链接的名称。
示例: 
硬链接和软链接的对比
| 特性 | 硬链接 | 软链接 |
|---|---|---|
| 指向目标 | 指向同一个 inode,文件的数据和内容完全相同 | 指向文件路径(路径名),是独立的文件 |
| 是否独立文件 | 不是独立的文件,和原文件共享 inode | 是独立的文件 |
| 删除时的影响 | 删除一个硬链接不会影响其他硬链接,文件只有在所有硬链接被删除时才会删除 | 删除软链接不会影响原文件,删除原文件会使软链接失效 |
| 跨文件系统 | 不能跨文件系统(只能在同一个磁盘分区内) | 可以跨文件系统(链接到不同分区或磁盘上的文件) |
| inode | 硬链接和原文件共享相同的 inode 号 | 软链接有自己的 inode 号 |
| 目标是文件还是目录 | 可以链接文件,不可以链接目录 | 文件,目录 |
关于各自的用途,其实硬链接就是为了切换目录更方便:. ..,而软链接可以帮助我们更好地调用较深的文件。
从进程看,打开一个文件发生了什么

假设每个页大小是 4KB(4096字节) 。
你现在要写的文件偏移量(pos)假设是 8193字节。
从 write() 到磁盘:完整路径
用户发出写请求 :
调用
write(fd, buf, 4096),内核根据文件描述符找到对应的inode和address_space。计算页号并查找页缓存 :
根据文件偏移量计算出页号(例如第 2 页),
调用
page = find_or_create_page(mapping, 2, ...),在内存页表中查找该页是否已缓存;
若不存在,就从物理内存中分配一个空闲页(如
mem_map[12345])并建立映射。
mem_map[12345]代表的是 第 12345 个物理内存页(RAM 页)。建立磁盘映射(逻辑块 → 物理块) :
文件系统调用
get_block()(如ext4_get_block()),确定文件的这一页对应的 磁盘物理块号 。
若文件还没写过该区域,则:
在磁盘的 数据块位图 中找到一个空闲块;
标记为已分配;
把该块号写入
inode的块指针表;返回该块号(即未来要写入的磁盘位置)。
这个"物理块号"是 磁盘上的块号,不是内存。
写入页缓存(内存中) :
用户数据先被拷贝进刚刚找到或创建的
struct page(即mem_map[12345]所代表的页)中,页被标记为 脏页(dirty page),表示数据尚未写回磁盘。
异步写回(writeback) :
后台的写回线程(如
pdflush或writeback)稍后会:
读取页缓存的脏页;
根据之前确定的 磁盘物理块号;
将页内容写入对应的磁盘块;
清除脏标记。
核心理解一句话总结:
内核先通过
mem_map[]在 物理内存 中找到或分配页缓存(RAM 页),同时通过文件系统的
get_block()确定对应的 磁盘块号 (磁盘位置),数据先写入页缓存,再由后台异步写回到磁盘。