ZFS文件系统

来源:互联网 发布:网站排名优化工具 编辑:程序博客网 时间:2024/05/06 13:09

 

ZFS (Zettabyte File System)源自于Sun Microsystems为Solaris操作系统开发的文件系统。ZFS是一个具有高存储容量、文件系统与卷管理概念整合、崭新的磁盘逻辑结构的轻量级文件系统,同时也是一个便捷的存储池管理系统。ZFS是一个使用Common Development and Distribution License (CDDL)协议条款授权的开源项目。 
ZFS可提供简单管理、事务性语义、端对端数据完整性以及极好的可伸缩性。ZFS 并不是在现有技术的基础上逐步改进而得到的,它是一种全新的数据管理方法。我们摒弃了 20 年来的传统观念,大大降低了源代码的复杂性,创建了一种真正易于使用的存储系统。 
ZFS 提供了池存储模型,完全淘汰了卷的概念,并避免了与分区、置备、带宽浪费和分散存储相关的问题。数千个文件系统可以利用同一个公用存储池,每个文件系统只占用实际所需的空间量。存储池中所有设备的 I/O 组合带宽对所有文件系统都始终可用。 
所有操作都是写复制事务,因此盘上状态始终有效。ZFS 文件系统不需要 fsck(1M)。每个块都经过校验和计算,以防止无提示数据损坏,并且数据在复制(镜像或 RAID)配置中可以自我修复。如果其中一个副本损坏,ZFS 会检测到这种情况,并使用另一个副本修复它。 
ZFS 引入了一个新的数据复制模型,称为 RAID-Z。它与 RAID-5 类似,但采用可变条带宽度来消除 RAID-5 写入漏洞(即由于数据和奇偶校验更新之间出现意外断电而导致条带损坏)。所有 RAID-Z 写操作都是完整条带化写操作。这样,既没有读取-修改-写入开销,也没有写入漏洞,并且最重要的一点是不需要 NVRAM 硬件。ZFS 偏爱廉价磁盘。 
但由于廉价磁盘容易出现故障,因此 ZFS 提供了磁盘清理功能。就像 ECC 内存清理一样,其理念是读取所有数据以检测潜在错误,而这些错误仍是可更正的。清理操作将遍历整个存储池,以读取每个块的每个副本,根据其 256 位校验和对其进行验证,并在必要时进行修复。所有这些操作都是在存储池运行和使用过程中进行的。 
ZFS 有一个管道化 I/O 引擎,它在概念上与 CPU 管道类似。管道作用于 I/O 依赖关系图,并提供记分板、优先级、最终期限调度、失序发射和 I/O 聚合。使用 ZFS I/O 管道,可以轻松处理使其他文件系统濒临崩溃的 I/O 负载。 
ZFS 提供了无限制的常量时间快照和克隆。快照是文件系统的只读即时副本,而克隆是快照的可写副本。克隆提供了一种极其节省空间的方法,可用于存储工作区、软件安装和无盘客户端等主要共享数据的许多副本。 
ZFS 备份和恢复由快照提供支持。任一快照都可生成完全备份,任意一对快照都可生成增量备份。增量备份效率很高,可用于远程复制-例如每 10 秒传送一个增量更新。 
在 ZFS 中没有任何限制。您可以拥有任意多个文件、完整 64 位文件偏移、无限制的链接、目录条目、快照等等。 
ZFS 提供了内置压缩。压缩不但将磁盘空间的使用量降低了 2-3 倍,还将 I/O 量减少了 2-3 倍。因此,启用压缩实际上能够提高某些工作负荷的运行速度。 
除文件系统外,ZFS 存储池可为需要原始设备语义的应用程序提供卷。例如,ZFS 卷可用作交换设备。如果在交换卷上启用压缩,您将立即拥有压缩虚拟内存。 
ZFS 管理既简单又功能强大。有关更多信息,请参见 zpool(1M) 和 zfs(1M) 手册页;并确保阅读了简要介绍的入门部分。 
ZFS 可轻松应对大多数工作负荷-让我们现在就开始吧。

