RFC-0223:zx_vmo_transfer_data

RFC-0223:zx_vmo_transfer_data
状态已接受
涉及的领域
  • Kernel
说明

引入了一个名为 zx_vmo_transfer_data 的新系统调用,可高效地将数据从一个 VMO 移至另一个 VMO。

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2023-05-22
审核日期(年-月-日)2023-08-14

摘要

我们建议添加一个新的系统调用 zx_vmo_transfer_data,以便调用方将页面从一个 VMO 移至另一个 VMO。您可以将其视为一种效率提升,它允许数据移动,而不会产生复制开销。

设计初衷

过去对 Fuchsia 性能的分析发现,Bootfs 的深层分层 CoW 克隆链在查找页面时会导致搜索时间过长。 此系统调用将通过将克隆链替换为包含 Bootfs 各个条目的“拼接”VMO 来减少此开销。

虽然 Bootfs 是当前的设计初衷,但未来可能还会有其他情况,在这些情况下,移动页面的能力可以提高性能。

利益相关方

哪些人会关心此 RFC 是否被接受?(此部分是可选的,但建议填写。)

Facilitator: cpu@

Reviewers: rashaeqbal@, jamesr@

Consulted: mcgrathr@, maniscalco@, adanis@, eieio@

Socialization: This proposal was socialized as a one pager to the Zircon team.

设计

我们将向 Zircon 系统调用 API 添加以下系统调用:

zx_status_t zx_vmo_transfer_data(zx_handle_t dst_vmo,
                                 uint32_t options,
                                 uint64_t offset,
                                 uint64_t length,
                                 zx_handle_t src_vmo,
                                 uint64_t src_offset);

其中:

  • dst_vmo 是目标 VMO 的句柄。此句柄必须具有 ZX_RIGHT_WRITE
  • options 是当前未使用的字段,允许将来扩展 API。
  • offset 是将页面移入目标的偏移量。
  • length 是要移至目标的字节数。
  • src_vmo 是源 VMO 的句柄。此句柄必须具有 ZX_RIGHT_READZX_RIGHT_WRITE
  • src_offset 是从源检索页面的偏移量。

此系统调用会将 src_vmo 中的 [src_offset, src_offset + length) 范围内的页面移至 dst_vmo 中的 [offset, offset + length) 范围。它在功能上等同于从 src_vmodst_vmomemmove,然后取消提交 src_vmo 中的关联页面。但是,实现此目的的机制不同;支持页面实际上是在 VMO 之间移动,而不是复制数据。这样可以实现更好的性能。尽管机制不同,但此系统调用与 memmove 具有相同的语义,即支持提供重叠的源区域和目标区域。

读者可能想知道,如果系统调用移动页面,为什么它被称为 zx_vmo_transfer_data 而不是 zx_vmo_transfer_pages。这是经过深思熟虑的选择,以防我们将来想要放宽严格的页面对齐要求。例如,我们可能希望支持用户请求传输一个半页面的用例。在这种情况下,我们会移动第一页,然后复制剩余的半页。这仍然比用户进行简单的复制更高效,因为它允许我们绕过将目标页面归零。请注意,初始实现不支持此用例;此处提及它仅是为了提供有关命名选择的背景信息。

目标范围内的现有页面将被覆盖。目标 VMO 的所有映射也将看到新内容。如果目标 VMO 有子项,则子项的类型将影响子项看到的内容。 类型为 ZX_VMO_CHILD_SNAPSHOTZX_VMO_CHILD_SNAPSHOT_MODIFIED 的子项将继续看到旧内容。所有其他类型的子项都将看到新内容。移动完成后,src_vmo 中的页面将被归零。

移动可能会因多种原因而失败。请参阅下面的“错误”部分,了解可能出现的错误代码及其返回场景的完整枚举。

如果移动失败,则 src_vmo VMO 中的任意数量的页面可能已移至 dst_vmo。我们不保证移动了多少数据。 但是,我们可以保证在满足以下条件时调用将成功:

  1. 不满足会导致下面列出的错误的任何条件。
  2. 在运行此操作时,src_vmodst_vmo 不会被任何其他线程修改。

在此上下文中,“修改”是指直接对 VMO 或对 VMO 的引用(例如切片、引用子项等)执行写入/调整大小/固定操作。 修改任何类型的快照的父项、子项或同级项都不应导致任何错误,但根据快照的不同,您可能会遇到写入撕裂。如果您操作 SNAPSHOT_AT_LEAST_ON_WRITE VMO 的父项,则可能会发生写入撕裂,因为实际传输没有承诺的原子性。请注意,在从 SNAPSHOT 子项传输页面的情况下,如果该特定页面尚未进行写入时复制,我们可能需要执行复制,即分配新页面。

