Linux系统-Ext系列文件系统

目录

一、理解硬件

1.1、磁盘、服务器、机柜、机房

1.2、磁盘的物理结构

1.3、磁盘的存储结构

1.4、磁盘的逻辑结构

1.5、CHS && LBA

二、引入文件系统

2.1、引入“块的概念”

2.2、引入“分区的概念”

三、ext2文件系统

3.1、宏观认识

3.2、Block Group

3.2.1、Data Blocks

3.2.2、inode Table

3.2.3、Block Bitmap 和 inode Bitmap

3.2.4、GDT

3.2.5、 super block

3.2.6、整体上地补充

3.2.7、通过inode就可以找到这个文件的全部信息

3.2.8、Linux下如何看待目录?文件名保存在哪里?为什么我们是用文件名找到的文件而不是inode?

1、路径解析

2、路径缓存

3、挂载分区

3.2.9、inode和block映射

3.2.10、总结

四、硬连接和软连接

4.1、硬连接

4.2、软连接


一、理解硬件

1.1、磁盘、服务器、机柜、机房

机械磁盘是计算机中唯一的一个机械设备;磁盘是外设,特点是运行速度慢,并且容量大、价格便宜

服务器:就是将很多磁盘放在一起

机柜:将很多服务器放在一起

机房:

关于磁盘,实际上就是很多小磁铁打磨光滑形成的,为什么使用磁铁呢?我们知道计算机中很多东西都是两态的,比如0、1等等,那么就可以用磁铁做到相对应(正极和负极)

1.2、磁盘的物理结构

1.3、磁盘的存储结构

每个磁盘有两面,每个盘面都能存储数据;每个盘面上有很多磁道,磁道上存在很多扇区,扇区就是存储数据的,相邻扇区之间有间隙;扇区是磁盘存储的基本单位,每个扇区存储512个字节,扇区是块设备

每个扇面上的相同半径的磁道共同构成一个柱面;

磁臂上的所有磁头都是共进退的,也就是说磁头的位置都相同,但是每个磁头可以分别作用;

如何定位一个扇区呢?

可以先定位磁头(header)
确定磁头要访问哪⼀个柱⾯(磁道)(cylinder)
定位⼀个扇区(sector)
CHS地址定位:
柱⾯(cylinder),磁头(head),扇区(sector)
先确定是哪个柱面,让磁臂移动到那个柱面,即C;之后这个柱面上可能并不是每个盘面都需要被读写,那么此时就需要确定哪些磁头需要工作,即H;确定了柱面磁头之后即找到了这个磁道,但是这个磁道上可能只需要读写一个扇区,那么就需要通过地址确定是哪个扇区,即S

1.4、磁盘的逻辑结构

磁带上面可以存储数据,可以把磁带拉直形成一个线性结构:

那么磁盘本质上虽然是硬质的,但是逻辑上我们可以把磁盘想象成为卷在⼀起的磁带,那么磁盘的逻辑存储结构我们也可以类似于:
这样每⼀个扇区,就有了⼀个线性地址(其实就是数组下标),这种地址叫做LBA
真实过程:
柱⾯是⼀个逻辑上的概念,其实就是每⼀⾯上,相同半径的磁道逻辑上构成柱⾯。
所以,磁盘物理上分了很多⾯,但是在我们看来,逻辑上,磁盘整体是由“柱⾯”卷起来的
所以,磁盘的真实情况是:
磁道:某⼀盘⾯的某⼀个磁道展开:
即:⼀维数组
柱⾯:
整个磁盘所有盘⾯的同⼀个磁道,即柱⾯展开:
柱⾯上的每个磁道,扇区个数是⼀样的
这不就是⼆维数组吗
整个磁盘不就是多张⼆维的扇区数组表(三维数组?)
所以,寻址⼀个扇区:先找到哪⼀个柱⾯(Cylinder) ,再确定柱⾯内哪⼀个磁道(其实就是磁头位置,Head),在确定扇区(Sector),所以就有了CHS。
我们之前学过C/C++的数组,在我们看来,其实全部都是⼀维数组:
所以,每⼀个扇区都有⼀个下标,我们叫做LBA(Logical Block Address)地址,其实就是线性地址。所以怎么计算得到这个LBA地址呢?
所以操作系统只需要LBA就行了,CHS和LBA可以相互转换,这个转化过程由磁盘自己来做