入门 
管理文件系统和卷的一切烦恼都已一扫而光,您不必再执行 format、newfs、mount、edit /etc/vfstab、fsck、growfs、metadb、metainit 等命令了。 
认识一下两个绝佳的新工具:zpool(1M) 和 zfs(1M)。 
ZFS 简单易用,让我们开始吧!先创建第一个存储池: 
# zpool create tank c1t2d0 
现在有了一个名为 tank 的单磁盘存储池,并且在 /tank 下挂载了一个文件系统。不再需要进行其他任何操作。 
如果要对邮件和主目录使用镜像存储,那也很简单: 
创建存储池: 
# zpool create tank mirror c1t2d0 c2t2d0 
创建 /var/mail 文件系统: 
# zfs create tank/mail 
# zfs set mountpoint=/var/mail tank/mail 
创建主目录,并将它们全部挂载到 /export/home/<username> 下: 
# zfs create tank/home 
# zfs set mountpoint=/export/home tank/home 
# zfs create tank/home/ahrens 
# zfs create tank/home/billm 
# zfs create tank/home/bonwick 
# zfs create tank/home/eschrock 
… 
ZFS 文件系统是分层的:每一层继承其上一层的属性。在此示例中,mountpoint 属性是作为路径名前缀继承的。也就是说,tank/home/ahrens 自动挂载在 /export/home/ahrens 下,因为 tank/home 挂载在 /export/home 下。您不必为每个用户分别指定挂载点,只需将所用的模式告知 ZFS 即可。 
这是我们在 zion.eng 中实际设置主目录和邮件服务的方式,zion.eng 运行 ZFS 的时间已有一年半了。 
但请稍等,下面还有更多内容! 
ZFS 提供了内置压缩。要压缩所有主目录: 
# zfs set compression=on tank/home 
要为 ahrens 分配 10G 配额: 
# zfs set quota=10g tank/home/ahrens 
要为 bonwick 分配 100G 预留空间(成员具有其权限): 
# zfs set reservation=100g tank/home/bonwick 
要以 NFS 方式自动导出所有主目录读/写内容: 
# zfs set sharenfs=rw tank/home 
要清理所有磁盘并验证存储池中所有数据的完整性: 
# zpool scrub tank 
要替换有故障的磁盘: 
# zpool replace tank c2t2d0 c4t1d0 
要添加更多空间: 
# zpool add tank mirror c5t1d0 c6t1d0 
要将存储池从 SPARC 机器 ’sparky’ 移动到 AMD 机器 ‘amdy’: 
[on sparky] 
# zpool export tank 
以物理方式将磁盘从 sparky 移动到 amdy。 
[on amdy] 
# zpool import tank 
每一步操作都行之有效-ZFS 将使用“自适应字节存储顺序”来处理不同平台上的不同字节顺序。 
您会体验到:它使用起来很简单。任何常见的 ZFS 操作都可以使用一个简短的命令来完成。

* 如何获得 ZFS? 
* ZFS 何时适于<在此处插入操作系统>? 
* ZFS 代表什么? 
* 为什么 ZFS 具有 128 位容量? 
* ZFS 有哪些限制? 
* 为什么 ZFS 没有类似于 fsck(1M) 的实用程序? 
* 为什么 du(1) 为 ZFS 和 UFS 报告的文件大小不同? 
* 如果每次引导时 ZFS 都出现故障,应该怎么做? 
* ZFS 是否支持热备件? 
* 能否从 ZFS 存储池中移除设备? 
* 能否将 ZFS 用作根文件系统? 
* 在群集环境中是否支持 ZFS? 
* 哪些第三方备份产品支持 ZFS? 
* ZFS 是否可以与 SAN 连接的设备一起使用? 
* 为什么 ZFS 没有用户或组配额? 
如何获得 ZFS? 
ZFS 可在以下发行版中获得: 
* OpenSolaris 发行版,内部版本 27a 及更高版本 
* Solaris Express 发行版 
* Solaris 10 6/06 发行版和 Solaris 10 11/06 发行版 
ZFS 何时适于<在此处插入操作系统>? 
现在有几个项目正在进行中,这些项目要将 ZFS 移植到 FreeBSD 和 Linux(使用 FUSE)。有关 CDDL 的更多信息,请参见有关许可的常见问答。 
ZFS 代表什么? 
最初,ZFS 是 "Zettabyte File System" 的首字母缩写。我们喜欢的最大 SI 前缀("yotta" 是不可能的)是 "zetta"。由于 ZFS 是一个 128 位文件系统,这表示 ZFS 可以存储 256 x 1015 ZB(其中,每个 ZB 是 270 字节)。随着时间的推移,除了 128 位容量之外,ZFS 还具备许多其他功能,如稳定的数据完整性、易于管理和用于数据管理的简化模型。 
为什么 ZFS 具有 128 位容量? 
业已证实,文件系统的生命周期比大多数传统软件各部分的生命周期长得多,原因在某种程度上是盘上格式非常难以更改。考虑到 UFS 的当前格式(大部分)已沿用了将近 20 年,因此让 ZFS 至少在未来 30 年内保持格式的一成不变也是合理的期望。就这一点,摩尔定律开启了存储领域的新纪元,我们可以预测,将能够在单个文件系统中存储超过 64 位的数据。有关此主题的更详细说明以及 128 位足够使用的原因,请参见 Jeff 的博客文章。 
ZFS 有哪些限制? 
ZFS 的限制如此宽泛,以至于在任何实际的操作中都不会遇到任何限制。ZFS 可在每个存储池、文件系统、文件或文件属性中存储 16 百亿亿字节。ZFS 可存储几十亿个名称:目录中的文件或目录、文件系统中的文件系统,或文件系统中的快照。ZFS 可存储几万亿个项目:文件系统中的文件、文件系统、卷或存储池中的快照。 
为什么 ZFS 没有类似于 fsck(1M) 的实用程序? 
需要具有类似于 fsck(1M) 的实用程序的基本原因有两个。 

