LWN:逐步统一kselftests和KUnit!

关注了就能看到更多这么棒的文章哦~

Toward the unification of kselftests and KUnit

By Jonathan Corbet
July 8, 2025
Gemini flash translation
https://lwn.net/Articles/1029077/

多年来,内核项目一直缺乏正式的测试机制;人们常开玩笑说,测试是该项目留住用户的主要原因。虽然许多类型的内核测试只能在特定硬件存在的情况下进行,但内核的其他部分可以得到更广泛的测试。然而,随着时间的推移,内核已经获得了两个独立的测试框架以及随之而来的越来越多的自动化测试。这两个框架——Kselftests 和 KUnit——对测试问题采取了不同的方法;现在,Thomas Weißschuh 的这个补丁系列旨在将它们整合起来。

Kselftests 和 KUnit

Kselftests 于 2012 年由 Frederic Weisbecker 首次添加,第一个测试 专注于 x86 架构上断点(breakpoints)的处理。这些自测试在用户空间运行,调用正常的内核系统调用(system-call)接口。多年来,Kselftests 已经发展出一套基于测试一切协议(Test Anything Protocol, TAP) 的测试套件结构,以及一套用于创建测试的函数、宏和 Makefile 支持。

在当前的内核中,kselftests 目录 包含 100 多个子目录,每个子目录都包含特定子系统的测试。其中有专注于系统调用、架构支持、sysctl 配置项、内核行为(例如系统映射(system mappings)的密封)、/proc 文件以及少数设备驱动程序等的测试。虽然这套测试并非(也可能永远不会)完整,但成功运行 Kselftests 足以让人相信内核的重要部分正在按预期工作。

KUnit 是一种不同的机制;其测试被构建为内核模块(kernel modules),并在内核内部运行。这赋予了 KUnit 测试验证用户空间无法访问的单个内核函数(kernel functions)操作的能力。KUnit 测试可以加载到正在运行的内核中并随时运行;它们也可以构建到内核中并在每次启动时自动运行。KUnit 也提供了一套支持函数,使测试变得更简单;它围绕 TAP 的一个版本,名为 KTAP,进行构建。

KUnit 于 2019年由 Felix Guo 添加。多年来,它也积累了越来越多的测试;DRM(图形)子系统有相当多的测试,并且有一组重要的测试覆盖了内核 `lib/` 目录中发现的通用支持例程。例如,请参阅 这组哈希表(hash-table)测试。

内核的两个测试套件针对测试问题的不同方面,因此它们最终采用不同的设计并非完全出乎意料。Kselftests 从外部探查内核,确保其用户空间应用程序二进制接口(user-space ABI)按预期运行,而 KUnit 则在内部工作,测试用户空间无法访问的组件。这种分离使得每个测试套件都能在其目标领域内发展,但也导致了一些偶尔的困扰。

或许殊途同归

Weißschuh 的工作似乎是由嵌入式开发人员感受到的一些特定需求所驱动的。KUnit 测试相对容易在新嵌入式系统上运行;它们可以构建到运行在这些系统上的内核中,无需额外的支持。Kselftests 测试则需要在目标系统上有一个完全正常工作的用户空间才能运行。用户空间和测试本身都必须与内核分开加载到目标系统上,使得整体测试任务更加困难。

Weißschuh 正在寻求的解决方案是整合这两个测试套件,特别是能够将 Kselftests 构建到内核中,并从 KUnit 框架中运行它们。一个成功的解决方案将允许将内核和一套完整的测试作为单个二进制文件加载到目标系统上,从而简化在新系统上使内核进入完全工作状态的过程。当然,要实现这一点,需要克服一些障碍。

Kselftests 被设计为独立程序运行,而不是像 KUnit 测试那样作为内核模块中的函数。Weißschuh 的系列补丁继续单独构建这些测试,但生成的二进制文件被链接到新的 `kunit-uapi` 模块中,然后该模块在单独的 per-CPU 内核线程(kernel thread)中运行它们。此代码基于最初作为 bpfilter 的一部分引入的用户模式辅助(user-mode-helper)功能,尽管需要进行多项更改。

用户空间程序期望有一个可用的 C 库;这正是 Weißschuh 正试图避免的用户空间设置的一部分。幸运的是,自 5.1 版本发布以来,内核碰巧拥有自己的最小 C 库实现,即 nolibc。它并非一个完整的实现,但包含足够的支撑来运行大部分 kselftest 套件。然而,这些测试的构建必须修改为使用 nolibc 而非系统的 C 库。

`kunit-uapi` 模块必须完成为每个 kselftest 创建足够环境的其余工作,以及实际运行测试。这需要访问内核目前未导出给模块的功能——例如 `kernel_execve()`、`replace_fd()`、`create_pipe_files()` 和 `do_exit()` 等内核函数。该系列补丁包含一个导出这些符号以及其他符号的补丁。该导出仅限于 `kunit-uapi` 模块,使用刚刚在 6.16 中添加的 `EXPORT_SYMBOL_GPL_FOR_MODULES()` 宏;这是最初于 2024 年提出的受限命名空间(restricted-namespace)功能的当前形式。

新导出的函数用于为每个测试设置标准输入、输出和错误流(输入在所有实际用途中都被设置为 `/dev/null`),挂载 `/proc`,运行测试本身,并在之后进行清理。测试的 TAP 输出被传回到 KUnit 框架,以便与其余测试结果一起报告。

所有这些工作都为打包现有 Kselftests 奠定了基础,但尚未完全实现该目标。相反,在该系列补丁结束时唯一启用的测试是一个简单的示例测试和一个验证 `/proc` 挂载的测试。引入现有测试将需要为每个测试添加一些“粘合”代码,使其嵌入到可加载模块中并在正确时间运行。一种更自动化的测试整合方式是未来的愿望清单,但目前尚未实现。

实际测试的整合可能正在等待围绕其框架的共识。截至撰写本文时,该系列补丁已是第四个版本,最重要的顾虑似乎已得到解决;最新的评论主要集中在相对较小的问题上。假设最大的问题已基本克服,核心框架可能会相对快速地进入主线(mainline);整合所有实际测试的工作很可能是接下来的任务。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值