Linux 内核 ABI 文档体系:从 abi-stable-files.rst 看懂内核-用户空间接口的稳定性契约
本文围绕 Linux 内核文档中的 abi-stable-files.rst 展开,讲清楚这个文件在内核文档体系中的角色:它如何通过 kernel-abi reST 指令自动生成“稳定 ABI 文件”的完整文档页,其背后依赖的四级 ABI 稳定性分类模型、每个 ABI 文档文件的标准字段格式、接口在不同稳定性级别之间的迁移规则,以及如何结合源码解析器(AbiParser)验证一份 ABI 文档的写法是否合规。读完本文,你将能够独立阅读 Documentation/ABI/ 下的任意条目、判断某接口的承诺程度,并在为自研接口编写 ABI 文档时遵循内核社区的统一规范。
一、abi-stable-files.rst 是什么:一个几乎“零内容”的自动生成页
abi-stable-files.rst 的原始内容只有短短两行有效语句:
.. kernel-abi:: stable
:no-symbols:
这正是它的设计精髓:页面本身不写任何接口说明,全部内容在 Sphinx 构建文档时被动态生成。该文件位于 admin-guide 文档树 中,作为 abi.rst 下 “ABI files” 章节的组成部分,与 abi-testing-files、abi-obsolete-files、abi-removed-files 三个姊妹文件共同构成完整的 ABI 文件文档集。
1.1 kernel-abi 指令的参数与选项
kernel-abi 指令由 Documentation/sphinx/kernel_abi.py 实现,其完整调用形式为:
.. kernel-abi:: <ABI 目录位置>
:debug:
- 位置参数(必填):指定要解析的 ABI 子目录。
abi-stable-files.rst传的是stable,即解析 Documentation/ABI/stable 目录下的所有文件;而 abi.rst 开头的.. kernel-abi:: README则直接渲染 Documentation/ABI/README 这份总纲。 :no-symbols:选项:只输出“文件型”ABI(sysfs、configfs、procfs 等文件路径接口),跳过“符号型”ABI(函数、数据结构、Kconfig 符号等 C 标识符)。abi-stable-files.rst之所以必须加这个选项,是因为它属于 “ABI files” 章节,与abi-stable.rst(symbols 章节)职责分离,避免同一接口在两个页面重复出现。:no-files:选项:与:no-symbols:相反,只输出文件型 ABI。:debug:选项:把生成的原始 reST 以带行号的代码块形式嵌入页面,方便维护者排查解析问题。
从 kernel_abi.py 的 option_spec 可以看到这三个选项均为 flag 类型;默认情况下(不带任何选项)symbols 与 files 都会输出。
1.2 构建时的解析流程
指令执行时(kernel_abi.py 的 run 方法):
- 通过
get_kernel_abi()全局单例初始化解析器,调用AbiParser对Documentation/ABI目录做一次性解析(parse_abi()),并执行check_issues()做一致性检查; AbiParser遍历目标子目录,按filter_path=stable过滤出stable/下的条目,逐条生成 reST 片段;- 每个被引用的 ABI 源文件都会通过
env.note_dependency(fname)登记为 Sphinx 构建依赖(kernel_abi.py),即你修改任何一个 ABI 条目文件,增量构建都会自动重排对应文档页; - 解析器实现位于 tools/lib/python/abi/abi_parser.py,配套的正则定义在 tools/lib/python/abi/abi_regex.py,内核符号提取逻辑在 tools/lib/python/abi/system_symbols.py。由于 Sphinx 不擅长一次性解析超大文档,代码中特意“逐个 symbol 分批
nested_parse”,保证上千个条目的页面也能顺利构建。
因此,Documentation/admin-guide/abi-stable-files.html 这类成品页面的每一条接口文档,其真实“源头”都是 Documentation/ABI/stable/ 目录下的一个纯文本文件(当前共 52 个条目文件,如 sysfs-block、sysfs-nvme、configfs-nvmet、syscalls 等)。
二、四级 ABI 稳定性模型:稳定接口背后的承诺等级
要理解“stable files”到底承诺了什么,必须先读 Documentation/ABI/README。它定义了内核与用户空间之间接口的四级稳定性分类,对应 Documentation/ABI/ 下的四个子目录:
| 目录 | 级别 | 对用户空间的含义 |
|---|---|---|
| stable/ | 稳定 | 开发者已明确定义为稳定。用户空间程序可无限制使用,向后兼容性至少保证 2 年;大多数接口(如系统调用)被期望永不改变、永久可用 |
| testing/ | 测试 | 主体开发已完成、感觉趋于稳定。可以扩展新功能但不允许破坏现有接口(除非发现严重错误或安全问题)。用户空间可以开始依赖,但必须知晓迁移到 stable 之前仍可能变化;强烈建议在此类条目的 Users: 字段登记自己的项目名,以便内核开发者在变更时通知 |
| obsolete/ | 废弃 | 仍存在于内核中,但已标记为将来某个时间点移除。条目描述中必须写明废弃原因和预计移除时间 |
| removed/ | 已移除 | 记录已经从内核中删除的历史接口(如 devfs、ip_queue、sysfs-mce 等) |
abi-stable-files.rst 生成的文档页,其价值正来源于这个承诺:列在 stable/ 下的 sysfs/configfs/procfs 文件接口,用户空间程序可以跨发行版、跨内核大版本安全依赖,内核侧至少 2 年内不会改变其语义或删除它。
三、ABI 文档文件的标准字段格式
README 规定,四个目录下的每一个 ABI 条目文件都必须包含以下字段(以 tab 缩进的简单标记编写,需兼容 reST):
What: 接口的简短描述(接口名/路径)
Date: 创建日期
KernelVersion:(可选)该功能首次出现的内核版本。
注意:git 历史往往能提供更精确的版本信息,故此字段可省略
Contact: 接口的主要联系人(可以是邮件列表)
Description: 对接口及其用法的详细描述
Users: 希望在接口变更时被通知的所有用户(项目名)。
对 "testing" 阶段的接口极其重要,便于内核与用户空间开发者
协作,避免接口以不可接受的方式被破坏,同时收集反馈
以确认接口是否已足够成熟、无需进一步修改
README 还特别强调一条格式纪律:字段值必须使用与 reST 兼容的简单记法,且文件不应带顶级标题(即不要写 === 形式的 foo 标题块),因为 Sphinx 会把多个条目合并渲染到同一个页面,重复的顶级标题会破坏文档结构。
3.1 真实条目示例:configfs-nvmet
以 Documentation/ABI/stable/configfs-nvmet 为例,一个典型的 stable 条目长这样:
What: /config/nvmet/ports/N/addr_adrfam
What: /config/nvmet/ports/N/addr_portid
What: /config/nvmet/ports/N/addr_traddr
What: /config/nvmet/ports/N/addr_trsvcid
What: /config/nvmet/ports/N/addr_trtype
What: /config/nvmet/ports/N/addr_treq
Date: June 2016
KernelVersion: 4.8
Contact: Christoph Hellwig <hch@lst.de>
Description:
Address attributes for an NVMe-oF target port.
addr_adrfam: Shows or sets the address family. Accepted
values: "pcie", "ipv4", "ipv6", "ib", "fc", "pci", "loop".
addr_trtype: Shows or sets the transport type. Accepted
values: "rdma", "fc", "tcp", "pci", "loop". ...
All attributes require the port to be disabled before
modification.
这个例子展示了几个关键惯例:
- 一个文件可登记多个
What::同一组语义相关的接口(这里是 NVMe-oF 目标端口的一组地址属性)聚在一个条目文件里,各自独立成What:行; KernelVersion:用于锁定能力边界:4.8明确告诉用户“低于 4.8 的内核上不要使用该接口”,用户空间程序可据此做版本探测;- Description 描述可写语义:如 “Shows or sets...” 区分只读/可写属性,并给出合法取值枚举(
"pcie", "ipv4", ...)与操作前置条件(“port 必须先 disable 才能修改”)——这些正是用户空间程序编码时需要逐字遵守的契约。
类似地,Documentation/ABI/stable/sysfs-devices、Documentation/ABI/stable/sysfs-block、Documentation/ABI/stable/sysfs-nvme 等条目分别锚定了设备树通用属性、块设备属性和 NVMe 控制器属性的稳定语义,是编写任何设备管理工具(如存储管理、总线枚举程序)时的第一手参考。
3.2 testing 与 stable 的规模差异
当前仓库中 Documentation/ABI/testing 约有 600 余个条目文件,而 Documentation/ABI/stable 仅 52 个——从源码结构看,绝大多数新接口都先停留在 testing 阶段,“进入 stable”本身是一次严肃的成熟度评审,这也是 stable 文档页对稳定性承诺可信度高的原因。
四、接口在稳定性级别之间的迁移规则
README 定义了级别迁移的状态机,理解它对评估接口生命周期至关重要:
- stable → obsolete:允许迁移,但前提是履行了规范的通知义务(通常意味着通知了
Users:字段中登记的所有用户); - obsolete → 从内核移除:允许,但必须满足条目中记录的时间期限——“obsolete 条目描述的移除时间到了,才能真正删代码”;
- testing → stable:由开发者判断接口开发完成时执行;而 testing 接口若要被移除,必须先经过 obsolete 阶段,不允许直接从内核树中消失;
- 新接口初始放在哪个级别,由引入它的开发者自行决定。
也就是说,一个 stable 接口若要被废弃,至少要走 stable → obsolete(含通知与等待期)→ removed 的完整链路。用户空间程序据此可以推断:只要接口仍在 stable/ 中,删除它就不符合内核自身的文档规范,可以放心依赖;若看到它出现在 obsolete/ 中,则应立即根据条目中承诺的移除时间点做迁移规划。
五、明确不属于 ABI 的东西:两条红线
README 末尾专门列出“在任何情况下都不应被视为稳定”的内容,这是使用 stable 文档页时必须对照的红线清单:
- Kconfig 符号不是 ABI:用户空间不得依赖任何特定 Kconfig 符号的存在与否——无论是在
/proc/config.gz、安装到/boot的.config副本,还是任何内核构建流程的调用中; - 内核内部符号不是 ABI:不得依赖
System.map文件或内核二进制中任何内核符号的存在、缺失、位置或类型。README 进一步指向 Documentation/process/stable-api-nonsense.rst,其中系统性地论证了“对外暴露内部 C API”为何是错误方向。
这解释了为何 kernel-abi 指令区分 “symbols”(C 符号,仅极少数被承诺为符号级 ABI)与 “files”(文件系统接口,是用户空间实际依赖的主渠道):用户空间可信赖的稳定性契约,绝大多数体现在 sysfs/configfs/procfs 文件与系统调用上,而非内核内部函数。
六、实践路径:如何查阅与编写 ABI 条目
查阅某接口的稳定性承诺:
- 先在 Documentation/ABI/stable/ 下按命名约定(
sysfs-、configfs-、procfs-前缀加驱动名/设备名)搜索对应文件,例如查找块设备接口看 Documentation/ABI/stable/sysfs-block; - 找不到再看 Documentation/ABI/testing/——能找到说明接口“可用但可能有变”,应关注
Users:字段并考虑登记自己的项目; - 已构建好的 HTML 版本对应
Documentation/admin-guide/下的 abi.rst 章节:ABI symbols下的abi-stable/abi-testing等页展示符号型 ABI,ABI files下的abi-stable-files/abi-testing-files等页展示文件型 ABI,全部由同一解析管线自动生成。
为自有接口新增条目(遵循 README 约定):
- 在合适的级别目录下新建文件,使用 tab 缩进的
What:/Date:/KernelVersion:/Contact:/Description:/Users:字段; - 不要加顶级标题;字段值保持 reST 兼容的简单记法;
- 文件类型条目只会被
:no-files:/:no-symbols:对应的那个页面收录——文件路径类接口(/sys/...、/config/...)放进条目后会出现在abi-*-files页,而 C 符号类条目出现在abi-*符号页; - 若处于 testing 阶段,务必填写
Users:,这是内核社区向用户空间承诺“变更前通知”的登记簿。
七、小结
abi-stable-files.rst 虽只有两行指令,却是 Linux 内核面向用户空间的稳定接口契约目录的入口:它通过 kernel_abi.py 提供的 kernel-abi 指令与 tools/lib/python/abi/ 下的解析器,把 Documentation/ABI/stable/ 下 52 个条目文件自动聚合为一页完整文档;而 Documentation/ABI/README 定义的四级稳定性模型、六字段标准格式与迁移规则,则保证了页面上每一条接口都带有可核验的承诺等级——stable 意味着至少两年的向后兼容保障,testing 意味着可用但需登记并关注变更,obsolete 意味着已进入有明确时间表的废弃流程。对于任何需要跨内核版本稳定运行的用户空间程序而言,这份文档与其背后的条目文件,就是接口选型的权威依据。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00