【Linux】万字详解:Linux文件系统与软硬链接

🌈 个人主页:Zfox_

🔥 系列专栏:Linux

目录

  • [🚀 前言](#🚀 前言)
  • [一: 🔥 磁盘的物理结构](#一: 🔥 磁盘的物理结构)
  • [二: 🔥 磁盘的存储结构](#二: 🔥 磁盘的存储结构)
  • [三: 🔥 磁盘的逻辑结构](#三: 🔥 磁盘的逻辑结构)
  • [四: 🔥 理解文件系统(重)](#四: 🔥 理解文件系统(重))
  • [五: 🔥 软硬链接(重)](#五: 🔥 软硬链接(重))
    • [🥝 5.1 软硬链接的创建](#🥝 5.1 软硬链接的创建)
    • [🥝 5.2 软硬链接的区别](#🥝 5.2 软硬链接的区别)
    • [🥝 5.3 软硬链接的应用](#🥝 5.3 软硬链接的应用)
      • [🦋 软链接](#🦋 软链接)
      • [🦋 硬链接](#🦋 硬链接)
  • [六:🔥 共勉](#六:🔥 共勉)

🚀 前言

🦁 上一篇博客 【Linux】文件IO深度解析:文件描述符与重定向的奥秘 讲的 FILE 也是文件,是打开文件。那么未被打开文件,也是放在磁盘上,磁盘上有大量的文件也是必须被静管理的,方便我们随时打开,这也是文件系统。文件系统既要管理动态打开文件,又要管理静态未被打开文件。文件是放在磁盘的,我们对于磁盘是陌生的。下面我们就会先了解硬件 -- 磁盘,然后再来学习文件系统。

一: 🔥 磁盘的物理结构

硬盘是什么样子:

磁盘是如何动的:

🍃 磁头摆动和盘片旋转是通过马达控制的,我们可以通过硬件电路组成伺服系统给磁盘发二进制指令,然后让磁盘定位去寻址某个特定的区域,然后从磁盘上读取数据。磁盘和磁头都有两面,两面都是可以进行读写数据的。
🍃 磁头和盘片是没有接触的!他们的距离就像一架波音757隔着1米的距离在飞行。而且磁盘是不能有一点灰尘的,就好像飞机飞行前没有障碍物一样。所以磁盘必须得防止抖动,一旦磁头和盘面接触就会使得盘面刮花,丢失数据
🍃 硬件上保存二进制,是跟对应的设备有关,寄存器和内存是通过触发器电脉冲,对硬件设备进行带点或者失电,通过电路的有无来代表二进制。每一个寄存器触发器存储单元,每一个单元都是硬件电路,他们都可以进行存放电的。。
🍃 在不同的设备,表示二进制的方式也是不同的,在网络里面通过信号的有无,通过信号的疏密来表示 01。
🍃 这里可以理解磁头通过带放电,对磁盘某一个位置进行 N/S 极互换,就完成了 0/1 的写入,如果需要写入 512比特位,就相当于触电 523 次。-- 磁化技术

二: 🔥 磁盘的存储结构

🦁 我们看到盘面是非常光滑的,但是在放大下,磁道和磁道之间是有间隙的。在微观下,一个扇区可存大量的电子。

磁盘寻址的基本单位是扇区(512byte),虽然越靠近圆心外侧面积越大,但是可以通过工艺进行不同扇区的密度大小进行调解,所以每个扇区存储都是512 byte。不考虑其他情况。

在单面中定位一个扇区:

  • 磁头来回摆动确认磁道,盘片旋转确定扇区。

  • 在立体视图中,有的时候会磁道就等于柱面,磁头和扇面不变。磁头是共同进退的 - 同时进行寻找磁道。

在磁盘中定位一个扇区:

  • 先定位在哪一个磁道,再定位磁头(盘面),最后定位在那个扇区。

三: 🔥 磁盘的逻辑结构

当把磁带扯直,我们就可以把它看成一条瘦长的矩形,这条矩形中存放这数据。磁盘其实也是一样,我们将磁盘中磁道拉直,也就变成矩形,里面存在着大量的数据。我们就可以把它想象成线性结构。

🐲 上述是对于一条磁道,那么多块磁盘呢?一般电脑选择的500GB,500GB是可以分盘的CDEF。那么我们就可以抽象化将不同盘面想象成一块数据,整个磁盘看做一个数组 sector arr[n],这样就方便对磁盘进行管理。

对磁盘进行管理就变成了对数组进行管理。CHS寻址模式将硬盘划分为柱面(Cylinder)、磁头(Heads)、扇区(Sector)。那在操作系统中我们就可以通CHS进行查找(方法)。

访问一个扇区是512字节,如果将磁盘的访问的基本单位设置512字节,对于IO访问来说效率太低,一般是对8个扇区进行同时访问,OS内的文件系统定制的进行多个扇区的读取4KB为基本单位即使是指向读取/修改1bit,那么必须将4KB load内存,进行读取或者修改,如果必要,在写回磁盘

内存是被划分成为了4KB大小的空间--页框;磁盘中的文件尤其是可执行文件是按照4KB大小划分好的块--页帧,磁盘向内存拷贝数据,实质也是页帧将数据拷贝到页框中。

不管是拷贝数据还是修改数据,那么最开始都是需要将数据管理起来,这里我们通过分治的思想,一级一级的到向下一层减少管理空间,我们将最底层管理,对于上层而言也就是重复的工作了。所以理解文件管理我们就开始从这5GB开始(自定义5GB)。

四: 🔥 理解文件系统(重)

我们使用ls -l的时候看到的除了看到文件名,还看到了文件元数据。

cpp 复制代码
[lisi@hcss-ecs-a9ee lesson22]$ ls -l
total 8
-rw-rw-r-- 2 lisi lisi    0 Oct 20 16:00 file-hard.link
lrwxrwxrwx 1 lisi lisi    8 Oct 20 16:03 file-soft.link -> file.txt
-rw-rw-r-- 2 lisi lisi    0 Oct 20 16:00 file.txt
drwxrwxr-x 3 lisi lisi 4096 Oct 21 20:00 other
drwxrwxr-x 3 lisi lisi 4096 Oct 21 19:47 stdio

每行包含7列:

cpp 复制代码
-rw-rw-r--    2       lisi     lisi    0    Oct 20 16:00   file-hard.link

  模式     硬链接数   文件所有者   组     大小   最后修改时间        文件名

ls -l 读取存储在磁盘上的文件信息,然后显示出来,为什么它能分开显示呢?我们知道:

  • 文件 = 内容 + 属性

🐮 linux的文件属性和文件内容是分批储存的,如下所示:

一个文件属性的,文件的大小,权限,等等信息在都在Inode中。

其实这个信息除了通过ls -l方式来读取,还有一个stat命令能够看到更多信息

cpp 复制代码
[lisi@hcss-ecs-a9ee lesson22]$ stat test.c 
  File: 'test.c'
  Size: 0             Blocks: 0          IO Block: 4096   regular empty file
Device: fd01h/64769d    Inode: 656174      Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1005/ hongxin)   Gid: ( 1005/ hongxin)
Access: 2023-01-16 15:44:36.036230458 +0800
Modify: 2023-01-16 15:44:36.036230458 +0800
Change: 2023-01-16 15:44:36.036230458 +0800
Birth: -

在这里也显示I/O块为4kb,也就再次证实磁盘的访问的基本单位4kb(大多数操作系统)。

上面的执行结果有信息需要解释清楚 inode,为了能解释清楚inode我们先简单了解一下文件系统。我们也知道了解文件系统就应该了解最底层这空间大小:

Linux ext2文件系统,上图为磁盘文件系统图(内核内存映像肯定有所不同),磁盘是典型的块设备,硬盘分区被 划分为一个个的block。一个block的大小是由格式化的时候确定的,并且不可以更改。

  • 启动块-Boot Block:大小就是1kB,由PC标准规定,用来存储磁盘分区的信息和启动信息,任何文件系统都不能使用该块。(如果这个块损坏,整个文件系统也就启动不起来了)。操作系统的开机,加电,启动相关的信息都是在这个块中的。

  • Block Group:ext2文件系统会根据分区的大小划分为数个Block Group。而每个Block Group都有着相同的结构组成。

  • 超级块(Super Block):存放文件系统本身的结构信息。记录的信息主要有:bolck 和 inode的总量,未使用的 block 和 inode 的数量,一个 block 和 inode 的大小,最近一次挂载的时间,最近一次写入数据的时间,最近一次检验磁盘的时间等其他文件系统的相关信息。Super Block 的信息被破坏,可以说整个文件系统结构就被破坏了。

  • inode 节点表:存放文件属性 如 文件大小,所有者,最近修改时间等

  • 正常情况下,保存的整个文件系统的信息不应该放在分区的最开始吗,为什么会在多个分组中存在呢,这里是为了备份,当文件受损时,就可以将其他分组的Super Block拷贝到当前,文件系统就得到恢复。

在学习下面内容之前,我们还是得对文件内容和属性深一步挖掘。我们知道文件是有文件内容和属性构成的,文件属性和文件内容是分批存储的。

文件内容:

  • data block就是存放文件内容,它的特性就是随着应用类型的变化,大小在变化。

文件属性:

  • ionde就是用来存储文件属性的,inodo属性信息不仅仅包括文件大小,属主,用户组,文件权限,修改时间,类型。还包含指向文件实体的指针功能,但是inode里面不包含文件名。inode的大小也是固定的。ionde为了区分彼此,每个inode都有自己的ID。

通过输入ls -li,我们发现他们文件的inode是不一样的。

cpp 复制代码
[lisi@hcss-ecs-a9ee lesson22]$ ls -li
total 0
926813 -rw-rw-r-- 1 hongxin hongxin 0 Jan 16 19:49 log.txt
926812 -rw-rw-r-- 1 hongxin hongxin 0 Jan 16 19:47 test.c

inode表(inode Table) :

  • 保存了分组内部所有可用的(已经使用+未被使用)inode。当我们创建一个文件时,第一时间找的就是inode Table,将文件属性如文件大小,所有者,最近修改时间等存放在这个表中。

inode位图(inode Bitmap):

  • 每个bit表示一个inode是否空闲可用。

例如:0000001

位图中比特位的位置和当前文件对应的inode位置是一一对应的。比特位的位置代表的是它是第几个inode,比特位为0 ,代表inode未被占用,比特位为1,代表inode被占用。通过比特位的偏移位置去找inode Table去找到该inode(inode自己的编号),增加属性等操作 。

块位图(Block Bitmap):

  • Block Bitmap中记录着Data Block中哪个数据块已经被占用,哪个数据块没有被占用

块组描述符GDT(Group Descriptor Table):对应分组的宏观的属性信息,

查找文件属性和内容原理

如何查找文件属性和内容,首先我们需要知道inode编号是如何形成的:

每个区都有自己编号,例如:Block group 0-Block group n: 1000-10000 ,每个区都有自己的组,组会通过比特位图进行增加值,例如:起始1000,当新建一个inode,那么比特位图就加1:1001,你从01也可以得知在inode table中,它是第一个建立的ionde。

查找文件属性:实质就是从文件中找到inode编号,然后通过inode编号找到inode Table。

我们知道ionde Table后,又是如何通inode查找dateblocks呢?如图所示:

在struct_ionde中,通过data数组找到相应的数据块,这里特别需要注意的是,0-11是特指,而12-14是泛指。例如12指向一个数据块,这块数据块可以指向其他块数据块,这个块数据块保存的是其他数据块的地址。如果12不够用,例如13就可以指向其他数据块,其他数据块又保存其他数据块的地址。12是一级索引,13就是二级索引。

最后在这里需要了解:删除一个文件,直接将inode和block比特位清零即可-惰性删除。

建新文件操作

新文件操作将属性和数据分开存放的想法看起来很简单,但实际上是如何工作的呢?我们在通过touch一个新文件来看看如何工作。

cpp 复制代码
[lisi@hcss-ecs-a9ee ~]$ touch abc

[lisi@hcss-ecs-a9ee ~]$ ls -i abc 
263466 abc

通过上面ls -i abc 我们可以发现文件名是不在ionde中的,不属于文件属性管的。我们查找文件通过的文化名,这个是因为目录的数据块放的是当前目录下的文件名和inode的映射关系。所以我们就可以通过文件名来查找文件信息。

为了说明问题,将上图简化:

建一个新文件主要有一下4个操作:

  1. 存储属性

内核先找到一个空闲的i节点(这里是263466)。内核把文件信息记录到其中。

  1. 存储数据

该文件需要存储在三个磁盘块,内核找到了三个空闲块:300,500,800。将内核缓冲区的第一块数据复制到300,下一块复制到500,以此类推。

  1. 记录分配情况

文件内容按顺序300,500,800存放。内核在inode上的磁盘分布区记录了上述块列表。

  1. 添加文件名到目录

新的文件名abc。linux如何在当前的目录中记录这个文件?内核将入口(263466,abc)添加到目录文件。文件名和inode之间的对应关系将文件名和文件的内容及属性连接起

最后为了避免知识混淆,我们汇聚一幅图,需要理解的是向磁盘进行I/O前,操作系统会读取该文件内容和属性,再进行加载(读取也要结合自身的操作)。

五: 🔥 软硬链接(重)

🥝 5.1 软硬链接的创建

我们先创建一个软链接文件,输入 ln -s myfile.c soft_file.link

[lisi@hcss-ecs-a9ee tmp]$ ln -s myfile.c soft_file.link

lrwxrwxrwx :l -- 是文件类型,链接文件

再查看inode,他们都有自己独立的inode,说明他们都是一个独立的文件。

我们再建立一个硬链接文件,输入ln myfile.c hard_file.link ,发现hard_file.link和 myfile.c的数字变成了2。

再查看inode,它的inode数是一样的。

为什么硬链接没有独立inode呢?我们通过测试来理解。

最开始我们没有给文件写入数据时,文件的大小为0

cpp 复制代码
[lisi@hcss-ecs-a9ee tmp]$ ls -li
total 0
1838455 -rw-rw-r-- 2 lisi lisi 0 Oct 25 20:43 hard_file.link
1838455 -rw-rw-r-- 2 lisi lisi 0 Oct 25 20:43 myfile.c
1838456 lrwxrwxrwx 1 lisi lisi 8 Oct 25 20:43 soft_file.link -> myfile.c

当我们给myfile.c写入时,文件的大小一起变成了12,再给hard_file.link 写入时,他们文件大小一起变成了24。不管是myfile.c还是hard_file.link写入时,他们大小都会变成一样的。

cpp 复制代码
[lisi@hcss-ecs-a9ee tmp]$ echo "hello  link" >> myfile.c 
[lisi@hcss-ecs-a9ee tmp]$ ls -li
total 8
1838455 -rw-rw-r-- 2 lisi lisi 12 Oct 25 20:47 hard_file.link
1838455 -rw-rw-r-- 2 lisi lisi 12 Oct 25 20:47 myfile.c
1838456 lrwxrwxrwx 1 lisi lisi  8 Oct 25 20:43 soft_file.link -> myfile.c
cpp 复制代码
[lisi@hcss-ecs-a9ee tmp]$ echo "hello  link" >> hard_file.link 
[lisi@hcss-ecs-a9ee tmp]$ ls -li
total 8
1838455 -rw-rw-r-- 2 lisi lisi 24 Oct 25 20:48 hard_file.link
1838455 -rw-rw-r-- 2 lisi lisi 24 Oct 25 20:48 myfile.c
1838456 lrwxrwxrwx 1 lisi lisi  8 Oct 25 20:43 soft_file.link -> myfile.c

相信大家心里已经有答案了,为了再次确认我们再看看他们文件的内容。所以实则hard_file.link和cat myfile.c 都是cat myfile.c 文件。

[lisi@hcss-ecs-a9ee tmp]$ cat hard_file.link

hello link

hello link

hello link

[lisi@hcss-ecs-a9ee tmp]$ cat myfile.c

hello link

hello link

hello link

cpp 复制代码
# 修改软链接
ln -sf test2.txt test_link

🥝 5.2 软硬链接的区别

软链接有独立的inode,可被当做独立文件看待。硬链接没有独立的inode,那么建立一个硬链接就是在指定路径下,新增文件名和inode编号的映射关系!

在shell中的做法 ,硬链接是通过inode引用另外一个文件,软链接是通过名字引用另外一个文件。

cpp 复制代码
1838455 -rw-rw-r-- 2 lisi lisi 24 Oct 25 20:48 hard_file.link
1838455 -rw-rw-r-- 2 lisi lisi 24 Oct 25 20:48 myfile.c
1838456 lrwxrwxrwx 1 lisi lisi  8 Oct 25 20:43 soft_file.link -> myfile.c

在硬链接中,那个链接数使用计数器,有一个文件指向myfile.c,count++。所以链接数为2,再有文件硬链接myfile.c,count++,所以链接数为2。

链接失效

硬链接的硬链接数变成1了,然后 cat hard_file.link ​​​​文件还有数据。​​​

cpp 复制代码
[lisi@hcss-ecs-a9ee tmp]$ 2023-1-17]$ cat hard_file.link 
hello  link
hello  link
hello  link 

**真正删除一个文件,文件的硬链接数0的时候这个文件才算真正被删除。**所以这个硬链接就好比重命名

我们发现软件连接文件变红了,那个这个文件还存在吗?答案是存在的,虽然myfile.c文件删除了但是soft_file.link -> myfile.c的 ionde 还是在的,因为我们访问一个文件是通过文件名路径进行访问的,删除了myfile.c 破坏了 soft_file.link -> myfile.c 的文件名,这个文件名是在上级目录中存放的。

我们再重新新建myfile.c,让文件路径完整,但是我们发现这个文件是新的文件了, myfile.c中也没有数据了。

我们删除软链接,是不影响链接的文件的。删除软链接: unlink soft_file.link

cpp 复制代码
[lisi@hcss-ecs-a9ee tmp]$  unlink soft_file.link 
[lisi@hcss-ecs-a9ee tmp]$ ll
total 8
-rw-rw-r-- 1 lisi lisi 24 Oct 25 20:48 hard_file.link
-rw-rw-r-- 1 lisi lisi  3 Oct 25 21:05 myfile.c

小结:

  • 软链接是一个特殊的独立文件,它内容记录源文件位置;硬链接只是源文件的引用,不占用实际空间。
  • 删除软链接不影响源文件:删除源文件,软链接失效。删除硬链接不影响源文件,需将源文件和全部硬链接删除,源文件才会删除(换句话说,对于硬链接来说,删除了源文件,访问硬链接依旧有效)。
  • 软链接可以跨分区;硬链接不能跨文件系统。
  • 软链接可以针对目录;硬链接不能针对目录。

🥝 5.3 软硬链接的应用

🦋 软链接

我们在目录下建立test文件,然后随便写上端代码,生成可执行文件。

当我们cd ...退出,在其他文件执行时,需要记住文件路径,发现是非常麻烦的!

我们就可以建立软链接,在当前文件下直接执行。

这里的软链接好比是Windows下的快捷方式。

🦋 硬链接

我们先在创建一个文件file.txt,然后在创建一个目录empty。

cpp 复制代码
[lisi@hcss-ecs-a9ee tmp]$ touch file.txt
[lisi@hcss-ecs-a9ee tmp]$ mkdir empty 

我们发现目录的链接数是2,普通文件连接数是1,这是为什么呢?

因为普通文件本身有一个文件名和自己的inode具有一个映射关系。

关于目录empty,我们发现empty中他不关有自己当前路径,还有他的上级路径 ...。

cpp 复制代码
[lisi@hcss-ecs-a9ee tmp]$ cd empty/
[lisi@hcss-ecs-a9ee empty]$ ls -lia
total 8
1838456 drwxrwxr-x 2 lisi lisi 4096 Oct 25 21:07 .
1838454 drwxrwxr-x 3 lisi lisi 4096 Oct 25 21:07 ..
[lisi@hcss-ecs-a9ee empty]$ cd ..
[lisi@hcss-ecs-a9ee tmp]$ ls -lia
total 12
1838454 drwxrwxr-x  3 lisi lisi 4096 Oct 25 21:07 .
1573076 drwx------ 12 lisi lisi 4096 Oct 25 20:42 ..
1838456 drwxrwxr-x  2 lisi lisi 4096 Oct 25 21:07 empty
1838455 -rw-rw-r--  1 lisi lisi    0 Oct 25 21:07 file.txt

./代表当前路径,cd..代表返回上级路径。 这个.就相当于是empty的硬链接。这个..就是上级目录中的硬链接。

最后一点注意:系统不让用户给普通文件建立硬链接的原因是,害怕文件出现死循环。这个./...系统默认创建的。

六:🔥 共勉

以上就是我对 【Linux】万字长文带你深入理解文件系统与软硬链接 的理解,觉得这篇博客对你有帮助的,可以点赞收藏关注支持一波~😉

相关推荐
qq_312920117 分钟前
docker 部署 kvm 图形化管理工具 WebVirtMgr
运维·docker·容器
踏雪Vernon8 分钟前
[OpenHarmony5.0][Docker][环境]OpenHarmony5.0 Docker编译环境镜像下载以及使用方式
linux·docker·容器·harmonyos
Onlooker1298 分钟前
云服务器部署WebSocket项目
服务器
学Linux的语莫21 分钟前
搭建服务器VPN,Linux客户端连接WireGuard,Windows客户端连接WireGuard
linux·运维·服务器
legend_jz25 分钟前
【Linux】线程控制
linux·服务器·开发语言·c++·笔记·学习·学习方法
Komorebi.py26 分钟前
【Linux】-学习笔记04
linux·笔记·学习
黑牛先生28 分钟前
【Linux】进程-PCB
linux·运维·服务器
Karoku06633 分钟前
【企业级分布式系统】ELK优化
运维·服务器·数据库·elk·elasticsearch
友友马1 小时前
『 Linux 』网络层 - IP协议(一)
linux·网络·tcp/ip
猿java2 小时前
Linux Shell和Shell脚本详解!
java·linux·shell