治肾虚不含糖,专注内核性能优化二十年。 https://github.com/KnightKu
分类:
2018-08-28 15:29:07
原文地址:ZFS磁盘格式(4) 作者:qincp-
DSL(数据集和快照层)提供了描述和管理对象集之间关系的机制。开始描述DSL和对象集关系之前,简单回顾一下各种对象集。
对象集回顾
ZFS提供创建四类对象集的能力:文件系统,克隆,快照,卷
ZFS文件系统:文件系统以一种易于访问,POSIX兼容方式存储和组织对象。
ZFS克隆:除来源外,克隆和文件系统相同。克隆源于快照,其初始内容和所基于的快照相同。
ZFS快照:快照是文件系统,克隆,或者卷在某个时刻的只读版本。
ZFS卷:逻辑卷对外表现为一个块设备。
ZFS支持的一些操作以及配置可能引起对象集之间的相互依赖。DSL的目的就是管理这些关系。下面列出这类关系:
克隆:克隆和其所基于的快照相关。一旦克隆被创建,其所基于的快照不能被删除。直到该快照上的所有克隆被删除后,快照才能被删除。
快照:快照是一个对象集在某个时刻的数据映像。除非其上的快照删除,否则文件系统,克隆或者卷不能被删除。
孩子:ZFS支持按继承方式组织对象集;对象集中可以包含其他对象集。孩子依赖于父亲的存在。必须要首先销毁所有孩子对象集,父对象集才能被销毁。
在DSL中,每个对象集由一个数据集(dataset)表示。数据集管理对象集的空间开销统计,包含对象集位置信息,跟踪快照的依赖关系。
数据集目录按层次关系对数据集进行组织。数据集目录管理相关的一组对象集以及该对象集组的属性。DSL目录始终有且只有一个“激活的数据集”,目录下所有其他数据集通过快照,克隆,或者父/子关系和这个激活数据集相关。
下图显示了DSL结构中,对象集关系如何通过DSL数据集和DSL目录来描述。图最顶层的正中是最上层的DSL目录,在目录下一层是“激活的数据集”,激活数据集表示当前文件系统。从激活数据集上,有个不同时间生成的快照链表。每个数据集结构指向一个DMU对象集,对象的数据就放在这里面。图顶层的左侧是一个子ZAP对象,包含了所有父子依赖关系。DSL目录右侧是ZAP属性,包含DSL目录中的数据集的属性。所有的属性在下面表12中列出。
数据集和DSL目录在随后的“数据集和DSL目录内部”一节进行详细描述。
图13 DSL基础架构
实现上,DSL是一个类型为DMU_OST_META的对象集。这个对象集通常称为元数据对象集,MOS。一个pool只有一个MOS,超级块uberblock直接指向它。
MOS中有一个独特的对象——对象目录,它始终位于dnode数组的第二个元素(下标1)。除对象目录外的所有对象,都可以从对象目录开始,通过一系列的对象引用关系进行定位。
对象目录
对象目录是一个ZAP对象(ZAP是包含name/value对的一个对象,参见第五章),包含三个属性对,分别为root_dataset,config,sync_bplist。
Root_dataset:该属性包含一个64位整数值,表示该pool的根DSL目录对象编号。根DSL目录是一个特殊的对象,其中包含了对pool中所有顶层数据集的引用。根数据集目录类型为DMU_OT_DSL_DIR,后面4.4节 “DSL目录”中对此进行更为详细的讨论。
Config:该属性包含一个64位整数值,表示该对象的对象编号,对象的类型为DMU_OT_PACKED_NVLIST,包含一个XDR_ENCODED类型的名称/值对,描述这个pool的vdev配置。内容类似于
Sync_bplist:该属性包含一个64位整数值,表示该对象的对象编号,对象类型为DMU_OT_SYNC_BPLIST,这个对象包含了下一个事务需要被释放的块指针链表。
下图显示了MOS和uberblock以及标签结构的关系。
图14 元数据对象集
数据集存在类型为DMU_OT_DSL_DATASET的对象中。对象类型使用了dnode_phy_t中的bonus缓存存储一个dsl_dataset_phys_t结构。dsl_dataset_phys_t中的内容如下:
uint64_t ds_dir_obj:引用该数据集的DSL目录的对象编号。
uint64_t ds_prev_snap_obj:如果数据集代表一个文件系统,卷,或者克隆,这个域包含了表示最近的快照的对象编号。如果数据集代表一个快照,这个域包含了该快照之前的一个快照的对象编号,如果之前没有快照,这个域为0。
uint64_t ds_prev_snap_txg:前一个快照(由ds_prev_snap_obj表示)生成时的事务组编号。
uint64_t ds_next_snap_obj:该域仅用于数据集代表一个快照时。它包含最近快照的数据集的对象编号。对于克隆,卷或者文件系统,这个域始终是0。
uint64_t ds_snapnames_zapobj:数据集中的每个快照都有包含name/value对的ZAP对象,该域保存ZAP对象的对象编号。每一name/value对包含快照名和它的DSL数据集结构集的对象编号。
uint64_t ds_num_children:如果不是快照,该域始终为0。对于快照而言,这是快照的引用计数:1+基于该快照的克隆数目。
uint64_t ds_creation_time:数据集创建时间,从
uint64_t ds_creation_txg:该数据集创建时的事务组编号
uint64_t ds_deadlist_obj:deadlist的对象编号(deadlist是自从上次快照生成后删除的blkptr指针数组)
uint64_t ds_used_bytes:仅供数据集代表的对象集所使用的字节数。
uint64_t ds_compressed_bytes:数据集代表的对象集中的压缩字节数。
uint64_t ds_uncompressed_bytes:数据集代表的对象集中的未压缩字节数。
uint64_t ds_unique_bytes:当快照生成时,其初始内容就是当前激活数据的一个拷贝。在激活数据发生变化时,其中的越来越多的数据会和快照中的数据不同,因此供快照单独使用的数据的数目会递增。这个域存储的就是这个数目。对于克隆,卷,文件系统而言,它的值为0。
uint64_t ds_fsid_guid: 64位唯一值,标识当前打开的数据集中的一个。需要注意的是,在后续数据集打开时,这个ID可能发生变化。
uint64_t ds_guid:数据集的64位全局标识。在对象集的生命周期中这个值不发生变化。
uint64_t ds_restoring:如果ZFS正在向这个数据集恢复数据,该域设置为1。
blkptr_t ds_bp: 指向该数据集代表的对象集的位置的块指针
DSL目录对象在其bonus缓存中包含一个dsl_dir_phys_t结构。该结构的内容详细描述如下:
uint64_t dd_creation_time:DSL目录创建时间,从
uint64_t dd_head_dataset_obj: 激活数据集对象的对象编号。
uint64_t dd_parent_obj:父DSL目录的对象编号。
uint64_t dd_clone_parent_obj: 对于克隆的对象集,该域包含用于创建克隆的快照的对象编号。
uint64_t dd_child_dir_zapobj:包含该DSL目录下每个孩子的Name/value对的ZAP对象的对象编号。
uint64_t dd_used_bytes: 该目录下所有数据集所使用的字节,包括所有快照和子数据集所使用的字节。
uint64_t dd_compressed_bytes: 该DSL目录下所有数据集的压缩字节数。
uint64_t dd_uncompressed_bytes:DSL目录下所有数据集的非压缩字节数。
uint64_t dd_quota:设计配额,该DSL目录下的数据集允许使用的最大字节数。
uint64_t dd_reserved:为该DSL目录下的数据集预留的空间大小。
uint64_t dd_props_zapobj:包含该DSL目录下每个孩子的属性的ZAP对象的对象编号。如果没有某个属性的话,缺省情况下通过继承获得。
下表列出有效的属性:
表12 dd_props_zapobj中保存的属性值
属性 |
描述 |
值 |
Aclinherit |
控制数据集的继承行为 |
discard = 0 noallow = 1 passthrough = 3 secure = 4 (default) |
Aclmode |
控制数据集的chmod和文件/目录创建的行为 |
discard = 0 groupmask = 2 (default) passthrough = 3 |
Atime |
控制数据集上的对象的atime是否被更新 |
off = 0 on = 1 (default) |
checksum |
DSL目录中所有数据集的效验和算法 |
on = 1 (default) off = 0 |
compression |
DSL目录中所有数据集的压缩算法 |
on = 1 off = 0 (default) |
Devices |
控制数据集上的设备节点是否可以被打开 |
devices = 0 nodevices = 1 (default) |
Exec |
控制数据集上的文件是否可以被执行 |
exec = 1 (default) noexec = 0 |
Mountpoint |
DSL目录中的数据集的挂载点路径 |
string |
Quota |
DSL目录中所有的数据集可以使用的空间上限 |
缺省为0,无配额限制 不为0则表示配额数 |
Readonly |
数据集上的对象是否可以被修改 |
只读,1 |
Recordsize |
该DSL目录下包含的数据集上的所有对象的块大小 |
字节数 |
Reservation |
为DSL目录保留的空间大小,包括所有子数据集和子DSL目录 |
字节数 |
Setuid |
控制数据集上的set-UID比特是否被使用 |
Setuid=1(缺省) Nosetuid=0 |
Sharenfs |
DSL目录下的数据集是否通过NFS进行共享 |
String——任何有效的nfs共享选项 |
Volblocksize |
卷的块尺寸。只能在卷创建时被设置一旦卷被写入,该尺寸不能被改变 |
512到128k之间,以2的幂次表示。 缺省为8K |
Volsize |
卷大小,仅用于卷对象 |
卷大小的字节数 |
Zoned |
数据集是否被一个本地zone所管理 |
On=1 Off=0(缺省) |