Linux 为什么这个内核模块在2.6.39上标记为永久

Linux 为什么这个内核模块在2.6.39上标记为永久,linux,module,kernel,permanent,Linux,Module,Kernel,Permanent,加载此模块时: #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> MODULE_LICENSE("Dual BSD/GPL"); static int hello_init(void) { printk("<1> Hello world!\n"); return 0; } static void hello_exit(void) {

加载此模块时:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void) {
  printk("<1> Hello world!\n");
  return 0;
}

static void hello_exit(void) {
  printk("<1> Bye, cruel world\n");
}


module_init(hello_init);
module_exit(hello_exit);
生成输出:

make -C /lib/modules/2.6.39-02063904-generic/build M=/home/douglas/kernelmod modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.39-02063904-generic'
Building with KERNELRELEASE = 2.6.39-02063904-generic
  CC [M]  /home/douglas/kernelmod/hello3.o
  Building modules, stage 2.
Building with KERNELRELEASE = 2.6.39-02063904-generic
  MODPOST 8 modules
  CC      /home/douglas/kernelmod/hello3.mod.o
  LD [M]  /home/douglas/kernelmod/hello3.ko
make[1]: Leaving directory `/usr/src/linux-headers-2.6.39-02063904-generic'
编辑2:

hello3.mod.c:

#include <linux/module.h>
#include <linux/vermagic.h>
#include <linux/compiler.h>

MODULE_INFO(vermagic, VERMAGIC_STRING);

struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {
 .name = KBUILD_MODNAME,
 .init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
 .exit = cleanup_module,
#endif
 .arch = MODULE_ARCH_INIT,
};

static const struct modversion_info ____versions[]
__used
__attribute__((section("__versions"))) = {
    { 0xbe4b3e92, "module_layout" },
    { 0xb4390f9a, "mcount" },
    { 0x5e3b3ab4, "printk" },
};

static const char __module_depends[]
__used
__attribute__((section(".modinfo"))) =
"depends=";


MODULE_INFO(srcversion, "D2A869459874C22AB265981");
编辑3:

更有趣的是,我自己编译的香草内核不会发生这种情况 加载和卸载模块都很好

编辑4:


我在虚拟机上安装了Oneiric beta 2构建版,3.0.0-11内核也没有任何问题。因此,它似乎仅限于Ubuntu香草PPA内核。解决这一问题不会有多大乐趣。

从内核源代码中可以看出,如果模块具有init函数,但缺少exit函数,则会将其标记为永久


在这种情况下,我不能完全确定,但您可能希望分别使用
\uuuu init
\uu exit
标记init和exit函数。(另外,请注意modpost发出的任何警告)

因此,在咨询Canonical后,我知道问题出在哪里:


是使用Hardy工具链构建的,11.04和11.10工具链对于构建树外内核模块是不兼容的。

“结构模块”布局取决于HAVE_JUMP_标签定义,它取决于CC_HAVE_ASM_GOTO define,它取决于gcc-GOTO.sh脚本结果,它取决于所使用的gcc版本。当存在不匹配时,模块退出回调(析构函数)获取NULL值,这导致模块被标记为[永久]。

此问题是由于编译器生成错误的模块二进制格式,并导致模块退出函数无法从内核获取正确的卸载信息

您可以检查您的gcc版本是否为4.4,如果是,请更改为使用4.6,问题将得到解决:

gcc--version


如果是4.4版本,请删除/usr/bin/gcc的符号链接,并将其重新链接到/usr/bin/gcc-4.6。模块删除应该在您重新编译后生效。

\u init和\uuuu exit指定部分,以便链接器将函数代码放入其中,因此我认为它与此无关that@gby:没错,那没关系。据我所知,假设模块已正确编译,
module\u exit()
宏应该为
cleanup\u module()
创建一个别名。可能是因为某种原因,modpost没有看到它,因此建议检查modpostwarnings@Hasturkun我已经尝试添加了_init和_exit,并添加了构建输出-我看不到任何错误。@Hasturkun发现Ubuntu主线构建是用Hardy工具链构建的,这与11.04和11.10构建的树内核模块不兼容。您是否也可以发布
hello3.mod.c
?@Hasturkun我已经添加了hello3.mod.c,并检查了配置是否设置了config\u MODULE\u UNLOAD(至少在/boot copy-/proc/config.gz中没有启用)。此外,模块卸载必须工作,因为我可以加载/卸载cifs。Ok,考虑到这一切,我一点也不知道为什么会失败。您可能仍然需要验证
/lib/modules/2.6.39-02063904-generic/build/.config
(即,您正在构建的配置)是否与
/boot
/proc/config.gz
(如果存在)@Hasturkun.config文件中的config\MODULE\u UNLOAD set.Wow匹配。你是知道还是研究过?最后,我停止在内核模块开发/测试中使用PPA内核……我一直在寻找这个问题,因为它影响了我正在处理的代码。首先,我尝试使用kbuild构建模块,它成功了。然后我将越来越多的内容转移到外部构建系统,直到我发现这是modpost生成的C文件的编译。然后我一个接一个地选择了C编译器选项。这是一个很老的问题:问题是内核是用hardy 8.04工具链构建的,而不是11.04工具链,所以事实上相反-新的gcc不起作用,旧的gcc会有。8.04 gcc=4.2.3,11.04 gcc=4.5.2oh,谢谢,在这个问题上,我没有注意到内核非常陈旧。我的内核是3.15.*并且在使用4.4 gcc编译器时有类似的[永久性]问题。
#include <linux/module.h>
#include <linux/vermagic.h>
#include <linux/compiler.h>

MODULE_INFO(vermagic, VERMAGIC_STRING);

struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {
 .name = KBUILD_MODNAME,
 .init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
 .exit = cleanup_module,
#endif
 .arch = MODULE_ARCH_INIT,
};

static const struct modversion_info ____versions[]
__used
__attribute__((section("__versions"))) = {
    { 0xbe4b3e92, "module_layout" },
    { 0xb4390f9a, "mcount" },
    { 0x5e3b3ab4, "printk" },
};

static const char __module_depends[]
__used
__attribute__((section(".modinfo"))) =
"depends=";


MODULE_INFO(srcversion, "D2A869459874C22AB265981");
# grep CONFIG_MODULE_UNLOAD /boot/config-2.6.39-02063904-generic 
CONFIG_MODULE_UNLOAD=y