![如何像构建树外内核模块一样构建树内内核模块?](https://linux22.com/image/212930/%E5%A6%82%E4%BD%95%E5%83%8F%E6%9E%84%E5%BB%BA%E6%A0%91%E5%A4%96%E5%86%85%E6%A0%B8%E6%A8%A1%E5%9D%97%E4%B8%80%E6%A0%B7%E6%9E%84%E5%BB%BA%E6%A0%91%E5%86%85%E5%86%85%E6%A0%B8%E6%A8%A1%E5%9D%97%EF%BC%9F.png)
我想使用Oracle Linux UEK7 内核但UEK7禁用 DRBD,我们严重依赖它。
但是,那.src.rpm 可用因此理论上,drbd.ko
可以使用 kernel-uek-devel 包将模块从其原始 .src.rpm 内核树构建/lib/modules/$(uname -r)/build
为树外模块。
一种方法是调整.config
整个rpmbuild -bb
RPM,但我想继续引导 Oracle 的原始内核并仅有的构建drbd.ko
模块,以便它们能够干净地加载到相同版本的内核中。
基本上,我们想要构建一个树内内核模块,就像它是一个树外内核模块一样。 (请注意,我们想要的 .ko 的内核版本和我们正在使用的内核版本完全相同。)
问题:
- 如何构建最初不是由发布者为 .src.rpm 提供的内核构建的特定内核模块?
答案1
这就是我为 UEK6 所做的
安装构建依赖项:
yum group install Development\ Tools -y
yum install kernel-uek-devel kernel-rpm-macros kernel-abi-whitelists -y
从 Linbit 下载 DRBD 源 tar 并制作 rpm:
DRBD_VER="9.1.11"
curl -LO https://pkg.linbit.com//downloads/drbd/9/drbd-${DRBD_VER}.tar.gz
tar xf drbd-${DRBD_VER}.tar.gz
(cd ./drbd-${DRBD_VER} && make kmp-rpm)
你的转速将在这里:
/root/rpmbuild/RPMS/x86_64
构建自己的内核模块的唯一问题是,每次升级内核时(即使是较小的升级),您可能都必须重建它们
答案2
它对于内核 UEK R7 的工作原理几乎相同,但您还需要安装 gcc-toolset-11-annobin-plugin-gcc 并使用 scl enable gcc-toolset-11 "make kmp-rpm" 进行构建
答案3
为了使这项工作顺利进行,需要进行大量的故障排除。首先,请按照另一个答案中的此链接说明作为第一遍,因为可能适合您:
如果这不起作用,请确保运行这些需要从内核源代码树运行的先决条件:
zcat /boot/symvers-5.15.0-7.86.6.1.el9uek.x86_64.gz > Module.symvers
cp /boot/System.map-5.15.0-7.86.6.1.el9uek.x86_64 System.map
cp Module.symvers vmlinux.symvers
./scripts/extract-vmlinux /boot/vmlinuz-5.15.0-7.86.6.1.el9uek.x86_64 > vmlinux
接下来,如果您遇到dmesg
以下错误:
module: x86/modules: Skipping invalid relocation target, existing value is nonzero for type 1, loc 00000000fbd7a560, val ffffffffc0b33cf0
...那么您需要密切注意您的.config
文件与发行版提供的配置文件相比的情况。
就我而言,我想要构建drbd.ko
不包含在我的发行版中的版本,并且我想从相同的源代码树构建它。我首先将发行版提供的配置复制到发行版提供的 Linux 源代码树(与我启动的版本相同),如下所示:
cd /usr/src/linux
cp /boot/config-$(uname -r) .config
然后运行make menuconfig
,启用 DRBD,然后退出并将新配置保存到.config
.根据 Linux 源代码树的发现,可能会打开或关闭一些配置选项。将生成的配置文件与发行版提供的配置文件进行比较,如下所示:
diff -uw /boot/config-$(uname -r) .config
我将逐步说明我的配置与发行版提供的配置之间的相关差异,如下所示:
-# Linux/x86_64 5.15.0-7.86.6.1.el9uek.x86_64 Kernel Configuration
+# Linux/x86 5.15.0 Kernel Configuration
这里有两个主要区别。第一个明显的区别是版本错误,所以我们必须通过EXTRAVERSION=-7.86.6.1.el9uek.x86_64
命令make
行。第二个区别稍微不太明显:请注意,第一个矿是x86_64
,但第二行是 ,x86
因为您必须将架构类型传递为ARCH=x86_64
。因此,我的 make 命令如下所示:
make EXTRAVERSION=-7.86.6.1.el9uek.x86_64 ARCH=x86_64 menuconfig
现在,如果您再次保存并比较,您应该注意到版本行是相同的。
虽然在我的例子中我使用相同的编译器,但请确保您的编译器版本没有更改。如果是这样,您需要获得与您的发行版使用的完全相同的编译器。例如:
CONFIG_CC_VERSION_TEXT="gcc (GCC) 11.3.1 20220421 (Red Hat 11.3.1-2.1.0.1)"
我在配置中显示的下一个差异是缺少 CTF:
-CONFIG_HAVE_CTF_TOOLCHAIN=y
...
-CONFIG_CTF=y
因为这是Oracle提供的UEK内核,所以dtrace
被启用了。通过下载并安装 dtrace 工具,构建链检测到了 CTF,并解决了配置中的两个不同的 CTF diff 问题。
有几个配置差异可以通过安装特定的软件包来修复,因此我将在这里列出它们,如下所示:
dnf install dwarves
-CONFIG_PAHOLE_HAS_SPLIT_BTF=y
:
dnf install dtrace-devel
-CONFIG_DEBUG_INFO_BTF_MODULES=y
-CONFIG_PAHOLE_HAS_SPLIT_BTF=y
-CONFIG_DEBUG_INFO_BTF_MODULES=y
-CONFIG_MODULE_ALLOW_BTF_MISMATCH=y
-CONFIG_CTF=y
我还安装了该binutils-x86_64-linux-gnu.x86_64
软件包,但我不确定这是否解决了上述任何问题。我提到它只是因为它是我测试的一部分。虽然可能没有必要,但目前我还不知道。
现在构建 DRBD 的命令行如下所示:
make \
EXTRAVERSION=-7.86.6.1.el9uek.x86_64 \
ARCH=x86_64 \
drivers/block/drbd/drbd.ko
但是,dmesg
仍然给出以下符号错误
drbd: Unknown symbol lc_seq_printf_stats (err -2)
drbd: Unknown symbol lc_get_cumulative (err -2)
drbd: Unknown symbol lc_del (err -2)
drbd: Unknown symbol lc_committed (err -2)
drbd: Unknown symbol lc_get (err -2)
drbd: Unknown symbol lc_try_get (err -2)
drbd: Unknown symbol lc_element_by_index (err -2)
drbd: Unknown symbol lc_create (err -2)
drbd: Unknown symbol lc_try_lock (err -2)
drbd: Unknown symbol lc_destroy (err -2)
drbd: Unknown symbol lc_reset (err -2)
drbd: Unknown symbol lc_is_used (err -2)
drbd: Unknown symbol lc_seq_dump_details (err -2)
drbd: Unknown symbol lc_put (err -2)
drbd: Unknown symbol lc_find (err -2)
diff
在上面的过程中我忽略的.config
是 DRBD 所依赖的一个新模块:
+CONFIG_LRU_CACHE=m
当我注意到这一点时,我做了一些查找丢失的符号的操作,发现内核模块lib/lru_cache.ko
也需要构建。这是我的最终内核构建命令行,它成功构建了 DRBD 模块,以便它将从发行版加载到我正在运行的内核中:
make \
EXTRAVERSION=-7.86.6.1.el9uek.x86_64 \
ARCH=x86_64 \
lib/lru_cache.ko \
drivers/block/drbd/drbd.ko
最后,我能够插入两个模块,并且它工作正常:
insmod lib/lru_cache.ko
insmod drivers/block/drbd/drbd.ko
现在只需将它们复制到您的/lib/modules
目录并运行depmod
,这样它们就可以像平常一样使用:
cp lib/lru_cache.ko drivers/block/drbd/drbd.ko /lib/modules/$(uname -r)/extra/
depmod -a
modprobe drbd
dmesg | tail
最后,如果你遇到这样的错误:
Skipping BTF generation for drivers/md/raid456.ko due to unavailability of vmlinux
那么您需要将发行版的vmlinux
二进制文件提取到内核源代码树中,如下所示:
./scripts/extract-vmlinux /boot/vmlinuz-5.15.0-7.86.6.1.el9uek.x86_64 > vmlinux
如果它有效,那么您应该看到块设备注册如下:
drbd: initialized. Version: 8.4.11 (api:1/proto:86-101)
drbd: srcversion: 98E710E58B3041F3046305B
drbd: registered as block device major 147