Содержание


Разработка модулей ядра Linux

Часть 12. Инструментарий разработчика модулей ядра

Comments

Серия контента:

Этот контент является частью # из серии # статей: Разработка модулей ядра Linux

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Разработка модулей ядра Linux

Следите за выходом новых статей этой серии.

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

Основные команды

В таблице 1 представлен набор специфических команд Linux, которыми чаще всего приходится пользоваться программисту при работе с модулями ядра, хотя большая их часть и не входит в набор рекомендуемых POSIX и не существует на других UNIX-платформах, в отличие от большинства утилит GNU. Стоит заметить, что знание представленных команд не отменяет необходимости изучения и последующего применения общесистемных команд.

Таблица 1. Команды, применяемые при работе с модулями ядра
КомандаОписание
# sudo insmod ./hello_printk.koзагрузка модуля в систему (вообще-то говоря, это попытка загрузки любого файла как модуля ядра).
# rmmod hello_printkудаление установленного модуля из системы.
# modprobe hello_printkпрограмма добавления модуля к ядру Linux, производится проверка всех зависимостей и загрузка всех модулей, требуемых этими зависимостями.
$ modinfo hello_printk.koвывод информации о файле модуля.
$ lsmodвывод списка модулей, установленных в системе, и их зависимостей.
# depmodобновление зависимостей модулей в системе.
$ dmesgвывод системного журнала, в том числе и диагностики от модулей.
# cat /var/log/messagesтот же вывод системного журнала, но формат отличается от dmesg и может требовать прав root.
$ nm mobj.koкоманда, возвращающая список имён объектного файла, в частности, для поиска имён с глобальной сферой видимости (тип T) и имён, импортируемых данным модулем для связывания (тип U).
$ objdump -t hello_printk.koдетальный анализ объектной структуры модуля.
$ readelf -s hello_printk.koещё один инструмент анализа объектной структуры модуля.

Примечание: Напомним, что некоторые команды требуют для выполнения прав root. Обычно (но не обязательно) настройками командного интерпретатора устанавливается приглашение в командной строке вида # для регистрации под именем root и вида $ для регистрации под именем любого другого ординарного пользователя. Именно так будут показываться команды, чтобы различать полномочия, требующиеся для их выполнения.

Команды rmmod, modprobe требуют указания имени модуля, а команды insmod, modinfo - указания имени файла модуля.

Системные файлы

В таблице 2 представлен краткий перечень системных файлов, к которым наиболее часто приходится обращаться при работе с модулями ядра.

Таблица 2. Системные файлы, используемые при работе с модулями ядра.
Системный файлОписание
/var/log/messagesжурнал системных сообщений, в том числе и сообщений модулей ядра.
/proc/modulesдинамически создаваемый (обновляемый) список имён модулей, установленных в системе.
/proc/kallsymsдинамически создаваемый список имён ядра.
/boot/System.map-`uname -r`содержит статическую таблицу имён ядра для образа, с которого загружена система, эта таблица может несколько отличаться от /proc/kallsyms.
/proc/slabinfoдинамическая детальная информация сляб-алокатора памяти (о нём мы будем говорить отдельно и подробно).
/proc/meminfoсводная информация об использовании памяти в системе.
/proc/devicesсписок драйверов устройств, встроенных в действующее ядро.
/proc/dmaсписок задействованных в данный момент каналов DMA.
/proc/filesystemsсписок файловых систем, встроенных в ядро.
/proc/interruptsсписок задействованных в данный момент прерываний.
/proc/ioportsсписок задействованных в данный момент портов ввода/вывода.
/proc/versionподробная информация о версии ядра.

Каталог типа /lib/modules/`uname -r`/build/include содержит все заголовочные файлы, необходимые для включения определений в код модуля и для получения справочной информации. Точное наименование каталога зависит от версии ядра и его можно узнать с помощью следующей команды:

$ echo /lib/modules/`uname -r`/build/include
/lib/modules/2.6.18-92.el5/build/include

Подсчёт ссылок использования

