Почему этот модуль ядра помечен как постоянный в версии 2.6.39?

Когда я загружаю этот модуль:

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

Модуль помечен как [permanent] в lsmod и не может быть выгружен на 2.6.39-02063904-generic (из файла Ubuntu PPA). Но он отлично работает на ядре 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.мод.с:

#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. Это не будет очень весело решить.


person Douglas Leeder    schedule 20.09.2011    source источник
comment
Не могли бы вы также опубликовать содержимое hello3.mod.c?   -  person Hasturkun    schedule 20.09.2011
comment
@Hasturkun Я добавил hello3.mod.c и проверил, что в конфигурации установлен CONFIG_MODULE_UNLOAD (по крайней мере, в копии /boot - /proc/config.gz не включен).   -  person Douglas Leeder    schedule 21.09.2011
comment
Также должна работать выгрузка модуля, так как я могу загружать/выгружать файлы cif.   -  person Douglas Leeder    schedule 21.09.2011
comment
Хорошо, учитывая все это, я не имею ни малейшего представления, почему это может потерпеть неудачу. Вы все еще можете проверить, что /lib/modules/2.6.39-02063904-generic/build/.config (т. е. конфигурация, с которой вы строите) соответствует конфигурации в /boot и /proc/config.gz (если они существуют).   -  person Hasturkun    schedule 21.09.2011
comment
В файле .config @Hasturkun также установлен параметр CONFIG_MODULE_UNLOAD.   -  person Douglas Leeder    schedule 21.09.2011
comment
@Hasturkun - этого не происходит с ядром vanilla 2.6.39, которое я скомпилировал на этой машине. Думаю, я изучу линию ядра Ubuntu.   -  person Douglas Leeder    schedule 22.09.2011


Ответы (4)


Итак, после консультации с Canonical я знаю, в чем проблема:

основные сборки Ubuntu создаются с помощью цепочки инструментов Hardy, а цепочки инструментов 11.04 и 11.10 несовместимы для сборка модулей ядра вне дерева.

person Douglas Leeder    schedule 27.09.2011

Макет «структурного модуля» зависит от определения HAVE_JUMP_LABEL, которое зависит от определения CC_HAVE_ASM_GOTO, которое зависит от результата сценария gcc-goto.sh, который зависит от используемой версии gcc. Когда есть несоответствие, обратный вызов выхода из модуля (деструктор) получает значение NULL, в результате чего модуль помечается как [постоянный].

person Nedko Arnaudov    schedule 20.09.2012
comment
Вот это да. Вы просто это знали или изучали? В конце концов, я просто перестал использовать ядра PPA для разработки/тестирования модулей ядра... - person Douglas Leeder; 21.09.2012
comment
Я искал эту проблему, потому что она затрагивала код, о котором я забочусь. Сначала я попытался собрать модуль с помощью kbuild, и это сработало. Затем я перемещал все больше и больше вещей во внешнюю систему сборки, пока не обнаружил, что это компиляция файла C, сгенерированного модпостом. Затем я взял параметры компилятора C один за другим. - person Nedko Arnaudov; 03.10.2012

Насколько я могу судить из исходников ядра, модуль считается постоянным, если он имеет функцию инициализации, но не имеет функции выхода.

Я не совсем уверен в этом случае, но вы можете пометить свои функции инициализации и выхода с помощью __init и __exit соответственно. (также обратите внимание на любые предупреждения, выдаваемые модпостом)

person Hasturkun    schedule 20.09.2011
comment
__init и __exit обозначают раздел, в который компоновщик помещает код функции, поэтому я не верю, что это имеет какое-либо отношение к этому. - person gby; 20.09.2011
comment
@gby: Правда, это не имеет значения. насколько я могу судить, при условии, что модуль правильно скомпилирован, макрос module_exit() должен создать псевдоним для cleanup_module(). Возможно, модпост не видит его по какой-то причине, поэтому предлагается проверить предупреждения модпоста. - person Hasturkun; 20.09.2011
comment
@Hasturkun Я пытался добавить __init и __exit и добавил вывод сборки - я не вижу ошибок. - person Douglas Leeder; 20.09.2011
comment
@Hasturkun Оказывается, основные сборки Ubuntu созданы с помощью цепочки инструментов Hardy, которая несовместима с модулями ядра 11.04 и 11.10, созданными вне дерева. - person Douglas Leeder; 27.09.2011

Эта проблема возникает из-за того, что старый компилятор gcc генерирует неправильный двоичный формат модуля и приводит к тому, что функция выхода модуля не может получить правильную информацию о выгрузке из ядра.

Вы можете проверить, является ли ваша версия gcc 4.4, если это так, перейдите на использование 4.6, и проблема будет устранена:

gcc --version

если версия 4.4, удалите символьную ссылку /usr/bin/gcc и повторно свяжите ее с /usr/bin/gcc-4.6. Удаление модуля должно работать после его перекомпиляции.

person Houcheng    schedule 26.06.2014
comment
Это довольно старый вопрос: проблема оказалась в том, что ядра были собраны с помощью надежной цепочки инструментов 8.04, а не цепочки инструментов 11.04, поэтому на самом деле наоборот - более новый gcc не работал, а более старый было бы. - person Douglas Leeder; 26.06.2014
comment
8.04 gcc = 4.2.3, 11.04 gcc = 4.5.2 - person Douglas Leeder; 26.06.2014
comment
о, спасибо, я не заметил, что ядро ​​в этом вопросе устарело. Мое ядро ​​3.15.* и имеет аналогичную [постоянную] проблему при использовании компилятора 4.4 gcc. - person Houcheng; 27.06.2014