RFC-0223:zx_vmo_transfer_data

RFC-0223:zx_vmo_transfer_data
状态已接受
区域
  • 内核
说明

引入了一个名为 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 的接受与否有利益相关?(此部分为可选部分,但建议填写。)

教员:cpu@

审核员:rasheqbal@, jamesr@

咨询者:mcgrathr@、maniscalco@、adanis@、eieio@

共享:此提案以一页纸的形式向 Zircon 团队共享。

设计

我们将向 Zircon syscall 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_offset, src_offset + length) 中的页面从 dst_vmo 中的 src_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 的引用(例如 slice、引用子项等)进行写入/调整大小/固定。修改任何类型的快照的父级、子级或同级兄弟姐妹应该不会导致任何错误,但具体取决于快照,您可能会遇到写入画面撕裂。如果您操控 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_STATE:将 src_vmodst_vmo 中指定范围内的网页固定。
  • ZX_ERR_NOT_SUPPORTEDsrc_vmodst_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. SupplyPageszx_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 克隆。不过,由于额外的复制开销,这会显著延长启动时间。