FreeBSD 中文社区 2025 第二季度问卷调查
FreeBSD 中文社区(CFC)
VitePress 镜像站QQ 群 787969044视频教程Ⅰ视频教程Ⅱ
  • FreeBSD 从入门到追忆
  • 中文期刊
  • 状态报告
  • 发行说明
  • 手册
  • 网络文章集锦
  • 笔记本支持报告
  • Port 开发者手册
  • 架构手册
  • 开发者手册
  • 中文 man 手册
  • 文章
  • 书籍
  • FreeBSD 中文期刊
  • 编辑日志
  • 2025-123 下游项目
    • FreeBSD 发布工程:新主管上任
    • GhostBSD:从易用到挣扎与重生
    • BSD Now 与将来
    • 字符设备驱动教程(第三部分)
    • 学会走路——连接 GPIO 系统
    • FreeBSD 中对 SYN 段的处理
    • FreeBSD 2024 年秋季峰会
  • 2024-1112 虚拟化
    • 字符设备驱动程序教程(第二部分)
    • 面向 Linux 和 Windows 用户的 bhyve
    • Xen 与 FreeBSD
    • Wifibox:一种嵌入式虚拟化无线路由器
    • 嵌入式 FreeBSD:Fabric——起步阶段
    • DGP:一种新的数据包控制方法
    • 会议报告:我在都柏林的 EuroBSDCon 体验
  • 2024-0910 内核开发
    • 字符设备驱动程序教程
    • VPP 移植到了 FreeBSD:基础用法
    • 利用 Kyua 的 Jail 功能提升 FreeBSD 测试套件的并行效率
    • FreeBSD 上的 Valgrind
    • 嵌入式 FreeBSD:探索 bhyve
    • TCP/IP 历险记:FreeBSD TCP 协议栈中的 Pacing
    • 实用软件:实现无纸化(Paperless)
  • 2024-0708 存储与文件系统
    • FreeBSD 中的 NVMe-oF
    • FreeBSD iSCSI 入门
    • 使用 ZFS 原生加密保护数据
    • 嵌入式 FreeBSD:打造自己的镜像
    • TCP LRO 简介
    • 基于 Samba 的时间机器备份
  • 2024-0506 配置管理对决
    • 基本系统中的 mfsBSD
    • rdist
    • Hashicorp Vault
    • 在 GitHub 上向 FreeBSD 提交 PR
    • 悼念 Mike Karels
    • 2024 年 5-6 月来信
    • 嵌入式 FreeBSD 面包板
    • TCP/IP 历险记:TCP BBLog
    • 实用软件:开发定制 Ansible 模块
  • 2024-0304 开发工作流与集成
    • FreeBSD 内核开发工作流程
    • FreeBSD 与 KDE 持续集成(CI)
    • 更现代的内核调试工具
    • 从零开始的 ZFS 镜像及 makefs -t zfs
    • 提升 Git 使用体验
  • 2024-0102 网络(十周年)
    • FreeBSD 中的 RACK 栈和替代 TCP 栈
    • FreeBSD 14 中有关 TCP 的更新
    • if_ovpn 还是 OpenVPN
    • SR-IOV 已成为 FreeBSD 的重要功能
    • FreeBSD 接口 API(IfAPI)
    • BATMAN:更优的可移动热点网络方式
    • 配置自己的 VPN——基于 FreeBSD、Wireguard、IPv6 和广告拦截
    • 实用软件:使用 Zabbix 监控主机
  • 2023-1112 FreeBSD 14.0
    • LinuxBoot:从 Linux 启动 FreeBSD
    • FreeBSD 容器镜像
    • 现在用 Webhook 触发我
    • 新的 Ports 提交者:oel Bodenmann (jbo@freebsd.org)
  • 2023-0910 Port 与软件包
    • 回忆录:与 Warner Losh(@imp)的访谈
    • 在你自己的仓库中定制 Poudriere 源
    • Wazuh 和 MITRE Caldera 在 FreeBSD Jail 中的使用
    • PEP 517
    • CCCamp 2023 旅行报告
  • 2023-0708 容器与云
    • 在 Firecracker 上的 FreeBSD
    • 使用 pot 和 nomad 管理 Jail
    • 会议报告:C 与 BSD 正如拉丁语与我们——一位神学家的旅程
    • 抒怀之旅:与 Doug Rabson 的访谈
    • 基于 Jail 的广告拦截教程
    • 我们收到的来信
  • 2023-0506 FreeBSD 三十周年纪念特刊
    • CheriBSD 近十多年的历程
    • AArch64:成为 FreeBSD 新的一级架构
    • 岁月如梭:我个人的时间线
    • 安装 FreeBSD 1.0:回顾 30 年前
    • ZFS 是如何进入 FreeBSD 的呢?
    • 我不是来自约克郡的,我保证!
    • 回忆录:采访 David Greenman Lawrence
    • FreeBSD 和早期的 Unix 社区
    • 早期的 FreeBSD 移植
    • FreeBSD 30 周年:成功的秘诀
    • FreeBSD 在日本:回忆之旅与今日之实
  • 2023-0304 嵌入式
    • CheriBSD port 和软件包
    • 让我们来试试 ChatGPT
    • GPU 直通
  • 2023-0102 构建 FreEBSD Web 服务器
    • ZFS 的原子 I/O 与 PostgreSQL
    • 虚拟实验室——BSD 编程研讨会
    • ZFS 简介
    • 会议报告:落基山庆祝女性计算机科学家
    • 进行中的工作/征求反馈:数据包批处理
    • 基金会与 FreeBSD 桌面
  • 2022-1112 可观测性和衡量标准
    • 在 FreeBSD 的 DDB 内核调试器中编写自定义命令
    • DTrace:老式跟踪系统的新扩展
    • 基于证书的 Icinga 监控
    • 活动监控脚本(activitymonitor.sh)
    • 实用 IPv6(第四部分)
    • EuroBSDCon 会议报道
    • 实用 Port:Prometheus 的安装与配置
    • 书评:《用火解决问题:管理老化的计算机系统(并为现代系统保驾护航)》Kill It with Fire: Manage Aging Computer Systems (and Future Proof Modern Ones)
  • 2022-0910 安全性
    • CARP 简介
    • 重构内核加密服务框架
    • PAM 小窍门
    • SSH 小窍门
    • 实用 IPv6(第三部分)
    • 书评:Understanding Software Dynamics(深入理解软件性能——一种动态视角)—— Richard L. Sites 著
    • 访谈:保障 FreeBSD 安全性
    • MCH 2022 会议报告
  • 2022-0708 科研、系统与 FreeBSD
    • 在 FreeBSD 上构建 Loom 框架
    • 教授本科生 Unix 课程
    • FreeBSD 入门研讨会
    • 实用 IPv6(第二部分)
    • 在 2022 年及以后推广 FreeBSD
    • 进行中的工作/征求反馈:Socket 缓冲区
    • FreeBSD 开发者峰会报告
    • 支持 Electromagnetic Field 2022
  • 2022-0506 灾难恢复
    • 使用 FreeBSD 构建高弹性的私有云
    • LLDB 14 —— FreeBSD 新调试器
    • 实用 IPv6(第一部分)
    • 利用 netdump(4) 进行事后内核调试
    • 进行中的工作/征求反馈:FreeBSD 启动性能
    • 实用 Port:在 OpenZFS 上设置 NFSv4 文件服务器
  • 2022-0304 ARM64 是一级架构
    • FreeBSD/ARM64 上的数据科学
    • Pinebook Pro 上的 FreeBSD
    • 嵌入式控制器的 ACPI 支持
    • 进行中的工作/征求反馈:Lumina 桌面征集开发人员
    • 实用 Port:如何设置 Apple 时间机器
  • 2022-0102 软件与系统管理
    • 为 FreeBSD Ports 做贡献
    • 使用 Git 贡献到 FreeBSD Ports
    • CBSD:第一部分——生产环境
    • 将 OpenBSD 的 pf syncookie 代码移植到 FreeBSD 的 pf
    • 进行中的工作/征求反馈:mkjail
    • 《编程智慧:编程鬼才的经验和思考》(The Kollected Kode Vicious)书评
    • 会议报告:EuroBSDCon 2021 我的第一次 EuroBSDCon:一位新组织者的视角
  • 2021-1112 存储
    • 开放通道 SSD
    • 构建 FreeBSD 社区
    • 与完美操作系统同行 27 年
    • 进行中的工作/征求反馈:OccamBSD
    • 通过 iSCSI 导入 ZFS ZIL——不要在工作中这样做——就像我做的那样
  • 2021-0910 FreeBSD 开发
    • FreeBSD 代码审查与 git-arc
    • 如何为 FreeBSD 实现简单的 USB 驱动程序
    • 内核开发技巧
    • 程序员编程杂谈
  • 2021-0708 桌面/无线网
    • 通往 FreeBSD 桌面的直线路径
    • FreeBSD 13 中的人机接口设备 (HID) 支持
    • Panfrost 驱动程序
    • 用 Git 更新 FreeBSD
    • FreeBSD 的新面孔
    • 想给你的桌面加点佐料?
  • 2021-0506 安全
    • 七种提升新安装 FreeBSD 安全性的方法
    • copyinout 框架
    • 使用 TLS 改善 NFS 安全性
    • Capsicum 案例研究:Got
    • 对 Jail 进行安全扫描
  • 2021-0304 FreeBSD 13.0
    • 展望未来
    • FreeBSD 13.0 工具链
    • FreeBSD 13.0 中有新加载器吗?
    • TCP Cubic 准备起飞
    • OpenZFS 中的 Zstandard 压缩
    • 会议报告:FreeBSD 供应商峰会
    • Git 不够吗?
  • 2021-0102 案例研究
    • Tarsnap 的 FreeBSD 集群
    • BALLY WULFF
    • Netflix Open Connect
    • FreeBSD 的新面孔
    • 写作学者的 FreeBSD
    • 在世界之巅
  • 2020-1112 工作流/持续集成(CI)
    • FreeBSD Git 快速入门
    • 使用 syzkaller 进行内核 Fuzzing
    • Mastering Vim Quickly 书评
    • 线上会议实用技巧
    • 在控制台上进行网络监控
  • 2020-0910 贡献与入门
    • 采访:Warner Losh,第 2 部分
    • 代码审查
    • 撰写良好的提交消息
    • 如何在不是程序员的情况下做出贡献——成为 FreeBSD 译者
    • 如何成为文档提交者
    • 谷歌编程之夏
    • 为 FreeBSD 期刊撰写文章
    • 你为什么使用 FreeBSD
    • FreeBSD 的新面孔
  • 2020-0708 基准测试/调优
    • FreeBSD Friday
    • 采访:Warner Losh,第 1 部分
    • 构建和运行开源社区
    • 在 FreeBSD 上轻松搭建我的世界(Minecraft)服务器
    • FreeBSD 的新面孔
  • 2020-0506 网络性能
    • 内核中的 TLS 卸载
    • 访谈:Michael W Lucas
    • FreeBSD 桌面发行版
    • 使用 Poudriere 进行 Port 批量管理
    • FreeBSD 的新面孔
