记第一次给Linux Kernel提交补丁 —— 修复笔记本的静音灯

小记一次简单但是却很有成就感的补丁提交。

目录

其实给Linux提交补丁patch代码并不是意料之内的事,虽然以前也挺羡慕有能力或者有机会给Linux内核提交代码的人,但是平时并没有在意这个事。这次事在我给自己的笔记本安装Linux的过程中发现的问题,然后才想着顺手解决一下并提交~因此写一篇博客记录一下,也把提交的流程分享跟更多的人~

构建内核

准备工作

  1. 首先当然是拉代码。如果从官方的git1直接拉比较慢的话,可以用国内的镜像,例如清华TUNA的源2
  2. 安装编译依赖: sudo apt install -y build-essential libncurses-dev bison flex libssl-dev libelf-dev dwarves git bc wget gawk
  3. 配置内核编译参数:推荐用make olddefconfig这个命令从当前的linux内核拷贝配置,然后可以再通过make menuconfig去进一步定制化。
踩过的坑

在编译过程中我碰到了这个报错:

1
2
3
make[3]: *** 没有规则可制作目标“debian/canonical-certs.pem”,由“certs/x509_certificate_list” 需求。 停止。
make[2]: *** [scripts/Makefile.build:556:certs] 错误 2
make[2]: *** 正在等待未完成的任务....

其根本原因应该是linux内核的源码没有Ubuntu打包的一些证书。解决方案是在配置编译参数时把pem文件的路径清空,具体修改界面在make menuconfig的这个位置:

界面位置:Cryptographic API -> Certificates for signature checking,删除掉这两个pem路径

编译及安装

编译很简答,就是直接make。不过编译时推荐使用CCache加速,因为linux内核没有用cmake或者ninja之类的编译工具。

使用CCache

安装CCache直接apt就可以:apt install ccache。在安装完成之后可以调整ccache的一些参数,例如设置缓存路径:export CCACHE_DIR=<you_location>,设置缓存大小为2G:ccache -M 2G

注:Linux编译在我的笔记本上CCache大概占用4G空间。

编译完成后安装使用下面这些命令:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 编译并安装模块
sudo make modules_install -j$(nproc)

# 安装内核
sudo make install -j$(nproc)

# 更新 GRUB 并重启
sudo update-initramfs -c -k all
sudo update-grub
sudo reboot
SHELL

安装完后测试新内核是否有安装成功:uname -r

踩过的坑

make install这个过程中我碰到amdgpu驱动编译的问题:

1
2
3
4
5
6
7
8
9
depmod...
dkms autoinstall on 6.18.0-rc6+/x86_64 succeeded for system76-io system76 system76_acpi
dkms autoinstall on 6.18.0-rc6+/x86_64 failed for amdgpu(10)
Error! One or more modules failed to install during autoinstall.
Refer to previous errors for more information.
 * dkms: autoinstall for kernel 6.18.0-rc6+                                                                                           [fail]
run-parts: /etc/kernel/postinst.d/dkms exited with return code 11
make[1]: *** [arch/x86/Makefile:317:install] 错误 11
make: *** [Makefile:248:__sub-make] 错误 2

让豆包老师看了下,这个错误是 DKMS 模块编译失败(主要是 amdgpu 驱动),但不影响新内核本身安装,关键是关闭 Secure Boot 并跳过 DKMS 自动编译,就能正常使用新内核。因此在这里可以直接忽略,直接跳到后面的update-initramfsupdate-grab即可。

我的修改

在编译成功内核后就可以着手修改啦~我的电脑的问题是静音键的指示灯跟系统静音状态不同步,搜索了一下其实还有挺多人碰到了这个问题,最后是在archlinux论坛的一个帖子里找到了怎么修改,实际上就是要在音频驱动里面针对机型增加一个音频相关的quirk特例修改。(对于其他指示灯,例如闭麦指示灯,内核的实现逻辑也是类似的)

寻找修改

Linux里面的quirk是针对每个机型都有一行宏定义(内核源码在这里),这个定义需要一个system id和device id,需要在alsa info中寻找。运行alsa-info这个命令可以获得一个系统音频驱动的诊断信息3,对于这次的修改来说的关键信息是:

