【Linux基础IO】文件系统(下)

目录

一、前言

二、inode

三、分区管理

四、组块内部构成

1.Super Block

2.GDT(Group Descriptor Table)

3.Block Bitmap & Inode Bitmap

4.inode Table

5.Date Block

6.Boot Sector

五、inode和Date Blocks的映射

六、如何看待目录和文件名

1.目录的本质

2.路径解析

3.路径缓存

4.挂载分区

七、再谈fopen

八、软硬链接

1.软链接

2.硬链接


一、前言

本文介绍了文件系统的下半部分,从记录文件属性的inode到记录文件内容的数据块,理解磁盘内部结构,分区分组,分组内的构造有超级块,GDT等,随后理解inode和数据块的映射关系,重新看待目录和文件名,所谓目录其实也就是普通文件,再详谈路径问题:如何根据inode寻找文件,最后总的理解fopen,介绍软硬链接。


二、inode

所有被存储在磁盘中的数据都是以文件的形式,而文件可以分为两个部分:内容和属性。

在Linux中,文件的内容和属性是分开管理的,因为文件的内容的大小是不确定的,而每个文件具有的属性是相同的,只是值不同而已,于是Linux把文件的属性放在了结构体struct inode中管理。

Linux 2.6.10内核的struct inode部分源码如下:

struct inode {
	struct hlist_node	i_hash;
	struct list_head	i_list;
	struct list_head	i_dentry;
	unsigned long		i_ino;//inode的编号,唯一标识
	atomic_t		i_count;
	umode_t			i_mode;
	unsigned int		i_nlink;
	uid_t			i_uid;//所有者id
	gid_t			i_gid;//所属组id
	dev_t			i_rdev;
	loff_t			i_size;//文件大小(字节单位)
	struct timespec		i_atime;
	struct timespec		i_mtime;
	struct timespec		i_ctime;
	//......
};

其中i_ino就是一个inode的唯一标识,OS对文件写入时,就是通过i_ino来查找文件的,称为inode编号,我们可以通过指令 ls -i 来查看文件的inode编号:


三、分区管理

硬盘可以被分为多个区,同时OS又会每个区分为多个组,这样OS只需要按照相同的方式管理一个个相同的分组即可管理好整个硬盘了:

若要看得更细致一些就是下图: 

文件系统的载体是分区。EXT2文件系统将整个分区划分为同样大小的块组Block Group,只要管理一个分区就能管理所有分区,也就能管理所有磁盘文件。


四、组块内部构成

1.Super Block

存放文件系统本身的结构信息,描述整个分区的文件系统信息,主要有:

  • block和inode的总量
  • 未使用的block和inode数量
  • 一个block和inode的大小
  • 最近一次写入数据的时间
  • 等等

super block的信息是整个文件系统的基础信息,如果super block被破坏,那么可以说整个文件系统就被破坏了,这意味着这个分区(几百个G)的数据都会被破坏,super block非常重要,因此在多个块组group的开头都有一份拷贝(第一个必须有,后面可能没有)。


2.GDT(Group Descriptor Table)

GDT块组描述符表,描述块组属性,整个分区分为多少个块组就有多少个GDT,包含描述该块组哪里开始是inode Table,哪里开始是Data Blocks,空闲的indoe和数据块还有多少个等信息。


3.Block Bitmap & Inode Bitmap

块位图和inode位图,存储的是数,有多少位就代表后续Data Blocks和inode Table有多少个数据块,如果一个数据块被占用,对应的那一位就为1,若空闲则为0。


4.inode Table

  • 存放文件属性
  • 存放当前分组所有inode的集合
  • inode存放文件属性如文件大小,所有者,最近修改信息等,但没有文件名
  • inode编号以分区为划分,不可跨分区,但是是跨分组的

5.Date Block

  • 存放文件内容
  • 对于普通文件,存放文件的所有数据
  • 对于目录文件,存放该目录下的文件、目录名称和对应的inode,即名字和inode的映射
  • Block号按分区划分,不可跨分区

6.Boot Sector

Boot Sector/Block 用于计算机开机时告知磁盘的分区情况,帮助计算机加载操作系统等。操作系统本质也是一个软件,开机时计算机要加载操作系统,毫无疑问操作系统也要被存储在磁盘中,Boot Sector就会存储操作系统的存储位置,帮助计算机启动操作系统。


五、inode和Date Blocks的映射

我们知道inode存放文件属性,Data Blocks存放文件内容,但一个文件属性的大小是有限的,但内容的大小却不一定,可以很大或者很小。属性和内容存在不同的数据块中,如何根据inode去找到其对应的文件内容呢?这就需要inode和data blocks的映射关系。

