记录人生第一个Linux内核Patch被采纳的经历
最近运气不错,提交的一个关于 Linux 内核 SMMUv3 驱动的补丁(Patch)被采纳了。虽然只是一个边界条件的微调,但作为自己的第一个 Patch,过程还挺有意思的,中间也暴露出自己不少技术盲区。趁着记忆热乎,把这次经历和踩坑记录下来。
起因:发现一处“不合理”的重试逻辑
最近在看 smmuv3的驱动代码,drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c。在读到 arm_smmu_init_one_queue() 这个初始化硬件队列的函数时,我注意到它的内存分配重试逻辑。
驱动在申请队列内存时,如果调用 dmam_alloc_coherent() 失败,会在一个循环里不断把队列大小减半(max_n_shift--)并重新尝试,直到成功或者尺寸小于一个页面。
原有的边界判断是这样的:
do { qsz = ((1 << q->llq.max_n_shift) * dwords) << 3; q->base = dmam_alloc_coherent(smmu->dev, qsz, &q->base_dma, GFP_KERNEL); if (q->base || qsz < PAGE_SIZE) break; q->llq.max_n_shift--; } while (1);我当时下意识地认为,DMA 内存分配底层都是按页(PAGE_SIZE,通常 4KB)对齐的,单次分配不可能小于一个 Page。如果连一个 Page 大小的内存都申请失败了,再去减半尺寸重试,在逻辑上是冗余的;而且万一刚好赶上内存释放,重试小尺寸成功了,硬件就会配置成一个很小的队列,但实际上底层还是占用了整页内存,这不就导致性能降级和内存浪费吗?
我觉得这地方是个可以优化的点,于是就写了补丁发到了邮件列表。
https://lore.kernel.org/linux-iommu/tencent_F6E384A40D990A279B460A0CDE1927FDF509@qq.com
过程:大牛的现场教学
补丁发出去之后,很快收到了社区维护者的回复,整个过程对我来说是一次很好的技术“上课”。
首先是 ARM64 架构和 SMMU 的主要维护者 Will Deacon。他指出了我的一个低级错误:我当时在 Commit 签名里用了 LoserJL。Will 直接回复:“No pseudonyms, please.”(请不要用伪名)。内核社区是很严肃的,必须用真名(Real Name)提交,这是对代码终身负责的态度。这算是我在社区礼仪上踩的第一个坑。
接着,IOMMU 领域的资深专家 Robin Murphy 对我的技术理由提出了质疑。他指出:DMA API 本身并没有承诺分配的内存一定不小于 PAGE_SIZE。在某些特殊配置下(比如设备命中了 per-device 或全局的 coherent pool 内存池),分配小于一个 Page 的尺寸是完全可能的。而且,如果系统真的连 PAGE_SIZE 都拿不出来,后面的 stream table 大概率也会失败,驱动基本上就 Probe 失败了,所以不用太纠结 over-allocate(过度分配)的问题。
看到这里,我发现自己对 DMA API 的底层细节理解确实不够全面,想当然了。
就在我以为这个补丁要被拒绝的时候,Will Deacon 出来查了历史提交记录(commit d25f6ead162e),并在邮件里公开表示:Robin 说的没错,不过看了下当年的代码,这里确实是他自己把边界条件写错了,原本的设计意图就是到 PAGE_SIZE 为止。并说虽然我写的理由不太对,但改动本身是符合最初代码预期的。
提交 v2 patch的流程
既然maintainer认可了改动的核心方向,也指出了问题,我感觉这个patch被采纳的希望大增,我立刻调整心态准备了 v2 版本:
- 把作者和签名改成了真名(Leo Jiang)。
- 删掉了我之前写得比较累赘的代码注释。
- 把原有的判断条件利落地改成了 qsz <= PAGE_SIZE。
- if (q->base || qsz < PAGE_SIZE) + if (q->base || qsz <= PAGE_SIZE) break;但是这次发送的patch直接回复到了之前的邮件列表,过了几天收到Pranjal Shrivastava回复,指导我v2要以全新邮件形式发送,避免在社区讨论中被忽略。
v2 patch的applied
在Pranjal Shrivastava的指导下,我这才明白内核patch提交的基本流程与规范,随即感谢指导之后,以全新邮件发送了v2 patch。
https://lore.kernel.org/all/tencent_F13723B53F68DC857410D3DBE4F6C895C106@qq.com/
过了几天,收到了Will 发来的邮件,表示这个改动已经正式入库:Applied to iommu (arm/smmu/updates), thanks!。
至此,我人生的第一个patch被正式采纳了。
几点体会
这次提交的patch虽然只是一个边界条件的微调,但收获确实比预想的多:
- 顶级维护者的严谨与胸怀。 大佬们在技术细节上非常敏锐,DMA 内存池那种边缘场景他们信手拈来。但同时他们也极其客观,即便我的理由说偏了,Will 发现是自己当年的手误后,依然非常大方地承认并帮忙推进合并。这种对事不对人、只看代码质量的氛围让人很舒服。
- 对底层的敬畏。 写内核代码真的不能靠“我觉得”或者“通常情况下”。一个看似理所当然的常识,在复杂的体系结构和子系统交叉下,都可能有特例。以后看代码和提 Patch,理论功课还得做得更扎实。
- 社区沟通要直白、严谨。 用真名、写清晰的 Commit Message、不加戏。
第一次内核提 Patch 顺利收尾,算是摸到了开源社区的门槛。以后继续努力,争取能提交一些更有含金量的patch。