验证文件系统完整性-很多时候,管理员只想要确保其文件系统中没有出现盘上损坏。对于大多数文件系统而言,当文件系统处于脱机状态时,就需要运行 fsck(1M)。这可能既耗时,成本又高。ZFS 在系统运行时提供了“清理”存储池中所有数据的功能,从而可在该过程中查找并修复任何坏数据。根据将来计划,会增强此功能以便实现后台清理,并精确跟踪哪些文件包含无法更正的错误。 

修复盘上状态-如果机器崩溃,有些文件系统的盘上状态将不一致。添加的日志记录功能已解决了其中一部分问题,但无法滚动日志仍可能导致文件系统需要修复。在这种情况下,就会出现已知的异常错误(如在更新父链接之前创建目录条目),不过这些错误能够可靠地修复。ZFS 不会遇到此问题,因为盘上数据总是一致的。 
如果硬件或软件出现故障,则会引发更具危害性的问题。即使那些文件系统或卷管理器具有基于块的校验和功能,也易于出现各种其他异常,进而生成有效但损坏的数据。在这种情况下,故障模式本质上是随机的,大多数文件系统将出现故障(如果是元数据),或无提示地将坏数据返回到应用程序。在上述任意一种情况下,使用 fsck(1) 实用程序几乎没有作用。由于这种损坏与已知异常不符,因此它可能无法修复。如果使用 ZFS,从统计学意义上讲,上述错误在冗余配置中是不存在的。在非冗余配置中,会正确地检测到这些错误,但在尝试读取块时会导致 I/O 错误。理论上可以编写一个工具来修复此类损坏,但进行这样的尝试可能要使用特殊的一次性工具。当然,ZFS 同样易于受软件错误的影响,但这些错误所导致的一致性损坏模式使用普通工具即可修复。在 5 年的 ZFS 开发过程中,还没有出现过这样的模式。 
为什么 du(1) 为 ZFS 和 UFS 报告的文件大小不同? 
在 UFS 中,du(1) 报告文件内数据块的大小。在 ZFS 中,du(1) 报告磁盘中存储的文件的实际大小,其中包括元数据和压缩数据。这确实有助于回答此问题:“如果删除此文件,将释放出多少额外空间?”。因此,即使在压缩处于关闭状态时,您仍会看到 ZFS 和 UFS 之间的不同结果。 
如果每次引导时 ZFS 都出现故障,应该怎么做? 
根据设计,ZFS 通过使用冗余(镜像或 RAID-Z)技术在发生任意硬件故障时保持完好。遗憾的是,非复制配置中的某些故障可能导致在尝试装入存储池时 ZFS 出现故障。这是一个错误,将在不久的将来得以修复(还会增强其他几个很好的功能,如后台清理以及查看已损坏文件列表的能力)。同时,如果发现您自己遇到因存储池损坏而无法引导的情况,请执行以下命令: 
1. boot using ‘-m milestone=none’ 
2. # mount -o remount / 
3. # rm /etc/zfs/zpool.cache 
4. # reboot 
这将从系统中删除有关存储池的所有信息。您将必须重新创建存储池,并从备份恢复。 
ZFS 是否支持热备件? 
支持,ZFS 热备件功能可用于 Solaris Express Community Release(内部版本 42)、Solaris Express July 2006 发行版和 Solaris 10 11/06 发行版。有关热备件的更多信息,请参见 ZFS 管理指南。 
能否从 ZFS 存储池中移除设备? 
ZFS 支持通过 "zpool detach" 从镜像中移除设备。当前不支持移除顶级 vdev(如整个 RAID-Z 组或未镜像的磁盘)。计划在将来的发行版中增加此功能。 
能否将 ZFS 用作根文件系统? 
ZFS 文件系统当前不能用作根文件系统,但将来支持此功能!ZFS Boot 项目的目的就是提供 ZFS 文件系统的引导和安装支持。敬请等待 ZFS Boot 发行计划的消息! 
在群集环境中是否支持 ZFS? 
SunCluster 3.2 支持本地 ZFS 文件系统在 Solaris 10 11/06 发行版中用作高可用性 (highly available, HA) 系统。此支持允许在系统间进行实时故障转移,以及在系统间自动导入存储池。 
如果使用 SunCluster 3.2 将本地 ZFS 文件系统配置为高可用性,请留意一下以下注意事项: 
不要将已配置的仲裁设备添加到 ZFS 存储池。如果将已配置的仲裁设备添加到存储池,将重新标记磁盘,仲裁配置信息将丢失。这意味着磁盘不再向群集提供法定票数。将磁盘添加到存储池之后,您可以将该磁盘配置为仲裁设备。或者,可以取消该磁盘的配置,将它添加到存储池,然后将该磁盘重新配置为仲裁设备。 
建议不要在 Nevada 发行版中将 SunCluster 3.2 与 HA-ZFS 一起使用。 
ZFS 不是本机群集,也不是分布式文件系统或并行文件系统,因此不能提供来自多台不同主机的并发访问。当在分布式 NFS 环境中共享时,ZFS 表现优异。 
从长远观点来看,我们打算就 ZFS 作为本机群集文件系统进行研究,以便实现并发访问。目前还未开展这项工作。 
哪些第三方备份产品支持 ZFS? 
# EMC Networker 7.3.2 可备份和恢复 ZFS 文件系统,包括 ZFS ACL。 
# Veritas Netbackup 将在 6.5 版中提供 Netbackup 支持,该版本计划在 2007 下半年发行。当前版本的 Netbackup 可备份和恢复 ZFS 文件系统,但不保留 ZFS ACL。 
# IBM Tivoli Storage Manager 可借助 CLI 工具备份和恢复 ZFS 文件系统,但 GUI 可能会排除 ZFS 文件系统。就像 Netbackup 产品一样,不保留重要的 ZFS ACL。 
# Computer Associates 的 BrightStor ARCserve 产品可备份和恢复 ZFS 文件系统,但不保留 ZFS ACL。
ZFS 是否可以与 SAN 连接的设备一起使用? 
可以,ZFS 可以与直接连接的设备或 SAN 连接的设备一起使用。但是,如果存储池不包含镜像或 RAID-Z 顶级设备,则 ZFS 只能报告校验和错误,但不能更正这些错误。如果存储池由镜像或 RAID-Z 设备(使用 SAN 连接的设备中的存储构建)组成,则 ZFS 可报告校验和错误,还可以对这些错误进行更正。 
例如,考虑一个 SAN 连接的硬件 RAID 阵列,设置该阵列以便向基于其内部镜像磁盘的 SAN Fabric(结构)提供 LUN。如果使用此阵列中的一个 LUN 来构建单磁盘池,则该存储池将不包含 ZFS 更正检测到的错误所需的副本数据。在这种情况下,ZFS 无法更正该阵列引入的错误。 
如果使用此阵列中的两个 LUN 来构建镜像存储池,或使用三个 LUN 来创建 RAID-Z 存储池,则 ZFS 将拥有可用于更正检测到的错误的副本数据。在这种情况下,ZFS 通常可更正该阵列引入的错误。 
在 ZFS 存储池缺少镜像或 RAID-Z 顶级虚拟设备的所有情况下,存储池的生存能力完全取决于基础存储设备的可靠性。 
如果 ZFS 存储池仅包含单个设备,不管它是来自 SAN 连接的存储还是直接连接的存储,您都无法利用 RAID-Z、动态条带化、I/O 负载平衡等功能。 
ZFS 总是可以检测到无提示数据损坏。有些存储阵列可以检测到校验和错误,但无法检测到以下种类的错误: 
* 意外覆写或虚写 
* 错误定向读写 
* 数据路径错误 
总的来说,ZFS 的设计考虑到与 SAN 连接的设备协同使用,但如果为 ZFS 呈现更简单的设备,则可以更好地利用所有可用功能。 
总之,如果将 ZFS 与 SAN 连接的设备一起使用,可通过在 ZFS 存储池中配置冗余(即使冗余在较低硬件级别上可用),来充分利用 ZFS 的自我修复功能。 
为什么 ZFS 没有用户或组配额? 
ZFS 文件系统可用作逻辑管理控制点,这样,您便可以查看使用情况、管理属性、执行备份、捕获快照等等。对于起始目录服务器,ZFS 模型使您可以轻松地基于每个用户设置一个文件系统。ZFS 配额并不特意与特定用户关联,因为文件系统是管理控制点。 
可以在能够代表用户、项目、组等的文件系统上设置 ZFS 配额,也可以针对文件系统分层结构的整个部分设置 ZFS 配额。这样,便能以一些方式合并配额,而这些方式是传统按用户配额所无法实施的。之所以引入按用户配额,是因为多个用户必须共享同一个文件系统。 
ZFS 文件系统的配额非常灵活,而且易于设置。在创建文件系统时,即可应用配额。例如: 
# zfs create -o quota=20g tank/home/users 
在此文件系统中创建的用户文件系统会自动继承在父文件系统中设置的 20 GB 配额。例如: 
# zfs create tank/home/users/user1 
# zfs create tank/home/users/user2 
# zfs list -r tank/home/users 
NAME USED AVAIL REFER MOUNTPOINT 
tank/home/users 76.5K 20.0G 27.5K /tank/home/users 
tank/home/users/user1 24.5K 20.0G 24.5K /tank/home/users/user1 
tank/home/users/user2 24.5K 20.0G 24.5K /tank/home/users/user2 
如果在文件系统处于活动状态时增大了 ZFS 存储池中的磁盘空间,则可以增大 ZFS 配额,而不需要任何停机时间。 
ZFS 小组正致力于改进多文件系统的管理,而不是尝试使基于用户的配额适合基于文件系统的管理模型,让该模型用作控制点。 
对于需要包含邮件所用磁盘空间的、基于用户的配额,另一种方法是使用具备配额功能的邮件服务器软件,如 Sun Java System Messaging Server。此软件提供了用户邮件配额、配额警告消息、配额到期和清除功能。 

