文件通常保存在磁盘上,因此想要实现文件系统,少不了要跟磁盘打交道。
本节带领大家了解磁盘的内部结构,看它是如何存储数据的。我们先讨论磁道、磁头和扇区等概念,再介绍 CHS 和 LBA 这两种不同的寻址方式。
内部结构
磁盘( disk )俗称 硬盘( hard disk ),通常是指 机械磁盘( mechanical disk )。其他类型的磁盘,诸如固态磁盘结构与机械磁盘有较大差异,不在本文的讨论范围内。
机械磁盘内部通常由若干个 磁片( platter )组成,磁片由中心轴驱动高速旋转。磁片正反两面均涂有磁性物质,用于保存数据。当磁片转动时,悬浮在它表面上的 磁头 ( head )就可以读写数据。
如上图,磁盘内有 3 个磁片,每个磁片由 2 个面,每个面均有一个读写磁头,总共 6 个磁头。
每个磁面被进一步划分成一个个环,这就是 磁道( track )。它们圆心相同,半径由内向外不断递增。所有磁头均由一个机械臂驱动,在磁片表面同步移动。如果机械臂保持不动,磁头便访问同一磁道(如图黄色圆环)。
由于不同盘面上的同一磁道半径相同,这些磁道组成一个圆柱面(如图蓝色部分),因此磁道也被称为 柱面( cylinder )。
一个磁道可以存储很多数据,但计算机访问硬盘的基本单位通常更小。因此,磁道需要进一步划分:如上图,红色扇形从每个磁道中划分出一小段,作为最基本的存储单位—— 扇区( sector ),大小通常是 512 字节。
如上图,磁盘总共有 6 个磁面,每个磁面有 6 条磁道,每条磁道有 8 个扇区,总共有 $6 \times 6 \times 8 = 288$ 个扇区。假设每个扇区大小为 512 字节,则总容量是 $288 \times 512 = 147456$ 字节,也就是 144 KB。
磁盘寻址
这块迷你磁盘总共有 288 个扇区,怎么定位到其中的某一个呢?这就是磁盘 寻址( addressing )要回答的问题。
CHS寻址
想要定位一个扇区,我们需要回答三个问题:
- 它在哪个磁道(柱面)上?
- 它在哪个磁面(磁头)上?
- 它在哪个扇形上?
因此,只要我们将 磁头 、磁道 和 扇形一一编号后,就可以通过一个三维坐标定位到一个指定扇区。
如上图,磁道从内往外分别编号为 0 到 5 ,磁头从上往下分别编号为 0 到 5 ,扇形从红色开始,顺时针分别编号为 1 到 8 。那么第一个磁面上,黄色磁道和红色扇形相交的扇区,坐标就是 (4, 0, 1)
。
至于为什么扇区是从 1 开始编号,我也没仔细研究,可能是历史原因。
像这样通过 磁道 、磁头 和 扇形 定位磁盘数据的方式,就叫 CHS 寻址。其中,
- C 代表柱面,也就是磁道;
- H 代表磁头,也就是磁面;
- S 代表磁面上的扇形;
分区位录写
磁道离圆心越远,半径越大,周长越长,能存储的数据也就越多。因此,简单粗暴地用扇形将磁道划分为扇区,会造成大量浪费。因为外圈扇区的长度要比内圈长,原本可以存储更多数据。
制作商通常会采用 分区位录写 ( zone bit recording )技术,在外圈磁道存储更多扇区,以便最大限度地提升磁盘的存储容量。但这样一来,同个扇形下不同磁道保存的扇区数是不固定的,这就给 CHS 寻址带来挑战!
如上图,由内往外每隔若干磁道,扇区数就翻倍。如果我们访问磁盘时,需要根据它的内部结构来判断某个磁道分为多少个扇区,那简直是个噩梦!
为了解决这个问题,磁盘一般内置一个控制器,将自己伪装成一个经典磁盘,对外提供 CHS 寻址。驱动器提供 CHS 寻址接口,然后根据自己的内部结构对 CHS 坐标进行换算。
至于 CHS 怎么换算,大家可以思考一下。我给点提示:将每条绿色磁道对外宣称为两条,各包含一半扇区。将每条灰色磁道对外宣称为四条,每条包含四分之一扇区。
这样一来,我们操作磁盘时只需按照 CHS 模型来传参,不用考虑它的物理构造。
LBA寻址
不管是 磁头 、磁道 还是 扇区 ,都只是机械磁盘的概念。因此,就算固态存储技术没有这些概念,也只能将自己伪装成磁盘,提供 CHS 寻址模型。如果能够采用线性寻址模型,由序号来定位扇区,磁盘访问便大大简化。
逻辑块寻址( logical block addressing )提供通过线性序号来访问磁盘数据的机制,将三维 CHS 坐标映射到一个简单的整数。这样一来,我们只需要通过简单的整数地址来访问磁盘扇区,完全不用关心磁头和磁道等内部结构。
LBA 地址跟 CHS 坐标的映射关系很简单,按顺序遍历每个 CHS 坐标,然后依次分配序号即可。以上图的迷你磁盘为例:
LBA地址 | CHS坐标 | 磁道 | 磁头 | 扇区 |
---|---|---|---|---|
0 | (0, 0, 1) | 0 | 0 | 1 |
1 | (0, 0, 2) | 0 | 0 | 2 |
2 | (0, 0, 3) | 0 | 0 | 3 |
7 | (0, 0, 8) | 0 | 0 | 8 |
8 | (0, 1, 1) | 0 | 1 | 1 |
40 | (0, 5, 1) | 0 | 5 | 1 |
47 | (0, 5, 8) | 0 | 5 | 8 |
48 | (1, 0, 1) | 1 | 0 | 1 |
96 | (2, 0, 1) | 2 | 0 | 1 |
240 | (5, 0, 1) | 5 | 0 | 1 |
280 | (5, 5, 1) | 5 | 5 | 1 |
287 | (5, 5, 8) | 5 | 5 | 8 |
如上表,迷你磁盘总共有 288 个扇区,对应 288 个坐标,被映射为一个从 0 到 287 的整数序号。这个序号通常被称为 逻辑扇区号 ,通过逻辑序号的寻址则称为 逻辑块寻址 ,简称 LBA 寻址。
举个例子,逻辑扇区号 100 表示 CHS 坐标为 2, 0, 5
的扇区,即磁道为 2 ,磁头为 0 ,扇形为 5 的扇区。
CHS 坐标到 LBA 序号的映射关系,实际上还因磁盘大小而异,具体细节这里不再展开。
最佳实践
那么,CHS 和 LBA 这两种寻址技术,应该怎么抉择呢?
实际上,CHS 坐标已经是老到掉牙的技术了,它有很多局限性:
- CHS 坐标使用起来比较繁琐,不如 LBA 直观;
- 磁盘分区表中的 CHS 坐标总共才 24 位,限制了磁盘大小不能超过 $512 \times 2^{24}$ 字节( 8GB );
因此,现代磁盘都采用 LBA 技术来寻址了。尽管如此,由于 磁头 、磁道 和 扇区 的概念在文件系统和磁盘 IO 场景中经常出现,简单了解下还是必要的。
总结
- 磁盘以 扇区 ( sector )为基本存储和读写单位;
- 扇区大小通常是 512 字节;
- 每个扇区依次分配一个线性序号作为地址,通过该地址可以读写扇区数据;
【小菜自制文件系统】系列文章首发于公众号【小菜学编程】,敬请关注: