摘要现场设备升级或重启后自定义内核模块突然加载失败这种事并不少见。这次报错是Module sio_gpio not found in directory /lib/modules/6.8.0-111-generic第一眼看很容易以为sio_gpio.ko被删了。实际查下来文件还在只是放在旧内核目录里。这次机器上旧模块放在/lib/modules/6.8.0-107-generic/extra/sio_gpio.ko但系统当前已经启动到6.8.0-111-generic而modprobe不会满机器乱找它默认只查当前运行内核的模块目录/lib/modules/$(uname-r)所以这次要确认的不是“机器上到底有没有这个.ko文件”而是这个模块是不是在当前运行内核对应的/lib/modules/$(uname -r)目录下。下面按现场排查顺序记录一下先怎么恢复再怎么避免下次重启又踩一次。一、问题现象现场执行sudomodprobe sio_gpio系统提示Module sio_gpio not found in directory /lib/modules/6.8.0-111-generic看/lib/modules机器上其实有好几个内核版本6.5.0-18-generic 6.8.0-90-generic 6.8.0-94-generic 6.8.0-107-generic 6.8.0-110-generic 6.8.0-111-generic再去旧内核目录看ls/lib/modules/6.8.0-107-generic/extra能看到sio_gpio.ko到这里就能先排除一件事模块文件不是完全丢了。问题卡在另一边系统现在跑的已经不是6.8.0-107-generic而是6.8.0-111-generic。二、先看当前内核排这种问题先别急着复制文件第一条命令看当前内核uname-r如果输出是6.8.0-111-generic那modprobe sio_gpio默认只会去这里找/lib/modules/6.8.0-111-generic/它不会因为旧目录里存在/lib/modules/6.8.0-107-generic/extra/sio_gpio.ko就自动跨版本加载。所以这句Module not found不能直接理解成“整个系统里没有这个文件”。放到这次现场它的意思更接近当前运行内核对应的模块目录里没有这个模块。三、为什么换个内核就不行Linux 内核模块不是普通动态库不能只看文件名一样不一样。.ko模块通常跟内核版本、内核配置、符号表和编译参数绑在一起。哪怕都是6.8.0系列6.8.0-107-generic和6.8.0-111-generic对模块来说也不是同一个目标。可以看一下这个模块当时是按哪个内核编出来的modinfo /lib/modules/6.8.0-107-generic/extra/sio_gpio.ko|grepvermagic如果看到类似vermagic: 6.8.0-107-generic SMP preempt mod_unload modversions而当前uname-r输出是6.8.0-111-generic那就很明确了这个模块原本是给6.8.0-107-generic编译的。这时有两种情况模块刚好还能被当前内核接受复制到当前目录后可以临时加载模块和当前内核 ABI 不匹配复制过去也会报Invalid module format所以复制.ko只能当现场尝试别把它当成正式修复。四、先恢复现场复制到当前内核目录如果当前目标是先让设备恢复起来可以先把旧目录里的模块放到当前内核目录。sudomkdir-p/lib/modules/$(uname-r)/extrasudocp/lib/modules/6.8.0-107-generic/extra/sio_gpio.ko\/lib/modules/$(uname-r)/extra/sudodepmod-a$(uname-r)sudomodprobe sio_gpio这里最容易漏的是这一步sudodepmod-a$(uname-r)depmod会重新生成模块依赖索引。否则文件虽然已经复制过去modprobe仍然可能查不到。加载后再确认lsmod|grepsio_gpio如果还想看内核侧日志sudodmesg|tail-50这套操作只能算临时恢复。它解决的是“当前内核目录里没有模块”的问题不保证模块一定适配当前内核。五、如果提示 Invalid module format如果复制后执行sudomodprobe sio_gpio报Invalid module format或者dmesg里出现类似version magic 6.8.0-107-generic ... should be 6.8.0-111-generic ...这就说明模块和当前内核对不上。这时继续复制就没意义了要在当前内核下重新编译。先装当前内核头文件sudoaptupdatesudoaptinstallbuild-essentiallinux-headers-$(uname-r)然后进入sio_gpio源码目录makecleanmake安装到当前内核目录sudomkdir-p/lib/modules/$(uname-r)/extrasudocpsio_gpio.ko /lib/modules/$(uname-r)/extra/sudodepmod-a$(uname-r)sudomodprobe sio_gpio最后再确认lsmod|grepsio_gpio这一步才算是针对当前内核处理。六、排查顺序这类问题按下面顺序走就行没必要一上来就重装系统也别先怀疑驱动源码。否是是否是否modprobe sio_gpio 失败查看当前内核 uname -r查看 /lib/modules/当前内核/extra当前内核目录下是否有 sio_gpio.ko从旧目录复制到当前内核目录执行 depmod -a 当前内核版本modprobe sio_gpio是否加载成功临时恢复完成查看 dmesg是否 Invalid module format按当前内核重新编译模块继续查依赖、符号、权限和路径这张图里别跳过前两步uname-r和ls/lib/modules/$(uname-r)/extra先把“当前内核”和“模块所在目录”对上后面的判断才不会跑偏。七、现场设备别让内核随便变这次问题说到底是系统升级后启动到了新内核。如果这台机器是机器人主机、工控机、采集设备或者任何依赖自定义驱动的现场设备内核版本就别让它随便变。可以把 GRUB 默认启动项固定到已验证过的内核比如6.8.0-107-generic先查看 GRUB 菜单项grep-E^[[:space:]]*(submenu|menuentry) /boot/grub/grub.cfg找到类似submenu Advanced options for Ubuntu ... Ubuntu, with Linux 6.8.0-107-generic编辑sudovim/etc/default/grub把GRUB_DEFAULT0改成类似GRUB_DEFAULTAdvanced options for UbuntuUbuntu, with Linux 6.8.0-107-generic这里的名称必须和/boot/grub/grub.cfg里的submenu、menuentry名称一致中间用连接。更新 GRUBsudoupdate-grub重启后确认uname-r如果输出6.8.0-107-generic说明启动内核已经回到指定版本。八、还要控制 apt 升级内核只固定 GRUB 还不够这个坑下次还可能被apt upgrade带回来。只要后面继续执行apt upgrade系统仍然可能安装新的内核包。现场设备如果没有驱动重编译流程下次重启还是可能回到同一个问题。先看本机实际安装的内核相关包dpkg-llinux-generic*linux-image*linux-headers*linux-modules*|grep^ii如果确认用的是 Ubuntu 普通 generic 内核元包可以锁定sudoapt-mark hold linux-generic linux-image-generic linux-headers-generic如果用的是 HWE 内核元包名称可能是linux-generic-hwe-*、linux-image-generic-hwe-*这一类不要照抄要按上一步查到的实际包名替换。如果要锁定具体内核版本也可以执行sudoapt-mark hold linux-image-6.8.0-107-genericsudoapt-mark hold linux-headers-6.8.0-107-genericsudoapt-mark hold linux-modules-6.8.0-107-genericsudoapt-mark hold linux-modules-extra-6.8.0-107-generic查看已经锁定的包apt-mark showhold|greplinux这个做法能稳住现场。代价也很直接内核安全更新不会再自动跟着走后面要有人安排升级窗口和验证流程。九、长期还是上 DKMS如果sio_gpio要长期用别一直靠手动复制.ko也别指望永远不升级内核。把它纳入 DKMS 更省心。DKMS 干的就是这件事安装新内核时自动为新内核重新编译并安装模块。也就是说系统从6.8.0-107-generic升级到6.8.0-111-genericDKMS 可以把sio_gpio重新编译到新内核对应的目录里。我一般按这个顺序处理DKMS 自动重编译 固定内核版本 手动复制 .ko手动复制是救急固定内核是稳住现场DKMS 才是长期维护自定义驱动该走的路。小结这次sio_gpio加载失败不是模块文件被删了而是模块还在旧内核目录系统却已经启动到了新内核。这几个对应关系别看错旧模块位置 /lib/modules/6.8.0-107-generic/extra/sio_gpio.ko 当前运行内核 6.8.0-111-generic modprobe 查找目录 /lib/modules/6.8.0-111-generic现场先恢复可以复制到当前内核目录并执行depmod -a $(uname -r)sudomkdir-p/lib/modules/$(uname-r)/extrasudocp/lib/modules/6.8.0-107-generic/extra/sio_gpio.ko\/lib/modules/$(uname-r)/extra/sudodepmod-a$(uname-r)sudomodprobe sio_gpio如果提示Invalid module format就别继续绕了直接按当前内核重新编译。以后遇到类似问题先记住这个判断modprobe找的是当前运行内核的模块目录不是以前放过模块的目录。对工控机、机器人主机、采集卡、GPIO、串口、CAN 这类依赖内核模块的设备来说内核升级一定要和驱动验证放在一起做。普通升级看着没什么落到现场设备上可能就是驱动直接起不来。参考modprobe(8) - Linux manual pagedepmod(8) - Linux manual pagemodinfo(8) - Linux manual pageUbuntu Manpageapt-mark(8)Ubuntu Community Help WikiGrub2/SubmenusUbuntu Community Help WikiGrub2/SetupUbuntu Community Help WikiDKMSUbuntu WikiKernel/Dev/DKMSPackaging
Linux 内核升级后驱动突然失效?一次 sio_gpio “Module not found” 排查记录
发布时间:2026/6/15 0:16:21
摘要现场设备升级或重启后自定义内核模块突然加载失败这种事并不少见。这次报错是Module sio_gpio not found in directory /lib/modules/6.8.0-111-generic第一眼看很容易以为sio_gpio.ko被删了。实际查下来文件还在只是放在旧内核目录里。这次机器上旧模块放在/lib/modules/6.8.0-107-generic/extra/sio_gpio.ko但系统当前已经启动到6.8.0-111-generic而modprobe不会满机器乱找它默认只查当前运行内核的模块目录/lib/modules/$(uname-r)所以这次要确认的不是“机器上到底有没有这个.ko文件”而是这个模块是不是在当前运行内核对应的/lib/modules/$(uname -r)目录下。下面按现场排查顺序记录一下先怎么恢复再怎么避免下次重启又踩一次。一、问题现象现场执行sudomodprobe sio_gpio系统提示Module sio_gpio not found in directory /lib/modules/6.8.0-111-generic看/lib/modules机器上其实有好几个内核版本6.5.0-18-generic 6.8.0-90-generic 6.8.0-94-generic 6.8.0-107-generic 6.8.0-110-generic 6.8.0-111-generic再去旧内核目录看ls/lib/modules/6.8.0-107-generic/extra能看到sio_gpio.ko到这里就能先排除一件事模块文件不是完全丢了。问题卡在另一边系统现在跑的已经不是6.8.0-107-generic而是6.8.0-111-generic。二、先看当前内核排这种问题先别急着复制文件第一条命令看当前内核uname-r如果输出是6.8.0-111-generic那modprobe sio_gpio默认只会去这里找/lib/modules/6.8.0-111-generic/它不会因为旧目录里存在/lib/modules/6.8.0-107-generic/extra/sio_gpio.ko就自动跨版本加载。所以这句Module not found不能直接理解成“整个系统里没有这个文件”。放到这次现场它的意思更接近当前运行内核对应的模块目录里没有这个模块。三、为什么换个内核就不行Linux 内核模块不是普通动态库不能只看文件名一样不一样。.ko模块通常跟内核版本、内核配置、符号表和编译参数绑在一起。哪怕都是6.8.0系列6.8.0-107-generic和6.8.0-111-generic对模块来说也不是同一个目标。可以看一下这个模块当时是按哪个内核编出来的modinfo /lib/modules/6.8.0-107-generic/extra/sio_gpio.ko|grepvermagic如果看到类似vermagic: 6.8.0-107-generic SMP preempt mod_unload modversions而当前uname-r输出是6.8.0-111-generic那就很明确了这个模块原本是给6.8.0-107-generic编译的。这时有两种情况模块刚好还能被当前内核接受复制到当前目录后可以临时加载模块和当前内核 ABI 不匹配复制过去也会报Invalid module format所以复制.ko只能当现场尝试别把它当成正式修复。四、先恢复现场复制到当前内核目录如果当前目标是先让设备恢复起来可以先把旧目录里的模块放到当前内核目录。sudomkdir-p/lib/modules/$(uname-r)/extrasudocp/lib/modules/6.8.0-107-generic/extra/sio_gpio.ko\/lib/modules/$(uname-r)/extra/sudodepmod-a$(uname-r)sudomodprobe sio_gpio这里最容易漏的是这一步sudodepmod-a$(uname-r)depmod会重新生成模块依赖索引。否则文件虽然已经复制过去modprobe仍然可能查不到。加载后再确认lsmod|grepsio_gpio如果还想看内核侧日志sudodmesg|tail-50这套操作只能算临时恢复。它解决的是“当前内核目录里没有模块”的问题不保证模块一定适配当前内核。五、如果提示 Invalid module format如果复制后执行sudomodprobe sio_gpio报Invalid module format或者dmesg里出现类似version magic 6.8.0-107-generic ... should be 6.8.0-111-generic ...这就说明模块和当前内核对不上。这时继续复制就没意义了要在当前内核下重新编译。先装当前内核头文件sudoaptupdatesudoaptinstallbuild-essentiallinux-headers-$(uname-r)然后进入sio_gpio源码目录makecleanmake安装到当前内核目录sudomkdir-p/lib/modules/$(uname-r)/extrasudocpsio_gpio.ko /lib/modules/$(uname-r)/extra/sudodepmod-a$(uname-r)sudomodprobe sio_gpio最后再确认lsmod|grepsio_gpio这一步才算是针对当前内核处理。六、排查顺序这类问题按下面顺序走就行没必要一上来就重装系统也别先怀疑驱动源码。否是是否是否modprobe sio_gpio 失败查看当前内核 uname -r查看 /lib/modules/当前内核/extra当前内核目录下是否有 sio_gpio.ko从旧目录复制到当前内核目录执行 depmod -a 当前内核版本modprobe sio_gpio是否加载成功临时恢复完成查看 dmesg是否 Invalid module format按当前内核重新编译模块继续查依赖、符号、权限和路径这张图里别跳过前两步uname-r和ls/lib/modules/$(uname-r)/extra先把“当前内核”和“模块所在目录”对上后面的判断才不会跑偏。七、现场设备别让内核随便变这次问题说到底是系统升级后启动到了新内核。如果这台机器是机器人主机、工控机、采集设备或者任何依赖自定义驱动的现场设备内核版本就别让它随便变。可以把 GRUB 默认启动项固定到已验证过的内核比如6.8.0-107-generic先查看 GRUB 菜单项grep-E^[[:space:]]*(submenu|menuentry) /boot/grub/grub.cfg找到类似submenu Advanced options for Ubuntu ... Ubuntu, with Linux 6.8.0-107-generic编辑sudovim/etc/default/grub把GRUB_DEFAULT0改成类似GRUB_DEFAULTAdvanced options for UbuntuUbuntu, with Linux 6.8.0-107-generic这里的名称必须和/boot/grub/grub.cfg里的submenu、menuentry名称一致中间用连接。更新 GRUBsudoupdate-grub重启后确认uname-r如果输出6.8.0-107-generic说明启动内核已经回到指定版本。八、还要控制 apt 升级内核只固定 GRUB 还不够这个坑下次还可能被apt upgrade带回来。只要后面继续执行apt upgrade系统仍然可能安装新的内核包。现场设备如果没有驱动重编译流程下次重启还是可能回到同一个问题。先看本机实际安装的内核相关包dpkg-llinux-generic*linux-image*linux-headers*linux-modules*|grep^ii如果确认用的是 Ubuntu 普通 generic 内核元包可以锁定sudoapt-mark hold linux-generic linux-image-generic linux-headers-generic如果用的是 HWE 内核元包名称可能是linux-generic-hwe-*、linux-image-generic-hwe-*这一类不要照抄要按上一步查到的实际包名替换。如果要锁定具体内核版本也可以执行sudoapt-mark hold linux-image-6.8.0-107-genericsudoapt-mark hold linux-headers-6.8.0-107-genericsudoapt-mark hold linux-modules-6.8.0-107-genericsudoapt-mark hold linux-modules-extra-6.8.0-107-generic查看已经锁定的包apt-mark showhold|greplinux这个做法能稳住现场。代价也很直接内核安全更新不会再自动跟着走后面要有人安排升级窗口和验证流程。九、长期还是上 DKMS如果sio_gpio要长期用别一直靠手动复制.ko也别指望永远不升级内核。把它纳入 DKMS 更省心。DKMS 干的就是这件事安装新内核时自动为新内核重新编译并安装模块。也就是说系统从6.8.0-107-generic升级到6.8.0-111-genericDKMS 可以把sio_gpio重新编译到新内核对应的目录里。我一般按这个顺序处理DKMS 自动重编译 固定内核版本 手动复制 .ko手动复制是救急固定内核是稳住现场DKMS 才是长期维护自定义驱动该走的路。小结这次sio_gpio加载失败不是模块文件被删了而是模块还在旧内核目录系统却已经启动到了新内核。这几个对应关系别看错旧模块位置 /lib/modules/6.8.0-107-generic/extra/sio_gpio.ko 当前运行内核 6.8.0-111-generic modprobe 查找目录 /lib/modules/6.8.0-111-generic现场先恢复可以复制到当前内核目录并执行depmod -a $(uname -r)sudomkdir-p/lib/modules/$(uname-r)/extrasudocp/lib/modules/6.8.0-107-generic/extra/sio_gpio.ko\/lib/modules/$(uname-r)/extra/sudodepmod-a$(uname-r)sudomodprobe sio_gpio如果提示Invalid module format就别继续绕了直接按当前内核重新编译。以后遇到类似问题先记住这个判断modprobe找的是当前运行内核的模块目录不是以前放过模块的目录。对工控机、机器人主机、采集卡、GPIO、串口、CAN 这类依赖内核模块的设备来说内核升级一定要和驱动验证放在一起做。普通升级看着没什么落到现场设备上可能就是驱动直接起不来。参考modprobe(8) - Linux manual pagedepmod(8) - Linux manual pagemodinfo(8) - Linux manual pageUbuntu Manpageapt-mark(8)Ubuntu Community Help WikiGrub2/SubmenusUbuntu Community Help WikiGrub2/SetupUbuntu Community Help WikiDKMSUbuntu WikiKernel/Dev/DKMSPackaging