Портирование модуля на более новое ядро ​​Linux: невозможно выделить память

У меня довольно большой модуль драйвера, который я пытаюсь скомпилировать для недавнего ядра Linux (3.4.4). Я могу успешно скомпилировать и insmod тот же модуль с ядром 2.6.27.25. Версия GCC также отличается, 4.7.0 против 4.3.0. Обратите внимание, что этот модуль довольно сложный, и я не могу просто просмотреть весь код и все make-файлы.

При "вставке" модуля я получаю 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 глобальный лимит в отношении общего использования памяти модулями)

Поэтому я подозреваю, что проблема с новым ядром не связана напрямую с ограниченным объемом памяти.

Новое ядро ​​жалуется на vmalloc() из 30000 КБ, но со старым ядром lsmod дает мне размер 4800 КБ. Должны ли эти цифры быть непосредственно связаны? Возможно ли, что во время сборки что-то пошло не так и запрошено слишком много оперативной памяти? Когда я компилирую размер разделов обоих .koЯ не вижу большой разницы.

Поэтому я пытаюсь понять, откуда проблема. Когда я проверяю выгруженный стек, я не могу найти соответствующий фрагмент кода. Кажется, что неисправный vmalloc() сделано sys_init_module(), который init_module() от kernel/module.c, Но код не совпадает. Когда я проверяю код объекта из моего .ko, init_module() Код также не совпадает.

Я более или менее заблокирован, так как недостаточно хорошо знаю ядро, и всю систему сборки и загрузку модулей довольно сложно понять. Ошибка возникает до загрузки модуля, так как я подозреваю, что некоторые функции отсутствуют и insmod не сообщает об этих ошибках на данный момент.

2 ответа

Я считаю, что распределение сделано в layout_and_allocate который называется load_module, Оба являются статическими функциями, поэтому они могут быть встроенными и, следовательно, не в стеке.
Так что это не распределение, сделанное вашим кодом, а выделение, сделанное Linux для загрузки вашего кода.

Если ваше старое ядро ​​имеет размер 4,8 МБ, а новое - 30 МБ, это может объяснить причину сбоя.
Так что вопрос в том, почему он такой большой.

Размер может быть связан с объемом кода (маловероятно, что он так сильно вырос) или статически распределенными данными.
Вероятное объяснение состоит в том, что у вас есть большой статически распределенный массив, размер которого определен в Linux. Если размер значительно увеличился, ваш массив будет расти.
Догадка - массив, размер которого NR_CPUS,

Вы должны быть в состоянии использовать такие команды, как nm или же objdump найти такой массив. Однако я не уверен, как именно это сделать.

Проблема была на самом деле из-за разделов отладки в модуле. Старое ядро ​​могло игнорировать эти разделы, но новое подсчитывало их в общем размере для выделения. Однако при включении 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.

Любая информация об этих изменениях приветствуется.

Другие вопросы по тегам