1.5、CHS && LBA

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地址。OS使⽤磁盘, 就可以用⼀个数字访问磁盘扇区了

二、引入文件系统

2.1、引入“块的概念”

其实硬盘是典型的“块”设备,操作系统读取硬盘数据的时候,其实是不会⼀个个扇区地读取,这样
效率太低,⽽是⼀次性连续读取多个扇区,即⼀次性读取⼀个”块”(block)。
硬盘的每个分区是被划分为⼀个个的”块”。⼀个”块”的⼤⼩是由格式化的时候确定的,并且不可
以更改,最常⻅的是4KB,即连续⼋个扇区组成⼀个 ”块”。”块”是⽂件存取的最⼩单位。
注意:
磁盘就是⼀个三维数组,我们把它看待成为⼀个"⼀维数组",数组下标就是LBA,每个元素都是扇
每个扇区都有LBA,那么8个扇区⼀个块,每⼀个块的地址我们也能算出来。
知道LBA:块号 = LBA/8
知道块号:LAB=块号*8 + n. (n是块内第⼏个扇区)

2.2、引入“分区的概念”

其实磁盘是可以被分成多个分区(partition)的,以Windows观点来看,你可能会有⼀块磁盘并且将它分区成C,D,E盘。那个C,D,E就是分区。分区从实质上说就是对硬盘的⼀种格式化。但是Linux的设备都是以⽂件形式存在,那是怎么分区的呢?
柱⾯是分区的最⼩单位,我们可以利⽤参考柱⾯号码的⽅式来进⾏分区,其本质就是设置每个区的起始柱⾯和结束柱⾯号码。 此时我们可以将硬盘上的柱⾯(分区)进⾏平铺,将其想象成⼀个⼤的平⾯,如下图所⽰:

三、ext2文件系统

3.1、宏观认识

想要在硬盘上存储文件,必须要把硬盘格式化为某种格式的文件系统,才能存储文件。文件系统的目的就是组织和管理硬盘中的文件

ext2文件系统将每一个分区又分为多个分组。

上图中启动块(Boot Block/Sector)的⼤⼩是确定的,为1KB,由PC标准规定,⽤来存储磁盘分区信
息和启动信息,任何⽂件系统都不能修改启动块。启动块之后才是ext2⽂件系统的开始。

3.2、Block Group

即Block Group;每个分区的文件系统可能不一样,因此文件系统的载体是分区,但是每个分区内部的每个分组的文件系统肯定是一样的

分组内是以数据块为单位进行IO的,也就是4KB

3.2.1、Data Blocks

文件 = 内容 + 属性,在linux 的ext2文件系统中,文件的内容和属性是分开存放的;

Data Groups就是存放内容的部分,这个部分占据Block Group的绝大部分,单位是数据块4KB

3.2.2、inode Table

文件的属性是由一个结构体struct inode管理的,里面包含文件的各种属性,这个结构体大小是固定的,128字节,但是因为是以4KB为单位,所以,每次filesystem和IO交互时,每次可以读取32个inode

文件名不会作为属性保存在inode中,因为文件名是变化的,要是固定死这个文件名的最大大小,可能会有浪费,由于有很多个inode struct,因此这个浪费不容小觑

在这个结构体中,有一个inode_number表示文件属性结构体的编号,可以ls -li查看

一个文件的inode

/*
* Structure of an inode on the disk
*/
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[EXT2_N_BLOCKS]; /* Pointers to blocks */
__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 */
};
/*
* Constants relative to the data blocks
*/
# 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

