二分查找回归

本文档介绍了如何使用 git bisect 查找破坏了某些功能的源码更改——例如,在从 Linux 6.0 升级到 6.1 后某些功能停止工作时。

本文重点介绍该过程的核心要点。如果您是第一次对内核进行二分查找,最好阅读如何验证错误并二分查找回归:它从头到尾详细描述了整个过程,并涵盖了连内核开发者也偶尔会忘记的多个方面。这包括尽早检测出进行二分查找是在浪费时间的情况,因为没有人会关心结果——例如,问题发生在内核将自己标记为“受污染”(tainted)之后、发生在已被放弃的版本中、已经被修复,或者是由您或您的 Linux 发行商进行的 .config 更改引起的。

使用二分查找寻找导致内核问题的更改

注意:以下过程假设您已为二分查找做好了各项准备工作。这包括拥有包含相应源码的 Git 克隆仓库,安装构建和安装内核所需的软件,以及存放在安全位置的 .config 文件(以下示例假设为 ‘~/prepared_kernel_.config’),以便在每个二分步骤中作为原始基础;理想情况下,您还应该已经摸索出一种完全可靠且直接的方法来复现该回归。

  • 准备工作:启动二分查找,并向 Git 告知您认为正常的历史节点和损坏的历史节点,Git 分别称之为“good”和“bad”

    git bisect start
    git bisect good v6.0
    git bisect bad v6.1
    

    除了像 ‘v6.0’ 和 ‘v6.1’ 这样的 Git 标签外,您也可以指定提交 ID(commit-id)。

  1. 将准备好的 .config 复制到构建目录中,并根据 Git 检出用于测试的代码库的需求对其进行调整

    cp ~/prepared_kernel_.config .config
    make olddefconfig
    
  2. 现在构建、安装并启动内核。这可能会由于不相关的原因而失败,例如,在二分查找的当前阶段发生了编译错误,而稍后的更改会解决该错误。在这种情况下,请运行 git bisect skip 并返回步骤 1。

  3. 检查刚才构建的内核中发生回归的功能是否正常工作。

    如果工作正常,执行

    git bisect good
    

    如果已损坏,运行

    git bisect bad
    

    注意,只要弄错一次,就会使接下来的二分查找完全偏离方向。为了避免以后不得不重新开始,您需要确保告知 Git 的信息是正确的;因此,如果您的复现脚本不够可靠,多花几分钟进行测试通常是明智之举。

    在执行这两条命令之一后,Git 通常会检出另一个二分点,并打印类似“Bisecting: 675 revisions left to test after this (roughly 10 steps)”的信息。在这种情况下,请返回步骤 1。

    如果 Git 打印的是类似“cafecaca0c0dacafecaca0c0dacafecaca0c0da is the first bad commit”的信息,则说明您已完成二分查找。此时请转到下一点。注意,在该行显示后,Git 会立即显示有关罪魁祸首的一些详细信息,包括其补丁描述;这很容易填满您的终端,因此您可能需要向上滚动才能看到提及罪魁祸首 commit-id 的消息。

    如果您错过了 Git 的输出,随时可以运行 git bisect log 来打印状态:它将显示剩余的步数或提及二分查找的结果。

  • 推荐的补充任务:将二分日志和当前的 .config 文件留作错误报告备用;此外,让 Git 将源码重置为二分查找之前的状态

    git bisect log > ~/bisection-log
    cp .config ~/bisection-config-culprit
    git bisect reset
    
  • 推荐的可选任务:尝试在最新代码库之上回滚该罪魁祸首提交,并检查这是否修复了您的错误;如果是这样,这就验证了二分查找的正确性,并使开发者能够通过回滚来解决回归问题。

    要尝试此操作,请更新您的克隆仓库并检出最新的主线。然后通过指定其 commit-id 让 Git 回滚该更改

    git revert --no-edit cafec0cacaca0
    

    Git 可能会拒绝此操作,例如当二分查找落在合并提交上时。在这种情况下,请放弃该尝试。如果由于后续更改依赖于该罪魁祸首而导致 Git 无法自行回滚,也请这样做——除非您对稳定版或长期支持内核系列进行了二分查找,这种情况下您需要检出其最新的代码库并在那里尝试回滚。

    如果回滚成功,请构建并测试另一个内核,以检查回滚是否解决了您的回归。

至此,整个过程就完成了。现在请按照报告问题中的说明报告该回归。

二分查找 linux-next

如果您遇到仅在 linux-next 中发生的问题,请在 linux-next 的 ‘stable’ 和 ‘master’ 分支之间进行二分查找。以下命令将针对您添加的名为 ‘next’ 的远程 linux-next 树启动该过程

git bisect start
git bisect good next/stable
git bisect bad next/master

‘stable’ 分支是指当前 linux-next 版本(位于 ‘master’ 分支中)所基于的 linux-mainline 的状态——因此,前者应该不会出现任何在 -next 中出现但在 Linus 的树中未出现的问题。

这将在广泛的更改范围内进行二分查找,其中一些更改您可能在早期的 linux-next 版本中正常使用过。遗憾的是,没有简单的方法可以避免检查它们:从一个 linux-next 版本二分查找另一个较新的版本(例如在 ‘next-20241020’ 和 ‘next-20241021’ 之间)是不可能的,因为它们没有共同的历史。

延伸阅读材料