由 GitBook 提供支持
LogoLogo

FreeBSD 中文社区(CFC) 2025

在本页
  • Git 工作树
  • 快速构建和启动自定义内核
  • 调试自定义内核
  • 测试自定义内核
  • stress2
  • syzkaller
在GitHub上编辑
导出为 PDF
  1. 2021-0910 FreeBSD 开发

内核开发技巧

上一页如何为 FreeBSD 实现简单的 USB 驱动程序下一页程序员编程杂谈

最后更新于1个月前

  • 原文链接:

  • 作者:MARK JOHNSTON

我经常看到的一个问题是类似于“如何开始操作系统内核开发?”这样的问题。这个问题很难普遍回答,但有一个更简单的方面是,“如何为自己设置一个(高效的)构建和测试内核更改的环境?”换句话说,虽然提交第一个内核补丁是一个重要的里程碑,但一个频繁的贡献者可能会处理多个不同的补丁,测试补丁(可能是从其他开发者那里获得的),通过二分查找找出回归的原因,或者调试内核崩溃。拥有一个能够最小化等待时间,避免不断调整配置选项或 shell 脚本的工作流程非常重要。

FreeBSD 是个庞大且历史悠久的项目(比一些开发者还要老),它的目标是支持各种硬件平台(从掌中宝般的小型系统到拥有 TB 级内存的大型多核服务器)。因此,它没有一种适用于所有任务的通用方法。然而,快速的编辑 - 编译 - 测试循环的好处是普遍适用的;本文旨在介绍一些技巧,可以减少许多内核开发任务的摩擦。

