目录

一、理解硬件

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

1.2. 磁盘的物理结构

1.3. 磁盘的存储结构

1.4. 磁盘的逻辑结构

1.4.1. 理解

1.4.2. 真实的内容

磁道:

柱面:

整盘:

1.5 CHS && LBA地址

二、理解文件系统

2.1. 块

2.2 分区

2.3. inode


一、理解硬件

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

已知:

  •         文件 = 内容 + 属性
  •         被打开的文件,属于基础IO,存储在内存当中       
  •         没有打开的文件,存储在磁盘中

这些文件是如何让我们找到的呢?

  1. 最基本的诉求:就是保存在磁盘的文件,要被我们快速找到
  2. 目录结构组织的,目录结构式树状的,有绝对路径和相对路径

上面是一些硬件设施的照片。

1.2. 磁盘的物理结构

        所有数据在底层都是二进制的(0和1),但不同的硬件设备使用不同的物理方式来表现和存储这些二进制位。

        磁盘盘片上覆盖着一层磁性材料,可以被磁化成两个不同的方向。

        可以理解成,磁盘的写入,本质就是:更改磁盘小颗粒的南北极,这两个方向分别代表二进制的 0 和 1。

        内存中则是由无数个微小的电容电路组成。电容要么充满电(高电平,例如代表 1),要么没有电(低电平,例如代表 0)

        网络则是用 波形图来传递的,在网线里,电压的快速高低变化(方波)就构成了比特流;在光纤里,是激光的亮灭;

        在Wi-Fi中,是无线电波的频率、相位或振幅的变化。这些都可以被抽象地看作是一种“波形图”。

1.3. 磁盘的存储结构

        

扇区:是磁盘存储数据的基本单位,512字节,是块设备。

        这个是读写数据的时候,盘片和传动臂的旋转的图片。其中,磁盘表面以固定的旋转速率旋转,通过在半径方向上移动,传动臂可以将读/写头定位在任何磁道上。

更加清晰的示意图。

        

上面多了一个概念:柱面:在所有盘片中,半径相同的所有磁道的集合。

既然我们已经知道了扇区是磁盘存储数据的基本单位,那么该如何定位一个扇区?

  • 先定位磁头(header)
  • 确定磁头要访问哪一个柱面(磁道)(cylinder)
  • 定位一个扇区(sector)

这个就是 CHS 寻址方法,只需要知道 磁头(h)、柱面(c) 和 扇区(s)即可

        sudo fdisk -l 是一个在 Linux 系统中用于查看系统所有磁盘及其分区信息的命令。

  • 扇区是从磁盘读出和写入信息的最小单位,通常大小为 512 字节。
  • 磁头(head)数:每个盘片一般有上下两面,分别对应1个磁头,共2个磁头
  • 磁道(track)数:磁道是从盘片外圈往内圈编号0磁道,1磁道…,靠近主轴的同心圆用于停靠磁头,不存储数据
  • 柱面(cylinder)数:磁道构成柱面,数量上等同于磁道个数
  • 扇区(sector)数:每个磁道都被切分成很多扇形区域,每道的扇区数量相同
  • 圆盘(platter)数:就是盘片的数量
  • 磁盘容量=磁头数 × 磁道(柱面)数 × 每道扇区数 × 每扇区字节数
  • 细节:传动臂上的磁头是共进退的(这点比较重要,后面会说明)

CHS寻址

对早期的磁盘非常有效,知道用哪个磁头,读取哪个柱面上的第几扇区就可以读到数据了。

但是CHS模式支持的硬盘容量有限,因为系统用8bit来存储磁头地址,用10bit来存储柱面地址,用6bit来存储扇区地址,而一个扇区共有512Byte,这样使用CHS寻址一块硬盘最大容量为256 * 1024 * 63 * 512B = 8064 MB (1MB = 1048576B)(若按1MB=1000000B来算就是8.4GB)

1.4. 磁盘的逻辑结构

1.4.1. 理解

        

        磁带上面是可以存储数据的,我们可以把 磁带 “拉直”,形成线性结构。

        磁盘本质上虽然是硬质的,但是在逻辑上我们可以把磁盘想象成卷在一起的磁盘,那么磁盘的逻辑存储结果,就可以类似成:

这样子每一个扇区,就有了一个线性地址(其实就是数组下标),这个地址叫做 LBA

1.4.2. 真实的内容

        之前说过的一个细节:传动臂的磁头是共同进退的!

柱面是一个逻辑上的概念,其实就是每一面上,相同半径的磁道逻辑上构成柱面。

所以,磁盘物理上分了很多面,但是在我们看来,逻辑上,磁盘整体是由“柱面”卷起来的。

所以,磁盘的真实情况是:

磁道:

某一盘面的某一个磁道展开:

即:一维数组

柱面:

整个磁盘所有盘面的同一个磁道,即柱面展开:

  • 柱面上的每个磁道,扇区个数是一样的

  • 这不就是二维数组吗

整盘:

        整个磁盘不就是多张二维的扇区数组表(三维数组?)

        所以,寻址一个扇区:先找到哪一个柱面(Cylinder),在确定柱面内哪一个磁道(其实就是磁头位置,Head),在确定扇区(Sector),所以就有了CHS。

        我们之前学过C/C++的数组,在我们看来,其实全部都是一维数组:

        所以,每个扇区都有一个下标,我们叫做 LBA (Logical Block Address)地址,其实就是线性地址。

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

  • 知道块号:LBA = 块号 * 8 + n. (n是块内第几个扇区)

2.2 分区

其实磁盘是可以被分成多个分区(partition)的,以Windows观点来看,你可能会有一块磁盘并且将它分区成C,D,E盘。那个C,D,E就是分区。分区从实质上说就是对硬盘的一种格式化。但是Linux的设备都是以文件形式存在,那是怎么分区的呢?

柱面是分区的最小单位,我们可以利用参考柱面号码的方式来进行分区,其本质就是设置每个区的起始柱面和结束柱面号码。此时我们可以将硬盘上的柱面(分区)进行平铺,将其想象成一个大的平面,如下图所示:

注意:

        柱面大小一致,扇区个位一致,那么其实只要知道每个分区的起始和结束柱面号,知道每一个柱面多少个扇区,那么该分区多大,其实和解释LBA是多少也就清楚了。

2.3. inode

        之前我们说过文件=数据+属性 ,我们使用 ls -l 的时候看到的除了看到文件名,还能看到文件元数据(属性)

        可以使用  ls -l 或者 stat + 文件,查看信息。

        文件数据都储存在“块”中,那么很显然,我们还必须找到一个地方储存文件的元信息(属性信息),比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做inode,中文译名为“索引节点”。

        每一个文件都有对应的inode,里面包含了与该文件有关的一些信息。为了能解释清楚inode,我们需要是深入了解一下文件系统。

注意:

        Linux下文件的存储是属性和内容分离存储的

        Linux下,保存文件属性的集合叫做inode,一个文件,一个inode,inode内有一个唯一的标识符,叫做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 */
};

再次注意:

  • 文件名属性并未纳入到inode数据结构内部

  • inode的大小一般是128字节或者256,我们后面统一128字节

  • 任何文件的内容大小可以不同,但是属性大小一定是相同的

到目前为止,相信大家还有两个问题:

  1. 我们已经知道硬盘是典型的“块”设备,操作系统读取硬盘数据的时候,读取的基本单位是“块”。“块”又是硬盘的每个分区下的结构,难道“块”是随意的在分区上排布的吗?那要怎么找到“块”呢?

  2. 还有就是上面提到的存储文件属性的inode,又是如何放置的呢?

文件系统就是为了组织管理这些的!

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