5

我有一个相当大的驱动程序模块,我正在尝试为最近的 Linux 内核(3.4.4)编译。我可以insmod使用 2.6.27.25 内核成功编译和相同的模块。GCC 版本也不同,4.7.0 和 4.3.0。请注意,这个模块非常复杂,我不能简单地浏览所有代码和所有 makefile。

当“插入”模块时,我得到一个Cannot allocate memory带有以下痕迹的:

vmap allocation for size 30248960 failed: use vmalloc=<size> to increase size.
vmalloc: allocation failure: 30243566 bytes
insmod: page allocation failure: order:0, mode:0xd2
Pid: 5840, comm: insmod Tainted: G           O 3.4.4-5.fc17.i686 #1
Call Trace:
 [<c092702a>] ? printk+0x2d/0x2f
 [<c04eff8d>] warn_alloc_failed+0xad/0xf0
 [<c05178d9>] __vmalloc_node_range+0x169/0x1d0
 [<c0517994>] __vmalloc_node+0x54/0x60
 [<c0490825>] ? sys_init_module+0x65/0x1d80
 [<c0517a60>] vmalloc+0x30/0x40
 [<c0490825>] ? sys_init_module+0x65/0x1d80
 [<c0490825>] sys_init_module+0x65/0x1d80
 [<c050cda6>] ? handle_mm_fault+0xf6/0x1d0
 [<c0932b30>] ? spurious_fault+0xae/0xae
 [<c0932ce7>] ? do_page_fault+0x1b7/0x450
 [<c093665f>] sysenter_do_call+0x12/0x28
-- clip --

显而易见的答案似乎是该模块分配了太多内存,但是:

  • 我对旧内核版本没有问题,这个模块的大小是多少
  • 如果我修剪该模块的某些部分以获得更低的内存消耗,我将始终收到与新内核相同的错误消息
  • 我可以卸载许多其他模块,但它没有影响(它是否仍然相关?Linux 是否存在关于模块总内存使用量的全局限制)

因此,我怀疑新内核的问题与有限的内存没有直接关系。

新内核抱怨 avmalloc()为 30,000 KB,但对于旧内核,lsmod 给我的大小为 4,800 KB。这些数字应该直接相关吗?是否有可能在构建过程中出现问题并且请求的 RAM 过多?当我编译两者的部分大小时.ko,我看不出有很大的差异。

所以我试图了解问题出在哪里。当我检查转储堆栈时,我找不到匹配的代码。似乎故障vmalloc()是由 完成的sys_init_module(),它init_module()来自kernel/module.c。但是代码不匹配。当我检查我的目标代码时.koinit_module()代码也不匹配。

我或多或少被阻塞了,因为我对内核不够了解,而且所有的构建系统和模块加载都很难理解。该错误发生在模块加载之前,因为我怀疑某些功能丢失并且insmod此时不报告这些错误。

4

2 回答 2

5

我相信分配是在 中完成的layout_and_allocate,由load_module. 两者都是静态函数,因此它们可能是内联的,因此不在堆栈中。
因此,这不是由您的代码完成的分配,而是由 Linux 为加载您的代码而完成的分配。

如果你的旧内核是 4.8MB,而新内核是 30MB,就可以解释为什么会失败。
所以问题是为什么它这么大。

大小可能是由于代码量(不太可能增长这么多)或静态分配的数据。
一个可能的解释是你有一个很大的静态分配数组,它的大小在 Linux 中定义。如果大小显着增长,您的数组将会增长。
一个猜测 - 一个大小为 的数组NR_CPUS

您应该能够使用诸如nm或之类的命令objdump来查找这样的数组。但是,我不确定该怎么做。

于 2012-07-19T13:14:09.903 回答
2

问题实际上是由于模块中的调试部分造成的。旧内核能够忽略这些部分,但新内核将它们计入要分配的总大小。但是,当pr_debug()在加载时启用来自 module.c 的跟踪时,这些部分不会与其他部分一起转储。

如何摆脱它们并解决问题:

objcopy -R .debug_aranges \
    -R .debug_info \
    -R .debug_abbrev \
    -R .debug_line \
    -R .debug_frame \
    -R .debug_str \
    -R .debug_loc \
    -R .debug_ranges \
    orignal.ko new.ko

该项目的特定构建文件也可能为旧内核版本添加了“量身定制”的调试信息,但是在尝试使用虚拟模块时,我发现附加了完全相同类型的调试部分,所以我宁愿怀疑一些关于内核或 Fedora 中模块管理的政策变更。

欢迎提供有关这些更改的任何信息。

于 2012-07-20T11:58:29.100 回答