以下步骤假设你使用的是 FreeBSD 主机和兼容 POSIX 的 shell(例如 /bin/sh)。虽然当前项目没有提供许多用于构建、启动和测试内核更改的现成脚本,但这里的一些建议可以融入到你的开发环境中,或者集成到由多个开发者共享的 CI 系统中。

Git 工作树

在开始任何 FreeBSD 的工作之前,你需要一个 src 仓库的副本:

$ git clone https://git.freebsd.org/src.git freebsd

在处理多个任务时,拥有多个 FreeBSD 源代码副本将会非常有用。如果只有一个副本,当当前分支的构建正在运行时,如果你想切换到另一个分支进行其他工作的操作就会变得很尴尬,或者切换分支会更新源代码文件的时间戳,从而不必要地减慢未来的增量构建速度。

当然,保持多个仓库副本是可行的,但更好的解决方案是使用 git 工作树,它允许你从单一的克隆中检出多个分支。这样不仅减少了磁盘空间的使用,还确保了你的所有工作都包含在仓库的一个副本中。例如,创建工作树用于频繁访问的稳定和发布分支是非常有用的。

$ cd freebsd
$ git worktree add dev/stable/13 origin/stable/13
$ git worktree add dev/releng/13.0 origin/releng/13.0
$ git worktree add dev/stable/12 origin/stable/12
$ git worktree add dev/releng/12.2 origin/releng/12.2
...

