LWN:关于module、GKI、以及火箭科学!
共 4753字,需浏览 10分钟
·
2021-10-28 21:48
关注了就能看到更多这么棒的文章哦~
The intersection of modules, GKI, and rocket science
By Jonathan Corbet
October 11, 2021
DeepL assisted translation
https://lwn.net/Articles/872209/
人们通常不认为那些围绕着对跟特定平台有关的 configuration 和 driver 进行修改的 patch series 会有多少争议。因此,近期看到三星 Exynos 平台上的一些工作引发的愤怒讨论就很令人惊讶了。当我们深入研究这个讨论时,就会意识到,这里主要是与硬件供应商与内核开发社区合作的最佳方式有关。
9 月中旬,Will McVicker 发布了一系列针对 Exynos config 文件的简单修改。一周后,提供了一个更新版本,不过改动非常多。这两次的目的都是为了修改一些芯片(SoC)的底层驱动程序,使它们能够被构建为 loadable module。这似乎是一个没有多少争议的改动。通常情况下,人们都期望设备驱动程序应该是可以编译为 module 的。但对于这些底层 SoC 驱动程序来说,情况有些不同。
Generic kernels and essential drivers
在很久以前,基于 Arm 的 SoC 的内核都是针对某个特定目标平台编译的。x86 内核通常可以在所有 x86 处理器上运行,而 Arm 内核却是为很小范围的目标平台建立的,无法在其他平台上启动。多年来,Arm 开发者努力使 64 位 Arm 内核具有足够的通用性,这样每一个二进制镜像文件就可以在各种平台上能正常启动了。在很大程度上,这种可移植性(portability)是通过将驱动程序构建为 module 来实现的,这样处理之后要在特定设备上运行内核就只需要加载与该设备相关的驱动程序就好。
不过,还有一个 bootstrapping 问题需要解决;在内核能够加载一个 module 之前,它必须能够先让这个平台启动到一个已知的稳定状态,并且能够 mount 一个基于 RAM 的 root 文件系统。只有当启动时所需的驱动程序被 built-in 到内核本身的情况下才能达到这个目标。因此,通用内核(generic kernel)就包含了许多个平台特有的驱动程序,用于配置 clock、pin controller 等。如果没有它们的话内核就无法完成启动。长期以来,维护者的政策都规定,任何对启动过程至关重要的驱动都必须编译到内核里面。
McVicker 的 patch set 把许多这类重要的驱动程序(原因下面要详细介绍)从内核镜像中移除,使其成为了 loadable module。表面上看,这种改动并不违反这些驱动的 policy,但必须要先证明这些驱动实际上不是内核要在相关硬件平台上能启动的必要条件。这就是这组 patch set 的第一个大问题,McVicker 在说明邮件中明确表示,这些改动实际上没有在相应的硬件上进行测试。虽然他很乐观地认为这些系统应该仍然可以 module 方式的驱动来启动,但还没有人来证实这一点。
在内核社区,仅靠这种乐观的态度是无法说服别人的。由于缺乏测试,Exynos 平台维护者 Krzysztof Kozlowski 多次拒绝这些 patch。在他确定所有 Exynos 系统都可以用这些 module 方式的驱动正常启动之前,他不愿意接受这些改动。他已经提出愿意帮助来进行一些必要的测试。同时,Arnd Bergmann 也支持 Kozlowski 的沉默态度:
"正确性第一" 的原则是没有商量余地的。如果对代码或测试的内容感到不满意,因为你认为它破坏了一些东西,那就应该拒绝这些 patch。把核心的 platform 功能移除出去本质上就是很难的,可能会在各种所有地方各种可能出错,比如过去有可能是因为固定的启动顺序而碰巧能正常工作。
缺乏测试似乎是可以解决的问题。不过,要让测试结果达到让大家有信心的水平可能还需要一段时间。比如说一些在运行某些特定 SoC 的系统可能可以在没有某些 clock driver 的情况下启动,这是因为 firmware 在开机时就将时钟初始化为正确的值了。不过,指望所有的 firmware 都会做这件事的话,可能有点天真了。无论如何这类测试都应该在提交 patch 之前就完成,应该也要在事后补上。
Out-of-tree code
还有一个问题是为什么要做这种可能有风险的改动。显而易见的一个好处是使 core kernel image 能更小。这在所有不使用相关驱动的平台上尤其是件好事,因为它们其实是没用的代码。但是,这里还有另一个动机,是来自另一个名字中也带 generic 的内核版本有关。
大家都知道安卓设备的内核包含了大量的树外(out-of-tree)代码,这些代码有时都比设备上正在使用的 mainline 代码更加重要(outweighs)了。这导致了整个生态系统出现问题,比如缺乏与上游内核开发者的合作、Android kernel space 的碎片化、当供应商停止(总有这一天)进行安全更新时就无法再得到更新、以及维护所有这些内核带来的额外成本。为了解决这个问题,谷歌一直在推动基于安卓的设备供应商来配合它的 "通用内核镜像(generic kernel image)"(GKI)进行开发,这是一个所有安卓设备都必须提供的 core kernel。供应商需要提供他们自己的 module 来加载到该内核中,但他们不能取代内核本身。
这个规则带来了一些好处。供应商的改动被限制在那些可以用 module API 来实现的功能之内,而谷歌也一直在推动对这些改动的限制。供应商替换掉 CPU scheduler 的日子现在就应该结束了。供应商自然对这些限制感到不满,但他们除了遵从之外没有什么其他选择。如果他们选择来运行自己的系统,也就是事实上是一个从安卓 fork 出来的系统,那么他们就会失去使用许多谷歌应用和服务权利,而这些应用和服务正是安卓对他们客户的价值。
因此,GKI 内核中的代码不能被 device vendor 修改。相应地,从 module 中加载的代码可以被拿掉或者替换掉。从这个角度来看,将内置驱动程序改成 module 的愿望就很容易理解了。即便如此,这种情况也还有两个方面值得研究。其一是供应商希望在他们的设备上能运行 out-of-tree module,而不是将他们的驱动程序推倒 upstream,这样就能对竞争对手来隐藏他们自己特有的一些做法。正如 Lee Jones 所描述的:
为了让供应商与 upstream 能更紧密地合作,他们希望在设备发布之前要有能力来替换掉 少数 的驱动程序,从而来添加一些他们认为能够为他们提供竞争优势的功能(大家之前称这为 "value-add")。这是一个无法绕过的要求。
可以想象,这一立场在许多内核开发社区中被认为是无法接受的。它也确实不完全令人信服,正如 Tomasz Figa 所说:
一般来说,这里提到的子系统都是非常基本的(clock、pinctrl、rtc),我真的无法想象人们会因为竞争的原因而在这里隐藏什么样的火箭科学尖端科技。
Jones 后来不再强调这个讨论点,但有点晚了。他已经大声说出了之前人们避免提及的部分内容。
另一个问题则更简单易懂。即使一组 clock driver 不包含竞争对手会感兴趣的什么秘密,供应商可能只是缺乏努力把驱动推倒 upstream 的意愿。虽然有可能将 out-of-tree 的驱动程序内置到 GKI 中,但谷歌显然不想再继续背负这些负担,所以他会一直感到将驱动程序放入 mainline 的压力。如果驱动可以直接由供应商作为 module 提供,那么它们就可以从 GKI 中拿出去了,这种压力也就消失了。关于 Exynos 的改动,估计合理的解释还是缺乏推向 upstream 的动力。正如 Kozlowski 在上述链接的邮件中指出的那样,自 2017 年以来,三星只对 Exynos 子系统做出过一次改动。
Jones 曾试图将供应商在 upstream 动力方面的问题定义为暂时性的问题,他说:"供应商不可能马上就将所有功能都上传到 upstream"。但后来,他说:
但是 [他们] 没有动力给 upstream 推送那些无法[为]他们继续赚钱的旧(死)平台的代码。我们在这里谈论的不是一个心地善良的个人,而是一些商业实体。
如果新的或旧的代码都不能被推到 upstream,那么对这些平台的 mainline 支持似乎就陷入了死胡同了。
Better or worse?
许多内核开发者的自然反应都是想让那些似乎正在寻找方法避免与开发社区接触的供应商的日子变得更难过。这就包括拒绝这里正在讨论的 patch set。Olof Johansson 的意见是:
这个 patch set 不应该被采纳。
GKI 是一项了不起的努力,因为它看起来像谷歌终于有骨气向供应商施加压力,让他们把所有的东西放到 upstream 去。
这个 patch set 通过打开一个像卡车那么大的漏洞,来稀释和破坏了所有这些努力、减少了 GKI 的影响,并从整体上消除了让供应商们做正确事情的动力。
相反,McVicker 认为,将这些驱动程序改为 module 是一种使供应商能更加参与到 upstream 的方式,并将改善整体情况:
我们相信,如果我们让 SoC 厂商在项目启动和开发阶段更容易直接使用 upstream 内核,那么这将减少与上游合作的阵痛(因为会有更少的 downstream 改动了)并增加对 upstream 的贡献。
很难说哪一种观点更接近事实。每一种立场可能都有一些厂商是属于这种情况、而对另一些厂商来说则是错误的。让供应商与 upstream 接触是一个持续进行的过程,需要明智地使用胡萝卜和大棒。
具体到这一次讨论,结果并不存在很大的疑问。让不配合的供应商能生活得更轻松,这通常本身并不是足以将 patch set 从内核中剔除的理由。在上面讨论信息很好地描述了这一点:
我理解对于 SoC 厂商来说,如果永远不必再把他们平台的代码上传到 upstream,那确实是很方便的,而且 Android 在短期内也会从中受益。
从我 upstream 的角度来看,这绝对不可以成为一个目标。如果将内核变得更加容易使用 module,那这个副作用还是不错的。
所以,从某种意义上说,许多讨论都是无关紧要的。如果这些 patch 能够被证明是可以正常工作的(目前这一点还没有完成验证),那么它们就与社区的众多长期目标是一致的,可能迟早会进入 mainline。不过关于这会鼓励供应商尽量在 upstream 工作还是正相反(使他们更倾向于远离 upstream),这还有待观察。但是,与不配合的供应商相关的问题已经存在了很长时间,无论如何这些问题今后也都会不断出现。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~