3.2.3、Block Bitmap 和 inode Bitmap

这两个是位图。分别用来记录块组里面的某个文件属性或者某个文件内容是否被占用,若是位图为1,则是有效文件属性或者内容

例如有100000个文件内容,通过Block Bitmap,用100000个比特位来表示,就是100000/8/4k=3.125,也就是用4个数据块就能表示100000个文件内容是否有效

这也是为什么在删除文件很快而下载文件很慢的原因,因为删除文件只是让这个文件的位图对应的比特位置为0,而下载文件是要将文件的属性和内容都拷贝到块组的对应位置;并且文件误删之后可以恢复的原因就是此时只是把位图置为0,文件内容和属性没有删除,只是可以覆盖,这也是为什么误删除文件之后最好不要新建文件的原因

3.2.4、GDT

group descriptor table 块组描述符表

块组描述符表,描述块组属性信息,整个分区分成多个块组就对应有多少个块组描述符。每个块组描 述符存储⼀个块组 的描述信息,如在这个块组中从哪⾥开始是inode Table,从哪⾥开始是DataBlocks,空闲的inode和数据块还有多少个等等。块组描述符在每个块组的开头都有⼀份拷⻉。
// 磁盘级 blockgroup 的数据结构
/*
* Structure of a blocks group descriptor
*/
struct ext2_group_desc
{
__le32 bg_block_bitmap; /* Blocks bitmap block */
__le32 bg_inode_bitmap; /* Inodes bitmap */
__le32 bg_inode_table; /* Inodes table block*/
__le16 bg_free_blocks_count; /* Free blocks count */
__le16 bg_free_inodes_count; /* Free inodes count */
__le16 bg_used_dirs_count; /* Directories count */
__le16 bg_pad;
__le32 bg_reserved[ 3 ];
};

3.2.5、 super block

存放⽂件系统本⾝的结构信息,描述整个分区的⽂件系统信息 。记录的信息主要有:bolck 和 inode的总量,未使⽤的block和inode的数量,⼀个block和inode的⼤⼩,最近⼀次挂载的时间,最近⼀次写⼊数据的时间,最近⼀次检验磁盘的时间等其他⽂件系统的相关信息。Super Block的信息被破坏,可以说整个⽂件系统结构就被破坏了
由于super block描述的是整个文件系统的信息,因此要是被破坏影响很大。所以不止第一个块组里面有super block,后面的部分block group 也存在super block的拷贝,目的是出现意外时能够恢复

3.2.6、整体上地补充

inode 和 blocks是跨分组编号的,不跨分区编号;意思就是每一个分区内部的inode和blocks的编号都是唯一的,但是分区却不是。

分区之后格式化地本质就是先分组,之后将管理信息写到每个分组,初始的管理信息都是0(管理信息就是上述介绍的各个区域)。

硬盘上文件的分区或者分组也需要管理,这同样由操作系统来进行,“先描述再组织”

3.2.7、通过inode就可以找到这个文件的全部信息

前置问题:通过inode如何知道这个inode在哪个分组?在这个分组位图的哪个位置上?由于文件系统划分分组时每个块组的大小都是一样固定的,并且块组里面的inode和data blocks的数量也是固定的,所以只需要拿着所给的inode的编号先整除上块的个数就能找到这个分组,之后用inode编号对分组个数取余就能找到在这个分组内的哪个位置上

怎么找到这个inode对应的数据块,inode里面存在一个数组,通过这个数组就可以找到

3.2.8、Linux下如何看待目录?文件名保存在哪里?为什么我们是用文件名找到的文件而不是inode?

在Linux文件系统中,目录这个概念不存在,也是文件,也包含inode和datablock,inode就是相关属性和文件差不多,但是block存放的是这个目录下的文件名和文件名对应的inode,也就是一种映射关系

文件名保存在所在目录的datablock里面