请注意,工作树可以位于克隆之外,例如:

$ git worktree add ../freebsd-stable/13 origin/stable/13

在处理一个较大的项目时,为该分支保留一个专门的工作树是非常有用的。

快速构建和启动自定义内核

假设你写了一个小的、简单的内核补丁,并希望在提交审查之前进行一些基本的测试。构建 FreeBSD 内核的标准命令是众所周知的:

$ cd freebsd
$ make buildkernel

这将执行一次干净的、单线程的内核构建。通常,更希望利用尽可能多的 CPU,因此可以考虑将 -j $(sysctl -n hw.ncpu) 添加到 make(1) 的参数中:这将并行运行与系统中的 CPU 数量相等的构建任务。待从特定源路径构建了内核,通常不需要每次测试更改时都重建每个单独的源文件——增量重建就足够了。要请求增量构建,可以将 -DKERNFAST 标志添加到 make(1) 命令中:

$ make -j $(sysctl -n hw.ncpu) -DKERNFAST buildkernel

默认情况下,buildkernel 会重建内核以及所有随之而来的内核模块,对于运行 GENERIC 内核的 amd64 系统来说,可能会重建多达 822 个模块。许多这些模块还会链接到内核中(取决于正在使用的内核配置文件),因此,buildkernel 可能会花费大量时间重建那些永远不会被加载的模块。可以使用 MODULES_OVERRIDE 变量来覆盖这一行为;通过 MODULES_OVERRIDE 进行构建时,将只构建内核和由该变量值指定的模块,而不是构建所有模块。例如,要仅与模块 tmpfs.ko 和 nullfs.ko 一起构建内核,请运行以下命令:

$ make -j $(sysctl -n hw.ncpu) -DKERNFAST \
 MODULES_OVERRIDE="tmpfs nullfs" buildkernel

如果你知道你的测试只需要少数几个模块,那么通过设置 MODULES_OVERRIDE 可能会加快构建时间,因为这可以大大减少在构建过程中执行的文件系统访问次数。例如,如果源代码树位于慢速磁盘上,或者远程访问并通过 NFS 访问,那么使用选项 MODULES_OVERRIDE 可能节省大量时间。

现在,测试内核已经准备好,可以进行测试了。测试更改的过程很大程度上依赖于更改的性质;例如,开发 WiFi 驱动程序的开发人员与开发在新平台上启动 FreeBSD 或内核内存分配器的开发人员将有不同的测试工作流。然而,出于许多目的,简单的 bhyve 虚拟机(VM)就足够了。

