RFC-0013:克隆 VMO 映射

RFC-0013:克隆 VMO 映射
状态已接受
领域
  • 内核
说明

一个系统调用,用于根据映射创建 VMO 的 CoW 克隆,而无需为其添加句柄。

问题
Gerrit 更改
作者
审核人
提交日期(年-月-日)2020-10-26
审核日期(年-月-日)2020-12-09

摘要

目前,只有当您拥有 VMO 的句柄时,才能创建 VMO 的 CoW 克隆。 这对于 zygote 用例是不够的, 这需要 CoW 克隆整个地址空间, 包括所有 VMO 句柄都已关闭的映射。 此 RFC 提出了新的系统调用来解决这一问题。

动机和问题陈述

Linux 上的 Chromium 通过从 Zygote 进程派生渲染程序来生成渲染程序, 从而节省大量内存和 CPU 我们希望能在 Fuchsia 上节省资金。

为此,我们需要通过某种方式实现“地址空间克隆”操作, 如果给定,则会发生以下情况:

  • 进程根 VMAR
  • 一些句柄引用了在地址空间中映射的 VMO

将返回:

  • 一个新进程,其地址空间由输入进程中映射的 VMO 的克隆填充
  • 对于输入过程中引用 VMO 的每个句柄, 一个新句柄,用于引用新进程中相应 VMO 的克隆

通过添加此系统调用,我们可以轻松在用户空间中实现这一点。 可通过使用 ZX_INFO_PROCESS_MAPS 获取地址空间布局来做到这一点。 并使用 zx_vmar_create_vmo_child 为每个映射创建克隆, 但有句柄的 VMO 除外 均使用 zx_vmo_create_child 处理。

设计

zx_vmar_create_vmo_child

zx_status_t zx_vmar_create_vmo_child(zx_handle_t handle,
                                     uint32_t options,
                                     zx_vaddr_t addr,
                                     size_t size,
                                     zx_handle_t* out)

addraddr+size 范围中映射的网页创建 CoW 克隆 (位于 handle 引用的 VMAR 中)。 该范围必须是单个 VMO 映射的子范围, 也就是说,它不能跨越两个映射,也不能包含任何未映射的页面。 结果会生成一个新的 VMO,它是范围内映射的 VMO 的子项。

允许的选项包括 ZX_VMO_CHILD_SNAPSHOTZX_VMO_CHILD_SNAPSHOT_AT_LEAST_ON_WRITEZX_VMO_CHILD_NO_WRITE。 它们的解释与 zx_vmo_create_child 中的解释相同。 (出于安全方面的考虑,目前不允许使用 ZX_VMO_CHILD_SLICE: 必须特别注意 修改父级 VMO 的功能不会打破任何安全边界。)

在以下情况下返回 ZX_ERR_INVALID_ARGS

  • 范围 addraddr + size 不是单个 VMO 映射的子范围
  • addrsize 未页面对齐

在以下情况下返回 ZX_ERR_ACCESS_DENIED

  • 映射是使用新标志 ZX_VM_CANNOT_CREATE_VMO_CHILD 完成的, 或者 vmar 选项包含此标志
  • handle 未提供 ZX_RIGHT_INSPECT

如果 handle 不是有效的句柄,则返回 ZX_ERR_BAD_HANDLEZX_ERR_WRONG_TYPE(如果 handle 不是 VMAR), 如果 VMAR 被销毁,则为 ZX_ERR_BAD_STATE。 如果记录的原因适用,还可以返回 zx_vmo_create_child 返回的任何错误。

返回的 VMO 句柄将包含 ZX_DEFAULT_VMO_RIGHTS,并发生以下更改:

  • 如果指定了 ZX_VMO_CHILD_NO_WRITE,系统将移除 ZX_RIGHT_WRITE
  • 如果映射可执行且未指定 ZX_VMO_CHILD_NO_WRITE,则系统会添加 ZX_RIGHT_EXECUTE。 这意味着,您可以创建可执行映射的可执行克隆, 但它们必须是只读的

ZX_VM_CANNOT_CREATE_VMO_CHILD

ZX_VM_CANNOT_CREATE_VMO_CHILD 是新的 zx_vm_options_t 标志 可为 VMO 映射或 VMAR 指定 这允许映射 VMO 或创建 VMAR 的代码 以禁止对它们执行 zx_vmar_create_vmo_child 操作。

实现

添加系统调用并不复杂;可以在一个 CL 中完成。 克隆算法的实现超出了此 RFC 的范围。

性能

不值得单独对此系统调用进行基准化分析, 因为它仅适用于 zygote 实现。 我们应该衡量 zygote 实现的整体性能。

安全注意事项

目前无法使用 VMAR 引用(而不是句柄)创建 VMO 子项, 但有了此 RFC,便有可能实现 这有点像凭空提供新功能。

在这种情况下,风险没那么大 因为最终结果与创建新的 VMO 相同,并将数据复制到 (但内存用量更少),这在以前是可以实现的。 如果需要禁止此项操作 此 RFC 提议了 zx_vm_options_t 标志 (ZX_VM_CANNOT_CREATE_VMO_CHILD) 可用。

测试

系统将对系统调用进行单元测试。 针对未来地址空间克隆实现的测试 也将用作系统调用的集成测试。

文档

此 RFC 是 zx_vmar_create_vmo_child 文档的基础。

缺点、替代方案和未知问题

哪些其他策略有可能解决同样的问题?

我们可以添加一个系统调用来执行整个地址空间克隆操作。 在接口和实现方面,这将是一个非常复杂的系统调用。 最好将复杂性引入用户空间。

我们可以添加一个系统调用,用于允许从映射中创建一个 VMO 句柄。 这样便可实现本质上是 zx_vmar_create_vmo_child 的用户空间实现, 首先根据映射创建一个句柄,然后调用 zx_vmo_create_child。 但是,Zircon API 通常仅允许新建对象的创建句柄, 以使界面更易于推断。 此系统调用必须凭空创建句柄。

有很多技巧可以用来避免关闭任何 VMO 句柄, 例如,修改用于创建和映射 VMO 的所有代码以避免关闭它们; 或拦截 zx_handle_close。 但是,这不足以实现地址空间克隆, 由于加载器服务会在开始运行之前将一些 VMO 映射到进程中, 这样并不能帮您处理这些事务 我们可以修改加载器服务,将必要的句柄传递给进程, 但这比添加此系统调用更复杂。

先验技术和参考资料

https://chromium.googlesource.com/chromium/src/+/master/docs/linux/zygote.md http://neugierig.org/software/chromium/notes/2011/08/zygote.html