治肾虚不含糖,专注内核性能优化二十年。 https://github.com/KnightKu
分类:
2018-08-28 15:28:49
原文地址:ZFS磁盘格式(2) 作者:qincp-
数据在磁盘和主存之间以块为单位进行传送。块指针blkptr_t是一个128字节大小的ZFS结构,用于对磁盘上数据块进行定位,验证和描述。
128字节的Blkptr_t结构如下图:
图8 块指针结构
块指针中的Vdev和offset字段部分构成了数据虚地址,例如vdev1和offset1组成DVA1。ZFS的块指针提供了指向三份数据的重复拷贝的能力,每一份拷贝由单独一个DVA指向。每个块指针中使用几个DVA是文件系统的实际策略,称为块指针的宽度:单宽块指针,双宽块指针,三宽块指针。
每个DVA的vdev部分是32位整数,唯一描述该数据块所在的vdevid;offset部分是63位整数,包含数据在所在设备上的偏移(从boot 块之后开始计算)。二者合在一起,唯一表示了数据的物理位置。
Offset的值以扇区为单位(512字节)。物理块以字节为单位的偏移需要进行左移位(移9位)并加上0x400000(L0+L1+boot)。
physical block address = (offset << 9) + 0x400000 (4MB)
Raid-Z布局信息,留作将来使用。
包含块指针的块叫做GANG块,在请求的空间无法在连续块中申请时,此时需要申请一些不连续的更小的块,此时需要创建一个gang块对这些块进行维护,将指向gang块的指针返回给请求者,请求者看到的是一个单独的(gang)块。
Gang块由“G”位标志。
表4 gang块标志
“G”位 |
描述 |
0 |
非gang块 |
1 |
Gang块 |
Gang块为512字节,有自己的效验和。Gang块包含最多3个块指针加上32字节的效验和。Gang块的格式描述如下。
typedef struct zio_gbh {
blkptr_t zg_blkptr[SPA_GBH_NBLKPTRS];
uint64_t zg_filler[SPA_GBH_FILLER];
zio_block_tail_t zg_tail.;
} zio_gbh_phys_t;
zg_blkptr: 块指针数组,最多可以有三个块指针
zg_filler: 填充
typedef struct zio_block_tail {
uint64_t zbt_magic;
zio_cksum_t zbt_cksum;
}
zbt_magic: ZIO块尾魔数,0x210da7ab
typedef zio_cksum {
uint64_t zc_word[4];
}zio_cksum_t;
zc_word: 四个8字节整数包含gang块的效验和
ZFS缺省对所有数据和元数据进行效验。ZFS支持多种效验和算法,包括fletcher2,fltecher4以及SHA-256。用于该块的效验和算法由块指针的8位整数cksum标识。下标对这些取值给出说明。
表5 cksum取值和对应算法
描述 |
值 |
算法 |
on |
1 |
fletcher2 |
off |
2 |
none |
label |
3 |
SHA-256 |
gang |
4 |
SHA-256 |
zilog |
5 |
fletcher2 |
fletcher2 |
6 |
fletcher2 |
fletcher4 |
7 |
fletcher4 |
SHA-256 |
8 |
SHA-256 |
使用cksum规定的算法,每一块计算出256位效验和,放入checksum[0], checksum[1], hecksum[2], 和checksum[3]中;如果cksum是2,则不进行效验和计算,此时checksum[0], checksum[1], hecksum[2], 和checksum[3]为0。
注意,计算的效验和都是针对数据进行的,gang块和zilog块都是自带效验和的。
ZFS支持多种压缩算法,块使用的压缩算法在块指针的comp中指示,如下表
表6 压缩算法
描述 |
值 |
算法 |
on |
1 |
lzjb |
off |
2 |
none |
lzjb |
3 |
lzjb |
在块指针中,有三个不同域描述块尺寸:psize,lsize,asize。
Lsize:逻辑尺寸,未压缩的数据大小,不包括gang,raidz开销。
Psize:压缩后的数据的物理尺寸
asize:申请尺寸,保存该数据申请的所有块的总尺寸,包括gang和raidz信息。
如果压缩被关闭,并且ZFS不使用raidZ存储,则lsize,asize,psize三者相同。
所有尺寸的取值按512字节的扇区为单位。
ZFS的字节序可以设置(第一章对此有限制除外),允许将pool在不同架构的机器间移动。块指针的“E”指示写块时的字节序。块总是按照机器的字节序写入。
表7 字节序
字节序 |
值 |
小尾 |
1 |
大尾 |
0 |
如果pool被移动到另外不同字节序的机器下,块内容在读的时候需要做字节转换。
块指针的type指示块中存储的数据类型。下表列出各种类型。
表8 对象类型
类型 |
值 |
DMU_OT_NONE |
0 |
DMU_OT_OBJECT_DIRECTORY |
1 |
DMU_OT_OBJECT_ARRAY |
2 |
DMU_OT_PACKED_NVLIST |
3 |
DMU_OT_NVLIST_SIZE |
4 |
DMU_OT_BPLIST |
5 |
DMU_OT_BPLIST_HDR |
6 |
DMU_OT_SPACE_MAP_HEADER |
7 |
DMU_OT_SPACE_MAP |
8 |
DMU_OT_INTENT_LOG |
9 |
DMU_OT_DNODE |
10 |
DMU_OT_OBJSET |
11 |
DMU_OT_DSL_DATASET |
12 |
DMU_OT_DSL_DATASET_CHILD_MAP |
13 |
DMU_OT_OBJSET_SNAP_MAP |
14 |
DMU_OT_DSL_PROPS |
15 |
DMU_OT_DSL_OBJSET |
16 |
DMU_OT_ZNODE |
17 |
DMU_OT_ACL |
18 |
DMU_OT_PLAIN_FILE_CONTENTS |
19 |
DMU_OT_DIRECTORY_CONTENTS |
20 |
DMU_OT_MASTER_NODE |
21 |
DMU_OT_DELETE_QUEUE |
22 |
DMU_OT_ZVOL |
23 |
DMU_OT_ZVOL_PROP |
24 |
块指针的level是块指针寻址到数据块需要经历的层数。第三章对层进行了更为完整的定义。
该块指针下子树中非零块指针的数量。对于数据块的块指针,fill为1,因为其下面已没有其他块指针了。
Fill在DMU_OT_DNODE类型的块指针中用法稍有不同,该值是指块指针下包含的空闲dnode数量,参见第三章。
申请该块指针是的事务组编号。
填充字段。