如何像构建树外内核模块一样构建树内内核模块?

如何像构建树外内核模块一样构建树内内核模块?

我想使用Oracle Linux UEK7 内核但UEK7禁用 DRBD,我们严重依赖它。

但是,那.src.rpm 可用因此理论上,drbd.ko可以使用 kernel-uek-devel 包将模块从其原始 .src.rpm 内核树构建/lib/modules/$(uname -r)/build为树外模块。

一种方法是调整.config整个rpmbuild -bbRPM,但我想继续引导 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

相关内容