此页面旨在让用户了解与 ZFS 文件系统相关的源代码的简要概述。它并不是对 ZFS 的介绍,而是假定您已初步熟悉常用术语和定义,并且对文件系统体系结构有了大致的了解。 
通常,我们将 ZFS 描述为由三个组件组成:ZPL(ZFS POSIX Layer,ZFS POSIX 层)、DMU(Data Management Unit,数据管理单元)和 SPA(Storage Pool Allocator,存储池分配器)。虽然这是用作概念版的有用示例,但其实际层次还是比较复杂。以下图像给出了一个更详细的概述;单击其中一个区域将显示更详细的描述,并显示指向源代码的链接。 
在此图片中,您仍可以看到三个基本层, 但每个层中有许多元素。另外,还显示 zvol 使用者以及管理路径,即 zfs(1M) 和 zpool(1M)。您可以在下文中找到所有这些子系统的简短描述。这并不是确切说明各子系统工作原理的详尽概述。最后一点需要注意的是,源代码是最终文档。我们希望它通俗易懂,注释详细。如有问题,随时欢迎在 ZFS 论坛中发表您的看法。 
文件系统使用者 
这些应用程序是基本的应用程序,可通过 POSIX 文件系统 API 单独与 ZFS 交互。实际上,每个应用程序都可归为此类别。系统调用通过通用 OpenSolaris VFS 层传递到 ZPL。 
设备使用者 
ZFS 提供了一种创建“仿真卷”的方式。这些卷利用存储池中的存储进行备份,但在 /dev 下显示为一个普通设备。这不是典型的用例,不过有一些用例充分说明了这种功能的用处。有少量应用程序直接与这些设备交互,但大多数普通使用者是位于设备层之上的内核文件系统或目标驱动程序。 
管理 GUI 
Solaris 在内部版本 28 中提供了基于 Web 的 ZFS GUI。虽然还不是 OpenSolaris 的组成部分,但它是位于 JNI 层之上基于 Java 的 GUI 的一个示例。 
管理使用者 
这些应用程序是处理 ZFS 文件系统或存储池(包括检查属性和数据集分层结构)的应用程序。在出现一些分散的异常(zoneadm、zoneadmd、fstyp)时,两个主要的应用程序是 zpool(1M) 和 zfs(1M)。 
zpool(1M) 
此命令负责创建和管理 ZFS 存储池。其主要目的是分析命令行输入,将其转换为 libzfs 调用,并顺带处理出现的任何错误。此命令的源代码可在 usr/src/cmd/zpool 中找到。它包含以下文件: 
zpool_main.c 批量命令,负责处理所有的参数和子命令 
zpool_vdev.c 代码,负责将一系列 vdev 转换成 libzfs 的 nvlist 表示 
zpool_iter.c 代码,用于在系统中方便地对一些或全部存储池进行迭代 
zpool_util.c 其他实用程序功能 
zfs(1M) 
此命令负责创建和管理 ZFS 文件系统。与 zpool(1M) 类似,其目的实际上只是分析命令行参数并将处理结果传递到 libzfs。此命令的源代码可在 usr/src/cmd/zfs 中找到。它包含以下文件: 
zfs_main.c 批量命令,负责处理所有的参数和子命令 
zfs_iter.c 代码,用于在系统中对一些或全部数据集进行迭代 
JNI 
此库提供了一个连接 libzfs 的 Java 接口。它当前是一个专用接口,专门为 GUI 定制。因此,它主要用于观察,因为 GUI 通过 CLI 执行大多数操作。此库的源代码可在 usr/src/lib/libzfs_jni 中找到。 
libzfs 
它是管理应用程序与 ZFS 内核模块交互时所用的主要接口。此库为访问和处理存储池和文件系统提供了一种统一的、基于对象的机制。用于与内核通信的基础机制是通过 /dev/zfs 调用 ioctl(2)。此库的源代码可以在 usr/src/lib/libzfs 中找到。它包含以下文件: 
libzfs_dataset.c 用于处理数据集的主要接口 
libzfs_pool.c 处理存储池的主要接口 
libzfs_changelist.c 在子级中传播属性更改的实用程序例程 
libzfs_config.c 读取和处理存储池配置信息 
libzfs_graph.c 构造数据集相关列表 
libzfs_import.c 搜索和导入存储池 
libzfs_mount.c 挂载、取消挂载和共享数据集。 
libzfs_status.c 根据存储池状态链接到 FMA 知识库文章 
libzfs_util.c 其他例程 
ZPL(ZFS POSIX Layer,ZFS POSIX 层) 
ZPL 是作为文件系统与 ZFS 交互的主要接口。它是一个薄层(相对来说),位于 DMU 顶部,并提供文件和目录的文件系统抽象。它负责连接 OpenSolaris VFS 接口和基础 DMU 接口。它还负责强制执行 ACL(Access Control List,访问控制列表)规则和同步 (O_DSYNC) 语义。 
zfs_vfsops.c OpenSolaris VFS 接口 
zfs_vnops.c OpenSolaris vnode 接口 
zfs_znode.c 每个 vnode 对应一个基础 znode 
zfs_dir.c 目录操作 
zfs_acl.c ACL 实现 
zfs_ctldir.c 伪文件系统实现。zfs/snapshot 
zfs_log.c 用于记录意图日志条目的 ZPL 接口 
zfs_replay.c 重放意图日志条目的 ZPL 接口 
zfs_byteswap.c 用于 ZPL 数据结构的字节交换例程 
ZVOL(ZFS 仿真卷) 
ZFS 具有提供原始设备的能力,这些原始设备利用存储池中的空间进行备份。这在源代码中称作 ‘zvol’,在 ZFS 源代码中通过单个文件实现。 
zvol.c 卷仿真接口 
/dev/zfs 
此设备是 libzfs 的主要控制点。当使用者可以直接使用 ioctl(2) 接口时,它与 libzfs 紧密结合,并且它不是公共接口(libzfs 也不是公共接口)。它由单个文件组成,该文件会对 ioctl() 参数进行某些验证,然后将请求转发到 ZFS 中的适当位置。 
zfs_ioctl.c /dev/zfs ioctl() 接口 
zfs.h 内核和用户空间之间共享的接口 
DMU(Data Management Unit,数据管理单元) 
DMU 负责提供事务对象模型,这些模型构建在 SPA 提供的单层地址空间之上。使用者可通过对象集、对象和事务与 DMU 交互。对象集是对象的集合,其中的每个对象都是 SPA 中的任意一个存储单元。每个事务是必须以组的形式向磁盘提交的一系列操作;其主要作用是为 ZFS 提供盘上一致性。 
dmu.c 主要的外部 DMU 接口 
dmu_objset.c 对象集打开/关闭/处理外部接口 
dmu_object.c 对象分配/释放接口 
txg.c 事务模型控制线程 
dmu_tx.c 事务创建/处理接口 
dnode.c 打开上下文对象级处理函数 
dnode_sync.c 同步上下文对象级处理函数 
dbuf.c 缓冲区管理函数 
dmu_zfetch.c 数据流预取逻辑 
refcount.c 通用引用计数接口 
dmu_send.c 发送和接收快照函数 
DSL(Dataset and Snapshot Layer,数据集和快照层) 
通过继承的属性以及配额和预留执行,DSL 可将 DMU 对象集聚合到一个分层的名称空间中。它还负责管理对象集的快照和克隆。 
有关如何实现快照的更多信息,请参见 Matt 的博客文章。 
dsl_dir.c 名称空间管理函数 
dsl_dataset.c 快照/回滚/克隆支持接口 
dsl_pool.c 存储池级支持接口 
dsl_prop.c 属性处理函数 
unique.c 用于唯一对象集 ID 的支持函数 
ZAP(ZFS Attribute Processor,ZFS 属性处理器) 
ZAP 构建在 DMU 之上,它使用可伸缩哈希算法在对象集内创建任意(名称、对象)关联。它最常用于在 ZPL 内实现目录,但也广泛用于整个 DSL 内,它还是对存储池范围的属性进行存储的方法。有两种不同的 ZAP 算法,专为不同类型的目录而设计。当条目数相对较小且每个条目比较短时,使用 "micro zap"。对于较大目录或具有极长名称的目录,则使用 "fat zap"。 
zap.c Fat ZAP 接口 
zap_leaf.c 低级别支持函数 
zap_micro.c Micro ZAP 接口 
ZIL(ZFS Intent Log,ZFS 意图日志) 
虽然 ZFS 在磁盘上提供始终一致的数据,但它遵循传统文件系统语义,根据这些语义,大部分数据不会立即写入磁盘,否则性能将下降。但是,有些应用程序要求更严格的语义,以保证在 read(2) 或 write(2) 调用返回时数据已在磁盘上。对于要求此行为(用 O_DSYNC 指定)的应用程序,ZIL 使用有效的、基于每个数据集的事务日志提供必要的语义,该事务日志可在出现崩溃时重放。 
有关 ZIL 实现的更多详细信息,请参见 Neil 的博客文章。 
zil.c 意图日志 
遍历 
遍历为在活动存储池中浏览所有数据提供了一种安全、有效、可重新开始的方法。它是重新同步和清理操作的基础。它可以在所有元数据中查找在某一期间内修改过的块。由于使用 ZFS 的写复制功能,它具有快速排除在故障期间未访问过的较大子树的优点。它本质上是一个 SPA 工具,但有某些 DMU 结构的锁定功能,以便能够处理快照、克隆以及盘上格式的某些其他特性。 
dmu_traverse.c 遍历代码 
ARC(Adaptive Replacement Cache,自适应替换缓存) 
ZFS 使用自适应替换缓存的修改版本来满足其主要缓存需求。此缓存在 DMU 和 SPA 之间分层,因而是在虚拟块级别上进行操作。这样,文件系统可与其快照和克隆共享其缓存数据。 
arc.c 自适应替换缓存实现 
存储池配置 (SPA) 
虽然整个存储池层经常被称作 SPA(Storage Pool Allocator,存储池分配器),但配置部分实际上是公共接口。它负责将 ZIO 和 vdev 层结合成一个一致的存储池对象。它包含一些例程,这些例程可根据其配置信息创建和销毁存储池,并定期将数据与 vdev 同步。 
spa.c 打开、导入、导出和销毁存储池的例程 
spa_misc.c 其他 SPA 例程,包括锁定 
spa_config.c 分析和更新存储池配置数据 
spa_errlog.c 持久性存储池范围的数据错误的日志。 
spa_history.c 修改存储池状态的命令成功运行的持久性环形缓冲区。 
zfs_fm.c 发布 ereport 以占用 FMA 的例程。 
ZIO(ZFS I/O Pipeline,ZFS I/O 管道) 
ZIO 管道是读取或写入磁盘时传递所有数据必经的地方。它负责将 DVA(Device Virtual Address,设备虚拟地址)转换成 vdev 上的逻辑位置,并在必要时对数据进行校验和以及压缩。它以多阶段管道的方式实现,并使用位掩码控制对每个 I/O 执行哪个阶段。管道本身很复杂,但可以通过以下图表作概括说明: 
I/O 类型 ZIO 状态 压缩 校验和 组块 DVA 管理 Vdev I/O 
RWFCI 打开 
RWFCI 等待 
子项就绪 
-W— 写入压缩 
-W— 校验和生成 
-WFC- 组管道 
-WFC- 获取组头 
-W— 重写组 
头 
–F– 释放组 
成员 
—C- 声明组 
成员 
-W— DVA 分配 
–F– DVA 释放 
—C- DVA 声明 
-W— 组校验和 
生成 
RWFCI 就绪 
RW–I I/O 开始 
RW–I I/O 完成 
RW–I I/O 访问 
RWFCI 等待 
子项完成 
R—- 校验和验证 
R—- 读取组 
成员 
R—- 读取解压缩 
RWFCI 完成 
I/O 类型 
I/O 管道的每个阶段应用于特定类型的 I/O。字母代表的含义:(R) 表示读取、(W) 表示写入、(F) 表示释放、(C) 表示声明、(I) 表示 loctl。 
ZIO 状态 
这些状态是用于同步 I/O 的内部状态。例如,具有子 I/O 的 I/O 必须在分配 BP 之前等待所有子项准备就绪,而且必须在返回之前等待所有子项完成。 
压缩 
此阶段应用任何压缩算法(如果适用)。 
校验和 
此阶段应用任何校验和算法(如果适用)。 
组块 
如果没有足够的连续空间可用来写入完整块,ZIO 管道会将 I/O 分成几个更小的“组块”,这些组块可以在以后进行透明汇编以显示为完整块。 
DVA 管理 
必须为每个 I/O 分配一个 DVA(Device Virtual Address,设备虚拟地址),以与存储池中 vdev 的特定部分相对应。通过使用 metaslab 和空间映射,这些阶段对这些地址执行必要的分配。 
Vdev I/O 
这些阶段是实际将 I/O 发出到包含在存储池中的 vdev 的阶段。 
zio.c ZIO 主要阶段,包括组块转换 
zio_checksum.c 通用校验和接口 
fletcher.c Fletcher2 和 Fletcher4 校验和算法 
sha256.c SHA256 校验和算法 
zio_compress.c 通用压缩接口 
lzjb.c LZJB 压缩算法 
uberblock.c 基本超级块(根块)例程 
bplist.c 跟踪块指针列表 
metaslab.c DVA 批量转换 
space_map.c 跟踪 DVA 转换期间使用的可用空间 
szio_inject.c 用于注入有关数据和设备的持久性错误的框架 
VDEV(Virtual Device,虚拟设备) 
虚拟设备子系统提供了排列和访问设备的统一方法。虚拟设备可形成一个树结构,其中包含一个根 vdev 以及多个内部(镜像和 RAID-Z)vdev 和叶(磁盘和文件)vdev。每个 vdev 负责表示可用空间,并在物理磁盘上排列块。 
vdev.c 通用 vdev 例程 
vdev_disk.c 磁盘虚拟设备 
vdev_file.c 文件虚拟设备 
vdev_mirror.c N 向镜像 
vdev_raidz.c RAID-Z 分组(请参见 Jeff 的博客)。 
vdev_root.c 顶级伪 vdev 
vdev_missing.c 用于导入的特殊设备 
vdev_label.c 用于读取和写入标识标签的例程 
vdev_cache.c 用于读取的简单设备级缓存 
vdev_queue.c 用于 vdev 的 I/O 调度算法 
LDI(Layered Driver Interface,分层驱动程序接口) 
在栈底部,ZFS 通过 LDI(即分层驱动程序接口)与基础物理设备交互;处理文件时,还与 VFS 接口交互。

