首页
/ Linux 内核 ABI 文档体系:从 abi-stable-files.rst 看懂内核-用户空间接口的稳定性契约

Linux 内核 ABI 文档体系:从 abi-stable-files.rst 看懂内核-用户空间接口的稳定性契约

2026-09-06 15:41:20作者:侯霆垣

本文围绕 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-filesabi-obsolete-filesabi-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.pyoption_spec 可以看到这三个选项均为 flag 类型;默认情况下(不带任何选项)symbols 与 files 都会输出。

1.2 构建时的解析流程

指令执行时(kernel_abi.pyrun 方法):

  1. 通过 get_kernel_abi() 全局单例初始化解析器,调用 AbiParserDocumentation/ABI 目录做一次性解析parse_abi()),并执行 check_issues() 做一致性检查;
  2. AbiParser 遍历目标子目录,按 filter_path=stable 过滤出 stable/ 下的条目,逐条生成 reST 片段;
  3. 每个被引用的 ABI 源文件都会通过 env.note_dependency(fname) 登记为 Sphinx 构建依赖(kernel_abi.py),即你修改任何一个 ABI 条目文件,增量构建都会自动重排对应文档页
  4. 解析器实现位于 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-blocksysfs-nvmeconfigfs-nvmetsyscalls 等)。

二、四级 ABI 稳定性模型:稳定接口背后的承诺等级

要理解“stable files”到底承诺了什么,必须先读 Documentation/ABI/README。它定义了内核与用户空间之间接口的四级稳定性分类,对应 Documentation/ABI/ 下的四个子目录:

目录 级别 对用户空间的含义
stable/ 稳定 开发者已明确定义为稳定。用户空间程序可无限制使用,向后兼容性至少保证 2 年;大多数接口(如系统调用)被期望永不改变、永久可用
testing/ 测试 主体开发已完成、感觉趋于稳定。可以扩展新功能但不允许破坏现有接口(除非发现严重错误或安全问题)。用户空间可以开始依赖,但必须知晓迁移到 stable 之前仍可能变化;强烈建议在此类条目的 Users: 字段登记自己的项目名,以便内核开发者在变更时通知
obsolete/ 废弃 仍存在于内核中,但已标记为将来某个时间点移除。条目描述中必须写明废弃原因和预计移除时间
removed/ 已移除 记录已经从内核中删除的历史接口(如 devfsip_queuesysfs-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-devicesDocumentation/ABI/stable/sysfs-blockDocumentation/ABI/stable/sysfs-nvme 等条目分别锚定了设备树通用属性、块设备属性和 NVMe 控制器属性的稳定语义,是编写任何设备管理工具(如存储管理、总线枚举程序)时的第一手参考。

3.2 testing 与 stable 的规模差异

当前仓库中 Documentation/ABI/testing 约有 600 余个条目文件,而 Documentation/ABI/stable 仅 52 个——从源码结构看,绝大多数新接口都先停留在 testing 阶段,“进入 stable”本身是一次严肃的成熟度评审,这也是 stable 文档页对稳定性承诺可信度高的原因。

四、接口在稳定性级别之间的迁移规则

README 定义了级别迁移的状态机,理解它对评估接口生命周期至关重要:

  1. stable → obsolete:允许迁移,但前提是履行了规范的通知义务(通常意味着通知了 Users: 字段中登记的所有用户);
  2. obsolete → 从内核移除:允许,但必须满足条目中记录的时间期限——“obsolete 条目描述的移除时间到了,才能真正删代码”;
  3. testing → stable:由开发者判断接口开发完成时执行;而 testing 接口若要被移除,必须先经过 obsolete 阶段,不允许直接从内核树中消失;
  4. 新接口初始放在哪个级别,由引入它的开发者自行决定

也就是说,一个 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 条目

查阅某接口的稳定性承诺

  1. 先在 Documentation/ABI/stable/ 下按命名约定(sysfs-configfs-procfs- 前缀加驱动名/设备名)搜索对应文件,例如查找块设备接口看 Documentation/ABI/stable/sysfs-block
  2. 找不到再看 Documentation/ABI/testing/——能找到说明接口“可用但可能有变”,应关注 Users: 字段并考虑登记自己的项目;
  3. 已构建好的 HTML 版本对应 Documentation/admin-guide/ 下的 abi.rst 章节:ABI symbols 下的 abi-stable/abi-testing 等页展示符号型 ABI,ABI files 下的 abi-stable-files/abi-testing-files 等页展示文件型 ABI,全部由同一解析管线自动生成。

为自有接口新增条目(遵循 README 约定):

  1. 在合适的级别目录下新建文件,使用 tab 缩进的 What:/Date:/KernelVersion:/Contact:/Description:/Users: 字段;
  2. 不要加顶级标题;字段值保持 reST 兼容的简单记法;
  3. 文件类型条目只会被 :no-files:/:no-symbols: 对应的那个页面收录——文件路径类接口(/sys/.../config/...)放进条目后会出现在 abi-*-files 页,而 C 符号类条目出现在 abi-* 符号页;
  4. 若处于 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 意味着已进入有明确时间表的废弃流程。对于任何需要跨内核版本稳定运行的用户空间程序而言,这份文档与其背后的条目文件,就是接口选型的权威依据。

登录后查看全文
热门项目推荐
相关项目推荐