目录
3.2.3、Block Bitmap 和 inode Bitmap
3.2.8、Linux下如何看待目录?文件名保存在哪里?为什么我们是用文件名找到的文件而不是inode?
一、理解硬件
1.1、磁盘、服务器、机柜、机房
机械磁盘是计算机中唯一的一个机械设备;磁盘是外设,特点是运行速度慢,并且容量大、价格便宜
服务器:就是将很多磁盘放在一起
机柜:将很多服务器放在一起
机房:
关于磁盘,实际上就是很多小磁铁打磨光滑形成的,为什么使用磁铁呢?我们知道计算机中很多东西都是两态的,比如0、1等等,那么就可以用磁铁做到相对应(正极和负极)
1.2、磁盘的物理结构
1.3、磁盘的存储结构
每个磁盘有两面,每个盘面都能存储数据;每个盘面上有很多磁道,磁道上存在很多扇区,扇区就是存储数据的,相邻扇区之间有间隙;扇区是磁盘存储的基本单位,每个扇区存储512个字节,扇区是块设备
每个扇面上的相同半径的磁道共同构成一个柱面;
磁臂上的所有磁头都是共进退的,也就是说磁头的位置都相同,但是每个磁头可以分别作用;
如何定位一个扇区呢?
1.4、磁盘的逻辑结构
磁带上面可以存储数据,可以把磁带拉直形成一个线性结构:








1.5、CHS && LBA
二、引入文件系统
2.1、引入“块的概念”

2.2、引入“分区的概念”


三、ext2文件系统
3.1、宏观认识
想要在硬盘上存储文件,必须要把硬盘格式化为某种格式的文件系统,才能存储文件。文件系统的目的就是组织和管理硬盘中的文件
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 块组描述符表
// 磁盘级 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
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

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 # 查看可以使⽤的分区


$ sudo umount /mnt/mydisk # 卸载分区
3.2.9、inode和block映射

3.2.10、总结
四、硬连接和软连接
4.1、硬连接
本质上没有创建新的文件(因为没有新的inode编号),只是增加了文件名到同一个inode的映射关系,采用引用计数来记录到同一个inode映射关系有多少个
作用是给文件做备份
建立连接:ln
解除连接:unlink
看例子
.表示当前目录,因为当前这个目录有一个名字ext2,所以引用计数为2
4.2、软连接
软连接本质上创建了新的文件(因为存在新的inode编号),映射方式当然也增加了但是是新的一组映射,因为新建了文件,inode内容不一样,inode也就不一样
作用相当于Windows下的快捷方式,也就是能够快速找到并且打开文件
建立连接:ln -s
解除连接:unlink