Linux驱动-modprobe加载oot驱动与重启系统自动加载分析
一、序言:
在进行linux驱动开发和调试的过程中,频繁地需要手动修改和编译驱动源代码,然后加载编译出来的out-of-tree驱动。初次涉足linux驱动开发时,一位老资深同事曾告诫我,在调试驱动时最好使用insmod命令来加载自行编译的oot驱动,这样既便捷又安全。
为何如此建议呢?因为我发现,当使用modprobe nfp加载自行编译的OOT驱动时,每次却发现系统加载的驱动文件竟然位于/lib/modules/目录下,这些文件是内核自带的驱动文件,而非我手动编译的驱动文件。于是,我开始探索的用法,并发现默认会在(uname -r)/目录下搜索要加载的模块,这让我想到,如果能够将/lib/modules/$(uname -r)/kernel/drivers/net/ethernet/netronome/nfp/目录下的驱动文件每次替换为我自行编译的OOT驱动文件,那么就能够成功加载我编译的驱动了。
于是,就对/lib/modules/$(uname -r)/kernel/drivers/net/ethernet/netronome/nfp/ 路径下的in-tree驱动文件备份,并用我手动编译出来的驱动文件替换该路径下的驱动文件。本以为这种方式很nice,结果老员工却告诉我当我编译出来的oot驱动文件有bug的时候,即使重新启动系统,原本的驱动也无法恢复,导致设备工作异常;因为该路径下原有的in-tree驱动文件已不存在,而使用insmod直接加载我编译出来的oot驱动时,即使该驱动文件有bug,系统重启后,依然可以通过使用/lib/modules/$(uname -r)/kernel/drivers/net/ethernet/netronome/nfp/路径下的in-tree驱动文件正常启动系统。
想一想,好像确实是这个道理,于是,在日后的工作中,但凡加载自己手动编译的oot驱动,我都是使用insmod命令。但是,后续的工作中,又遇到了一个问题,就是使用insmod加载的驱动,在系统重新启动后,又变成了系统自带的in-tree驱动。于是,只能再次手动卸载in-tree驱动,再加载oot驱动。如果该主机上部署了与该oot驱动模块紧密相关的业务环境,意味着一切将需要重新手动设置一遍,不可谓不麻烦。于是乎,系统重启后自动加载oot驱动就成了一个亟待解决的问题。
因此,遂考虑可能是因为使用insmod加载驱动的缘故,导致系统重新启动后无法自动加载oot驱动。于是,便研究如何在工作中通过modprobe来加载oot驱动。
注意::其实导致系统重新启动后无法自动加载oot驱动,与使用insmod或modprobe加载没有关系,后续内容会讲解。
【拓展:】:模块依据代码编写与编译时的位置可分:内部模块和外部模块,即 in-tree模块 和 out-of-tree(即oot)模块,在内核树外部编写并构建的模块就是外部模块。动态加载的模块包括in-tree模块和out-of-tree(oot)模块。in-tree 模块是 Linux 内核树的内部自带的模块,即它们已经是内核的一部分。树外模块是 来自 Linux 内核树的外部。它们通常是为开发和测试目的编写的,例如测试树级或处理不兼容的内核模块的新版本。往往oot模块虽然安装成功了,但是会提示loading out-of-tree module taints kernel,可通过dmesg查看到。
经过针对 modprobe 的研究和实验,本文总结三种方法:拷贝法、软链接法和配置 external 路径法。
注意::本文所有实验均在CentOS Stream 8系统上进行,一切配置和命令仅适用于CentOS系列机器,Ubuntu与其他机器具体配置指令可能有所区别。
二、modprobe加载oot驱动总结:
这里有关modprobe的使用总结的三种方法,均需要依赖/etc/depmod.d/下的配置文件来实现自动识别驱动加载路径。/etc/depmod.d/下通常会含有如下配置文件:
[root@localhost ~]# ls -l /etc/depmod.d/ total 8 -rw-r--r--. 1 root root 116 Jun 5 2021 dist.conf -rw-r--r--. 1 root root 115 Nov 10 2021 kvdo.conf登录后复制
接下来,让我们一起了解一下有关使用modprobe的三种方法。
1、拷贝法
将自己编译生成的oot驱动文件拷贝到/lib/modules/$(uname -r)/extra/目录下,再执行echo "override xxx * extra" > /etc/depmod.d/xxx.conf命令,确保当Linux内核中存在多个同名的内核模块时,优先安装/lib/modules/$(uname -r)/extra/目录下的文件。随后,再执行depmod -a 进行模块依赖的更新(驱动如果存在依赖项,必须先加载依赖项后才能进行驱动的安装)。
注意::echo "override xxx * extra" > /etc/depmod.d/xxx.conf 命令表示在/etc/depmod.d/目录下创建一个 xxx.conf文件,在里面添加override xxx * extra(其中,xxx表示待加载的驱动名字(不带.ko后缀),*表示匹配任何内核版本,也可以指定具体的内核版本),通过/etc/depmod.d目录内的配置文件,设置override命令,确保安装在 /lib/modules/$(uname -r)/extra/下的任何匹配模块名称将优先于内核已经提供的任何类似名称的模块。外部开发的模块一般我们都放在/lib/modules/$(uname -r)/extra 目录下使用:。
【拓展:】:depmod配置文件的override命令格式和解析如下:
override modulename kernelversion modulesubdirectory登录后复制
This command allows you to override which version of a specific module will be used when more than one module sharing the same name is processed by the depmod: command. It is possible to specify one kernel or all kernels using the * wildcard. modulesubdirectory is the name of the subdirectory under /lib/modules (or other module location) where the target module is installed. For example, it is possible to override the priority of an updated test module called kmod: by specifying the following command: “override kmod * extra”. This will ensure that any matching module name installed under the extra: subdirectory within /lib/modules (or other module location) will take priority over any likenamed module already provided by the kernel.
实战演示如下:
# 将自己编译的oot nfp驱动拷贝到/lib/modules/$(uname -r)/extra/路径下 [root@localhost ~]# cp /home/xxx/nfp-drv-kmods-private/src/nfp.ko /lib/modules/$(uname -r)/extra/nfp.ko [root@localhost ~]# ls -l /lib/modules/$(uname -r)/extra total 50900 -rw-r--r--. 1 root root 52121240 Nov 15 19:49 nfp.ko # 如果/etc/下不存在depmod.d目录,则执行如下命令创建depmod.d目录,否则无需执行 [root@localhost ~]# mkdir -p /etc/depmod.d # 该命令确保在depmod命令处理多个共享相同名称的内核模块时,优先安装/lib/modules/$(uname -r)/extra/下的模块 [root@localhost ~]# echo "override nfp * extra" > /etc/depmod.d/nfp.conf # 探测所有模块。如果在命令行中没有给出文件名,则默认启用此选项。 [root@localhost ~]# depmod -a # depmod创建一个模块依赖列表,并确定它导出了什么符号以及它需要什么符号。默认情况下,该列表被写入modules.dep [root@localhost ~]# cat /lib/modules/$(uname -r)/modules.dep | grep nfp extra/nfp.ko: [root@localhost ~]# # 系统自带in-tree nfp驱动,显示大小为442368字节 [root@localhost ~]# lsmod | grep nfp nfp 442368 0 tls 110592 1 nfp # 卸载系统自带的in-tree nfp驱动 [root@localhost ~]# rmmod nfp # 直接modprobe nfp就会加载手动编译的oot nfp驱动 [root@localhost ~]# modprobe nfp # 手动编译的oot nfp驱动,显示大小为585728字节 [root@localhost ~]# lsmod | grep nfp nfp 585728 0 # 将depmod -a更新后的结果保存到initramfs中,这一步可选 [root@localhost ~]# dracut -f登录后复制
根据上面的结果,可以看出来拷贝法需要将手动编译的oot驱动复制到/lib/modules/$(uname -r)/extra目录下,创建depmod的配置文件,即/etc/depmod.d/nfp.conf,使用depmod创建模块依赖列表,再使用modprobe加载驱动的时候,就可以成功安装我们手动编译的oot驱动了。这里之所以将oot驱动复制到extra目录下,是为了更新依赖列表后就可以使用modprobe成功安装,因为执行了echo "override nfp * extra" > /etc/depmod.d/nfp.conf这一步,override命令确保安装在 /lib/modules/$(uname -r)/extra/下的nfp 驱动将优先于内核已经提供的任何同名的模块。
上面实战演示中的dracut -f是可选的步骤,可以执行,也可以不执行。具体作用后面再详细介绍。
2、软链接法
软链接法与拷贝法比较相似,区别仅在于将自己编译生成的 oot 驱动文件通过建立软链接链接到 /lib/modules/$(uname -r)/extra/ 目录下,而非拷贝到 extra 目录下,其余步骤与拷贝法基本相同。
注意::uname -r 是获取系统当前使用的内核版本,不同内核版本有各自的内核目录。
实战演示如下:
[root@localhst ~]# rm -f /lib/modules/$(uname -r)/extra/nfp.ko [root@localhost ~]# ls -l /lib/modules/$(uname -r)/extra total 0 # 建立软链接 [root@localhost ~]# ln -sf /home/xxx/nfp-drv-kmods-private/src/nfp.ko /lib/modules/$(uname -r)/extra/nfp.ko [root@localhost ~]# ls -l /lib/modules/$(uname -r)/extra total 0 lrwxrwxrwx. 1 root root 42 Nov 16 12:20 nfp.ko -> /home/xxx/nfp-drv-kmods-private/src/nfp.ko # 因拷贝法中已创建并配置该文件,因此,这里直接使用即可。否则,需要创建并配置该文件内容如下 [root@localhost ~]# cat /etc/depmod.d/nfp.conf override nfp * extra # 创建依赖列表 [root@localhost ~]# depmod -a # 卸载掉之前安装的驱动模块 [root@localhost ~]# rmmod nfp # 安装手动编译的oot nfp驱动 [root@localhost ~]# modprobe nfp # 查看新加载的oot nfp驱动 [root@localhost ~]# lsmod | grep nfp nfp 585728 0 # 将depmod -a更新后的结果保存到initramfs中,这一步可选 [root@localhost ~]# dracut -f登录后复制
根据上面的结果,可以看出来软链接法需要将手动编译的oot驱动链接到/lib/modules/$(uname -r)/extra目录下,创建并配置depmod的配置文件,再使用depmod创建模块依赖列表。当使用modprobe加载驱动的时候,就可以成功安装我们手动编译的oot驱动了。这里之所以将oot驱动软链接到extra目录下,更新依赖列表后就可以使用modprobe成功安装,是因为创建并配置了depmod的配置文件,override命令确保安装在 /lib/modules/$(uname -r)/extra/下的nfp 驱动将优先于内核已经提供的任何同名的模块。
上面实战演示中的dracut -f是可选的步骤,可以执行,也可以不执行。具体作用后面再详细介绍。
3、配置external路径
【解析】使用external关键字,可以指定系统上的任意编译生成oot驱动的目录作为modprobe安装驱动的路径。
配置external路径法无需将自己编译生成的oot驱动文件拷贝或者建立软链接到/lib/modules/$(uname -r)/extra/目录下,但是需执行echo "external * /home/xxx/nfp-drv-kmods-private/src" > /etc/depmod.d/xxx.conf命令以及配置/etc/depmod.d/dist.conf 文件。随后,再执行depmod -a 进行模块依赖表的更新,即更新modules.dep和modules.dep.bin文件。这时,再进行modprobe的时候,直接安装的则是通过external命令指定的路径下的oot驱动。
注意::echo "external * /home/xxx/nfp-drv-kmods-private/src" > /etc/depmod.d/xxx.conf 命令表示在/etc/depmod.d/目录下创建一个 xxx.conf文件,在里面添加external * /home/xxx/nfp-drv-kmods-private/src(其中,/home/xxx/nfp-drv-kmods-private/src为编译出oot驱动的路径(xxx表示一个实际的路径名字而已), *表示匹配任何内核版本,也可以指定具体的内核版本),通过/etc/depmod.d目录内的配置文件,设置external命令,表示这是一个外部的路径。/etc/depmod.d/dist.conf的内容则表示搜索路径的优先级,如果想优先匹配external指定的路径下的文件,则需将external放在extra和built-in之前。这样external指定的路径下的任何匹配模块名称将优先于extra内保存的同名模块和内核已经提供的同名模块。
【拓展:】:depmod配置文件的external命令格式和解析如下:
external kernelversion absolutemodulesdirectory...登录后复制
This specifies a list of directories, which will be checked according to the priorities in the search: command. The order matters also, the first directory has the higher priority. The kernelversion is a POSIX regular expression or * wildcard, like in the override:.
实战演示如下:
# 创建并配置depmod配置文件auto_define.conf [root@localhost ~]# echo "external * /home/xxx/nfp-drv-kmods-private/src" > /etc/depmod.d/auto_define.conf [root@localhost ~]# cat /etc/depmod.d/auto_define.conf external * /home/xxx/nfp-drv-kmods-private/src [root@localhost ~]# ls -l /etc/depmod.d/ auto_define.conf dist.conf kvdo.conf # 编辑dist.conf文件内容,使external指定的路径优先级高于extra和built-in,即将external放在extra和built-in前面 [root@localhost ~]# vi /etc/depmod.d/dist.conf # 查看dist.conf文件内容 [root@localhost ~]# cat /etc/depmod.d/dist.conf # # depmod.conf # # override default search ordering for kmod packaging search updates external extra built-in weak-updates # 创建依赖列表 [root@localhost ~]# depmod -a # 查看modules.dep内容,根据检索结果可知,加载驱动使用的是/home/xxx/nfp-drv-kmods-private/src/路径下的oot nfp驱动 [root@localhost ~]# cat /lib/modules/4.18.0-500.el8.x86_64/modules.dep | grep nfp.ko /home/xxx/nfp-drv-kmods-private/src/nfp.ko: # 卸载掉系统上原有已加载的驱动 [root@localhost ~]# rmmod nfp # 重新加载驱动 [root@localhost ~]# modprobe nfp [root@localhost ~]# # oot nfp驱动加载成功 [root@localhost ~]# lsmod | grep nfp nfp 585728 0 # 将depmod -a更新后的结果保存到initramfs中,这一步可选 [root@localhost ~]# dracut -f登录后复制
需要注意的是:因为在/etc/depmod.d/dist.conf中,external的优先级高于extra,因此使用modprobe的时候,优先加载的是external 指定路径下的驱动文件。否则,如果dist.conf的内容如下所示:
[root@localhost ~]# cat /etc/depmod.d/dist.conf # # depmod.conf # # override default search ordering for kmod packaging search updates extra external built-in weak-updates登录后复制
即extra位于external之前,则modprobe的时候,优先加载的将是/lib/modules/$(uname -r)/extra/目录下的驱动文件。
注意::built-in表示/lib/modules/$(uname -r)/kernel/drivers/net/ethernet/netronome/nfp/目录。
三、重启系统后自动加载oot驱动:
在日常Linux驱动开发及调试的过程中,经常遇到需要手动加载oot驱动成功的情况下,一旦重启系统以后,机器上重启前已成功加载的驱动就不见了,又需要重新再手动加载一遍,要是上面部署着复杂的业务,则全部都需要再重新部署一遍,就极其麻烦了。于是乎,系统重启后自动加载oot驱动就成了一个亟待解决的问题。针对这个问题,小编经过学习以及工作中实战,终于摸索出这里面的规律,总结如下:
规律一::无论是使用insmod或modprobe 加载驱动,如果未执行dracut --force 指令,均有可能会出现重启系统后系统中原来加载的oot驱动消失,被in-tree驱动替代的现象。 规律二::如果initramfs中包含相关驱动且系统硬盘驱动库目录下存在同名的驱动,则系统重启时,会加载initramfs中的该驱动(in-tree或oot 均适用)。 规律三::如果initramfs中包含多个同名驱动(in-tree或oot),则会根据这些同名驱动的优先级(/etc/depmod.d/dist.conf中含有优先级),系统启动时选择优先级最高的驱动加载。 规律四::如果initramfs中不包含相关驱动,而系统硬盘驱动库下存在同名的驱动,则系统启动时会选择系统硬盘驱动库目录下的该同名驱动加载。
【拓展:】initramfs 即 initram file system,翻译成中文意思就是 初始 ram 文件系统:,基于 tmpfs,是一种大小灵活,直接作用在内存中的文件系统。initramfs包含的工具和脚本,在正式的根文件系统的初始化脚本 init 启动之前,就被挂载。Linux系统开机后,首先加载initramfs文件中包含的驱动程序,如果相应的设备对应的驱动不在initramfs文件包含范围内,那么会去系统硬盘存储的驱动库中去寻找匹配的驱动进行加载;系统硬盘驱动库的位置即为:/lib/modules/$($uname -r)/(下面讲系统硬盘驱动库时,即表示该目录:);所以相应的驱动只要在系统硬盘的驱动库下或者initramfs中至少存在一个就可以正常加载,一旦在initramfs中加载成功,无论系统硬盘的驱动库中存在的驱动版本是否相同都不会重新去加载。initramfs中包含的驱动ko文件在目录lib/modules/下,具体包含的ko可依次查看。
针对上述总结的规律,让我们通过实战演示来验证一下。
1、规律一
无论是使用insmod或modprobe 加载驱动,如果未执行dracut --force 指令,均有可能会出现重启系统后系统中原来加载的oot驱动消失,被in-tree驱动替代的现象。:
实战演示如下:
# 卸载掉系统中原来安装的nfp驱动 [root@localhost ~]# rmmod nfp [root@localhost ~]# lsmod | grep nfp [root@localhost ~]# ls -l /home/xxx/nfp-drv-kmods-private/src/ | grep nfp.ko -rw-r--r--. 1 root root 52121240 Nov 17 19:10 nfp.ko # insmod安装自己编译的oot nfp驱动 [root@localhost ~]# insmod /home/xxx/nfp-drv-kmods-private/src/nfp.ko [root@localhost ~]# lsmod | grep nfp nfp 585728 0 # insmod安装完oot nfp驱动后,直接重启系统 [root@localhost ~]# reboot # 重启系统后虽然加载了nfp驱动,但是并非自己编译的oot nfp驱动,而是系统内核自带的in-tree nfp驱动 [root@localhost ~]# lsmod | grep nfp nfp 442368 0 tls 110592 1 nfp登录后复制
通过对比系统重启前后,加载的nfp驱动的大小可以知道,前后加载的驱动并非同一个驱动。果然,如果未执行dracut --force 指令,系统启动后,系统内核自带的in-tree驱动会取代了我自己编译的oot驱动。那dracut --force指令的作用是什么呢?其实这个命令的作用就是将当前系统硬盘驱动库中包含的驱动写入到initramfs镜像中,该镜像会在系统启动过程中,将里面含有的相关驱动加载到系统中。让我们执行这个命令后,再看一下结果:
[root@localhost ~]# rmmod nfp [root@localhost ~]# insmod /home/xxx/nfp-drv-kmods-private/src/nfp.ko [root@localhost ~]# lsmod | grep nfp nfp 585728 0 # dracut -f为 dracut --force的缩写 [root@localhost ~]# dracut -f [root@localhost ~]# [root@localhost ~]# reboot # 重启后,加载的是in-tree nfp驱动 [root@localhost ~]# lsmod | grep nfp nfp 442368 0 tls 110592 1 nfp登录后复制
明明前面说oot驱动加载后,未执行dracut --force,系统启动后,系统内核自带的in-tree驱动会取代了我自己编译的oot驱动。为什么我现在执行了这个命令,我编译的 oot 驱动却还是被系统内核自带的in-tree驱动取代了呢?因为dracut -f这个命令的作用是将当前系统硬盘驱动库中包含的驱动写入到initramfs镜像中,而我使用 insmod 加载的是我自己编译目录下的驱动,而系统硬盘驱动库中并未含有我编译的 oot 驱动,让我将自己编译的oot驱动放置到系统硬盘驱动库下属的extra目录下,再验证一下结果会是怎么样。
[root@localhost ~]# cd /lib/modules/$(uname -r)/extra/ [root@localhost extra]# ls [root@localhost extra]# cp /home/xxx/nfp-drv-kmods-private/src/nfp.ko . [root@localhost extra]# ls nfp.ko [root@localhost extra]# pwd /lib/modules/4.18.0-500.el8.x86_64/extra [root@localhost extra]# rmmod nfp # insmod加载编译路径下的oot驱动 [root@localhost extra]# insmod /home/xxx/nfp-drv-kmods-private/src/nfp.ko [root@localhost extra]# lsmod | grep nfp nfp 585728 0 #建立模块依赖列表 [root@localhost extra]# depmod -a # 将oot驱动复制到extra目录下以后,执行depmod -a果然更新了模块依赖列表 [root@localhost extra]# cat /lib/modules/$(uname -r)/modules.dep | grep nfp.ko extra/nfp.ko: # 更新initramfs镜像 [root@localhost extra]# dracut -f # 拷贝initramfs到新创建的test1目录下 [root@localhost test1]# cp /boot/initramfs-4.18.0-500.el8.x86_64.img . [root@localhost test1]# ls initramfs-4.18.0-500.el8.x86_64.img # 解压缩initramfs到新创建的test1目录下 [root@localhost test1]# /usr/lib/dracut/skipcpio ./initramfs-4.18.0-500.el8.x86_64.img | zcat | cpio -ivd . bin dev dev/console dev/kmsg dev/null dev/random dev/urandom etc ...... [root@localhost test1]# ls bin etc init lib opt root sbin sys tmp var dev home initramfs-4.18.0-500.el8.x86_64.img lib64 proc run shutdown sysroot usr # initramfs镜像的lib/modules/4.18.0-500.el8.x86_64/extra/目录下含有nfp.ko [root@localhost test1]# ls ./lib/modules/4.18.0-500.el8.x86_64/extra/ nfp.ko # 重新启动系统 [root@localhost test1]# reboot #重启系统后,加载的是我自己编译的oot驱动 [root@localhost ~]# lsmod | grep nfp nfp 585728 0登录后复制
果然,将自己编译的oot驱动放置到系统硬盘驱动库下属的extra目录下,执行depmod -a,再执行dracut -f,即会更新initramfs镜像,使其在initramfs镜像内的驱动库下属的extra目录下含有我编译的oot驱动,这样系统再重启以后,就会自动加载我编译的oot驱动了。因此,无论是使用insmod或modprobe加载oot驱动,重点是将自己编译的oot驱动放置到硬盘驱动库下属的相关目录下,执行depmod -a,再执行dracut -f,更新initramfs镜像,使其在initramfs镜像内的驱动库下属相关目录下含有我编译的oot驱动,这样系统再重启以后,就会自动加载我编译的oot驱动了。
这里,modprobe加载oot驱动的演示就不再给出,感兴趣的小伙伴可以自行尝试。
2、规律二
如果initramfs中包含相关驱动且系统硬盘驱动库目录下存在同名的驱动,则系统重启时,会加载initramfs中的该驱动(in-tree或oot 均适用)。:
实战演示如下:
# 创建test2目录,并将dracut -f生成的initramfs镜像拷贝到该目录下 [root@localhost test2]# cp /boot/initramfs-4.18.0-500.el8.x86_64.img . [root@localhost test2]# ls initramfs-4.18.0-500.el8.x86_64.img # 解压initramfs镜像到当前目录下 [root@localhost test2]# /usr/lib/dracut/skipcpio ./initramfs-4.18.0-500.el8.x86_64.img | zcat | cpio -ivd . bin dev dev/console dev/kmsg ...... [root@localhost test2]# ls bin etc init lib opt root sbin sys tmp var dev home initramfs-4.18.0-500.el8.x86_64.img lib64 proc run shutdown sysroot usr # 解压的initramfs镜像的lib/modules/4.18.0-500.el8.x86_64/extra/目录下含有nfp.ko,该驱动为oot驱动 [root@localhost test1]# ls ./lib/modules/4.18.0-500.el8.x86_64/extra/ nfp.ko # 系统硬盘驱动库目录下属目录中存在同名的驱动,该驱动为in-tree驱动 [root@localhost ~]# ls /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/netronome/nfp/ nfp.ko.xz # 重启系统 [root@localhost ~]# reboot # 根据nfp驱动的大小,可知重启后加载的驱动为oot驱动 [root@localhost ~]# lsmod | grep nfp nfp 585728 0登录后复制
根据实战演示的结果可知,当initramfs镜像和系统硬盘驱动库目录下存在同名的驱动时,重启操作系统后,加载的是位于initramfs镜像内的oot驱动。
3、规律三
如果initramfs中包含多个同名驱动(in-tree或oot),则会根据这些同名驱动的优先级(/etc/depmod.d/dist.conf中含有优先级),系统启动时选择优先级最高的驱动加载。:
实战演示如下:
[root@localhost ~]# vi /etc/depmod.d/dist.conf [root@localhost ~]# vi /etc/depmod.d/auto_define.conf [root@localhost ~]# cat /etc/depmod.d/auto_define.conf external * /home/xxx/nfp-drv-kmods-private/src # external位于extra和built-in之前,表示其优先级高于后两者 [root@localhost ~]# cat /etc/depmod.d/dist.conf # # depmod.conf # # override default search ordering for kmod packaging search updates external extra built-in weak-updates #更新模块依赖列表 [root@localhost ~]# depmod -a # 查看模块依赖列表,优先级最高的是external设定的/home/xxx/nfp-drv-kmods-private/src/目录下的nfp驱动 [root@localhost ~]# cat /lib/modules/$(uname -r)/modules.dep | grep nfp /home/xxx/nfp-drv-kmods-private/src/nfp.ko: # 更新initramfs镜像 [root@localhost ~]# dracut -f # 创建test3目录,并将dracut -f生成的initramfs镜像拷贝到该目录下 [root@localhost test3]# cp /boot/initramfs-4.18.0-500.el8.x86_64.img . [root@localhost test3]# ls initramfs-4.18.0-500.el8.x86_64.img # 解压initramfs镜像到当前目录下 [root@localhost test3]# /usr/lib/dracut/skipcpio ./initramfs-4.18.0-500.el8.x86_64.img | zcat | cpio -ivd . bin dev dev/console dev/kmsg ...... [root@localhost test3]# ls bin etc init lib opt root sbin sys tmp var dev home initramfs-4.18.0-500.el8.x86_64.img lib64 proc run shutdown sysroot usr # initramfs镜像中含有/etc/depmod.d/auto_define.conf中定义的external目录下含义oot驱动 [root@localhost test3]# ls -l ./home/xxx/nfp-drv-kmods-private/src/ | grep nfp.ko -rw-r--r--. 1 root root 52119640 Nov 18 21:51 nfp.ko # initramfs镜像中含有驱动库目录下的in-tree驱动 [root@localhost test3]# ls ./lib/modules/$(uname -r)/kernel/drivers/net/ethernet/netronome/nfp/ nfp.ko.xz # 重启系统 [root@localhost ~]# reboot # 由已加载驱动的大小与前面均不同可知,加载的为external指定的目录下加载的oot驱动 [root@localhost ~]# lsmod | grep nfp nfp 589824 0登录后复制
根据实战演示结果可知,当initramfs中包含多个同名驱动(in-tree或oot)时,则会根据这些同名驱动的优先级,选择优先级最高的驱动加载,无论其是in-tree或oot驱动。
4、规律四
如果initramfs中不包含相关驱动,而系统硬盘驱动库下存在同名的驱动,则系统启动时会选择系统硬盘驱动库目录下的该同名驱动加载。:
实战演示如下:
# 创建一个临时目录test4,存放initramfs镜像及解压后的文件 [root@localhost tmp]# mkdir test4 # 构造系统上不包含任何nfp驱动的当前内核对应的initramfs镜像并拷贝到test4目录下 [root@localhost test4]# cp /boot/initramfs-$(uname -r).img . [root@localhost test4]# ls initramfs-4.18.0-500.el8.x86_64.img # 使用skipcpio解压缩当前目录下的initramfs镜像 [root@localhost test4]# /usr/lib/dracut/skipcpio ./initramfs-4.18.0-500.el8.x86_64.img | zcat | cpio -ivd . bin dev dev/console dev/kmsg dev/null dev/random dev/urandom etc etc/centos-release etc/cmdline.d etc/conf.d etc/conf.d/systemd.conf ... # 查看当前目录解压后包含的文件 [root@localhost test4]# ls bin etc init lib opt root sbin sys tmp var dev home initramfs-4.18.0-500.el8.x86_64.img lib64 proc run shutdown sysroot usr # 查看解压后的initramfs中是否存在nfp驱动及依赖 [root@localhost test4]# cat ./lib/modules/4.18.0-500.el8.x86_64/modules.dep | grep nfp # 解压后的initramfs中,连extra目录都不存在 [root@localhost test4]# ls -l ./lib/modules/4.18.0-500.el8.x86_64/extra/ ls: cannot access './lib/modules/4.18.0-500.el8.x86_64/extra/': No such file or directory # 解压后的initramfs中,连lib/modules/4.18.0-500.el8.x86_64/kernel/drivers/net/ethernet/netronome/nfp/目录都不存在 [root@localhost test4]# ls -l ./lib/modules/4.18.0-500.el8.x86_64/kernel/drivers/net/ethernet/netronome/nfp/ ls: cannot access './lib/modules/4.18.0-500.el8.x86_64/kernel/drivers/net/ethernet/netronome/nfp/': No such file or directory # 解压后的initramfs中,完全检索不到nfp.ko文件 [root@localhost test4]# find ./ -name "nfp.ko" [root@localhost test4]# # 查看当前系统驱动库下模块依赖列表/lib/modules/$(unaem -r)/modules.dep中是否包含nfp驱动 # 只有该列表中包含nfp驱动记录且硬盘驱动库下存在nfp驱动,在系统重启后,才能够成功加载硬盘上驱动库目录下的nfp驱动, # 否则将不会加载nfp驱动。 [root@localhost ~]# cat /lib/modules/$(uname -r)/modules.dep | grep nfp kernel/drivers/net/ethernet/netronome/nfp/nfp.ko.xz: kernel/net/tls/tls.ko.xz # 检查系统硬盘驱动库下是否存在nfp驱动 [root@localhost ~]# ls -l /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/netronome/nfp/ total 176 -rw-r--r--. 1 root root 176228 Jun 28 08:17 nfp.ko.xz # 卸载掉系统上当前安装的nfp驱动 [root@localhost ~]# rmmod nfp # 重启操作系统 [root@localhost ~]# reboot # 查看重启后的系统中是否成功加载nfp驱动,果然加载的是in-tree nfp驱动,即硬盘驱动目录下的nfp驱动 [root@localhost ~]# lsmod | grep nfp nfp 442368 0 tls 110592 1 nfp登录后复制
上述实战结果证明,initramfs 镜像中如果不包含相关驱动,而系统驱动库下的模块依赖列表中含有驱动依赖记录,且系统硬盘驱动库下属目录(即/lib/modules/$(uname -r)/kernel/drivers/net/ethernet/netronome/nfp/)存在同名的驱动,则系统启动时会选择系统硬盘驱动库目录下属目录包含的该同名驱动进行加载。然而,如果系统驱动库下的模块依赖列表中不包含驱动依赖记录,则即使系统硬盘驱动库下属目录中含有相关驱动,操作系统亦不会加载:。如下结果能够证明该结论。
[root@localhost ~]# cat /lib/modules/$(uname -r)/modules.dep | grep nfp [root@localhost ~]# [root@localhost ~]# ls -l /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/netronome/nfp/ total 176 -rw-r--r--. 1 root root 176228 Jun 28 08:17 nfp.ko.xz [root@localhost ~]# rmmod nfp [root@localhost ~]# lsmod | grep nfp [root@localhost ~]# reboot # 重启系统后,检查系统中是否含有nfp驱动,结果显示没有加载nfp驱动 [root@localhost ~]# lsmod | grep nfp [root@localhost ~]#登录后复制
至此,有关modprobe加载oot驱动与重启系统后自动加载oot驱动的分析就总结完毕了。俗话讲:“好记性不如烂笔头”;将相关知识总结成文,等日后有需要的时候可以拿出来快速回顾一下,当然这也有助于加深对这方面知识的理解。
最后,希望对于从事Linux驱动的朋友们有所帮助和启发。