1、路径解析

硬盘上的文件系统只认识inode;使用文件名查找文件时OS先通过进程提供的路径找到此时这个文件名所在的目录,之后将目录这个文件的数据部分的映射关系IO进入内存,得到inode,相当于找到了这个文件

查找文件需要路径加文件名,路径由进程提供(访问文件本质上是进程通过CWD访问),而文件名由我们提供,例如ls code.c ,ls就会提供路径,code.c就是文件名

解析时需要打开上一级目录,而这个目录也是文件,也需要打开上上一级目录,因此实际上就是从根目录向右解析,每个文件都这样的话就会有大量的IO,效率低下

2、路径缓存

有这样的一种解决方法:在进行解析时,会把历史所有的路径形成一颗多叉树进行保存,下一次就不需要从头开始解析

这个多叉树就是目录,保存在内存中

在内存中维护这个树状路径结构的内核叫做struct dentry

每个⽂件其实都要有对应的dentry结构,包括普通⽂件 。这样所有被打开的⽂件,就可以在内存中
形成整个树形结构
整个树形节点也同时会⾪属于LRU(Least Recently Used,最近最少使⽤)结构中,进⾏节点淘汰
整个树形节点也同时会⾪属于Hash,⽅便快速查找
更重要的是,这个树形结构,整体构成了Linux的路径缓存结构,打开访问任何⽂件,都在先在这
棵树下根据路径进⾏查找,找到就返回属性inode和内容,没找到就从磁盘加载路径,添加dentry
结构,缓存新路径
3、挂载分区

通过文件名可以得到inode之后得到属性和内容,inode编号可以只到所在分组和位图位,但是现在我们无法知道分区是哪个,而不能只到所在分区有很大影响,因为inode和block是不跨分区编号的,也就是说,现在不知道分区可能会导致查找错误

挂载分区:我们的分区需要一个特定的目录进行关联,通过这个目录就能够进入对应的分区

一个挂载分区的实验:

$ dd if =/dev/zero of=./disk.img bs=1M count=5 # 制作⼀个⼤的磁盘块,就当做⼀个分区
$ mkfs.ext4 disk.img # 格式化写⼊⽂件系统
$ mkdir /mnt/mydisk # 建⽴空⽬录
$ df -h # 查看可以使⽤的分区
将新建的分区进行挂载到指定的目录
mounted on后面就是每个filesystem也就是分区挂载的目录
$ sudo umount /mnt/mydisk # 卸载分区

分区写⼊⽂件系统,⽆法直接使⽤,需要和指定的⽬录关联,进⾏挂载才能使⽤。
所以,可以根据访问⽬标⽂件的"路径前缀"准确判断inode在哪⼀个分区,也就说,访问文件时,可以确定的是我们知道了路径,而路径前缀就是这个当前这个分区挂载的目录。

3.2.9、inode和block映射

inode内部存在 __le32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ ,
EXT2_N_BLOCKS =15,就是⽤来进⾏inode和block映射的
这样⽂件=内容+属性,就都能找到了。
12个直接块指针,每个指针指向一个数据块;一级的先指向4KB的地址,这个地址指向数据块;后面二级三级地址依次增多

3.2.10、总结


四、硬连接和软连接

4.1、硬连接

本质上没有创建新的文件(因为没有新的inode编号),只是增加了文件名到同一个inode的映射关系,采用引用计数来记录到同一个inode映射关系有多少个

作用是给文件做备份

建立连接:ln

解除连接:unlink

看例子

.表示当前目录,因为当前这个目录有一个名字ext2,所以引用计数为2

4.2、软连接

软连接本质上创建了新的文件(因为存在新的inode编号),映射方式当然也增加了但是是新的一组映射,因为新建了文件,inode内容不一样,inode也就不一样

作用相当于Windows下的快捷方式,也就是能够快速找到并且打开文件

建立连接:ln -s

解除连接:unlink

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值