FreeBSD 项目提供了 VM 镜像,这些镜像对于测试内核更改非常方便。虽然当然可以通过本地构建 VM 镜像,例如使用 release(7) 脚本,但预构建的镜像非常方便:

$ IMAGE="FreeBSD-14.0-CURRENT-amd64.raw.xz"
$ URL="https://ftp.freebsd.org/pub/FreeBSD/snapshots/VM-IMAGES/14.0-CURRENT/amd64/Latest"
$ fetch -o "/tmp/${IMAGE}" "${URL}/${IMAGE}"
$ unxz "/tmp/${IMAGE}"
$ sudo pkg install -y bhyve-firmware
$ sudo sh /usr/share/examples/bhyve/vmrun.sh -E -d \
 "/tmp/${IMAGE%.xz}" myvm

这将使用 bhyve 启动快照镜像,虚拟机名称为“myvm”。然而,虚拟机将运行与快照一起提供的内核。有几种方法可以更新镜像的内核。例如,可以将源代码树复制或挂载到已启动的虚拟机中,并在虚拟机内构建一个新的内核。然而,这样会很慢,除非虚拟机分配大量的 CPU 和 RAM,并且会面临导出源代码树的后勤问题。另一种方法是将磁盘镜像挂载到主机上,直接安装一个新内核,但这需要一些同步,以确保虚拟机和主机不会同时挂载镜像。

另一种方法是提供一个第二个磁盘,只包含自定义内核和模块,并将虚拟机配置为从该磁盘启动。这样的磁盘镜像可以快速创建,并且不需要主机上的特殊权限。首先,可以使用以下命令来创建这样的镜像:

$ cd /usr/src
$ make buildkernel
$ make installkernel -DNO_ROOT DESTDIR=/tmp/kernel
$ cd /tmp/kernel
$ makefs -B little -S 512 -Z -o version=2 /tmp/kernfs METALOG
$ rm -f /tmp/kernfs.raw
$ mkimg -s gpt -f raw -S 512 -p freebsd-ufs/kern:=/tmp/kernfs \
 -o /tmp/kernfs.raw

这些 make 命令会构建并安装一个内核到 /tmp/kernel,而无需 root 权限。这也会在 /tmp/kernel/METALOG 创建一个 mtree(8) 清单,供 makefs(8) 用于构建一个小型文件系统。最后,mkimg(1) 会向文件系统添加一个 GPT,使其可供 FreeBSD 引导加载程序访问。

现在,我们可以使用额外的磁盘再次启动虚拟机:

$ sudo sh /usr/share/examples/bhyve/vmrun.sh -E -d /tmp/kernfs.raw \
 -d "${IMAGE%.xz}" myvm

这仍然会从原始镜像启动内核。然而,可以通过在 /boot/loader.conf 中添加以下行,配置引导加载程序从 kernfs.raw 加载内核:

kernel="disk0p1:/boot/kernel"

这里的“disk0p1”指的是 disk0 的第一个分区,disk0 是在 vmrun.sh 命令行参数中列出的第一个磁盘,在这个例子中是 /tmp/kernfs.raw。进行此更改并重启后,虚拟机应该会启动到自定义内核。

默认情况下,自定义内核的文件系统不会自动挂载,这意味着像 kldload(8) 这样的工具将无法自动加载与自定义内核对应的内核模块。为了解决这个问题,可以将以下行添加到相应的系统配置文件中:

/boot/loader.conf:
# 确保 nullfs 可用。
nullfs_load="YES"
/etc/sysctl.conf:
# 修正内核链接器使用的路径。
kern.bootfile=/boot/kernel/kernel
kern.module_path=/boot/kernel
/etc/fstab:
# 将自定义内核文件系统挂载到 /boot/kernel。
/dev/gpt/kern /mnt ufs ro 0 0
/mnt/boot/kernel /boot/kernel nullfs ro 0 0

最后,可以考虑将 autoboot_delay=1 添加到 /boot/loader.conf 中:这将引导延迟从十秒减少到一秒,当频繁重启时,这会带来相当大的帮助。

