Linux - модулі ядра

У сучасних ядрах при підключенні обладнання модулі підключаються автоматично, а ця подія обробляється демоном udev, який створює відповідний файл пристрою в каталозі "/dev". Все це виконується в тому випадку, якщо відповідний модуль коректно встановлено дерево модулів. У випадку з файловими системами ситуація така сама: при спробі монтування файлової системи ядро ​​підвантажує необхідний модуль автоматично і виконує монтування. Якщо необхідність у модулі не так очевидна, ядро ​​його не завантажує самостійно. Наприклад, для підтримки функції шифрування на loop пристрої потрібно вручну підвантажити модуль cryptoloop, а для безпосереднього шифрування модуль алгоритму шифрування, наприклад blowfish.

Пошук необхідного модуля

Модулі зберігаються у каталозі "/lib/modules/ " як файлів з розширенням «ko». Для отримання списку всіх модулів з дерева можна виконати команду пошуку всіх файлів з розширенням ko в каталозі з модулями поточного ядра:

find /lib/modules/`uname -r` -name '*.ko'

Отриманий список дасть деяке уявлення про доступні модулі, їх призначення та імена. Наприклад, шлях «kernel/drivers/net/wireless/rt2x00/rt73usb.ko» явно вказує на те, що цей модуль є драйвером пристрою бездротового зв'язку на базі чіпа rt73. Більш детальну інформацію про модуль можна отримати за допомогою команди modinfo:

Завантаження та вивантаження модулів

Завантажити модуль в ядро ​​можна за допомогою двох команд: insmod і modprobe, що відрізняються один від одного можливістю прорахунку і задоволення залежностей. Команда insmod завантажує конкретний файл з розширенням ko, при цьому, якщо модуль залежить від інших модулів, ще не завантажених в ядро, команда видастьпомилку і не завантажить модуль. Команда «modprobe» працює тільки з деревом модулів, і можливе завантаження тільки звідти на ім'я модуля, а не на ім'я файлу. Звідси випливає область застосування цих команд: за допомогою insmod підвантажується файл модуля з довільного місця файлової системи (наприклад, користувач скомпілював модулі і перед перенесенням в дерево ядра вирішив перевірити його працездатність), а modprobe - для підвантаження вже готових модулів, включених у дерево модулів поточної версії ядра. Наприклад, для завантаження модуля ядра «rt73usb» з дерева ядра, включаючи всі залежності, та відключивши апаратне шифрування, потрібно виконати команду:

# modprobe rt73usb nohwcrypt=0

Завантаження цього модуля командою «insmod» відбудеться так:

# insmod /lib/modules/2.6.38-gentoo-r1/kernel/drivers/net/wireless/rt2x00/rt73usb.ko nohwcrypt=0

Але потрібно пам'ятати, що при використанні insmod всі залежності доведеться підвантажувати вручну. Тому ця команда поступово витісняється командою "modprobe".

Після завантаження модуля можна перевірити наявність у списку завантажених в ядро ​​модулів за допомогою команди «lsmod»:

# lsmod grep rt73usb

Module Size Used by
rt73usb173050
crc_itu_t9991rt73usb
rt2x00usb57491rt73usb
rt2x00lib194842rt73usb,rt2x00usb

З висновку команди ясно, що модуль завантажений, а також у своїй роботі використовує інші модулі. Щоб його вивантажити, можна скористатися командою rmmod або тією ж командою modprobe з ключем "-r". Як параметр обом командам потрібно передати лише ім'я модуля. Якщомодуль не використовується, він буде вивантажений, а якщо використовується — буде видана помилка, і доведеться вивантажувати всі модулі, які від нього залежать:

# rmmod rt2x00usb ERROR: Module rt2x00usb is in use by rt73usb # rmmod rt73usb # rmmod rt2x00usb

Після вивантаження модуля всі можливості, які він надавав, буде видалено з таблиці ядра.

Для автоматичного завантаження модулів у різних дистрибутивах передбачено різні механізми. Я не вдаватимуся тут у подробиці, вони для кожного дистрибутива свої, але один метод завантаження завжди дієвий і зручний: за допомогою стартових скриптів. У тих же RedHat системах можна записати команди завантаження модуля прямо у "/etc/rc.d/rc.local" з усіма опціями. Файли конфігурації модулів знаходяться в каталозі "/etc/modprobe.d/" і мають розширення "conf". У цих файлах переважно перераховуються альтернативні імена модулів, їх параметри, які застосовуються під час їх завантаження, а також чорні списки, заборонені для завантаження. Наприклад, щоб вищезазначений модуль відразу завантажувався з опцією «nohwcrypt=1», потрібно створити файл, в якому записати рядок:

