9

当我加载这个模块时:

#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);

(来自http://www.freesoftwaremagazine.com/articles/drivers_linux?page=0,2

该模块在 2.6.39-02063904-generic (来自Ubuntu PPA)上被标记为[permanent]inlsmod并且无法卸载。但它在默认的 2.6.38 内核上运行良好。(都在 Ubuntu 11.04 x86 上)。

2.6.39 发生了什么变化?我需要在我的代码中更改什么?

当我遇到这个问题时,我试图找出一个更复杂的问题。

编辑:

根据答案的建议,我编辑了要添加的代码__init__exit(hello3.c):

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

MODULE_LICENSE("Dual BSD/GPL");

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

static void __exit 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:

你好3.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");

# grep CONFIG_MODULE_UNLOAD /boot/config-2.6.39-02063904-generic 
CONFIG_MODULE_UNLOAD=y

编辑3:

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

编辑4:

我在虚拟机上安装了 Oneiric beta 2 版本,3.0.0-11 内核也没有任何问题。所以它似乎仅限于 Ubuntu Vanilla PPA 内核。解决这个问题不会很有趣。

4

4 回答 4

7

所以,在咨询了 Canonical 之后,我知道问题出在哪里:

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

于 2011-09-27T19:27:52.917 回答
6

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

于 2012-09-20T17:22:00.913 回答
1

据我从内核源代码中可以看出,如果模块具有 init 函数但缺少退出函数,则该模块被标记为永久。

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

于 2011-09-20T09:42:26.877 回答
0

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

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

gcc --version

如果是 4.4 版本,删除 /usr/bin/gcc 的符号链接并将其重新链接到 /usr/bin/gcc-4.6。重新编译后,模块删除应该可以工作。

于 2014-06-26T07:20:49.067 回答