上一小节,我们学习了磁盘的内部结构,掌握了磁头、磁道、扇区等概念。
现代磁盘以扇区为基本存储和读写单位,采用 LBA 线性寻址机制,每个扇区都有一个线性序号作为地址。因此,磁盘可以简单看作是一个由一系列扇区组成的存储阵列。
我们知道,磁盘是支持分区的,分区可大可小。那么,磁盘分区是怎么实现的呢?一个分区都包含哪些扇区,又是怎么决定的呢?哪些 Linux 命令可以用来对磁盘进行分区呢?本文带领大家一探究竟!
磁盘分区原理
按照惯例,每块磁盘的首个扇区保存着一个特殊的 主引导记录( master boot record ),内容由 3 部分组成:
- 引导代码区 ,保存可以直接被 CPU 执行的代码指令,用于启动引导,总共 446 字节;
- 磁盘分区表 ,保存磁盘的分区信息,共 4 条记录,每条 16 字节,共 64 字节;
- 有效标志 ,占 2 个字节,通常为
0x55
和 0xaa
,表示主引导记录有效;
主分区
磁盘分区表有 4 条记录,这意味着一个磁盘可以被划分为 4 个分区,这就是所谓的 主分区( main partition )。
每条分区记录保存一个分区的基本信息,相关字段依次是:
- 分区状态 ,占 1 字节;
- 起始扇区CHS坐标 ,占 3 字节,现已弃用;
- 分区类型 ,占 1 字节;
- 结束扇区CHS坐标 ,占 3 字节,现已弃用;
- 起始扇区号 ,即该分区在磁盘中的起始位置,占 4 字节;
- 总扇区数 ,即该分区的大小,占 4 字节;
换句话讲,组成磁盘分区的扇区是连续的,起始扇区号 记录起始位置,总扇区数 记录扇区个数。
以上图为例,根据分区表我们知道磁盘被划分为 4 个分区。其中,第一个分区的起始扇区为 2048 ,包含 2097152 个扇区,见磁盘绿色区域。因此,该分区总容量为 $512 \times 2097152$ 字节,也就是 1GB 。
扩展分区
由于 MBR 分区表只有 4 个条目,意味着一个磁盘最多只能划分为 4 个主分区,这肯定有不够用的时候。
如果想将磁盘划分为更多分区,可以将主分区标记为 扩展分区( extended partition ),再将它进一步划分为若干 逻辑分区( logical partition )。
这又是怎么实现的呢?答案是—— 扩展启动记录( extended boot record ),简称 EBR 。
分区类型如果被设置为 0x05
表示这个分区是一个扩展分区,分区的首个扇区会保存一条扩展启动记录。这个记录的字段结构跟主引导记录类似,也包含一个分区表,进一步将扩展分区划分为逻辑分区。
扩展分区表结构跟主分区表一样,同样是 4 条,只是用法稍有不同。扩展分区表通常只用前 2 条,一条描述当前逻辑分区的信息,另一条则指明下一个逻辑分区 EBR 记录的位置。
如上图,这是一个扩展分区,它作为整体由 MBR 中的分区表描述,但又通过 EBR 分为 4 个逻辑分区。扩展分区的首个扇区保存 EBR 记录,EBR 分区表第一项描述第一个逻辑分区,另一项描述下一个分区。
因此,扩展分区中的每个逻辑分区前面都有一个 EBR 记录,它可以看作一个链表节点。通过一个 EBR 节点,我们可以找到对应的逻辑分区,以及下一个 EBR 节点。因此,逻辑分区个数没有数量限制,可以按照需要任意划分。
- 主引导记录分区表先将磁盘分为 主分区 ,最多 4 个;
- 主分区 可以被标注为 扩展分区 ;
- 扩展引导记录进一步将 扩展分区 划分为 逻辑分区 ,个数不限;
Linux分区操作
那么,用什么工具来给磁盘分区呢?接下来,以 Linux 系统为例,讲解磁盘分区的基本操作。
块设备文件
在 Linux 系统,每个磁盘都有一个 设备文件( device file)与之对应,位于 /dev 目录下。设备文件可分为两种: 字符设备( char device )和 块设备( block device )。磁盘为块设备,其设备文件名通常为 sda
、sdb
等。
我有一台 VirtualBox 虚拟机,给它加了一块额外的虚拟硬盘,启动后就可以看到它的设备文件:
1
2
|
$ ls /dev/sd*
/dev/sda /dev/sda1 /dev/sda2 /dev/sdb
|
sda 和 sdb 分别是系统的第一和第二块磁盘,第一块是原来就有的,第二块是我后来加的。
查看分区信息
Linux 系统一般执行 fdisk 来操作磁盘分区,通过设备文件来指定要操作的硬盘。第一块磁盘为系统盘,装系统时已经做好分区,我们执行 fdisk 来查看分区信息:
1
2
3
4
5
6
7
8
9
10
11
12
|
$ sudo fdisk -l /dev/sda
Disk /dev/sda: 10 GiB, 10737418240 bytes, 20971520 sectors
Disk model: VBOX HARDDISK
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 3F3307E6-C4C2-4B3C-86D7-F838A037E7D6
Device Start End Sectors Size Type
/dev/sda1 2048 4095 2048 1M BIOS boot
/dev/sda2 4096 20969471 20965376 10G Linux filesystem
|
fdisk 通过设备文件 /dev/sda 来读写磁盘,因此需要超级用户权限。
可以看到,第一块磁盘分为两个分区,第一个大小为 1MB ,BIOS 引导时用的;第二个大小是 10GB ,也就是安装这个 Linux 系统的分区。注意到,每个分区也都有个设备文件与之对应,名字为磁盘设备名加上序号,依次是 sda1 和 sda2 。
调整分区
那么,怎么调整磁盘的分区呢?我们以 sdb 为例,讲解如何给新磁盘分区。
首先,执行 fdisk 命令并指定磁盘的设备文件(不加 -l
选项),进入交互界面:
1
2
3
4
5
6
7
8
9
10
|
fasion@u2004 [ ~ ] ➜ sudo fdisk /dev/sdb
Welcome to fdisk (util-linux 2.34).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0xd8ea500a.
Command (m for help):
|
进入交互界面后,可以执行很多子命令。其中,子命令 m
可以查看帮助,敲入 m
并按回车:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
Command (m for help): m
Help:
DOS (MBR)
a toggle a bootable flag
b edit nested BSD disklabel
c toggle the dos compatibility flag
Generic
d delete a partition
F list free unpartitioned space
l list known partition types
n add a new partition
p print the partition table
t change a partition type
v verify the partition table
i print information about a partition
Misc
m print this menu
u change display/entry units
x extra functionality (experts only)
Script
I load disk layout from sfdisk script file
O dump disk layout to sfdisk script file
Save & Exit
w write table to disk and exit
q quit without saving changes
Create a new label
g create a new empty GPT partition table
G create a new empty SGI (IRIX) partition table
o create a new empty DOS partition table
s create a new empty Sun partition table
|
查看分区信息
子命令 p 可以查看磁盘当前分区信息,新磁盘 sdb 上还没有任何分区:
1
2
3
4
5
6
7
8
|
Command (m for help): p
Disk /dev/sdb: 5 GiB, 5368709120 bytes, 10485760 sectors
Disk model: VBOX HARDDISK
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xd8ea500a
|
新建空分区表
先执行子命令 o
创建一个空的分区表( MBR ):
1
2
|
Command (m for help): o
Created a new DOS disklabel with disk identifier 0xd2a1c801.
|
创建主分区
执行子命令 n
可以添加一个新分区,我们先添加一个大小为 1GB 的主分区:
1
2
3
4
5
6
7
8
9
10
11
12
|
Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p):
Using default response p.
Partition number (1-4, default 1):
First sector (2048-10485759, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-10485759, default 10485759): +1G
Created a new partition 1 of type 'Linux' and of size 1 GiB.
|
创建逻辑分区
现在尝试建一个 2G 的扩展分区,分区类型为 e
表示扩展分区 :
1
2
3
4
5
6
7
8
9
10
|
Command (m for help): n
Partition type
p primary (1 primary, 0 extended, 3 free)
e extended (container for logical partitions)
Select (default p): e
Partition number (2-4, default 2):
First sector (2099200-10485759, default 2099200):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2099200-10485759, default 10485759): +2G
Created a new partition 2 of type 'Extended' and of size 2 GiB.
|
然后再将其分为两个 1G 的逻辑分区,分区类型选 l
表示逻辑分区:
1
2
3
4
5
6
7
8
9
10
11
|
Command (m for help): n
Partition type
p primary (1 primary, 1 extended, 2 free)
l logical (numbered from 5)
Select (default p): l
Adding logical partition 5
First sector (2101248-6293503, default 2101248):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2101248-6293503, default 6293503): +1G
Created a new partition 5 of type 'Linux' and of size 1 GiB.
|
重复这个操作可以将扩展分区中的剩余空间建成另一个 1G 的逻辑分区:
1
2
3
4
5
6
7
8
9
10
11
|
Command (m for help): n
Partition type
p primary (1 primary, 1 extended, 2 free)
l logical (numbered from 5)
Select (default p): l
Adding logical partition 6
First sector (4200448-6293503, default 4200448):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (4200448-6293503, default 6293503):
Created a new partition 6 of type 'Linux' and of size 1022 MiB.
|
现在查看分区表可以看到我们建好的扩展分区,序号为 2 ;以及它包含的 2 个逻辑分区,序号分别是 5 和 6 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
Command (m for help): p
Disk /dev/sdb: 5 GiB, 5368709120 bytes, 10485760 sectors
Disk model: VBOX HARDDISK
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x7487e2a0
Device Boot Start End Sectors Size Id Type
/dev/sdb1 2048 2099199 2097152 1G 83 Linux
/dev/sdb2 2099200 6293503 4194304 2G 5 Extended
/dev/sdb5 2101248 4198399 2097152 1G 83 Linux
/dev/sdb6 4200448 6293503 2093056 1022M 83 Linux
|
小结
- 一个磁盘最多可以划分为 4 个主分区,由主引导记录分区表决定;
- 主分区可以设为扩展分区,再分为若干逻辑分区,由扩展引导记录实现;
- Linux 下每个磁盘都有一个设备文件与之对应,例如 sda 和 sdb 等;
- 磁盘的每个分区也都有一个设备文件与之对应,为磁盘设备文件名加上序号,例如 sdb1 和 sdb2 等;
- 通过设备文件可以直接读写一个磁盘,或者一个磁盘分区的扇区;
【小菜自制文件系统】系列文章首发于公众号【小菜学编程】,敬请关注: