Linux: LKM — Linux Kernel Module, модули ядра Linux

Автор: | 10/22/2014
 

linux_logoФайлы и директории

Файл /proc/modules предоставляет информацию о модулях, которые установлены в ядре.

Именно его содержимое используется утилитой lsmod для отображения данных:

# head /proc/modules
autofs4 20405 3 - Live 0xf8bbd000
ipt_REJECT 1867 2 - Live 0xf8b80000
nf_conntrack_ipv4 7694 2 - Live 0xf8b77000
nf_defrag_ipv4 1039 1 nf_conntrack_ipv4, Live 0xf8b6d000
iptable_filter 2173 1 - Live 0xf8b65000
ip_tables 9567 1 iptable_filter, Live 0xf8b5c000
ip6t_REJECT 3987 2 - Live 0xf8b4e000
nf_conntrack_ipv6 6940 2 - Live 0xf8b45000
nf_defrag_ipv6 8839 1 nf_conntrack_ipv6, Live 0xf8b3a000
xt_state 1064 4 - Live 0xf8b30000

Хотя информация схожа с данными lsmod, но тут её представлено немного больше: первым указано имя модуля, потом его размер, третья колонка — количество «пользователей» этого модуля. В четвёртой колонке, Live, указывается состояние модуля. Состояние может так же быть Loading или Unloading, если в настоящий момент выполняется insmod или rmmod. В последней колонке указывается адрес модуля в памяти.

Файл /proc/kallsyms содержит таблицу символов ядра (/proc/ksyms в ядрах до 2.6). Мы рассмотрим этот файл и саму таблицу в другом посте, а символы вспомним дальше, в Зависимостях модулей.

Директория /boot содержит необходимые данные для загрузки системы, в том числе — и само ядро:

# ls -l /boot/
total 43451
-rw-r--r--. 1 root root   109958 Jun 19 23:16 config-2.6.32-431.20.3.el6.i686
-rw-r--r--. 1 root root   109953 Nov 22  2013 config-2.6.32-431.el6.i686
drwxr-xr-x. 3 root root     1024 Jun 26 19:38 efi
drwxr-xr-x. 2 root root     1024 Jun 30 14:10 grub
-rw-------. 1 root root 15965151 Jun 30 14:10 initramfs-2.6.32-431.20.3.el6.i686.img
-rw-------. 1 root root 15921010 Jun 26 19:47 initramfs-2.6.32-431.el6.i686.img
drwx------. 2 root root    12288 Jun 26 19:28 lost+found
-rw-r--r--. 1 root root   190237 Jun 19 23:17 symvers-2.6.32-431.20.3.el6.i686.gz
-rw-r--r--. 1 root root   190104 Nov 22  2013 symvers-2.6.32-431.el6.i686.gz
-rw-r--r--. 1 root root  1983932 Jun 19 23:16 System.map-2.6.32-431.20.3.el6.i686
-rw-r--r--. 1 root root  1982877 Nov 22  2013 System.map-2.6.32-431.el6.i686
-rwxr-xr-x. 1 root root  4006368 Jun 19 23:16 vmlinuz-2.6.32-431.20.3.el6.i686
-rwxr-xr-x. 1 root root  4002656 Nov 22  2013 vmlinuz-2.6.32-431.el6.i686

Директория /boot/grub/ — файлы загрузчика GRUB.

Файлы vmlinuz (иногда — vmlinux) и являются самим ядром. В примере выше имеется два файла ядра:

# ls -l /boot/ | grep vm
-rwxr-xr-x. 1 root root  4006368 Jun 19 23:16 vmlinuz-2.6.32-431.20.3.el6.i686
-rwxr-xr-x. 1 root root  4002656 Nov 22  2013 vmlinuz-2.6.32-431.el6.i686

Узнать, какое из них загружено в настоящий момент можно командой uname:

# uname -r
2.6.32-431.20.3.el6.i686

Модули ядра хранятся в директории /lib/modules/<версия ядра>/kernel/lib/:

# ls -l /lib/modules/
total 8
drwxr-xr-x. 7 root root 4096 Jun 30 14:05 2.6.32-431.20.3.el6.i686
drwxr-xr-x. 7 root root 4096 Jun 26 19:41 2.6.32-431.el6.i686

А просмотреть их можно следующей командой:

# modprobe -l | head
kernel/arch/x86/kernel/cpu/mcheck/mce-inject.ko
kernel/arch/x86/kernel/cpu/cpufreq/powernow-k8.ko
kernel/arch/x86/kernel/cpu/cpufreq/mperf.ko
kernel/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.ko
kernel/arch/x86/kernel/cpu/cpufreq/pcc-cpufreq.ko
kernel/arch/x86/kernel/cpu/cpufreq/p4-clockmod.ko
kernel/arch/x86/kernel/cpu/cpufreq/intel_pstate.ko
kernel/arch/x86/kernel/test_nx.ko
kernel/arch/x86/kernel/microcode.ko
kernel/arch/x86/crypto/ablk_helper.ko

Или, что бы получить информацию о конкретном модуле:

# modprobe -l ext4
kernel/fs/ext4/ext4.ko

Либо по маске:

# modprobe -l ext*
kernel/fs/ext3/ext3.ko
kernel/fs/ext2/ext2.ko
kernel/fs/ext4/ext4.ko

Linux Kernel Module — модули ядра Linux

Linux является монолитным ядром. Монолитное ядро предоставляет базовый интерфейс для доступа к аппаратной части, и API для процессов в пространстве пользователя для предоставления этого доступа. В отличии от этого подхода, в системах, основанных на «микроядерном» (micro-kernel) подходе, в котором в ядре содержатся только базовые службы, тогда как службы более высокого уровня вытеснены из ядра. Основным достоинством такого подхода считается высока масштабируемость.

Хотя Linux и является монолитным ядром — оно позволяет выполнять динамическую конфигурацию благодаря использованию системы модулей. Модули ядра представляют собой специальные объекты, которые могут быть добавлены в ядро или удалены из него в любое время. После добавления — модуль расширяет возможности ядра, добавляя новые службы.

Модули так же называются «специальными» объектами, так как только в них реализованы два интерфейса — один для инициализации модуля, при первой загрузке модуля в ядро, и второй — для «уборки», когда модуль выгружается из ядра.

Управление модулями

Linux предоставляет полный набор утилит для управления модулями. На изображении ниже предоставлены основные утилиты, а так же зависимость их от некоторых важных системных файлов модулей:

managing-moduls-on-the-linux-kernel

Получение информации о модулях

lsmod

Утилита lsmod (list modules) используется для отображения загруженных в ядро модулей. В результатах отображается имя модуля, размер занятой им памяти, счётчик использования (как много других модулей используют этот модуль) и список ссылающихся на этот модуль модулей:

# lsmod
Module                  Size  Used by
autofs4                20405  3
ipt_REJECT              1867  2
nf_conntrack_ipv4       7694  2
nf_defrag_ipv4          1039  1 nf_conntrack_ipv4
iptable_filter          2173  1
ip_tables               9567  1 iptable_filter
ip6t_REJECT             3987  2

modinfo

Утилита modinfo предоставляет расширенную информацию об указанном модуле, например —  информация про модуль powernow-k8:

# modinfo powernow-k8
filename:       /lib/modules/2.6.32-431.29.2.el6.i686/kernel/arch/x86/kernel/cpu/cpufreq/powernow-k8.ko
license:        GPL
description:    AMD Athlon 64 and Opteron processor frequency driver.
author:         Paul Devriendt <paul.devriendt@amd.com> and Mark Langsdorf <mark.langsdorf@amd.com>
srcversion:     F5108448E2E5864C4428DD0
depends:        mperf
vermagic:       2.6.32-431.29.2.el6.i686 SMP mod_unload modversions 686

В строке depends отображаются зависимости этого модуля, в данном случае — это mperf.

Разрешение зависимостей модулей

Модули ядра Linux могут предоставлять службы (называемые «символами», symbols) для использования другими модулями (при помощи EXPORT_SYMBOL в коде). Если другой модуль использует этот «символ», то этот модуль непосредственно зависит от первого модуля.

Зависимости прописываются в файле /lib/modules/<версия ядра>/modules.dep. Создаются они с помощью утилиты depmod.

Пример зависимостей модуля powernow-k8.ko:

# cat /lib/modules/2.6.32-431.20.3.el6.i686/modules.dep | grep powernow-k8.ko
kernel/arch/x86/kernel/cpu/cpufreq/powernow-k8.ko: kernel/arch/x86/kernel/cpu/cpufreq/mperf.ko

Как видно, информация совпадает с данными из modinfo:

depends:        mperf

Другой вариант — использование утилиты modprobe для получения списка зависимостей:

# modprobe --show-depends powernow-k8
insmod /lib/modules/2.6.32-431.29.2.el6.i686/kernel/arch/x86/kernel/cpu/cpufreq/mperf.ko
insmod /lib/modules/2.6.32-431.29.2.el6.i686/kernel/arch/x86/kernel/cpu/cpufreq/powernow-k8.ko

Что бы сгенерировать зависимости новых модулей — выполните:

# deplmod -A

Что бы выполнить проверку зависимостей, но без перезаписи файла modules.dep — выполните:

# depmod -n

Например, для модуля ipv6:

 # depmod -n -v /lib/modules/2.6.32-431.20.3.el6.i686/kernel/net/ipv6/ipv6.ko | head -n 30
kernel/net/ipv6/ipv6.ko:
# pci module         vendor     device     subvendor  subdevice  class      class_mask driver_data
# usb module         match_flags idVendor idProduct bcdDevice_lo bcdDevice_hi bDeviceClass bDeviceSubClass bDeviceProtocol bInterfaceClass bInterfaceSubClass bInterfaceProtocol driver_info
# ccw module         match_flags cu_type cu_model dev_type dev_model
# ieee1394 module    match_flags vendor_id model_id specifier_id version
# isapnp module      cardvendor carddevice driver_data vendor     function   ...
# module         matchBits bustype vendor product version evBits keyBits relBits absBits mscBits ledBits sndBits ffBits [swBits] driver_info
# of module          name                 type                 compatible
# serio module       type extra id   proto
# Aliases extracted from modules themselves.
alias net-pf-10 ipv6
# Aliases for symbols, used by symbol_request().
alias symbol:ip6_local_out ipv6
alias symbol:ipv6_getsockopt ipv6
alias symbol:ip6_route_me_harder ipv6
alias symbol:ip6_frag_match ipv6
alias symbol:inet6_csk_search_req ipv6

Опция -n выведет все данные на экран, вместо записи в файл modules.dep.

Будьте осторожны с этими данными, и делайте резервную копию файлов modules.*.

Что бы сгенерировать зависимости для всех модулей — используйте опцию -a, например:

# depmod -a -v | tee depmod.log
...
/lib/modules/2.6.32-431.20.3.el6.i686/kernel/net/openvswitch/openvswitch.ko needs "vxlan_sock_add": /lib/modules/2.6.32-431.20.3.el6.i686/kernel/drivers/net/vxlan.ko

Как видим, depmod указывает, что для модуля openvswitch.ko требуется «символ» vxlan_sock_add из модуля vxlan.ko.

Проверим файл modules.dep:

# cat /lib/modules/2.6.32-431.20.3.el6.i686/modules.dep | grep "openvswitch"
kernel/net/openvswitch/openvswitch.ko: kernel/drivers/net/vxlan.ko

Загрузка и удаление модулей

insmod

insmod (insert module) выполняет загрузку модуля в ядро. Для ядра 2.6 файл должен иметь расширение .ko (kernel object). Если модуль содержит символы — они могут быть проинициализирвоанны в процессе загрузки модуля. Пример ниже демонстрирует загрузку модуля с опцией инициализации:

# insmod my_module.ko my_option=1

Однако, эта утилита не рекомендуется для использования, т.к. не проверяет и не загружает зависимости модулей. Далее мы рассмотрим утилиту modprobe, которая умеет это.

rmmod

rmmod (remove module) применяется для удаления модуля из ядра. Модуль указывается без расширения. Если счётчки использования (см. lsmod) больше 0 — то rmmod не выгрузит модуль, однако можно указать опцию -w — тогда ядро выгрузит модуль, как только счётчик станет 0 (т.е. — никакие другие модули больше не будут использовать удаляемый модуль):

# rmmod my_module

Как и в случае с insmod — рекомендуется использование modprobe для удаления модулей.

modprobe

Утилита modprobe является наиболее важной утилитой в управлении модулями ядра Linux. Фактически, она является собой «обёртку» утилит insmod  и rmmod, но выполняет все действия более качественно. Вызов insmod просто выполняет попытку загрузки модуля и в случае, если у этого модуля есть зависимости, insmod вернёт ошибку. modprobe же выполняет проверку зависимостей, указанных в файле module.dep. Если модуль-зависимость не загружен — modprobe сначала загрузит его. Кроме того, он выполняет эту проверку рекурсивно для всех модулей, которые загружает при загрузке нужного нам модуля.

modprobe так же принимает опцию -v, что бы отображать больше информации:

# modprobe -v snd_intel8x0
insmod /lib/modules/2.6.32-431.20.3.el6.i686/kernel/sound/core/snd-page-alloc.ko
...
insmod /lib/modules/2.6.32-431.20.3.el6.i686/kernel/sound/pci/snd-intel8x0.ko

При установке модулей, учитывайте факт, что modprobe ищет файлы модулей по пути /lib/module/$(uname -r).

С помощью modprobe так же можно удалять модули. Вместо того, что бы слепо удалять модули, как это делает rmmod, modprobe проверяет какие модули можно удалить вместе с этим модулем, если они являются его зависимостями и не используются другими модулями. Для удаления используется опция -r:

# modprobe -r -v snd_intel8x0
rmmod /lib/modules/2.6.32-431.20.3.el6.i686/kernel/sound/pci/snd-intel8x0.ko
...
rmmod /lib/modules/2.6.32-431.20.3.el6.i686/kernel/sound/core/snd-page-alloc.ko

У modprobe существует много других интересных опций, например — вывод списка всех доступных модулей (-l), или модулей, соответствующих маске:

# modprobe -l dccp
kernel/net/dccp/dccp.ko

Он умеет выполнять перенаправление sterr в syslog, выполнять dry-run (-n), вместо установки или удаления и многое другое.

Почитать по теме: https://access.redhat.com