Linux内核模块加载及更新问题

背景

最近碰到了一个Linux内核模块更新问题,比较有意思,特此记录。

问题: 一款我们内核已经适配过的蓝牙模块在一台机器上用不了,驱动加载不起来,看内核日志报一堆的符号问题:

29.784454] rtk_btusb: Unknown symbol hci_free_dev(err -22)
29.784483] rtk_btusb: disagrees about version of symbol hci_alloc_dev_priv
29.784484] rtk_btusb: Unknown symbol hci_alloc_dev_priv(err-22)
29.784571] rtk_btusb: disagrees about version of symbol hci_unregister_dev
29.784573] rtk_btusb: unknown symbol hci_unregister_dev (err -22)
29.784583] rtk_btusb: disagrees about version of symbol hci_recv_frame	
29.784584] rtk btusb: unknown symbol hci_recv_frame (err -22)	
29.784608] rtk_btusb: disagrees about version of symbol hci_register_dev
29.784610] rtk_btusb: Unknown symbol hci_register_dev (err -22)	
29.784618] rtk_btusb: disagrees about version of symbol _hci_cmd_sync	
29.784620] rtk btusb: Unknown symbol_hci_cmd_sync(err-22)
29.808471] rtk_btusb: disagrees about version of symbol hci_free_dev
...

分析

从内核日志来看很明显是内核和驱动模块不匹配导致,但是内核包是用的我们正式发布的版本,按道理来说应该不会出现这种最低级的问题,于是开始一步步排查。

  1. 确认系统带的蓝牙驱动是否手动升级或修改
    进入/lib/modules/xxx-generic/kernel/drivers目录,确认使用的蓝牙内核模块也未手动升级或修改,是和内核包一起的模块。
  2. 手动加载驱动模块验证
    首先手动modprobe xxx这个驱动,发现加载报错;
    然后我直接手动insmod了一下这个蓝牙驱动(/lib/modules/xxx-generic/kernel/drivers目录下的),惊奇地发现居然成功加载了,而且蓝牙可以正常使用了。
    难道是系统之前使用的蓝牙驱动不是这个目录下的?
  3. 确认是否有其他同名驱动
    带着前面的疑问,我在/lib/modules/xxx-generic/目录查找了一番,果然发现新大陆,在/lib/modules/xxx-generic/updates/下也有一个同名的驱动
  4. 确认是否是updates/目录下的同名驱动引起
    难道现在系统使用的是updates/目录下的驱动?
    于是直接手动insmod了一下该目录下的同名驱动,报错;
    然后我将该驱动mv掉,然后depmod,再modprobe这个驱动,成功了!果然是这个updates/目录下的同名驱动引起的。

至此问题解决!

扩展updates目录

有时候 Linux 内核模块有更新,或者有第三方的改动需要用,要替换原来的模块。

比较简单的方法是把原来的 *.ko 文件直接替换,但这样有不好的地方,如果想换回来,比较麻烦。

较好的方法是把模块装在 /lib/modules/uname -r/updates/ 下面,再运行 depmod,这样下次开机自动加载模块,或者用 modprobe 加载模块时,就会用 updates 下面的

后面有时间想仔细去看看modprobe的加载机制和流程。最近事情太多,先到这。

参考