以下是此系统调用可以返回的错误及其含义:

  • ZX_ERR_BAD_HANDLEsrc_vmodst_vmo 不是有效的 VMO 句柄。
  • ZX_ERR_INVALID_ARGSoffsetlengthsrc_offset 未与页面 对齐。如前所述,我们可能希望将来移除此限制。
  • ZX_ERR_ACCESS_DENIEDsrc_vmo 没有 ZX_RIGHT_WRITEZX_RIGHT_READ,或者 dst_vmo 没有 ZX_RIGHT_WRITE
  • ZX_ERR_BAD_STATEsrc_vmodst_vmo 中指定范围内的页面已固定。
  • ZX_ERR_NOT_SUPPORTEDsrc_vmodst_vmo 是物理 VMO、连续 VMO 或分页器支持的 VMO。我们将来或许能够支持分页器支持的 VMO。
  • ZX_ERR_OUT_OF_RANGEdst_vmosrc_vmo 中指定的范围无效。
  • ZX_ERR_NO_MEMORY:因内存不足而失败。

实现

这应该是一组相对简单的 CL,因为我们有一个现有的系统调用 zx_pager_supply_pages,它为分页器支持的 VMO 执行非常类似的操作。因此,我们可以重复使用支持该系统调用的大部分代码。 但是,我们需要进行一些更改来支持此新用例:

  1. zx_pager_supply_pages 验证提供的 VMO 是否由给定的分页器对象支持。我们需要在新的系统调用中移除此验证。
  2. SupplyPages,即 zx_pager_supply_pages 用于将页面插入 VMO 的函数,假定存在分页器,在代码中称为 page_source_。我们必须通过在对 page_source_ 进行操作之前添加 NULL 检查并移除对其存在性的任何断言来移除此假设。
  3. SupplyPages 还会解压缩任何压缩页面,并在将页面拼接到目标之前添加标记,因为它希望目标是分页器支持的。对于匿名 VMO,这不是必需的,因此我们需要根据目标是否由分页器支持来使其成为有条件的。
  4. SupplyPages 目前会跳过目标中存在的任何页面,但仍会释放源中的页面。如前所述,我们会将其更改为始终覆盖目标。
  5. SupplyPages 目前不考虑具有父项的 VMO。在大多数情况下,这不是问题。但是,如果目标是类型为 ZX_VMO_CHILD_SNAPSHOT 的子项,我们需要更新父项中的拆分位,以表明 VMO 已与隐藏的父项分离。

性能

我们预计这将显著提高 Bootfs 中的 VMO 页面查找性能。 具体来说,从当前使用的 CoW 克隆链切换到使用此系统调用移动页面应该会使 bootfs 查找性能提高约 20%。请注意,我们可以通过创建 VMO 的副本而不是像此系统调用建议的那样移动页面来获得类似的 bootfs 查找性能提升。但是,这种方法会将系统启动时间降低高达 70%(具体取决于我们运行的硬件目标)。使用此 RFC 提出的方法可以弥补大部分这种降低。

向后兼容性

我们的目标不是移除现有的 zx_pager_supply_pages 系统调用,因此我们预计不会出现任何向后兼容性问题。

安全注意事项

我们预计此提案不会产生任何安全影响,因为新操作旨在在功能上等同于现有操作 (memcpy() + uncommit),但性能更好。它并非旨在允许进程执行其无法执行的操作。

不过,它增加了攻击面。如果系统调用实现中存在可利用的 bug,则任何进程都可能利用这些 bug。

隐私注意事项

我们预计此提案不会产生任何隐私影响。

测试

我们将添加利用新系统调用的核心测试,并验证上述所有行为(页面移动、约束和源页面归零)。我们还将添加一个基准,用于衡量此系统调用的性能,然后我们可以将其与复制的性能进行比较。

文档

我们将添加描述 zx_vmo_transfer_data 的新文档。

缺点、替代方案和未知事项

我们可以将 zx_pager_supply_pages 泛化为与匿名 VMO 配合使用。这将大大增加该系统调用的实现复杂性,并且可能仍然需要修改 API 以接受匿名 VMO 作为输入。

如果我们的唯一目标是提高 bootfs 中 CoW 克隆层次结构中的页面查找性能,我们也可以只使用 VMO 的副本,而不是创建 CoW 克隆。但是,由于额外的复制开销,这会显著降低启动时间。