原文链接

从内核引入tracepoint开始,开发者们就对这些tracepoint是否为内核ABI的一部分而发生过争执。过去由于破坏了已有存在依赖的用户态程序,tracepoint相关变更被回退过。同时,对内部代码无法改变的恐慌使得在多个内核子系统中新增tracepoint变得困难。如今,一个新的tracing功能被提了出来以避开这些问题。

tracepoint是否作为内核ABI的一部分并非是无关紧要的问题。内核ABI承诺运行应用程序不会因内核更新而遭到破坏。很明确这个承诺在过去就已扩展覆盖到tracepoint。尤其是2011年当一个tracepoint变更因破坏了powertop而不得不被回退。一些内核维护者禁止或严格控制其维护的子系统中新增tracepoint,就是担心类似的事情会同样发生在自己身上。其结果导致内核缺乏用户认为有用的tracepoint。

这个主题在多个会议上作为议程讨论过,包括2017年维护者峰会。正是那时提出一个更聪明的想法:与其将tracepoint放置到敏感位置,不如由开发者简单地做好标记,而这些标记可以在运行时显示地连接并转化成tracepoint。通过跳出束缚 (jump through some hoops) 以此期望保证这个新机制将不会创建任何新的ABI。接下来几个月一切归于平静。

但最近tracing的维护者Steve Rostedt面临该提案的一个变化,他称之为“动态创建基于函数的事件 (dynamically created function-based events) ”。细节上发生了一些变化,但ABI规避本质上保持一致。关键细节差异来源于其观察到内核已经在特定位置上有了tracing代码可以利用的一种类型的标记。内核代码通常带有正常用于代码分析的参数编译。结果,每个函数都以调用mcount() (或新编译器使用的__fentry()__ ) 开始。当分析用户态程序时,mcount()追踪每个函数的调用并因此很耗时。尽管内核使用支持诸如function tracing的特性版本来替换mcount()。但大多时候都是直接整体打上mcount()调用,只是可以在运行时需要tracing特定函数调用时启用。

也存在其他可能使用函数入口钩子的场景。Rostedt的补丁可在运行时任何内核函数的开始处启用创建tracepoint。在tracefs控制文件系统挂载的前提下,一个新tracepoint可通过如下命令创建:

echo 'SyS_openat(int dfd, string path, x32 flags, x16 mode)' \
	> /sys/kernel/tracing/function_events

SyS_openat()是openat()系统调用的内核实现,该命令请求在SyS_openat()入口处创建一个tracepoint。4个值将从tracepoint报告出来:目录文件描述符 (dfd),给定路径名(path),以及标记和模式参数。这个tracepoint将在events/functions下显示出来,跟内核中其他tracepoint看上去一样。也可以像平常那样被查询,启用和关闭。有趣地是,这个例子中的路径指向用户空间,但tracing系统能恰当地获取并打印出相应数据。

很明显还存在进一步的工作要做:“我需要重写function graph tracer,并且能在函数返回时增加动态事件”。其核心部分看上去已经有了且能正常工作。但这里遗留了一个重要问题:这是否已经足够确保避免创建一个新ABI的内核接口集?Mathieu Desnoyers担心仍然不够。

让这些工具在函数名/参数上挂个钩子无法解决该问题。一旦内核代码变更,广泛使用的trace分析工具将开始变得不正常。而此时,其内部函数签名将会成为ABI。

Linus Torvalds却不同意该担心。内核钩子需要的额外步骤隐含了不同状态视角:

每个人*理解*这像一个调试工具:如果你有一个gdb脚本显示某些信息,接着你到处修改源代码,*明显*你同样需要回过头来修改调试脚本。你并没有没有保持源代码不变来使gdb脚本无需变更,这看上去很傻。 相反,显示的tracepoint使人们相信它们有着长远的意义。

如果现实与该观点一致,那么新的动态tracepoint机制将在缓解ABI问题有很大帮助。大量内核新增的tracepoint将很可能被丢弃,因为开发者将简单地使用动态变种来替代。将来增加tracepoint时,相对可能的是这些tracepoint将被设计成支持某些系统管理工具,并且在外部看上去是ABI的一部分。

当然那是假定这个系列补丁最终会被合入。Alexei Starovoitov对此有些不同意见,他抱怨新接口在kprobe现有的基础上增加很少。同时他也不喜欢面向文本的接口,建议使用BPF来替代以提取内核数据的某些特定信息。但Rostedt指出,许多开发者因BPF上手复杂性而退却,而更偏向简单的。

Rostedt认为该接口将很有用,但如果其他人存在不同意见的话他将不再继续开发:“如果其他人认为这将有用,那么我想让他们现在大声地说出来”。然而迄今为止,几乎没有人明确表达出来。如果动态函数tracing机制的确是其他开发者想要的,他们需要显示发声以表示支持。