一. 内核模块加载情况查询
Linux提供了三种方法查询加载到内核的模块,一种方法是直接访问proc虚拟文件系统获取,一种方法则是比较常用的lsmod方法获取,而lsmod的输出其实是基于/proc/modules。另外还有一种就是查看/sys/module/目录下是否生成已加载模块的目录。
1、/proc/modules文件
Linux 内核提供了一种通过 /proc 文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。
/proc 中的大多数虚拟文件都可以使用cat、more和less等命令查看。其中,/proc/modules列出了所有load进入内核的模块列表,里面的内容会随着系统使用和配置的变化而变化。/proc/modules内模块加载情况查询如下:
[root@localhost]# cat /proc/modules
hellomod 16384 0 - Live 0xffffffffc1072000 (OE)
openvswitch 212992 0 - Live 0xffffffffc103d000
nf_conncount 24576 1 openvswitch, Live 0xffffffffc1036000
xt_nat 16384 15 - Live 0xffffffffc1022000
vhost_net 40960 1 - Live 0xffffffffc102b000
vhost 65536 1 vhost_net, Live 0xffffffffc0ea4000
...
intel_uncore 258048 0 - Live 0xffffffffc0d39000
pcspkr 16384 0 - Live 0xffffffffc05ad000
mei_me 57344 0 - Live 0xffffffffc0d2a000
ipmi_ssif 49152 0 - Live 0xffffffffc0d16000
mei 184320 1 mei_me, Live 0xffffffffc0cd8000
i2c_i801 36864 0 - Live 0xffffffffc0c46000
...
#hellomod是小编自定义的模块,加载后可在/proc/modules中查询到
[root@localhost]# cat /proc/modules | grep hellomod
hellomod 16384 0 - Live 0xffffffffc1072000 (OE)
上述查询结果大家看起来可能会比较懵,接下来让我们解析下各列的含义:
- 第一列:模块的名字
- 第二列:模块的内存大小,单位是bytes
- 第三列:被load的次数,0意味着没有被load过
- 第四列:是否依赖第三方moudle,列出这些module
- 第五列:模块的状态,有Live, Loading, Unloading三种状态
- 第六列:模块当前的内核内存偏移位置。这些信息,debug的时候会非常有用。例如使用诊断工具 addr2line时就可能会用到该内存偏移位置。
2、lsmod命令
Linux lsmod命令用于显示已经加载到内核中的模块的状态信息,原理就是将/proc/modules 中的信息调整一下格式输出。
执行lsmod命令后会列出所有已载入系统的模块,lsmod 输出列表中有一列 Used by
,它表明此模块正在被其他模块使用。Linux操作系统的核心具有模块化的特性,因此在编译核心时,无须把全部的功能都放入核心。您可以将这些功能编译成一个个单独的模块,待需要时再分别载入。
[root@localhost]# lsmod
Module Size Used by
hellomod 16384 0
openvswitch 212992 0
tun 69632 4 vhost_net
bridge 393216 0
...
mei 184320 1 mei_me
i2c_i801 36864 0
ioatdma 69632 0
lpc_ich 28672 0
...
dm_mirror 28672 0
dm_region_hash 28672 1 dm_mirror
dm_log 24576 2 dm_region_hash,dm_mirror
dm_mod 204800 12 dm_log,dm_mirror
#hellomod是小编自定义的模块,加载后可通过lsmod查询到
[root@localhost]# lsmod | grep hellomod
hellomod 16384 0
上述查询结果虽然比第一种方法输出列少,但是可能大家依然不知道什么意思,接下来让我们解析下各列的含义:
- 第一列:模块的名字
- 第二列:模块的大小
- 第三列:被其他模块所依赖的次数
- 第四列:依赖该模块的模块名称
3、/sys/module 目录
该目录下有系统中所有的模块信息,不论这些模块是以内联(inlined) 方式 编译到内核镜像文件中,还是编译为外部模块(.ko),均会在/sys/module目录下生成以模块名命名的目录 。
[root@localhost]# ls -l /sys/module
total 0
drwxr-xr-x. 3 root root 0 Feb 23 19:32 8250
drwxr-xr-x. 3 root root 0 Feb 23 19:32 acpi
drwxr-xr-x. 5 root root 0 Feb 23 19:32 acpi_ipmi
...
drwxr-xr-x. 3 root root 0 Feb 23 19:32 firmware_class
drwxr-xr-x. 5 root root 0 Feb 23 19:32 ghash_clmulni_intel
drwxr-xr-x. 3 root root 0 Feb 23 19:32 gpiolib_acpi
drwxr-xr-x. 5 root root 0 Feb 23 19:32 grace
drwxr-xr-x. 3 root root 0 Feb 23 19:32 haltpoll
drwxr-xr-x. 5 root root 0 Feb 23 19:34 hellomod
drwxr-xr-x. 3 root root 0 Feb 23 19:32 hid
...
[root@localhost]# ls -l /sys/module | grep hellomod
drwxr-xr-x. 5 root root 0 Feb 23 19:34 hellomod
当我们加载驱动程序之后,我们可以通过 调用cat /proc/modules、lsmod命令或者查看 /sys/module/,查看我们刚加载的模块有没加载成功。
二. 内核模块加载与卸载工具
1、insmod
将指定模块加载到内核,insmod命令完全由用户自行加载一个完整文件名的模块,不会主动分析模块依赖性,需要自己手动加载。
语法格式:
insmod [ 文件名 ] [ 模块参数... ]
例如:
insmod /path/xxx.ko
其中,path表示ko文件的绝对路径或相对路径。
2、depmod
分析可加载模块的依赖性,生成modules.dep文件和modules.dep.bin文件,以便modprobe加载模块时根据modules.dep.bin进行依赖模块加载。
语法格式:
[root@localhost]# depmod [-adeisvV][-m< 文件 >][--help][模块名称]
-a 分析所有可用的模块
-d 执行排错模式
-e 输出无法参照的符号
-i 不检查符号表的版本
-m< 文件 > 使用指定的符号表文件
-n 不写入 modules.dep ,而是将结果输出到萤幕上(standard out);
-s 在系统记录中记录错误
-v 执行时显示详细的信息
-V 显示版本信息
--help 显示帮助
Linux内核模块可以为其它模块提供提供服务(在代码中使用EXPORT_SYMBOL),这种服务被称作”symbols”。若第二个模块使用了这个symbol,则该模块很明显依赖于第一个模块。这些依赖关系是非常繁杂的。
depmod 通过读取 /lib/modules/$(uname -r) /下的每个模块并确定它导出的符号和需要的符号,创建一个模块依赖关系列表。默认情况下,此列表将写入modules.dep和名为modules.dep.bin的二进制哈希版本,这两个文件位于同一目录中。如果在命令行中给出了文件名,则只检查这些模块(除非列出了所有模块,否则这些模块很少有用)。
depmod 还创建由 modules.symbols
文件及其二进制散列版本 modules.symbols.bin
中的模块提供的符号列表。
最后,如果模块提供了特殊的设备名(devname),则 depmod 将输出一个名为 modules.devname
的文件,该设备名应在启动时填充在 /dev
中(由 udev
等实用程序填充)。
3、modprobe
加载或卸载内核模块;
语法格式:
modprobe [ 参数] [模块名称] [模块参数...]
modprobe需要根据modules.dep.bin文件的内容进行加载操作,可以自动解决模块间的依赖关系表,一次性将有依赖关系的驱动全部加载到内核,不需要驱动的具体地址,但需要将驱动拷贝或设置软链接到/lib/modules/$(uname -r)/
或者/lib/modules/$(uname -r)/extra/
目录下。modprobe加载模块时并不需要指定ko文件的具体目录,直接使用modprobe 模块名字即可,我们不妨测试下:
#加载hellomod.ko模块之前,默认的模块信息如下
[root@localhost 6.2.0-rc5+]# modinfo hellomod
filename: /lib/modules/6.2.0-rc5+/hellomod.ko
license: Dual BSD/GPL
srcversion: DEA7EE7031439C7A120C77C
depends:
retpoline: Y
name: hellomod
vermagic: 6.2.0-rc5+ SMP preempt mod_unload modversions
#删除调/lib/modules/$(uname -r)/目录下的hellomod软链接
[root@localhost 6.2.0-rc5+]# rm -f hellomod.ko
[root@localhost 6.2.0-rc5+]# ls -l
total 3800
lrwxrwxrwx. 1 root root 27 Feb 20 11:17 build - > /usr/src/kernels/6.2.0-rc5+
drwxr-xr-x. 13 root root 141 Feb 24 10:46 kernel
-rw-r--r--. 1 root root 943175 Feb 24 19:26 modules.alias
-rw-r--r--. 1 root root 899138 Feb 24 19:26 modules.alias.bin
-rw-r--r--. 1 root root 8920 Jan 30 10:22 modules.builtin
-rw-r--r--. 1 root root 11118 Feb 24 19:26 modules.builtin.bin
-rw-r--r--. 1 root root 69179 Jan 30 10:22 modules.builtin.modinfo
-rw-r--r--. 1 root root 313395 Feb 24 19:26 modules.dep
-rw-r--r--. 1 root root 429116 Feb 24 19:26 modules.dep.bin
-rw-r--r--. 1 root root 405 Feb 24 19:26 modules.devname
-rw-r--r--. 1 root root 106408 Jan 30 10:22 modules.order
-rw-r--r--. 1 root root 833 Feb 24 19:26 modules.softdep
-rw-r--r--. 1 root root 494353 Feb 24 19:26 modules.symbols
-rw-r--r--. 1 root root 593333 Feb 24 19:26 modules.symbols.bin
lrwxrwxrwx. 1 root root 27 Feb 20 11:17 source - > /usr/src/kernels/6.2.0-rc5+
#复制源文件路径下的hellomod.ko到/lib/modules/$(uname -r)路径下
[root@localhost 6.2.0-rc5+]# cp /tmp/28/hellomod.ko .
[root@localhost