在struct inode中存在一个属性int datablocks[N] ,其中N=15,前[0,11]都是直接指向数据块,而12指向一级间接块,13指向二级间接块,14指向三级间接块,它们能存储的数据量是指数级增长。


六、如何看待目录和文件名

1.目录的本质

目录同样也是文件,同样具有属性和内容。属性存储在inode中,那么目录的内容是什么呢?

目录的内容就是:文件名和inode的映射关系

也就是说我们当前所在的目录是一个文件,内容是该目录下的文件名和对应inode,我们通过文件名查找,也就是通过映射获取其对应的inode,再通过inode去查找到对应文件。


2.路径解析

由上文我们知道了当前目录也是一个文件,我们要访问这个文件的内容又必须得到当前文件的inode,这又是从哪来的?这就需要追溯到上一级目录,上一级目录的内容自然包含当前目录的名字和对应inode,如此递归向上,最终就能到达根目录 / ,而根目录是开机时OS就已经打开了,这样我们就能根据路径来找到对应的文件。

例如: /home/zyh/code/test/test.c 我当前在test目录要去访问test.c,访问本质也是一个进程,开启一个进程,通过进程的环境变量CWD获取路径,这样再从根目录开始通过文件名映射inode依次向下直到找到test.c文件的inode,打开test.c


3.路径缓存

根据上文所学,我们又知道了访问任何文件,实际上都是通过根目录到其对应的路径来访问,但如果每次都从根目录开始解析是不是效率很低呢?因此Linux会缓存历史路径结构。

Linux中,在内核维护树状路径结构的内核结构体叫做:struct dentry

dentry的作用有:

提高文件系统操作的速度:dentry会缓存最近访问过的目录项,进行文件查找或路径解析时就会先在缓存中查找,避免频繁访问磁盘;同时dentry对应的多叉树的数据结构也能帮助OS快速定位文件和目录,提高效率。

需要的注意的点:

  • 每个文件都有对应的dentry结构,包括普通文件。这样所有被打开的文件在内存中形成整个树形结构
  • 所有树形节点同时也隶属于LRU结构中,进行节点淘汰(树不可能无限大,消耗内存)
  • 所有树形节点也同时隶属于Hash表,方便快速查找
  • 整个树形结构构成了Linux的路径缓存结构,打开任何文件先在树中进行查找,找到则返回inode和内容,没找到才从磁盘加载路径,并添加dentry结构,缓存新路径 

4.挂载分区

我们已经能够根据inode编号去查找文件了,但这里有个问题,inode是不能跨区的,也就是说在不同的分区中存在同一编号的inode,那我就算知道了inode,又该去哪个分区找呢?

这里就要提到挂载(Mount)的概念了,挂载实际上是将一个分区“贴”到目录树的某个位置(挂载点),让这个分区的文件系统成为目录树的一部分。

例如:将U盘(/dev/sdb1)挂载到 /mnt/usb ,那么访问/mnt/usb/file时实际访问的是U盘内部的文件

本质上,挂载点就是一个传送门,通过挂载点的目录,我们就能直接进入该分区的文件系统。


七、再谈fopen

学习了所有以上的知识,我们就可以重新再完整地理解下fopen实际的操作了:

首先fopen要打开文件,必须传入一个文件名,路径可以指明或者不指明,若不指明则由进程的环境变量CWD提供。

有了路径后,进行路径解析,OS使用dentry缓冲去查找已经访问过的目录项,快速定位到指定目录。

找到指定目录后访问其文件内容,就是文件名和inode的映射关系,找到打开文件的inode,有了inode就得考虑分区,根据路径的前缀得到分区(挂载),通过inode计算其所在的block group,查找的对应的inode,再从该文件的inode中映射到其内容的数据块。


八、软硬链接

1.软链接

软链接实际上就是创建快捷方式。如下图使用指令:ln -s 就能为code创建快捷方式code2

可以发现code和code2的inode是不同的,也就是说它们是不同的文件,只是软链接的文件内容是目标文件的路径,而不是实际文件的内容。


2.硬链接

使用指令ln创建硬链接:

可以发现code3的inode和code是相同的,这意味这硬链接不是一个文件,因为它没有独立的inode编号,硬链接本质上只是在目录内部,多了一个文件名与inode的映射关系。

而蓝框内的数字,叫做硬连接数,即有多少个文件名指向这一个inode,例如创建一个目录文件:

可以发现它一来就是2,这意味这还有一个硬链接是指向它的,是谁?

其实就是它自身内部的. ,这个.就是指向它自身的,如果再在内部创建一个目录,就会变为3,因为新创建目录内的..也要指向它。

使用指令unlink即可删除软硬链接。

注意:Linux不允许用户自己建立目录的硬链接,尽管.和..就是系统建立的目录硬链接。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值