options rt73usb nohwcrypt=1

Чорний список модулів зберігається переважно у файлі "/etc/modules.d/blacklist.conf" у форматі "blacklist". Ця функція використовується для заборони завантаження глючних або конфліктних модулів.

Складання модуля та додавання його в дерево

Іноді потрібного драйвера в ядрі немає, тому його компілювати вручну. Це також той випадок, якщо додаткове ПЗ вимагає додавання свого модуля в ядро, типуvmware,virtualbox або пакет підтримки картNvidia. Сам процес компіляції не відрізняється від процесу складання програми, але певні вимоги все ж таки є. По-перше, потрібен компілятор. Зазвичайустановка "gcc" встановлює все, що потрібно для збирання модуля. Якщо чогось не вистачає — програма складання про це скаже, і потрібно буде доустановити пакети, що бракують. По друге, потрібні заголовні файли ядра. Річ у тім, що модулі ядра завжди збираються разом із ядром, використовуючи його заголовні файли, т.к. будь-яке відхилення та невідповідність версій модуля та завантаженого ядра веде до неможливості завантажити цей модуль у ядро. Якщо система працює на базі ядра дистрибутива, то потрібно встановити пакети із заголовними файлами ядра. У більшості дистрибутивів це пакети "kernel-headers" та/або "kernel-devel". Для збирання модулів цього буде достатньо. Якщо ядро ​​збиралося вручну, ці пакети не потрібні: достатньо зробити символічне посилання "/usr/src/linux", що посилається на дерево налаштованих вихідних кодів поточного ядра. Після компіляції модуля на виході буде отримано один або кілька файлів з розширенням ko. Можна спробувати їх завантажити за допомогою команди insmod і протестувати їх роботу. Якщо модулі завантажилися і працюють (або ліньки вручну підвантажувати залежності), потрібно їх скопіювати в дерево модулів поточного ядра, після чого обов'язково оновити залежності модулів командою «depmod». Вона пройде рекурсивно по дереву модулів і запише всі залежності у файл "modules.dep", який, згодом, буде аналізуватися командою "modprobe". Тепер модулі готові до завантаження командою modprobe і можуть завантажуватися на ім'я з усіма залежностями. Слід зазначити, що при оновленні ядра цей модуль не працюватиме. Потрібні будуть нові файли заголовків і потрібно заново перезбирати модуль.

«Слухаємо» що каже ядро

При появі найменших неполадок із модулем, потрібно дивитися повідомлення ядра. Вони виводяться за командою"dmesg" і, залежно від налаштувань syslog, у файл "/var/log/messages". Повідомлення ядра можуть бути інформативними або налагоджувальними, що допоможе визначити проблему в процесі роботи модуля, а можуть повідомляти про помилку роботи з модулем, наприклад недостатність символів і залежностей, некоректні передані параметри. Наприклад, вище розглянутий модуль rt73usb вимагає параметр типу bool, що говорить про те, що параметр може приймати або 0, або 1. Якщо спробувати передати «2», система видасть помилку:

# modprobe rt73usb nohwcrypt=2 FATAL: Error inserting rt73usb (/lib/modules/2.6.38-gentoo-r1/kernel/drivers/net/wireless/rt2x00/rt73usb.ko): Invalid argument

Помилка Invalid argument може говорити про що завгодно, саму помилку ядро ​​на консоль написати не може, тільки за допомогою функції printk записати в системний лог. Подивившись логи можна вже дізнатися, в чому помилка:

# dmesg tail -n1 rt73usb: '2' invalid for parameter 'nohwcrypt'

У цьому прикладі виведено лише останній рядок з помилкою, щоб не захаращувати статтю. Модуль може написати і кілька рядків, тому краще виводити повний лог, або хоча б останніх десять. Помилка вже легко знайти: значення «2» неприйнятне для параметра «nohwcrypt». Після виправлення модуль коректно завантажиться в ядро.

З усього сказаного можна зробити висновок: ядро ​​Linux грає за своїми правилами і займається серйозними речами. Проте — це лише програма, воно, по суті, не дуже відрізняється від інших звичайних програм. Розуміння того, що ядро ​​не таке страшне, як здається, може стати першим кроком до розуміння внутрішнього пристрою системи і, як результат, допоможе швидко і ефективно вирішувати завдання, з якими стикається будь-який адміністратор Linux у повсякденнійроботи.