Linux内核模块是一种可以根据需要动态加载和卸载的代码,可以在不重启系统的情况下扩展内核功能。
这里演示一个最简单的内核模块的开发过程。

开发环境

内核模块开发需要内核头文件和Makefile等特定的依赖。Centos下为了解决依赖需要安装kernel-devel包,需要与内核版本一致,比如内核版本3.10.0-862.el7.x86_64,那么需要安装kernel-devel-3.10.0-862.el7.x86_64。

kernel-devel安装/usr/src/kernels/目录下。但系统在/lib/modules/3.10.0-862.el7.x86_64/source和/lib/modules/3.10.0-862.el7.x86_64/build两个位置有软链到合适版本的kernel-devel安装位置。因此需要指定路径时,我会使用/lib/modules/3.10.0-862.el7.x86_64/build。

代码样例

hello.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Hu Yu <hyuuhit@gmail.com>");
MODULE_DESCRIPTION("hello world");
MODULE_VERSION("0.1");

static int __init hello_init(void)
{
printk(KERN_INFO "Hello world!\n");
return 0;
}

static void __exit hello_exit(void)
{
printk(KERN_INFO "Goodbye world.\n");
}

module_init(hello_init);
module_exit(hello_exit);

module_init宏指定的函数在模块插入内核时运行。
module_exit宏指定的函数在模块被移出内核时运行。

Makefile
1
2
3
4
5
6
7
8
9
10
11
obj-m := hello.o

PWD:=$(shell pwd)
KVER:=$(shell uname -r)
KDIR:=/lib/modules/$(KVER)/build

all:
$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean

编译一下

1
2
3
4
5
6
7
8
9
[huyu@centos1804 kernel-hello]$ make
make -C /lib/modules/3.10.0-862.el7.x86_64/build M=/home/huyu/workspace/kernel-hello modules
make[1]: Entering directory `/usr/src/kernels/3.10.0-862.el7.x86_64'
CC [M] /home/huyu/workspace/kernel-hello/hello.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/huyu/workspace/kernel-hello/hello.mod.o
LD [M] /home/huyu/workspace/kernel-hello/hello.ko
make[1]: Leaving directory `/usr/src/kernels/3.10.0-862.el7.x86_64'

编译完成后可以看到hello.ko

工具包

内核模块的加载、卸载等操作需要一系列命令工具支持,在centos7.5下属于kmod包。

  • insmod
    将模块插入到内核。

    1
    2
    3
    [huyu@centos1804 kernel-hello]$ sudo insmod hello.ko
    [huyu@centos1804 kernel-hello]$ sudo tail -n 1 /var/log/messages
    Jul 9 12:45:17 centos1804 kernel: Hello world!
  • lsmod
    显示已经加载的内核模块。

    1
    2
    3
    [huyu@centos1804 kernel-hello]$ lsmod
    Module Size Used by
    hello 12425 0
  • rmmod
    将模块移出内核。

    1
    2
    3
    4
    [huyu@centos1804 kernel-hello]$ sudo rmmod hello
    [huyu@centos1804 kernel-hello]$ sudo tail -n 2 /var/log/messages
    Jul 9 12:45:17 centos1804 kernel: Hello world!
    Jul 9 12:47:37 centos1804 kernel: Goodbye world.
  • modinfo
    显示模块信息。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [huyu@centos1804 kernel-hello]$ modinfo hello.ko
    filename: /home/huyu/workspace/kernel-hello/hello.ko
    version: 0.1
    description: hello world
    author: <hyuuhit@gmail.com>
    license: GPL
    retpoline: Y
    rhelversion: 7.5
    srcversion: E48DBB5483D6F8CDDBCF041
    depends:
    vermagic: 3.10.0-862.el7.x86_64 SMP mod_unload modversions
  • modprobe
    可以完成其他命令工具的功能,更灵活。其他命令一般是modprobe的封装。

  • depmod
    用于生成模块依赖相关的文件。我没有使用过。