dm-zoned

dm-zoned 设备映射器目标将分区块设备(符合 ZBC 和 ZAC 标准的设备)公开为常规块设备,不受任何写入模式限制。实际上,它实现了一个驱动器管理的分区块设备,它向用户(文件系统或执行原始块设备访问的应用程序)隐藏了主机管理分区块设备的顺序写入限制,并且可以缓解由于主机感知分区设备上的过度随机写入而导致的潜在设备端性能下降。

有关分区块设备模型及其限制的更详细描述,请参阅(针对 SCSI 设备)

https://www.t10.org/drafts.htm#ZBC_Family

以及(针对 ATA 设备)

http://www.t13.org/Documents/UploadedDocuments/docs2015/di537r05-Zoned_Device_ATA_Command_Set_ZAC.pdf

dm-zoned 实现简单,并最大限度地减少了系统开销(CPU 和内存使用以及存储容量损失)。对于一个拥有 256 MB 区域的 10TB 主机管理磁盘,每个磁盘实例的 dm-zoned 内存使用量最多为 4.5 MB,并且内部将仅使用 5 个区域来存储元数据和执行回收操作。

dm-zoned 目标设备使用 dmzadm 工具进行格式化和检查,该工具可在以下位置获取:

https://github.com/hgst/dm-zoned-tools

算法

dm-zoned 实现了一种磁盘缓冲方案,用于处理对分区块设备的顺序区域的非顺序写入访问。传统区域用于缓存以及存储内部元数据。它还可以将常规块设备与分区块设备一起使用;在这种情况下,常规块设备将在逻辑上被分割成与分区块设备大小相同的区域。这些区域将放置在分区块设备的区域之前,并将像传统区域一样进行处理。

设备(或多个设备)的区域分为 2 种类型

1) 元数据区域:这些是用于存储元数据的传统区域。元数据区域不作为可用容量报告给用户。

2) 数据区域:所有剩余区域,其中绝大多数是专门用于存储用户数据的顺序区域。设备的传统区域也可用于缓冲用户随机写入。这些区域中的数据可以直接映射到传统区域,但随后会移动到顺序区域,以便传统区域可以重复用于缓冲传入的随机写入。

dm-zoned 公开了一个逻辑设备,其扇区大小为 4096 字节,无论所使用的后端分区块设备的物理扇区大小如何。这有助于减少管理有效块(已写入块)所需的元数据量。

磁盘上的元数据格式如下

1) 找到的第一个传统区域的第一个块包含超级块,该超级块描述了磁盘上元数据块的数量和位置。

2) 在超级块之后,一组块用于描述逻辑设备块的映射。映射按块的块(chunk)进行,块大小等于分区块设备大小。映射表按块编号索引,每个映射条目指示存储数据块的设备的区域编号。每个映射条目还可以指示用于缓冲对数据区域的随机修改的传统区域的区域编号。

3) 在映射表之后,有一组块用于存储位图,指示数据区域中块的有效性。有效块定义为已写入且未丢弃的块。对于缓冲数据块,块仅在映射该块的数据区域或该块的缓冲区区域中始终有效。

对于映射到传统区域的逻辑块,所有写入操作都通过直接写入该区域来处理。如果映射区域是顺序区域,则仅当逻辑块内的写入偏移量等于顺序数据区域内的写入指针偏移量(即写入操作与区域写入指针对齐)时,才直接处理写入操作。否则,写入操作将使用缓冲区区域间接处理。在这种情况下,分配一个未使用的传统区域并将其分配给正在访问的块。将块写入块的缓冲区区域将自动使映射该块的顺序区域中的相同块无效。如果顺序区域的所有块都变得无效,则该区域将被释放,并且块缓冲区区域将成为映射该块的主区域,从而实现类似于常规块设备的本地随机写入性能。

读取操作根据位图提供的块有效性信息进行处理。有效块从映射块的顺序区域读取,或者如果块被缓冲,则从分配的缓冲区区域读取。如果访问的块没有映射,或者访问的块无效,则读取缓冲区将被清零,并且读取操作终止。

一段时间后,可用传统区域的有限数量可能会耗尽(全部用于映射块或缓冲顺序区域),并且对未缓冲块的非对齐写入变得不可能。为避免这种情况,回收过程定期扫描已使用的传统区域,并尝试通过将缓冲区区域的有效块复制到空闲顺序区域来回收最近最少使用的区域。复制完成后,块映射将更新以指向顺序区域,并且缓冲区区域被释放以供重用。

元数据保护

为了防止在突然断电或系统崩溃时元数据损坏,使用了两组元数据区域。其中一组(主集)用作主要的元数据区域,而次级集用作暂存区。修改后的元数据首先写入次级集,并通过更新次级集中的超级块进行验证,一个代计数器用于指示此集包含最新的元数据。此操作完成后,可以在主元数据集中进行元数据块的原地更新。这确保了其中一组始终保持一致(所有修改都已提交或都未提交)。刷新操作用作提交点。收到刷新请求后,元数据修改活动将暂时阻塞(包括传入的 BIO 处理和回收过程),并且所有脏元数据块都将暂存并更新。然后恢复正常操作。因此,刷新元数据只会暂时延迟写入和丢弃请求。在执行元数据刷新时,读取请求可以并发处理。

如果常规设备与分区块设备结合使用,则第三组元数据(不包含区域位图)将写入分区块设备的开头。此元数据具有一个“0”的代计数器,在正常操作期间永远不会更新;它仅用于识别目的。元数据的第一份和第二份副本位于常规块设备的开头。

用法

分区块设备必须首先使用 dmzadm 工具进行格式化。这将分析设备区域配置,确定元数据集在设备上的放置位置,并初始化元数据集。

示例

dmzadm --format /dev/sdxx

如果使用两个驱动器,则必须指定这两个设备,其中常规块设备作为第一个设备。

示例

dmzadm --format /dev/sdxx /dev/sdyy

格式化后的设备也可以使用 dmzadm 工具启动。

示例

dmzadm --start /dev/sdxx /dev/sdyy

可以使用 dmsetup 的“status”回调获取有关区域内部布局和当前使用情况的信息

示例

dmsetup status /dev/dm-X

将返回一行

0 <size> zoned <nr_zones> zones <nr_unmap_rnd>/<nr_rnd> random <nr_unmap_seq>/<nr_seq> sequential

其中 <nr_zones> 是区域总数,<nr_unmap_rnd> 是未映射(即空闲)随机区域的数量,<nr_rnd> 是随机区域的总数,<nr_unmap_seq> 是未映射顺序区域的数量,<nr_seq> 是顺序区域的总数。

通常,一旦空闲随机区域少于 50%,回收过程就会启动。为了在此阈值之前手动启动回收过程,可以使用“dmsetup message”功能

示例

dmsetup message /dev/dm-X 0 reclaim

将启动回收过程,并将随机区域移动到顺序区域。