Subsystem Id: 0x103c8bd6
Product Name: HP Pavilion Aero Laptop 13z-be200

这里的Subsystem ID拆成前四位和后四位即为内核代码中SND_PCI_QUIRK这个宏的前两个参数,因此我只需要参考别的HP Pavilion机型的quirk依葫芦画瓢即可。Subsystem ID相关的介绍还可以参考linux内核文档的音频部分

如果你的机型没有可参考的quirk,或者参考的quirk在你的机型上并不能用,那么你就需要参考之前提到的archlinux论坛帖子里使用的脚本来暴力逆向工程出来怎么实现指示灯的控制了。

提交修改

修改完,验证好修复有效之后自然就是提交代码了。给linux提交代码和给普通仓库提交代码没有本质区别,最大的区别只是最后提交的时候不是git push,而是生成一个patch文件,并且通过邮件发给linux的邮件列表(需要找到对应模块的邮件列表和维护者,然后邮件发送给其中一个维护者,并且抄送邮件列表)。

生成补丁
SHELL
1
2
3
4
5
6
7
8
9
# 创建一个新分支进行开发
git checkout -b my-feature

# 修改代码后,提交更改
git add <修改的文件>
git commit -s  # -s 会自动添加 Signed-off-by 信息,对于给内核提交代码来说这个是必须的

# 生成补丁
git format-patch -1  # 生成最近一次提交的补丁,假设生成0001-my-feature.patch文件
检查补丁格式
SHELL
1
2
3
4
5
# 安装内核补丁检查工具
sudo apt install -y linux-tools-common

# 检查补丁格式
./scripts/checkpatch.pl 0001-my-feature.patch
发送补丁
SHELL
1
2
3
4
5
6
7
8
# 安装依赖
sudo apt install -y git-email

# 发送补丁
git send-email --to=maintainer@example.com --cc=linux-kernel@vger.kernel.org 0001-my-feature.patch

# 以下是我实际执行的发送命令
git send-email --to=tiwai@suse.com --cc=alsa-devel@alsa-project.org --cc=linux-kernel@vger.kernel.org 0001-add-the-SND-quirk-for-HP-pavilion-aero-laptop-13z-be.patch

在发送邮件之前,你还需要提前给git设置好SMTP服务器,参考教程git文档或者这个stackoverflow回答

提交之后,你的patch便会显示在linux邮件列表中,例如我的提交就在上面

清理内核

在测试完内核之后,如果你想用回原来的稳定内核,那可以参考下面这段操作。

豆包老师最开始的建议是:

1
2
3
# 删除新内核(替换为你的内核版本号)
sudo apt purge linux-image-6.8.0-mycustom
sudo update-grub
SHELL

但由于我make install没成功,因此只能手动删除文件了:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 1. 删除 /boot 目录下的新内核文件
sudo rm -f /boot/config-6.18.0-rc6+
sudo rm -f /boot/initrd.img-6.18.0-rc6+
sudo rm -f /boot/System.map-6.18.0-rc6+
sudo rm -f /boot/vmlinuz-6.18.0-rc6+

# update vmlinuz linking (optional. system boots based on grub)
sudo rm /boot/vmlinuz
sudo ln -s /boot/vmlinuz-6.16.3-76061603-generic /boot/vmlinuz

# 2. 删除 /lib/modules 下的新内核模块目录,避免残留
sudo rm -rf /lib/modules/6.18.0-rc6+

# 3. 更新 grub (不过我用的 popos 好像不用grub? 因此我实际上没有执行这最后一步)
sudo update-grub
SHELL

以上就是这次内核补丁提交的过程了,希望能帮到大家~


  1. Linux内核官方git地址:git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git ↩︎

  2. TUNA的Linux内核源码镜像:https://mirrors.tuna.tsinghua.edu.cn/help/linux.git/ ↩︎

  3. 这里是我的笔记本的info ↩︎

Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackedJimmy 设计,Jacob 修改