RFC-0013:克隆 VMO 映射 | |
---|---|
状态 | 已接受 |
领域 |
|
说明 | 系统调用会根据映射创建 VMO 的 CoW 克隆,而无需句柄。 |
问题 | |
Gerrit 更改 | |
作者 | |
审核人 | |
提交日期(年-月-日) | 2020-10-26 |
审核日期(年-月-日) | 2020-12-09 |
总结
目前,仅当您拥有 VMO 的句柄时,才能创建 VMO 的 CoW 克隆。这对于 Zygote 用例来说是不够的,因为 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)
在 handle
引用的 VMAR 中,为从 addr
到 addr
+size
范围映射的网页创建 CoW 克隆。该范围必须是单个 VMO 映射的子范围,也就是说,它不能跨越两个映射或包含任何未映射的页面。结果会生成一个新的 VMO,它是在该范围内映射的 VMO 的子级。
允许的选项包括 ZX_VMO_CHILD_SNAPSHOT
、ZX_VMO_CHILD_SNAPSHOT_AT_LEAST_ON_WRITE
和 ZX_VMO_CHILD_NO_WRITE
。它们的解释方式与 zx_vmo_create_child
中相同。(出于安全考虑,目前不支持ZX_VMO_CHILD_SLICE
:必须格外小心,确保能够修改父级 VMO 不会破坏任何安全边界。)
如果存在以下情况,则返回 ZX_ERR_INVALID_ARGS
:
- 范围
addr
到addr
+size
不是单个 VMO 映射的子范围 addr
或size
未与页面对齐
如果存在以下情况,则返回 ZX_ERR_ACCESS_DENIED
:
- 映射是使用新标志
ZX_VM_CANNOT_CREATE_VMO_CHILD
完成的,或者 vmar 选项包含此标志 handle
没有ZX_RIGHT_INSPECT
如果 handle
不是有效的句柄,则返回 ZX_ERR_BAD_HANDLE
;如果 handle
不是 VMAR,则返回 ZX_ERR_WRONG_TYPE
;如果 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 映射到进程中,这对您获取这些 VMO 没有帮助。我们可以修改加载器服务,将必要的句柄传递给进程,但这比添加此系统调用更复杂。
早期技术和参考资料
https://chromium.googlesource.com/chromium/src/+/master/docs/linux/zygote.md http://neugierig.org/software/chromium/notes/2011/08/zygote.html