RFC-0218:IOBuffer:高效 IO 的对等互连共享内存对象 | |
---|---|
状态 | 已接受 |
领域 |
|
说明 | 引入了一个新的共享内存对象,旨在改进分布式 IO 用例。 |
问题 |
|
Gerrit 更改 | |
作者 | |
审核人 | |
提交日期(年-月-日) | 2022-09-29 |
审核日期(年-月-日) | 2023-05-09 |
摘要
我们提议采用新的 IOBuffer 内核基元来提高安全性、便利性和 使用共享的 IO 用例的通信和性能 内存和可选的内核中介操作。
设计初衷
大部分 Fuchsia 操作系统都是在用户空间中实现的, 多个通信进程和组件之间分配的资源。这个 相比应用场景, 等效实现,尤其是当 等效功能直接在单体式内核中实现。虽然 这种分布式方法对于安全、开发、 和可更新性,但非常重要的一点是,许多操作都需要 Fuchsia 中的 IPC(当 单体式内核中。此外,使用现有 Fuchsia 通道和套接字的 IPC 基元涉及多个系统调用、模式切换、线程跃点和数据 以完成端到端操作。这种开销的影响可以 对通信和 IO 工作负载具有重要意义,尤其是那些涉及 数据量、高频率和/或低延迟操作。
原则上,可以使用共享内存来避免 同时保留 Fuchsia 用户空间隔离的优势 模型。然而,原始共享内存具有局限性, 和可靠的沟通,尤其是在许多情况下, 涉及多个客户,信任度或可靠性各不相同; 共享资源
部分挑战包括:
- 安全性和正确性:直接访问共享内存通信模式 难以应对滥用或滥用, 或极其复杂。重要的是,系统调用更容易 比任意内存访问更有效。
- 同步:直接内存访问提供有限的同步 架构内存模型以外的机制。
- 生命周期和会话:内存访问的范围可能难以推断 并强制执行现有基元。
此方案是一种切实可行的方法来应对这些及其他挑战, 利用 Zircon 对等互连对象模型实现更好的会话管理和 利用内核作为可信中介来履行义务。
利益相关方
教员:
- cpu@google.com
审核者:
- adanis@google.com
- rashaeqbal@google.com
- fmeawad@google.com
- gmtr@google.com
- maniscalco@google.com
- johngro@google.com
- abarth@google.com
- cpu@google.com
已咨询:
- miguelfrde@google.com
- puneetha@google.com
- mseaborn@google.com
- mcgrathr@google.com
- quiche@google.com
- mvanotti@google.com
- brunodalbo@google.com
社交化:
RFC 对 Fuchsia Performance 进行了设计审核和迭代, 和 Zircon Performance Tools WG。
设计
IOBuffer (IOB) 设计引入了一种新型内存对象,可提高 和分布式 IO。这个新对象封装了多个内存 具有不同属性和角色的单个连贯实体 有用的生命周期管理、访问控制和内核中介操作。
IOB 是具有两个端点的对等互连对象对。端点提供 与其他对等互连对象类似的生命周期管理和信号传输,例如 通道、套接字、fifos 和事件对。除了访问权限控制 由常规端点处理权限提供,则对每个内存区域的访问 可针对每个端点单独进行配置,以支持精细的安全性 属性。
由可配置的内核中介支持更强大的安全属性 此类操作通过以下方法代表用户执行内存访问: 内核系统调用,内核充当始终如一的可信中介 遵循所请求的访问规则。中介操作牺牲一些开销 稳健性和安全性,同时保持比 通信基元。
生命周期管理、内存区域封装、 可配置的访问控制和内核中介操作支持各种 支持多种共享内存通信和 IO 模式,安全性更高 它具有很强的便利性和便利性。 对象的操作。
目标
该提案的总体目标如下:
- 通过减少内存分配,缩小与单体式系统的性能差距, 系统调用以及通信和 IO 的调度开销。
- 简化共享内存生命周期管理和同步。
- 在需要时强制执行强大的安全性不变性。
- 为将来的内核和用户空间接口奠定基础。
端点
每个 IOB 有两个端点,Ep0 和 Ep1。IOB 端点句柄可能重复 并由多个进程共享底层内存对象由 只要存在至少一个端点句柄,系统就会运行 IOB,从而提供类似的 与其他对等对象的生命周期语义相同。
内存区域
IOB 封装由一个或多个内存区域组成的集合, 独立的媒体资源和访问权限控制,以支持每个区域的预期 在通信协议中发挥的作用。例如,不同的区域可能会用于 包括键/值存储、客户端协调、状态管理和 数据载荷传输。
访问权限控制
在 IOB 期间,按端点和区域组合配置内存访问 创建过程。可为每个端点授予对每个区域的不同访问权限。 在以下情况下,区域访问权限控制会与端点的句柄权限合并: 验证操作。某项操作的有效权利可能更严格 但不能超出标识名权限所允许的上限。
内存访问也可以通过内核进行中介 没有映射
下表列出了与 区域。可以设置映射(用户)和中介(内核)访问权限控制 而各区域的端点权限则由 执行操作
类型 | Ep0 | Ep1 |
---|---|---|
映射(用户) | uR0、uW0 | uR1、uW1 |
参与中介(内核) | kR0、kW0 | kR1、kW1 |
端点(句柄) | hR0、hW0 | hR1、hW1 |
映射或中介操作的有效访问权限(eRn 和 eWn) 按端点 Epn 计算的:
操作 | 读取权限 (eRn) | 写权限 (eWn) |
---|---|---|
地图 | uRn 和hRn | uWn 和hWn |
参与中介的操作 | kRn 和hRn | 千瓦和hWn |
中介访问控制和方向性
用户和内核访问控制之间的细微区别在于,前者 在绝对意义上控制读写访问,而 逻辑或方向意义例如,内核中介的读取操作 可能需要更新一个地区的簿记数据结构,以指明 从缓冲区读取了大量数据。这种意义上的只读权限 用于阻止内核更新簿记,而是指示 允许逻辑读取操作和相关的簿记更新。
示例
以下示意图显示了具有三个内存区域的 IOB, 逻辑函数。端点 Ep0 和 Ep1 以逻辑方式分配给服务器 和客户角色
- 区域 0“对照组”:
<ph type="x-smartling-placeholder">
- </ph>
- 第 0 集:RW 映射访问权限。
- 第 1 集:RO 映射访问权限。
- 用法:服务器在此区域中写入原子变量以发布状态 并协调客户的活动。
- 区域 1“字符串映射”:
<ph type="x-smartling-placeholder">
- </ph>
- 第 0 集:RO 映射访问权限。
- 第 1 集:参与中介的 WO 访问。
- 用法:客户端使用内核中介操作来内化字符串, 服务器使用映射进行无锁解读因为 客户端访问仅限中介操作,客户端不得篡改字符串 不仅可以添加新条目,还可以省去潜在的检查时间、 使用时间危害。
- 区域 2“数据环缓冲区”:
<ph type="x-smartling-placeholder">
- </ph>
- 第 0 集:RW 映射访问权限。
- 第 1 集:RW 映射访问权限。
- 用法:客户端和服务器直接通过映射访问此区域 使用商定的协议并接受潜在的完整性问题。
创建
IOB 通过使用一组选项调用 zx_iob_create
来创建。
zx_status_t zx_iob_create(uint64_t options,
const zx_iob_region_t* regions,
uint32_t region_count,
zx_handle_t* ep0_out,
zx_handle_t* ep1_out);
参数
options 是为将来的扩展程序预留的。
regions 是指向
zx_iob_region_t
区域描述数组的指针。region_count 指定区域数组中的元素数量。
ep0_out 和 ep1_out 是 IOB 的端点。
区域说明
区域的几何图形和配置由 zx_iob_region_t
指定
区域说明结构。基本结构包括
所有区域类型
struct zx_iob_region_t {
uint32_t type;
uint32_t access;
uint64_t size;
zx_iob_discipline_t discipline;
union {
zx_iob_region_private_t private_region;
uint8_t max_extension[4 * 8];
};
};
type 指定区域类型和支持该区域的内存对象。
- 类型 0:专用区域。
- 类型 1+:预留以备将来使用。
access 为每个端点指定访问控制修饰符。回忆 访问规则可以指定哪些访问位组合对 支持安全性或正确性属性。
- 位 0:第 0 集的 uR0 映射。
- 位 1:对第 0 集的 uW0 进行映射。在某些系统上可能暗示 uR0。
- 位 2:kR0 中介了对第 0 集的访问。
- 位 3:kW0 中介访问第 0 集。
- 位 4:第 1 集的 uR1 映射。
- 位 5:第 1 集的 uW1 映射。在某些系统上可能暗示 uR1。
- 位 6:kR1 参与了对第 1 集的访问。
- 位 7:kW1 参与了对第 1 集的访问。
- [8..31]:预留以供日后使用。
size 是请求的区域大小(以字节为单位)。大小会四舍五入 最高不超过系统页面大小边界针对主题使用“
zx_object_get_info
”ZX_INFO_IOB_REGIONS
用于确定区域的实际大小。discipline 用于指定要采用的内存访问规则 内核中介的操作。
区域类型 0:专用
指定 IOB 唯一拥有的私有内存对象支持的区域。 此内存对象只能通过对、 所有者的 IOO 中
struct zx_iob_region_private_t {
uint64_t options;
};
- options。
区域类型 1+:预留以备将来使用
未来的扩展可能会包含共享区域类型,其中同一内存对象 由多个 IOB 共享,以支持高效的多代理协调。
映射
IOB 的内存区域通过调用 zx_vmar_map_iob
进行映射。这场通话
与 zx_vmar_map
的语义类似。
zx_status_t zx_vmar_map_iob(zx_handle_t vmar,
zx_vm_option_t options,
size_t vmar_offset,
zx_handle_t ep,
uint32_t region_index,
uint64_t region_offset,
size_t region_len,
zx_vaddr_t* addr_out);
参数
- vmar 是要向其中映射区域的目标 VMAR 的句柄。
- options 等效于
zx_vmar_map
的 options 参数。只有 下列选项受支持。 - vmar_offset 相当于
zx_vmar_map
的 vmar_offset 参数。 - ep 是包含要映射的区域的端点。
- region_index 是要映射的内存区域的索引。
- region_offset 相当于
zx_vmar_map
的 vmo_offset 参数。 - region_len 相当于
zx_vmar_map
的 len 参数。 - addr_out 是一个输出参数,用于返回映射的虚拟地址。
支持的选项:
ZX_VM_SPECIFIC
ZX_VM_SPECIFIC_OVERWRITE
ZX_VM_OFFSET_IS_UPPER_LIMIT
ZX_VM_PERM_READ
ZX_VM_PERM_WRITE
ZX_VM_MAP_RANGE
预留供日后使用的其他选项,如果ZX_ERR_INVALID_ARGS
。
映射专用区域与映射不可调整大小的区域在功能上相同
VMO。如果映射延伸超出以下部分,则返回 ZX_ERR_BUFFER_TOO_SMALL
且 ZX_VM_ALLOW_FAULTS
未设置。
最佳做法是添加 region_offset 和 region_len 参数 映射 API采用这项最佳实践的动机包括:
- 支持拦截映射调用的排错程序。使用显式范围 简化了对有效地图区域的跟踪。
- 支持明确管理地址空间位置和 区域覆盖。
- 更笼统地说,使用
ZX_VM_SPECIFIC_OVERWRITE
。
VMAR 操作
映射的区域通常支持 VMAR 操作,例如 zx_vmar_protect
,
zx_vmar_op_range
、zx_vmar_destroy
。区域的访问权限规则可以修改
或者按照规则规范中所述限制这些操作。
对象信息查询
IOB 支持通过以下方式查询对象属性和内存区域:
zx_object_get_info
。返回的详细信息包括
为验证和安全目的而为每个区域提供支持的内存对象
主题“ZX_INFO_IOB
”
返回有关整个 IOB 实例的信息。
struct zx_iob_info_t {
uint64_t options;
uint32_t region_count;
uint8_t padding1[4];
};
成员
- options 是传递给
zx_iob_create
的 options 参数的值。 - region_count 是 IOB 中的区域数。
主题“ZX_INFO_IOB_REGIONS
”
以
zx_iob_region_info_t
区域说明元素。
struct zx_iob_region_info_t {
zx_iob_region_t region;
zx_koid_t koid;
};
- region 是区域说明,可能包含交换的访问位。
- koid 是底层内存对象的 koid。
访问修饰符位会进行交换,以便 Ep0 访问位反映 端点的访问权限,Ep1 位反映 从而确定本地和 但不知道在创建时哪个标识名是 Ep0 和 Ep1 的情况下远程处理的。
主题“ZX_INFO_PROCESS_VMOS
”
为了保持现有内存归因机制的连续性,内存对象 支持 IOB 区域按照此主题进行计数,就像常规 VMO 一样,包括 标识名和映射的可单手操作性。
对于专用区域类型,系统会为后备内存对象分配不同的 KOID 并且默认情况下与所属 IO 共享相同的名称但可以有 覆盖或修改专用区域的默认名称。
参与中介的访问
IOB 支持可配置的内核中介访问内存区域。参与中介 提供更严格的数据完整性和其他不变量 通过使用内核作为可信中间方直接访问这些后端。内核 可以保证遵循由 规则。
参与中介的读取、写入等操作...
中介操作通过 IOB 读取、写入和辅助系统调用来执行, 在将来的扩展程序中指定。访问权限规则可能会定义新的 IOB 系统调用或重载之前定义的调用,前提是用法是 语义一致性一般目标是定义一些可重复使用的系统调用 适合许多应用场景。
权限
IOB 默认拥有以下权限:
ZX_RIGHTS_BASIC
= (ZX_RIGHT_TRANSFER
|ZX_RIGHT_DUPLICATE
|ZX_RIGHT_WAIT
|ZX_RIGHT_INSPECT
)ZX_RIGHTS_IO
= (ZX_RIGHT_READ
|ZX_RIGHT_WRITE
)ZX_RIGHTS_PROPERTY
ZX_RIGHTS_MAP
ZX_RIGHTS_SIGNAL
ZX_RIGHTS_SIGNAL_PEER
属性
IOB 支持 ZX_PROP_NAME
来提供诊断和归因信息。
IOB 可以支持由区域访问规则定义的其他属性。
信号
IOB 支持类似应用信号和用户信号,以提醒用户注意重要情况。未来 扩展程序可以定义可配置的信号。
ZX_IOB_PEER_CLOSED
ZX_IOB_PEER_CLOSED
会在对
另一个端点。端点句柄以及通过
端点数量作为此用途的参考。
ZX_USER_SIGNAL_*
用户可能会引发 ZX_USER_SIGNAL_*
以指示明显情况。
内核中介访问规则
为便于执行中介操作,内核必须了解如何正确访问 内存区域区域内存访问的规则和配置是 所谓的访问规则,这可能包括:
- 记账的位置和格式。
- 覆盖/失败政策。
- 水印和超时设置。
- 内存顺序和栅栏要求。
处罚说明
访问学科使用可扩展的说明结构进行指定,其中包含 用于指定说明的类型和格式的 32 位标头。
#define ZX_IOB_DISCIPLINE_TYPE_NONE (0)
struct zx_iob_discipline_t {
uint32_t type;
union {
uint8_t max_extension[4 * 15];
};
};
未来 RFC 中可能会定义的学科示例包括:
- 提供方 / 使用方环缓冲区
- ID / Blob 映射
- 键 / 值存储
- 散布 / 收集内存文案
- 目录条目缓存
实现
初始实现是支持跟踪和日志记录的基础步骤 客户。接下来的说明是案例研究,阐述了 所定义的 IOB 功能的动机以及需要解决的潜在扩展 用例要求
系统事件跟踪
IOB 旨在为打造更安全、更高效的系统奠定基础 事件跟踪:
- 通过迁移会话协调、元数据和事件降低运行时开销 收集到 IOB 区域,因此无需调度 线程和通道 IPC。
- 通过以下方式启用低级别设施(如 FDIO 和 FIDL)的插桩 消除除 IOB 内核 API 以外的依赖项。
- 通过允许内核安全回收跟踪事件来提高稳健性 缓冲区,以避免严重的 OOM 条件,同时避免 RFC 0181: Lockless Visibilityable VMO。
系统跟踪 IOB 可以使用如下配置:
- 角色:
<ph type="x-smartling-placeholder">
- </ph>
- 第 0 集:跟踪管理器
- 第 1 集:跟踪提供程序
- 区域 0:跟踪类别位矢量
<ph type="x-smartling-placeholder">
- </ph>
- 类型:不公开
- 权限:
- 第 0 集:uR0、uW0 (R/W)
- 第 1 集:uR1 (RO)
- 处罚:无
- 用法:表示已启用跟踪的
uint64_t
位矢量数组 类别。
- 区域 1:跟踪记录类别
<ph type="x-smartling-placeholder">
- </ph>
- 类型:不公开
- 权限:
- 第 0 集:uR0、uW0 (R/W)
- 第 1 集:kW1(仅限参与中介的添加条目)
- 规则:未来的 ID/blob 分配器规则。
- 用法:表示每个类别位的序列 ID/字符串映射 跟踪提供程序使用的跟踪类别。
- 区域 2:内部化字符串
<ph type="x-smartling-placeholder">
- </ph>
- 类型:不公开
- 权限:
- 第 0 集:uR0、uW0 (R/W)
- 第 1 集:kW1(仅限参与中介的添加条目)
- 规则:未来的 ID/blob 分配器规则。
- 用法:表示 的内化字符串的序列 ID/字符串映射 跟踪事件名称和其他经常引用的名称。
- 区域 3:低速率 / 静态元数据
<ph type="x-smartling-placeholder">
- </ph>
- 类型:不公开
- 权限:
- 第 0 集:uR0、uW0 (R/W)
- 第 1 集:uR1、uW1 (R/W)
- 准则:未来的多生产方/单消费方环形缓冲区规则。
- 用法:适用于低速率 / 静态跟踪事件(例如 线程名称。这些事件通常需要正确解读 高速率缓冲区中的其他跟踪事件。
- 区域 4:高速率跟踪事件
<ph type="x-smartling-placeholder">
- </ph>
- 类型:不公开
- 权限:
- 第 0 集:uR0、uW0 (R/W)
- 第 1 集:uR1、uW1 (R/W)
- 准则:未来的多生产方/单消费方环形缓冲区规则。
- 用途:适用于高速率跟踪事件的无锁环形缓冲区。容忍数据 循环缓冲区模式下的损失。
系统日志记录
IOB 旨在为打造更安全、更高效的系统奠定基础 通过支持以下各项来记录日志:
- 隔离不同组件和/或严重级别的日志, 跨组件和跨严重级别的日志滚动。
- 避免处理当前未主动观察的日志。
- 无需使用调度线程来处理严重级别更改。
- 按组件(内存)进行资源管理和问责。
涉及以下操作者:
- 日志生产方:发出日志的组件。
- Log Manager (Archivist):将来自所有提供方的日志路由到所有使用方。
- 日志使用方:连接到日志管理器并读取合并的日志流。
系统日志记录 IOB 可以使用如下配置:
- 角色:
<ph type="x-smartling-placeholder">
- </ph>
- 第 0 集:日志管理器(档案管理员)
- 第 1 集:日志生产者(某些组件)
- 区域 0:控制
<ph type="x-smartling-placeholder">
- </ph>
- 类型:不公开
- 权限:
- 第 0 集:uR0、uW0 (R/W)
- 第 1 集:uR1 (RO)
- 处罚:无
- 用法:存储运行时配置,例如最低严重级别。还可能会 存储有关日志循环缓冲区最大大小的信息, 具体取决于对内存管理的要求。
- 区域 1:字符串表
<ph type="x-smartling-placeholder">
- </ph>
- 类型:不公开
- 权限:
- 第 0 集:uR0 (RO)
- 第 1 集:kW1 (WO)
- 规则:未来的 ID/blob 分配器规则。
- 用法:表示 的内化字符串的序列 ID/字符串映射 经常引用的日志字符串、标记、键、元数据。
- 区域 2:日志环形缓冲区
<ph type="x-smartling-placeholder">
- </ph>
- 类型:不公开
- 权限:
- 第 0 集:uR0、uW0 (R/W)(对 R/W/C 指针写入和运行中写入操作 计数器)
- 第 1 集:kW1 (WO)
- 准则:未来的多生产方/单消费方环形缓冲区规则。
- 用途:用于日志记录的无锁环形缓冲区。容忍数据丢失 循环缓冲模式我们计划从 生产者直接从 Manager 读取。可能会在以下日期之前转为直接访问 生产者。
实现步骤
实现过程将遵循一系列开发步骤:
- 在 @next 属性下引入 IOB 接口:
<ph type="x-smartling-placeholder">
- </ph>
- 实现基本 IOB 调度程序。
- 实现系统调用和通用验证。
- 对基于 IOB 的跟踪和日志记录以及必要的 IOB 扩展进行原型设计 放在分支中。
- 为必要的扩展编写并批准 RFC。
- 添加扩展程序并移除 @next 属性。
- 在 IOB 上执行 rebase 跟踪和日志记录,并将现有客户软传输到 新界面
性能
可以通过比较端到端延迟时间和 在弃用和移除当前 跟踪/日志记录实现。正在进行的基准测试可能包括缓冲区内存 出处(虚拟机开销)、关键操作的延迟时间/并发测试,以及 分配测试来验证稳态内存消耗属性。
工效学设计
从设计上来讲,IOB 比 VMO、事件、 以及实现类似功能所需的 IPC 对象。从始至终, 此外,与 Google Cloud Storage 端点的 多个对象,并且有关内存访问的规则比
向后兼容性
IOB 仅影响 FIDL 文件源代码兼容性和 ABI 传输格式 通过为语言引入新的句柄类型来实现兼容性, 会影响向后兼容性。
安全注意事项
共享内存用例始终存在一些安全潜力 漏洞大多数 IOB 用途不会带来共享 VMO 的新危险 不受。不过,IOB 确实可以降低出现某些错误的风险, 关于权限和内存访问生命周期的更严格的规则。
将省略和检查时间复制到使用时间危害
共享内存用例中出现的一类重要的软件 bug 是 所谓的“检查时间到使用时间危害”(TOCTOU)。TOCTOU 危害 由检查某个状态与使用 检查后,状态在检查和使用期间可能失效 结果的一部分。
要避免开放式共享内存用例中的 TOCTOU 危险, 具有挑战性,通常需要将数据从共享内存区域复制到 避免在验证期间或之后进行修改。即使是复制 使用时,必须小心防止复制省略,因为编译器 优化副本并直接在共享内存区域执行操作,除非 采用具体的干预措施。
内核中介操作可以通过 可以保证内核遵循元数据更新、载荷 访问的存储顺序。例如,在使用环形缓冲区时 则保证内核不会覆盖记录的内容 直到使用方确认可以通过更新环形缓冲区来确认操作是安全的 避免在验证前复制有效负载。
尽管有上述规定,用户仍须负责正确应用 或特定语言的等效项 优化导致的正确性危害。为了减轻用户的负担, Fuchsia SDK 将包含用于实现受支持语言的库, 正确的访问例程。准则规范 还应包含足够的详细信息,以确保安全正确应用 访问规则
隐私注意事项
除了已有的隐私保护注意事项外,IOOB 不会引入其他新的隐私注意事项 适用于 IPC 和共享内存用例系统最初的应用场景 事件跟踪和日志记录将继续履行相同的隐私权义务。
测试
测试包括以下内容:
- IOB 的核心测试。
- 用于新类型的处理类型验证的 FIDL 一致性测试。
- 扩展了 Fuchsia 跟踪系统测试,以包含特定于 IOB 的测试 功能
- 对系统日志记录测试进行了扩展,以包含 IOB 专用功能。
不依赖于底层实现的现有跟踪和日志记录测试 实现细节应继续有效并顺利传递。
文档
文档更新包括:
- 系统调用引用。
- 内核概念。
- FIDL 句柄类型。
缺点、替代方案和未知问题
实施此方案的成本相对较低, 基于现有机器构建,适用于虚拟内存和对等调度程序。通过 独特的功能集中在非对称访问权限、内核中介区域 以及“关闭时取消映射”功能