Одним из важнейших понятий (и часто объясняемым крайне запутанно) в области модулей ядра является подсчёт ссылок использования модуля. Счётчик ссылок является внутренним полем структуры описания модуля и в принципе непосредственного доступа к нему у пользователя нет (по крайней мере, простыми способами этот доступ не получить). При загрузке модуля начальное значение счётчика ссылок равно нулю. При загрузке следующего модуля, который использует имена (импортирует), экспортируемые данным модулем, счётчик ссылок данного модуля инкрементируется. Модуль, в котором счётчик ссылок использования не равен нулю, не может быть выгружен командой rmmod. Этот момент так тщательно отслеживается из-за критичности наличия модулей в системе: некорректное обращение к несуществующему модулю гарантирует крах всей системы.

Рассмотрим такую простейшую команду:

$ lsmod | grep i2c_core 
i2c_core               21732  5 videodev,i915,drm_kms_helper,drm,i2c_algo_bit

Здесь модуль, зарегистрированный в системе под именем i2c_core (это не имя файла, и оно произвольно взято из числа загруженных модулей системы), имеет текущее значение счётчика ссылок 5, и далее следует список имён 5-ти модулей, на него ссылающихся. До тех пор, пока все эти 5 модулей не будут удалены из системы, удалить модуль i2c_core будет невозможно.

В чём состоит отмеченная выше путаница, относящаяся к обсуждениям счетчика ссылок? В том, что в области этого понятия от ядра к ядру происходят постоянные изменения, и происходят они с такой скоростью, что литература и обсуждения не поспевают за ними, а поэтому часто описывают какие-то несуществующие механизмы. До сих пор в описаниях часто можно встретить ссылки на макросы MOD_INC_USE_COUNT() и MOD_DEC_USE_COUNT(), которые увеличивают и уменьшают счётчик ссылок. Но эти макросы остались в ядрах 2.4. В ядре 2.6 их место заняли следующие функциональные вызовы (определённые в <linux/module.h>):

  1. int try_module_get( struct module *module ) - увеличить счётчик ссылок для модуля (возвращается признак успешности операции);
  2. void module_put( struct module *module ) - уменьшить счётчик ссылок для модуля;
  3. unsigned int module_refcount( struct module *mod ) - возвратить значение счётчика ссылок для модуля;

В качестве параметра во все эти вызовы, как правило, передаётся константный указатель THIS_MODULE, так что примеры вызовов, в конечном итоге, выглядят следующим образом:

try_module_get( THIS_MODULE );

Таким образом, видно, что имеется некоторая возможность управлять значением счётчика ссылок из кода собственного модуля. Делать это нужно крайне осторожно, поскольку если счетчик увеличить и симметрично его впоследствии не уменьшить, то модуль станет невозможно выгрузить (до перезагрузки системы). Это один из вариантов возникновения в системе «перманентных» модулей, другая возможность их возникновения: модуль, не имеющий в своём коде функции завершения. В некоторых случаях может оказаться необходимым динамически изменить счётчик ссылок, препятствуя на время возможности выгрузки модуля. Это актуально, например, в функциях, реализующих операции open() (увеличить счётчик обращений) и close() (уменьшить / восстановить счётчик обращений) для драйверов устройств, иначе станет возможна выгрузка модуля, обслуживающего открытое устройство, а следующие обращения (из процесса пользовательского пространства) к открытому дескриптору устройства будут направлены в неинициированную память!

И здесь возникает очередная путаница (которую можно наблюдать и в коде некоторых модулей): во многих источниках рекомендуется при открытии устройства инкрементировать счётчик использований из собственного кода модуля и декрементировать при его закрытии. Это было актуально, но с некоторой версии ядра (я не смог отследить, с какой именно) это отслеживание числа ссылок выполняется автоматически при выполнении открытия и закрытия. Примеры этого будут детально изучены позже при рассмотрении множественного открытия для устройств (архив mopen.tgz с этим примером будет представлен в одной из следующих статей).

Заключение

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


Ресурсы для скачивания


Похожие темы


Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Linux, Open source
ArticleID=818660
ArticleTitle=Разработка модулей ядра Linux: Часть 12. Инструментарий разработчика модулей ядра
publish-date=05292012