| RFC-0013:克隆 VMO 映射 | |
|---|---|
| 状态 | 已接受 |
| 区域 |
|
| 说明 | 一种系统调用,用于从映射创建 VMO 的 CoW 克隆,而无需获取其句柄。 |
| 问题 | |
| Gerrit 更改 | |
| 作者 | |
| 审核人 | |
| 提交日期(年-月-日) | 2020-10-26 |
| 审核日期(年-月-日) | 2020-12-09 |
摘要
目前,只有在拥有 VMO 的句柄时,才能创建 VMO 的 CoW 克隆。这对于 zygote 用例来说是不够的,因为 zygote 需要对整个地址空间(包括所有 VMO 句柄都已关闭的映射)进行 CoW 克隆。此 RFC 提议了一种新的系统调用来弥补这一不足。
动机和问题陈述
Linux 上的 Chromium 通过从 zygote 进程分叉来生成渲染器,从而显著节省内存和 CPU。 我们希望在 Fuchsia 上实现这些节省。
为此,我们需要以某种方式实现“地址空间克隆”操作,该操作在给定以下内容时:
- 进程根 VMAR
- 一些引用地址空间中映射的 VMO 的句柄
将返回:
- 一个新进程,其地址空间由输入进程中映射的 VMO 的克隆填充
- 对于输入进程中引用 VMO 的每个句柄,新进程中都会有一个引用相应 VMO 克隆的新句柄
通过添加此系统调用,我们可以在用户空间中轻松实现此功能。
此功能通过以下方式实现:使用 ZX_INFO_PROCESS_MAPS 获取地址空间布局,并使用 zx_vmar_create_vmo_child 创建每个映射的克隆,但有句柄的任何 VMO 除外,这些 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 是在相应范围内映射的 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_vmo_create_child,即可实现 zx_vmar_create_vmo_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