虽然设置过程有点复杂,但只需要执行一次,现在我们就有了一个快速启动新构建的内核的方法!在虚拟机运行时可以进行内核构建,重启虚拟机会导致加载并运行最新的内核构建。在创建更复杂的测试环境时,可能希望本地构建基础虚拟机镜像,在这种情况下,上述配置更新可以实现自动化。

调试自定义内核

使用 bhyve(8) 的一个好处是可以向主机提供 GDB 协议存根。QEMU 也有类似的功能。使用这个功能,主机系统可以在客户机内核上运行调试器。由于我们的自定义内核是在主机上构建的,因此此功能非常容易使用。vmrun.sh 目前不支持启用 GDB 存根,但可以通过原始的 bhyve(8) 调用来启用它:

# bhyve -c 1 -m 512M -H -A -P -G :1234 \
 -s 0:0,hostbridge \
 -s 1:0,lpc \
 -s 2:0,virtio-blk,kernfs.raw \
 -s 3:0,virtio-blk,FreeBSD-14.0-CUREENT-amd64.raw \
 -l com1,stdio \
 -l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \
 myvm

在这里,-G :1234 参数指示 bhyve(8) 在端口 1234 上监听来自调试器的连接。启动虚拟机时,bhyve(8) 可以选择暂停,等待连接后再启动内核;这对于调试内核启动过程中的早期问题非常有用。要启用此功能,可以指定 -G w:1234。

当虚拟机正在运行(或等待连接)时,可以使用 kgdb 程序(与 gdb 软件包一起安装)通过端口 1234 连接到客户机:

$ kgdb -q /tmp/kernel/usr/lib/debug/boot/kernel/kernel.debug
Reading symbols from /tmp/kernel/usr/lib/debug/boot/kernel/kernel.debug...
(kgdb) target remote localhost:1234
Remote debugging using localhost:1234
cpu_idle_acpi (sbt=432162053) at
/usr/home/markj/src/freebsd/sys/x86/x86/cpu_machdep.c:551
551 atomic_store_int(state, STATE_RUNNING);
(kgdb) set solib-search-path /tmp/kernel/usr/lib/debug/boot/kernel
Reading symbols from
/tmp/kernel/usr/lib/debug/boot/kernel/nullfs.ko.debug...
(kgdb) bt
#0 cpu_idle_acpi (sbt=432162053) at
/usr/home/markj/src/freebsd/sys/x86/x86/cpu_machdep.c:551
#1 0xffffffff81096ccf in cpu_idle (busy=0) at
/usr/home/markj/src/freebsd/sys/x86/x86/cpu_machdep.c:668
#2 0xffffffff80c62b41 in sched_idletd (dummy=<optimized out>,
dummy@entry=0x0 <nullfs_init>)
 at /usr/home/markj/src/freebsd/sys/kern/sched_ule.c:2952
#3 0xffffffff80be838a in fork_exit (callout=0xffffffff80c62660
<sched_idletd>, arg=0x0 <nullfs_init>,
 frame=0xfffffe0001141f40) at
/usr/home/markj/src/freebsd/sys/kern/kern_fork.c:1088
#4 <signal handler called>
(kgdb)

此时,虚拟机已暂停,等待调试器的命令。可以使用 continue 命令恢复虚拟机,按下调试器窗口中的 ctrl-C 会再次暂停虚拟机。这一功能对于调试内核死锁和启动时问题非常有用。也可以在客户机内核崩溃后附加调试器,从而无需配置和恢复内核转储就能轻松检查线程和局部变量。

测试自定义内核

现在,我们已经拥有了一个相当快速的循环,用于增量测试 FreeBSD 内核的更改,并且拥有了一些调试工具来解决问题。此时,某些手动测试可能表明补丁是正确的并且准备好进行审查。不过,为了增加对补丁的信心,运行一些自动化测试可能会有帮助;FreeBSD 内核是一个庞大的单体代码库,总是有潜在的未预见回归问题。一个好的起点是 FreeBSD 回归测试套件。

如果你按照上述步骤设置了内核开发虚拟机,那么测试套件已经安装好了;使用以下命令运行它:

# cd /usr/tests
# kyua -v test_suites.FreeBSD.allow_sysctl_side_effects=1 test

