最近针对文件系统问题,复盘了下硬盘结构,在此记录
扇区sector
磁盘由多个扇区组成,每个扇区大小为512 bytes(0~0x1FF)(现代硬盘也有可能使用4K扇区);扇区是物理结构层次的概念。
分区Partition
硬盘结构中的分区,也是物理结构概念,如MBR硬盘最多支持四个分区,分区会格式化为当前OS可识别的文件系统,其文件系统格式可以为FAT32, NTFS等等,而FAT32的分区会自动挂载simple file system protocol;每个分区可以理解为一个Block
块Block
为了提高数据读取速度,操作系统引入了块(block)的概念,即文件系统操作的最小单元,一个块可能由多个扇区组成;block是逻辑结构层次的概念
LBA -Logical Block Address 逻辑区块地址
磁盘上逻辑结构寻址的一种方法,可以理解为一个LBA等同于物理层次的一个扇区,读取块设备需要知道blk起始LBA,即分区起始扇区号。MBR分区LBA是32bit,GPT分区是64bit
实例看到一个GPT硬盘有4个patition,对应5个block,多出来一个block应该是首个扇区开始的一块block,shell下用dblk指令查看blk0,对应数据为第一个扇区保护性MBR内容
MBR硬盘
传统硬盘的一种分区,全称是主引导记录(Master Boot Record),是硬盘的首个扇区(LBA0),用于存放启动代码和分区表,MBR分区没有提供分区表备份机制
GPT(GUID Partition table)硬盘结构
UEFI系统主要硬盘结构,仍然将硬盘划分为扇区,扇区地址从0开始编号。
GPT弥补MBR不足,如能支持更多分区,有备份分区表,分区表有CRC32校验,GPT每个分区都有一个唯一GUID。其结构如下
LBA0是保护性MBR,用来兼容MBR硬盘;LBA1是GPT头,描述硬盘结构;LBA2开始是GPT分区表,如果扇区大小是512bytes,那么“First Usable LBA” 必须大于等于34,也就是GPT分区表占32个LBA;如果扇区大小是4096bytes,那么“First Usable LBA” 必须大于等于6,也就是GPT分区表占4个LBA;“First Usable LBA”开始则为每个分区结构;硬盘结尾的分区用作备份分区表和GPT头。
PMBR-保护性MBR
格式与MBR硬盘的0号扇区格式相同,各个域可能有不同,大部分区域都为0,partition Record第一个分区表必须参照如下定义,其他三个都为0;
partition Record第一个分区表定义如下,bootIndicator为0,OSType为0xEE,StartingLBA为1
GPT头(Header)
硬盘的1号扇区,存储了硬盘的结构信息,其数据结构如下
typedef struct {
EFI_TABLE_HEADER Header;
EFI_LBA MyLBA;
EFI_LBA AlternateLBA;
EFI_LBA FirstUsableLBA;
EFI_LBA LastUsableLBA;
EFI_GUID DiskGUID;
EFI_LBA PartitionEntryLBA;
UINT32 NumberOfPartitionEntries;
UINT32 SizeOfPartitionEntry;
} EFI_PARTITION_TABLE_HEADER;
Header | 包括EFIPART标志,Revision,GPT头字节数,表头CRC32校验码等,一共24bytes |
MyLBA | GPT头所在LBA,64bits |
AlternateLBA | 备份GPT头的LBA,64bits |
FirstUsableLBA | 可用于分区的第一个LBA,64bits,下图读到为0x22-》34 |
LastUsableLBA | 可用于分区的最后一个LBA,64bits |
DiskGUID | 硬盘GUID,16 bytes |
PartitionEntryLBA | 分区表所在LBA,64bits |
NumberOfPartitionEntries | 分区表项数目 32bits |
SizeOfPartitionEntry | 每个分区表项字节数 32bits |
GPT分区表
表头的PartitionEntryLBA 指明了分区表的LBA地址,如02;NumberOfPartitionEntries为0x80表明分区表项有128个;SizeOfPartitionEntry为0x80表示每个分区表项大小为128bytes。每个分区表项数据结构如下
typedef struct {
EFI_GUID PartitionTypeGUID;
EFI_GUID UniquePartitionGUID;
EFI_LBA StartingLBA;
EFI_LBA EndingLBA;
UINT64 Attributes;
CHAR16 PartitionName[36];
} EFI_PARTITION_ENTRY;
PartitionTypeGUID | 代表PartitionType的GUID,参考Note2; 0表示不使用;16bytes |
UniquePartitionGUID | 分区表唯一标志;16bytes |
StartingLBA | 这个分区表定义的partition首扇区;64bits |
EndingLBA | 这个分区表定义的partition结束扇区;64bits |
Attributes | 参考Note3;64bits |
PartitionName | 以Null结尾的字符串名称 |
Note2
Note3