有些用户问到有关如何将 ZFS 移植到其他平台的问题,并且他们愿意尝试自行移植代码。本页面旨在协助他们完成移植过程,并为用户提供一个公用页面,共享其经验和他们发现的陷阱。如果要将 ZFS 移植到另一个平台,并想将相关内容添加到此页面中,请通过电子邮件与其中一个社区发起人联系,他可让您成为发起人,以便您可以编辑此内容。 
现行的移植 
FUSE 
Ricardo Correia 正在将 ZFS 移植到 FUSE,作为用户空间文件系统。可以在以下位置找到此项目页面: 
http://www.wizy.org/wiki/ZFS_on_FUSE 
Ricardo 的博客: 
http://zfs-on-fuse.blogspot.com/ 
FreeBSD 
Pawel Jakub Dawidek 正在将 ZFS 移植到 FreeBSD。可以在以下位置找到 FreeBSD 信息库: 
http://perforce.freebsd.org/depotTreeBrowser.cgi?FSPC=//depot/user/pjd/zfs 
gcc 信息 
与所有 ON 一样,ZFS 源代码是使用 gcc 构建的,作为“阴影编译”的一部分,用于检测特定于 gcc 的警告。 不过,我们使用了一组稍做修改的警告,从而获得目前所拥有的无错误的内部版本。您可以在用于 ON 的编译器包装函数中查看一些详细信息。特别地,我们使用了以下警告标志: 
-Wall 
-Wno-unknown-pragmas 
-Wno-missing-braces 
-Wno-sign-compare 
-Wno-parentheses 
-Wno-uninitialized 
-Wno-implicit-function-declaration 
-Wno-unused 
-Wno-trigraphs 
-Wno-char-subscripts 
-Wno-switch 
还使用 -std=gnu99 选项来强制执行 C99 兼容性规则。如果使用上述相同的选项,毋庸置疑地会使移植变得更简单。 
建议的阶段 
进行 ZFS 移植的方法有多种,下面列出的是建议执行的某些重要阶段。这里使用了源代码概览中的术语,因此,在进一步阅读信息之前,您应该大致了解 ZFS 源代码布局。 
libzpool 和 ztest 
libzpool 是 SPA(Storage Pool Allocator,存储池分配器)和 DMU(Data Management Unit,数据管理单元)的用户空间移植,它包括较大百分比的相关源代码。根据其设计,允许使用 ztest 进行用户空间测试,还允许通过 zdb 进行调试。它具有一个方便的属性,特定于内核的代码已经将该属性用作 zfs_context.h 的参数,这样移植起来相对简单。您可以在 usr/src/lib/libzpool/common 中找到这些接口(不能用 #define 实现的接口)的 Solaris 端口。 
如果您可以在一个循环中成功运行 ztest 一整天而没有出现任何问题,则可能移植了 80% 的内核代码(尽管最难的 20% 代码仍未移植)。此过程还需要移植 zdb,它用作 ztest 的一部分。 
zpool(1M) 和 zfs(1M) 
下一步是获取用户空间管理工具 [zfs(1M)]( http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/zfs) 和 zpool(1M),前者可使用数据集,后者可创建数据集。这实际上不会挂载文件系统(可能需要 ZPL),但是会建立用户空间 -> 内核接口,并验证 DSL 是否正常工作。 
对于内核而言,需要创建 /dev/zfs 并支持 zfs_ioctl.c 中定义的 ioctl。 
zvol 
要运行的简单内核内部使用者是 zvol(ZFS volume,ZFS 卷)接口。这将需要一些特定于操作系统的设备信息,但 DMU 接口非常简单。请参见 zvol.c。 
ZFS 文件系统 
最后的障碍是最困难的,因为必须使用特定于操作系统的 VFS 接口从头开始大规模写入代码。当前的 ZPL 代码可以用作如何达成实现的理念指导,但它在极大程度上是特定于 Solaris 的。有些理念(扩展属性,NFSv4/NT ACL)可能根本不会转化为某些操作系统中的内容。

 

原创粉丝点击