allow_sysctl_side_effects 标志启用了一些依赖于能够修改全局 sysctl 值的测试,在专用虚拟机中这是完全可以接受的。如果某些测试依赖于第三方端口(如 Python),则它们会被跳过。运行完测试后,可以使用以下命令查看结果总结(包括跳过的测试):

# kyua report

可以设置 bhyve 虚拟机,在启动时自动运行测试套件。一种简单的方法是添加一个脚本 /etc/rc.local,该脚本运行测试套件,将结果打印到控制台,并关闭虚拟机。可以使用一个单独的磁盘来存储 kyua report 的输出,这样结果就可以轻松地在主机上恢复。

回归测试套件涵盖了大量的 FreeBSD 特性,但设计上能够快速完成。因此,尽管它可以通过相对较少的工作帮助找到错误,但可能需要进行更为密集的压力测试。FreeBSD 提供了几种进一步测试内核更改的方法。

stress2

stress2 是一个由 Peter Holm 维护的大型压力测试套件。它包含数百个针对内核核心的文件系统和内存管理子系统的回归测试。stress2 套件包含在 FreeBSD 源代码树中,位于 tools/test/stress2,但并不包含在安装中。要运行这些测试,假设测试系统中有源代码树,可以运行:

# cp -R ${SRCDIR}/tools/test/stress2 /tmp/stress2
# pw user add stress2
# cd /tmp/stress2
# echo stress2 | make test

stress2 套件至少需要几 GB 的 RAM 和一个大磁盘。完成这些测试可能需要几天时间,但它是测试内核系统性更改的绝佳方式。各个单独的测试位于 misc 子目录下,可以直接运行。

syzkaller

最后,syzkaller 已成为一种有效的工具,用于测试从系统调用接口可达的内核部分。作为一个模糊测试工具,它对于证明更改的正确性并不特别有用,但它非常擅长触发不常执行的错误路径,因此可以帮助验证错误处理代码,这些代码可能很难触发。它还有效地引发竞争条件。

# pkg install bastille
# bastille bootstrap 13.0-RELEASE
# bastille bootstrap https://github.com/markjdb/bastille-syzkaller
# bastille create -V syzkaller 13.0-RELEASE 0.0.0.0 epair0b

这假设 epair0b 是 Bastille 的“上行”接口;它可以与主机接口桥接,以提供完整的网络访问。

然后,按照 bastille-syzkaller 模板 README 中记录的设置步骤,创建一个 ZFS 数据集供 syzkaller 使用,并在 syzkaller jail 中启用所需的功能。最后,可以应用该模板并启动 syzkaller,如下所示:

# bastille template syzkaller markjdb/bastille-syzkaller \
 --arg FREEBSD_HOST_SRC_PATH=${SRCDIR}
# bastille service syzkaller syz-manager onestart

通常,${SRCDIR} 将是一个 git worktree,引用要构建和测试的分支;该 worktree 被通过 nullfs 挂载到 jail 中。syzkaller 测试的内核可以通过模板在 jail 根用户的主目录中安装的 build.sh 脚本重新构建:

# bastille console syzkaller
# service syz-manager onestop
# sh /root/build.sh
# service syz-manager onestart

此时,syzkaller 启动一个监听 8080 端口的 web 服务器,显示崩溃报告和模糊测试过程的进度。


自 2010 年以来 MARK JOHNSTON 一直是 FreeBSD 用户,并从 2013 年开始成为提交者。目前他在 FreeBSD 基金会工作,致力于提高内核的稳定性和性能,并提供代码审查。

syzkaller 的详细概述出现在之前的 中。设置一个 syzkaller 实例是一个相对复杂的任务。可以参考 中的文档,了解如何设置一个 FreeBSD 主机来运行 syzkaller(它通过 QEMU 或 bhyve 虚拟机执行模糊测试)。

一种自动化许多设置步骤的替代方法是使用 Bastille 模板。 是一个在 FreeBSD 上部署和管理 jail 系统的工具;Bastille 允许在运行中的 jail 中运行代码并修改配置。运行 syzkaller 的 Bastille 模板已经可用。要使用它,首先安装 Bastille 并基于 FreeBSD 13.0 创建一个精简的、基于 VNET 的 jail:

Kernel Development Recipes
FreeBSD Journal 文章
syzkaller 仓库
Bastille
模板