Модуль 18. Управление устройствами и модулями Ядро ОС

Введение

Из этого модуля вы узнаете, что такое служба systemd-udevd и как с помощью ее правил заставить работать 4G-модем, который упорно притворяется, что он USB-флешка. Мы посмотрим внимательнее, что такое модули ядра, и научимся не только загружать драйверы, но и намертво блокировать работу отдельных устройств, а то вдруг заклеить камеру стикером нам покажется недостаточной мерой.

Управление устройствами

В операционной системе Linux наиболее полная информация об устройствах доступна в псевдофайловой системе sysfs, которая монтируется в каталог /sys. Что такое псевдофайловые системы и как они работают мы уже рассматривали в модуле по управлению процессами, и, как вы помните, sysfs пришла на замену procfs, но вот порядка в ней на порядок больше.

По мере развития системы procfs ее файлы потеряли однообразие и используют теперь совершенно разные форматы, в то время как в системе sysfs одному параметру соответствует строго один файл, поэтому намусорить там значительно сложнее. Имя файла в sysfs является именем параметра, а содержимое файла — его значением, и в подавляющем большинстве случаев это действительно так.

Псевдофайловая система sysfs

В sysfs находятся следующие каталоги:

  • Каталог /sys/block — тут содержатся символические ссылки на блочные устройства, найденные в системе, по одной ссылке на каждое устройство. Символические ссылки указывают на соответствующие каталоги в /sys/devices.

  • Каталог /sys/bus — содержит каталоги для всех типов шин ядра. Один каталог на один тип шины. При этом каждый из этих каталогов содержит два подкаталога:

    • Каталог /sys/bus/devices — содержит символические ссылки на элементы в /sys/devices, соответствующие устройствам этого типа шины;

    • Каталог /sys/bus/drivers — содержит каталоги с драйверами устройств, подгруженных для работы с этой шиной. По одному каталогу на один драйвер.

  • Каталог /sys/class — содержит структуру из подкаталогов, по одному на каждый класс устройств, зарегистрированных в системе. Внутри размещаются символические ссылки на элементы в /sys/devices, соответствующие этим устройствам.

  • Каталог /sys/dev — содержит два подкаталога block и char для блочных и символьных устройств соответственно. Внутри этих подкаталогов находятся символические ссылки на каталоги в /sys/devices, соответствующие этим устройствам. Имена ссылок имеют вид X:Y, где X – это основной ID, а Y – дополнительный ID устройства.

  • Каталог /sys/devices — содержит отражение структур device в ядре ОС в виде дерева каталогов и файлов.

  • Каталог /sys/digsig — содержит данные, связанные с работой в замкнутой программной среде (ЗПИ).

  • Каталог /sys/firmware — содержит интерфейсы для просмотра и изменение параметров прошивок, например, UEFI.

  • Каталог /sys/fs — содержит подкаталоги для некоторых файловых систем, в том числе и cgroup. Этот каталог обычно используется как точка монтирования для tmpfs, в которой содержатся точки монтирования файловых систем контрольных групп.

  • Каталог /sys/hypervisor — используется в случае работы гипервизора на компьютере.

  • Каталог /sys/kernel — содержит интерфейсы для просмотра информации о работе ядра ОС.

  • Каталог /sys/module — содержит подкаталоги для всех подгруженных модулей ядра, по одному на каждый модуль.

  • Каталог /sys/power — содержит интерфейсы для просмотра и изменения параметров управления питанием и режимами энергосбережения.

Правила udev

Служба udev является диспетчером устройств ядра Linux, который обрабатывает все события пользовательского пространства, возникающие при добавлении/удалении аппаратных устройств и изменении их характеристик.

Обработчики событий службы udev называют также правилами, и с их помощью, например, служба управления сетевыми подключениями NetworkManager автоматически перенастраивает сетевые интерфейсы при перемещении портативного устройства в другой сегмент сети. Вы можете создать собственные правила, с помощью которых можно выполнить переименование устройства или загрузку необходимых драйверов.

На рис. 109 представлена схема работы подсистемы udev, которая включает следующие шаги:

  • Во время загрузки системы еще на самых ранних стадиях инициализации ядра создается псевдофайловая система tmpfs, которая монтируется в каталог /dev.

  • В определенный момент стартует служба systemd-udevd, и в первую очередь она загружает в оперативную память базу данных правил (обработчиков), опираясь на файлы из каталогов /usr/lib/udev/rules.d/ и /etc/udev/rules.d/ (последние в приоритете).

    Файлы правил имеют суффикс *.rules и загружаются в алфавитном порядке, поэтому в названиях файлов первые два символа используют в качестве числа, которое задает приоритет.

  • После загрузки правил служба отправляет ядру запрос на передачу всех событий uevent, возникших в системе еще до запуска systemd-udevd. Обмен информацией между ядром и пользовательским пространством осуществляется через сокет netlink.

../_images/alse_mod18_image4.png

рис. 109 Схема работы подсистемы udev

  • При подключении/отключении периферийного устройства (например, usb-накопителя), ядро ОС производит обновление своих структур и отражает эти изменения в псевдофайловой системе sysfs. При этом происходит оповещение службы systemd-udevd о произошедшем событии (uevent).

  • Служба systemd-udevd удаляет дубликаты событий uevent и обеспечивает их сортировку в правильном порядке, чтобы события о подключении родительских устройств (например, шины usb) обрабатывались раньше, чем события о подключении дочерних устройств (например, usb-накопителя).

  • Далее в соответствии с информацией из базы udev проводит поиск и применение правил, соответствующих пришедшему событию. В правилах описаны действия (скрипты), которые должны быть выполнены.

    Кроме этого, udev собирает информацию об устройствах из sysfs и создает файлы устройств, выдает на них необходимые разрешения и добавляет символические ссылки в каталоге /dev. При необходимости udev отправляет ядру запросы на подгрузку необходимых модулей (драйверов устройств) и размещает информацию об устройствах в своей базе.

  • На последнем этапе процесса служба udev через шину D-Bus оповещает о появлении нового устройства или изменении его физического состояния все приложения, заинтересованные в получении этой информации.

Примечание

Обработка событий в udev происходит параллельно, поэтому в файле /etc/fstab диски монтируются не по именам sda или sdb, а по их UUID, чтобы исключить ошибку, которая может возникнуть в связи с тем, что диски поменяются именами. Но в то же время с помощью правил udev имя устройства можно сделать постоянным.

Синтаксис правил

Правила udev хранятся в каталогах:

  • Каталог /usr/lib/udev/rules.d — системные правила, созданные при установке системы или ПО.

  • Каталог /etc/udev/rules.d — пользовательские правила, созданные администратором, более приоритетные (при совпадении имен файлов в этих двух каталогах).

Пример файла с правилами /usr/lib/udev/rules.d/50-udev-default.rules:

# do not edit this file, it will be overwritten on update

# run a command on remove events
ACTION=="remove", ENV{REMOVE_CMD}!="", RUN+="$env{REMOVE_CMD}"
ACTION=="remove", GOTO="default_end"

SUBSYSTEM=="virtio-ports", KERNEL=="vport\*", ATTR{name}=="?\*", SYMLINK+="virtio-ports/$attr{name }"

# select "system RTC" or just use the first one
SUBSYSTEM=="rtc", ATTR{hctosys}=="1", SYMLINK+="rtc"
SUBSYSTEM=="rtc", KERNEL=="rtc0", SYMLINK+="rtc", OPTIONS+="link_priority=-100"

...

Файлы правил имеют суффикс *.rules и состоят из множества строк, где каждая строка – это отдельное правило за исключением пустых строк с комментариями, начинающихся с символа решетки.

Каждое правило состоит из серии выражений {ключ}{оператор}{значение}, которые отделяются друг от друга запятыми. Выражения должны задавать как минимум один ключ соответствия и один ключ присвоения, где:

  • Ключ соответствия — это условие, по которому определяется, соответствует ли конкретное устройство данному правилу или нет. Если ключей соответствия несколько, то правило применяется только в том случае, если устройство удовлетворяет сразу всем указанным критериям.

  • Ключ присвоения — это действие, которое должно быть выполнено в системе, если текущее устройство удовлетворяет критериям ключей соответствия.

Ключи соответствия:

Ключи соответствия могут определять критерии как для самого устройства, так и для его родительских устройств. Например, для жесткого диска родителем будет устройство SСSI, а для него, в свою очередь, шина BUS).

Большинство ключей поддерживают шаблоны подстановки (от англ. wildcard pattern) в стиле оболочки: «*», «?», «[]», «|».

Основные ключи для критериев соответствия самого устройства:

  • KERNEL — соответствие с именем устройства в ядре ОС;

  • SUBSYSTEM — соответствие с подсистемой устройства;

  • DRIVER — соответствие с именем драйвера, обслуживающего устройство;

  • DEVPATH — соответствие пути до устройства в sysfs;

  • ATTR{атрибут} — соответствие содержимому файла для этого атрибута в каталоге устройства sysfs;

  • ENV{переменная} — соответствие значению переменной окружения.

Аналогичные ключи для определения соответствия как самому устройству, так и устройствам-предкам (родителям, дедушкам и т.д.):

  • KERNELS — соответствие с именем устройства и/или его предка в ядре ОС;

  • SUBSYSTEMS — соответствие с подсистемой устройства и/или его предка;

  • DRIVERS — соответствие с именем драйвера, обслуживающего устройство и/или его предка;

  • ATTRS{атрибут} — соответствие содержимому файла для этого атрибута в каталоге sysfs устройства и/или его предка.

С ключами соответствия используются два простых оператора:

  • Оператор «==» — устройство соответствует критерию;

  • Оператор «!=» — устройство не соответствует критерию.

Ключи присвоения (действий)

Ниже представлены основные ключи для действий, которые будут выполнены в случае, если правило применимо:

  • NAME — устанавливает имя файла устройства в каталоге /dev;

  • SYMLINK — создает символические ссылки, который действуют как альтернативные имена для этого устройства;

  • RUN — задает список команд для запуска (это может быть имя скрипта с необходимыми операциями);

  • OWNER — устанавливает владельца для файла устройства;

  • GROUP — устанавливает группу-владельца для файла устройства;

  • MODE — устанавливает права доступа на файл устройства.

Все вышеперечисленные ключи действий поддерживают шаблоны подстановки, подобные в команде printf:

  • Шаблон %k — имя устройства, данное ему ядром,

  • Шаблон %n — номер устройства (например, для sda2, номером является число 2),

  • Шаблон %p — путь к файлу устройства,

  • Шаблон $name — текущее имя устройства,

  • Шаблон $env{ключ} — значение переменной окружения,

  • Шаблон $driver — драйвер устройства.

С ключами присвоения используются следующие операторы:

  • Оператор «=» — очистить список и добавить указанное действие;

  • Оператор «+=» — добавить указанное действие без очистки списка;

  • Оператор «-=» — удалить указанное действие из списка;

  • Оператор «:=» — присвоить значение и запретить его изменение другими правилами.

Инструменты управления udev

Для управления udev предназначена утилита udevadm. Она управляет поведением systemd-udevd во время выполнения, запрашивает события ядра, управляет очередью событий и предоставляет простые механизмы отладки.

Основные опции утилиты udevadm:

  • Команда udevadm info <имя_устройства или путь_до_устройства> — выводит информацию об устройстве из базы данных udev.

  • Команда udevadm test <путь_до_устройства_в_sysfs> — имитирует запуск события udev для выбранного устройства и выводит отладочную информацию. Полезно для проверки работоспособности правил.

  • Команда udevadm monitor — выводит события uevent в режиме реального времени.

  • Команда udevadm settle — наблюдает за очередью событий udev. Если все события обработаны, через определенное время (по умолчанию 120 секунд) команда завершает свою работу.

  • Команда udevadm control — управляет внутренним состоянием запущенного демона udev.

udevadm info

Для вывода информации об устройствах используется команда udevadm info <имя_устройства/путь_до_устройства>. Если необходимо вывести информацию и об устройствах-предках, то следует добавить параметр -a в команду udevadm info -a <имя_устройства/путь_до_устройства>.

Например, выведем информацию о диске udevadm info /dev/sda.

localadmin@astra:~$ udevadm info /dev/sda
P: /devices/pci0000:00/0000:00:0d.0/ata1/host0/target0:0:0/0:0:0:0/block/sda
N: sda
L: 0
S: disk/by-id/ata-VBOX_HARDDISK_VB6a0f90fb-c5f1dd19
S: disk/by-path/pci-0000:00:0d.0-ata-1
E: DEVPATH=/devices/pci0000:00/0000:00:0d.0/ata1/host0/target0:0:0/0:0:0:0/block/sda
E: DEVNAME=/dev/sda
...

udevadm test

Имитировать событие udev для выбранного устройства и вывести отладочную информацию можно командой udevadm test <путь_до_устройства_в_sysfs> (DEVPATH). Реальных изменений не происходит, полезно для проверки работоспособности правил.

localadmin@astra:~$ udevadm test /sys/block/sda
This program is for debugging only, it does not run any program
specified by a RUN key. It may show incorrect results, because
some values may be different, or not available at a simulation run.

Load module index
Network interface NamePolicy= disabled on kernel command line, ignoring.
Parsed configuration file /usr/lib/systemd/network/99-default.link
Created link configuration context.
Skipping empty file: /etc/udev/rules.d/10-usb-drive.rules
Reading rules file: /usr/lib/udev/rules.d/50-firmware.rules
Reading rules file: /usr/lib/udev/rules.d/50-udev-default.rules
. . .
Reading rules file: /usr/lib/udev/rules.d/99-systemd.rules
Rules contain 196608 bytes tokens (16384 \* 12 bytes), 26950 bytes strings
19410 strings (154764 bytes), 16958 de-duplicated (130267 bytes), 2453 trie nodes used
Invalid inotify descriptor.
Starting 'ata_id --export /dev/sda'
Process 'ata_id --export /dev/sda' failed with exit code 1.
Starting 'scsi_id --export --whitelisted -d /dev/sda'
'scsi_id --export --whitelisted -d /dev/sda'(out) 'ID_SCSI=1'
'scsi_id --export --whitelisted -d /dev/sda'(out) 'ID_VENDOR='
'scsi_id --export --whitelisted -d /dev/sda'(out) 'ID_VENDOR_ENC='
'scsi_id --export --whitelisted -d /dev/sda'(out) 'ID_MODEL='
'scsi_id --export --whitelisted -d /dev/sda'(out) 'ID_MODEL_ENC='
'scsi_id --export --whitelisted -d /dev/sda'(out) 'ID_REVISION='
'scsi_id --export --whitelisted -d /dev/sda'(out) 'ID_TYPE='
Process 'scsi_id --export --whitelisted -d /dev/sda' succeeded.
PDAC: PDPL is zero
PDAC: AUDIT is empty or invalid
DEVPATH=/devices/pci0000:00/0000:00:0d.0/ata1/host0/target0:0:0/0:0:0:0/block/sda
DEVNAME=/dev/sda
DEVTYPE=disk
DISKSEQ=9
MAJOR=8
MINOR=0
ACTION=add
SUBSYSTEM=block
ID_SCSI=1
ID_BUS=scsi
ID_PATH=pci-0000:00:0d.0-ata-1
ID_PATH_TAG=pci-0000_00_0d_0-ata-1
DEVLINKS=/dev/disk/by-path/pci-0000:00:0d.0-ata-1
TAGS=:systemd:
USEC_INITIALIZED=3952844
Unload module index
Unloaded link configuration context.

udevadm monitor

Команда udevadm monitor используется для вывода событий uevent в режиме реального времени. Если запустить утилиту и после этого вставить оптический диск в виртуальную машину, то мы увидим соответствующее событие.

localadmin@astra:~$ udevadm monitor
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent

KERNEL[237008.787520] change  /devices/pci0000:00/0000:00:01.1/ata3/host2/target2:0:0/2:0:0:0/b lock/sr0 (block)
UDEV [237008.836023]  change  /devices/pci0000:00/0000:00:01.1/ata3/host2/target2:0:0/2:0:0:0/b lock/sr0 (block)

udevadm control

Для управления внутренним состоянием запущенного демона udev и диагностики его работы используются команды sudo udevadm control [параметры].

  • Команда sudo udevadm control --ping — проверяет, запущена ли служба systemd-udevd и отвечает ли она на запросы.

  • Команда sudo udevadm control --reload — заставляет службу перечитать правила udev и других баз данных (например, индекс модуля ядра). Изменения не повлияют на уже существующие устройства. Новые правила будут применяться только к новым событиям uevent.

  • Команда sudo udevadm control --stop-exec-queue — приостановит обработку новых событий службой systemd-udevd. События будут помещаться в очередь до востребования.

  • Команда sudo udevadm control --start-exec-queue — возобновит обработку событий службой systemd-udevd после выполнения предыдущей команды stop-exec-queue.

  • Команда sudo udevadm control -log-priority=<уровень_журналирования> — установит уровень журналирования службы systemd-udevd. Может принимать одно из следующих значений: emerg, alert, crit, err, warning, notice, info, debug.

Проверим работу команд на следующем примере:

  • остановим обработку сообщений uevent командой sudo udevadm control --stop-exec-queue;

  • Далее необходимо переподключить оптический диск;

  • запустим udevadm settle в отдельном терминале и убедимся, что команда не завершила свою работу мгновенно, так как в очереди есть необработанные сообщения;

  • возобновим обработку сообщений sudo udevadm control --start-exec-queue и

  • убедимся, что команда udevadm settle завершила свою работу, т.к. все сообщения из очереди были обработаны.

Создание правила udev

Создадим правило udev для usb-накопителя, которое позволит логировать серийный номер и время подключения устройства к компьютеру.

Во-первых, создадим сам файл для правила в каталоге /etc/udev/rules.d/ с помощью команды:

sudo touch /etc/udev/rules.d/99-usb-drive.rules

Во-вторых, создадим в текстовом редакторе скрипт /usr/bin/usb_disk_log.sh, который будет записывать необходимую нам информацию в файл.

#!/bin/bash
/bin/echo $(/bin/date) был вставлен usb-диск. Серийный номер: $1" >> /var/log/usb_disk.log

Разрешим выполнение файла usb_disk_log.sh командой

localadmin@astra:~$ sudo chmod 744 /usr/bin/usb_disk_log.sh

Проверим работоспособность скрипта командой sudo /usr/bin/usb_disk_log.sh 1234 — в файле /var/log/usb_disk.log должна появиться соответствующая строка.

localadmin@astra:~$ sudo /usr/bin/usb_disk_log.sh 1234
localadmin@astra:~$ cat /var/log/usb_disk.log
В Чт авг 24 11:28:46 MSK 2023 был вставлен usb-диск. Серийный номер: 1234

Теперь посмотрим параметры нашего usb-накопителя. Для этого подключим его к хостовой и гостевой машине и выведем информацию о пути до этого устройства udevadm info /dev/sdb1 | grep DEVPATH | awk -F '=' '{print $2}.

localadmin@astra:~$ udevadm info /dev/sdb1 | grep DEVPATH | awk -F '=' '{print $2}'
/devices/pci0000:00/0000:00:0b.0/usb1/1-1/1-1:1.0/host3/target3:0:0/3:0:0:0/block/sdb/sdb1

И информацию о его атрибутах:

localadmin@astra:~$ udevadm info --attribute-walk /dev/sdb1 | grep -P '(usb|block)'
 looking at device '/devices/pci0000:00/0000:00:0b.0/usb1/1-1/1-1:1.0/host3/target3:0:0/3:0:0:0 /block/sdb/sdb1':
   SUBSYSTEM=="block"
 looking at parent device '/devices/pci0000:00/0000:00:0b.0/usb1/1-1/1-1:1.0/host3/target3:0:0/ 3:0:0:0/block/sdb':
   SUBSYSTEMS=="block"
 looking at parent device '/devices/pci0000:00/0000:00:0b.0/usb1/1-1/1-1:1.0/host3/target3:0:0/ 3:0:0:0':
   ATTRS{device_blocked}=="0"
 looking at parent device '/devices/pci0000:00/0000:00:0b.0/usb1/1-1/1-1:1.0/host3/target3:0:0' :
 looking at parent device '/devices/pci0000:00/0000:00:0b.0/usb1/1-1/1-1:1.0/host3':
 looking at parent device '/devices/pci0000:00/0000:00:0b.0/usb1/1-1/1-1:1.0':
   SUBSYSTEMS=="usb"
   DRIVERS=="usb-storage"
 looking at parent device '/devices/pci0000:00/0000:00:0b.0/usb1/1-1':
   SUBSYSTEMS=="usb"
   DRIVERS=="usb"
 looking at parent device '/devices/pci0000:00/0000:00:0b.0/usb1':
   KERNELS=="usb1"
   SUBSYSTEMS=="usb"
   DRIVERS=="usb"

В созданный нами файл правила /etc/udev/rules.d/99-usb-drive.rules добавим следующий текст:

SUBSYSTEM=="block", DRIVERS=="usb-storage", RUN+="/usr/bin/usb_disk_log.sh $env{ID_SERIAL}"

Протестируем наше правило:

localadmin@astra:~$ udevadm test `udevadm info /dev/sdb1 | grep DEVPATH | awk -F '=' '{print $2}'`
Load module index
Network interface NamePolicy= disabled on kernel command line, ignoring.
Parsed configuration file /usr/lib/systemd/network/99-default.link
Created link configuration context.
Reading rules file: /usr/lib/udev/rules.d/50-firmware.rules
Reading rules file: /usr/lib/udev/rules.d/50-udev-default.rules
Reading rules file: /usr/lib/udev/rules.d/55-dm.rules
. . .
USEC_INITIALIZED=46104098
run: '/bin/ln -f /dev/sdb1 /dev/sdb1_vfat'
run: '/usr/bin/usb_disk_log.sh Kingston_DataTraveler_2.0_5B791A91D481-0:0'

Теперь перезагрузим правила командой sudo udevadm control -reload и повторно подключим «флешку» к нашей гостевой машине. В журнале usb_disk.log появится новая информация:

localadmin@astra:~$ cat /var/log/usb_disk.log
В Чт авг 24 11:28:46 MSK 2023 был вставлен usb-диск. Серийный номер: 1234
В Thu Aug 24 12:34:46 MSK 2023 был вставлен usb-диск. Серийный номер: Kingston_DataTraveler_2.0_
5B791A91D481-0:0

Еще несколько практических примеров:

Некоторые модели USB-модемов могут по ошибке определяться как USB-накопители. Чтобы исправить эту проблему, можно создать правило udev и настроить его на выполнение команды для смены режима работы модема. Для этого нужно:

  1. Создать файл правила /etc/udev/rules.d/10-modem_mode_switch.rules с содержимым:

ACTION=="add",SUBSYSTEM=="usb",ATTRS{idVendor}=="12d1",ATTRS{idProduct}=="1f01",RUN+="/usr/sbin/usb_modeswitch --quiet --config-file /usr/share/usb_modeswitch/12d1:1f01"
  1. Создать конфигурационный файл /usr/share/usb_modeswitch/12d1:1f01 с содержимым:

DefaultVendor = 0x12d1
DefaultProduct = 0x1f01
TargetVendor = 0x12d1
TargetProduct = 0x14dс
# switch to 12d1:14dc (default HiLink CDC-Ether mode)
MessageContent="55534243123456780000000000000a11062000000000000100000000
000000"

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


Когда на сервере несколько сетевых карт, с помощью udev правил сетевым интерфейсам можно присвоить собственные имена, чтобы было проще ориентироваться. Например:

  1. Создадим файл /etc/udev/rules.d/10-interface_rename.rules с содержимым:

KERNEL=="eth\*", ATTR{address}=="00:52:8b:d5:04:48", NAME="localnet"

Это правило переименует сетевой интерфейс с MAC-адресом 00:52:8b:d5:04:48 в localnet, и вы будете точно знать, что интерфейс «смотрит» в локальную сеть.

  1. По тому же принципу можно создать правило для интерфейса в Интернет. Не забудьте только изменить сетевые настройки в соответствии с новыми именами интерфейсов.

Просмотр информации об устройствах

Для просмотра информации об устройствах кроме утилиты udevadm и псевдофайловой системы sysfs существуют и другие способы.

Графический менеджер устройств

Менеджер устройств (fly-admin-device-manager) позволяет просматривать и управлять устройствами, которые зарегистрированы в системе, так же удобно, как мы это могли делать в диспетчере устройств Windows. Запустить его можно через меню пуск Пуск ‣ Системные ‣ Менеджер устройств.

../_images/alse_mod18_image5.png

рис. 110 Графический менеджер устройств

../_images/alse_mod18_image6.png

рис. 111 Свойства выбранного устройства

Утилиты для просмотра информации об устройствах

Для командной строки тоже есть ряд удобных утилит.

Утилита lspci выводит информацию об устройствах, подключенных к шине PCI.

localadmin@astra:~$ lspci
00:00.0 Host bridge: Intel Corporation 440FX - 82441FX PMC [Natoma] (rev 02)
00:01.0 ISA bridge: Intel Corporation 82371SB PIIX3 ISA [Natoma/Triton II]
00:01.1 IDE interface: Intel Corporation 82371AB/EB/MB PIIX4 IDE (rev 01)
00:02.0 VGA compatible controller: VMware SVGA II Adapter
. . .

Утилита lsusb выводит информацию об устройствах, подключенных к шине USB.

localadmin@astra:~$ lsusb
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 004: ID 13fe:1d00 Kingston Technology Company Inc. DataTraveler 2.0 1GB/4GB Flash
Drive / Patriot Xporter 4GB Flash Drive
. . .

Утилита lscpu выводит информацию о процессорах.

localadmin@astra:~$ lscpu
Архитектура: x86_64
CPU op-mode(s): 32-bit, 64-bit
Порядок байт: Little Endian
Address sizes: 46 bits physical, 48 bits virtual
CPU(s): 2
. . .

Утилита lshw выводит информацию о всех устройствах в системе. Доступна в расширенном репозитории для установки.

localadmin@astra:~$ sudo apt install lshw
Чтение списков пакетов… Готово
Построение дерева зависимостей
. . .
Обрабатываются триггеры для man-db (2.8.5-2) …

localadmin@astra:~$ sudo lshw -short
H/W path              Device      Class        Description
===========================================================
                                 system       VirtualBox
/0                                bus          VirtualBox
/0/0                              memory       128KiB BIOS
/0/1                              memory       2GiB System memory
/0/2                              processor    Intel(R) Xeon(R) CPU E5-2680 v4 @ 2.40GHz
/0/100                            bridge       440FX - 82441FX PMC [Natoma]
/0/100/1                          bridge       82371SB PIIX3 ISA [Natoma/Triton II]
...

Модули ядра операционной системы

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

Размещение модулей ядра

Все модули для установленных ядер хранятся директории /lib/modules/.

localadmin@astra:~$ ls -l /lib/modules
итого 24
drwxr-xr-x 6 root root 4096 мая 20 08:52 5.15.0-33-generic
drwxr-xr-x 3 root root 4096 авг 15 12:19 5.15.0-33-hardened
drwxr-xr-x 3 root root 4096 авг 15 12:19 5.15.0-33-lowlatency
drwxr-xr-x 6 root root 4096 авг 15 11:07 5.15.0-70-generic
drwxr-xr-x 3 root root 4096 авг 21 16:20 5.15.0-70-hardened
drwxr-xr-x 3 root root 4096 авг 21 16:21 5.15.0-70-lowlatency

Для каждой версии ядра создается свой подкаталог с необходимыми для него модулями. Содержимое каталога для текущий версии ядра можем посмотреть командой:

localadmin@astra:~$ ls -l /lib/modules/$(uname -r)
итого 6380
lrwxrwxrwx  1 root root      40 апр  5 15:31 build -> /usr/src/linux-headers-5.15.0-70-generic
drwxr-xr-x  2 root root    4096 авг 15 11:07 initrd
drwxr-xr-x 14 root root    4096 авг 15 10:54 kernel
drwxr-xr-x  2 root root    4096 авг 15 11:07 misc
-rw-r--r--  1 root root 1501834 авг 15 11:07 modules.alias
-rw-r--r--  1 root root 1475077 авг 15 11:07 modules.alias.bin
-rw-r--r--  1 root root   10631 апр  5 15:31 modules.builtin
-rw-r--r--  1 root root   26392 авг 15 11:07 modules.builtin.alias.bin
-rw-r--r--  1 root root   13110 авг 15 11:07 modules.builtin.bin
-rw-r--r--  1 root root   83254 апр  5 15:31 modules.builtin.modinfo
-rw-r--r--  1 root root  710075 авг 15 11:07 modules.dep
-rw-r--r--  1 root root  973048 авг 15 11:07 modules.dep.bin
-rw-r--r--  1 root root     314 авг 15 11:07 modules.devname
-rw-r--r--  1 root root  242771 апр  5 15:31 modules.order
-rw-r--r--  1 root root    1826 авг 15 11:07 modules.softdep
-rw-r--r--  1 root root  654201 авг 15 11:07 modules.symbols
-rw-r--r--  1 root root  790611 авг 15 11:07 modules.symbols.bin
drwxr-xr-x  3 root root    4096 авг 15 10:54 vdso

У файлов модулей расширение *.ko. Посмотреть все модули для текущей версии можно командой:

localadmin@astra:~$ find /lib/modules/$(uname -r) -name *.ko | head
/lib/modules/5.15.0-70-generic/misc/vboxguest.ko
/lib/modules/5.15.0-70-generic/misc/digsig_verif.ko
/lib/modules/5.15.0-70-generic/misc/parsec.ko
/lib/modules/5.15.0-70-generic/misc/vboxvideo.ko
/lib/modules/5.15.0-70-generic/misc/vboxsf.ko
/lib/modules/5.15.0-70-generic/misc/parsec-cifs.ko
/lib/modules/5.15.0-70-generic/kernel/net/nfc/nci/nci_spi.ko
/lib/modules/5.15.0-70-generic/kernel/net/nfc/nci/nci_uart.ko
/lib/modules/5.15.0-70-generic/kernel/net/nfc/nci/nci.ko
/lib/modules/5.15.0-70-generic/kernel/net/nfc/hci/hci.ko

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

localadmin@astra:~$ cat /lib/modules/$(uname -r)/modules.dep | head
kernel/arch/x86/events/amd/amd-uncore.ko:
kernel/arch/x86/events/intel/intel-cstate.ko:
kernel/arch/x86/events/rapl.ko:
kernel/arch/x86/kernel/cpu/mce/mce-inject.ko:
kernel/arch/x86/kernel/msr.ko:
kernel/arch/x86/kernel/cpuid.ko:
kernel/arch/x86/crypto/twofish-x86_64.ko: kernel/crypto/twofish_common.ko
kernel/arch/x86/crypto/twofish-x86_64-3way.ko: kernel/arch/x86/crypto/twofish-x86_64.ko
kernel/arch/x86/crypto/twofish-avx-x86_64.ko: kernel/crypto/crypto_simd.ko kernel/crypto/cryptd.
ko kernel/arch/x86/crypto/twofish-x86_64-3way.ko kernel/arch/x86/crypto/twofish-x86_64.ko kernel
/crypto/twofish_common.ko
...

Просмотр модулей ядра

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

localadmin@astra:~$ lsmod
Module                  Size  Used by
binfmt_misc            24576  1
udp_diag               16384  0
tcp_diag               16384  0
inet_diag              24576  2 tcp_diag,udp_diag
. . .
psmouse               176128  0
hid                   147456  2 usbhid,hid_generic
usb_storage            77824  1 uas
e1000                 151552  0
i2c_piix4              28672  0
drm                   618496  8 vmwgfx,drm_kms_helper,vboxvideo,drm_ttm_helper,ttm
pata_acpi              16384  0
video                  61440  0
parsec                253952  0
digsig_verif          507904  1 parsec

Она выводит таблицу, в которой три столбца:

  • Module – название модуля.

  • Size – размер модуля в байтах.

  • Used by – показывает количество экземпляров модуля, используемое в настоящее время, и список зависимостей, указываются через запятую. Значение ноль говорит о том, что модуль не используется.

Для вывода подробной информации о загруженном модуле, используется команда:

modinfo <имя_модуля>

Выведем информацию о модуле, который реализует драйвер сетевого адаптера e1000 с помощью команды:

localadmin@astra:~$ sudo modinfo e1000
[sudo] пароль для localadmin:
filename:       /lib/modules/5.15.0-70-generic/kernel/drivers/net/ethernet/intel/e1000/e10
00.ko
license:        GPL v2
description:    Intel(R) PRO/1000 Network Driver
author:         Intel Corporation, <linux.nics@intel.com>
srcversion:     B4D2D3AB3E4A089C43DAE56
alias:          pci:v00008086d00002E6Esv*sd*bc*sc*i*
. . .
alias:          pci:v00008086d00001000sv*sd*bc*sc*i*
depends:
retpoline:      Y
intree:         Y
name:           e1000
vermagic:       5.15.0-70-generic SMP mod_unload modversions
parm:           TxDescriptors:Number of transmit descriptors (array of int)
parm:           RxDescriptors:Number of receive descriptors (array of int)
parm:           Speed:Speed setting (array of int)
parm:           Duplex:Duplex setting (array of int)
parm:           AutoNeg:Advertised auto-negotiation setting (array of int)
parm:           FlowControl:Flow Control setting (array of int)
parm:           XsumRX:Disable or enable Receive Checksum offload (array of int)
parm:           TxIntDelay:Transmit Interrupt Delay (array of int)
parm:           TxAbsIntDelay:Transmit Absolute Interrupt Delay (array of int)
parm:           RxIntDelay:Receive Interrupt Delay (array of int)
parm:           RxAbsIntDelay:Receive Absolute Interrupt Delay (array of int)
parm:           InterruptThrottleRate:Interrupt Throttling Rate (array of int)
parm:           SmartPowerDownEnable:Enable PHY smart power down (array of int)
parm:           copybreak:Maximum size of packet that is copied to a new buffer on receive (uint)
parm: debug:Debug level (0=none,...,16=all) (int)

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

Для управления модулями ядра есть несколько инструментов:

  • команды для загрузки и выгрузки модулей ядра;

  • конфигурационные файлы загрузки модулей;

  • конфигурационные файлы для автозагрузки модулей;

  • конфигурационные файлы для запрета загрузки модулей (черные списки);

  • конфигурационные файлы для задания параметров модулей.

Конфигурационные файлы находятся в следующих каталогах:

  • Каталоги /etc/modules-load.d/ и /usr/lib/modules-load.d/ – каталоги с конфигурационными файлами *.conf для автозагрузки модулей при старте системы;

  • Каталоги /etc/modprobe.d/ и /lib/modprobe.d/ – каталоги с конфигурационными файлами *.conf для блокировки модулей, создания псевдонимов и настройки параметров модулей.

Загрузка и выгрузка модулей ядра

Загрузка модулей ядра осуществляется командой:

modprobe [параметры] <имя_модуля> или insmod <полный_путь_до_файла_модуля>.

Выгрузка модулей осуществляется командой:

modprobe -r <имя_модуля> или rmmode <имя_модуля>.

Выгрузим модуль e1000 и загрузим его заново:

localadmin@astra:~$ sudo modprobe -r e1000 && sudo modprobe e1000

При выполнении команды вы могли заметить, что сетевое соединение прерывалось.

У команды modprobe кроме ключа -r есть еще много параметров. С полным списком вы можете ознакомиться в справке man modprobe. Рассмотрим только пару наиболее часто используемых:

  • Ключ --show-depends – вывод зависимостей модуля (в том числе и файл самого модуля), например:

localadmin@astra:~$ sudo modprobe --show-depends ttm
insmod /lib/modules/5.15.0-70-generic/kernel/drivers/gpu/drm/drm.ko
insmod /lib/modules/5.15.0-70-generic/kernel/drivers/gpu/drm/ttm/ttm.ko
  • Ключ --showconfig – вывод эффективных настроек модулей, например:

localadmin@astra:~$ sudo modprobe --showconfig | wc
   45962 137729 2162220
localadmin@astra:~$ sudo modprobe --showconfig | head
blacklist ath_pci
blacklist ohci1394
blacklist sbp2
blacklist dv1394
blacklist raw1394
blacklist video1394
blacklist aty128fb
blacklist atyfb
blacklist radeonfb
blacklist cirrusfb
localadmin@astra:~$ sudo modprobe --showconfig | tail
alias symbol:zgid ib_core
alias symbol:zl10036_attach zl10036
alias symbol:zl10039_attach zl10039
alias symbol:zl10353_attach zl10353
alias symbol:zpa2326_isreg_precious zpa2326
alias symbol:zpa2326_isreg_readable zpa2326
alias symbol:zpa2326_isreg_writeable zpa2326
alias symbol:zpa2326_pm_ops zpa2326
alias symbol:zpa2326_probe zpa2326
alias symbol:zpa2326_remove zpa2326

Автозагрузка модулей ядра

Для автозагрузки модулей ядра службой udev при старте системы их имена достаточно добавить в один из файлов с суффиксом .conf в каталоге /etc/modules-load.d/.

localadmin@astra:~$ ls -l /etc/modules-load.d/
итого 8
-rw-r--r-- 1 root root 123 авг 15 11:03 cups-filters.conf
lrwxrwxrwx 1 root root  10 апр  4 18:15 modules.conf -> ../modules
-rw-r--r-- 1 root root  30 мая  5  2022 usb-over-ip-load.conf

Пустые строки и комментарии игнорируются /etc/modules-load.d/modules.conf:

# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.

localadmin@astra:~$ cat /etc/modules-load.d/cups-filters.conf
# Parallel printer driver modules loading for cups
# LOAD_LP_MODULE was not 'yes' in /etc/default/cups
lp
ppdev
parport_pc

Кроме этой директории существует еще директория /usr/lib/modules-load.d/, конфигурационные файлы которой тоже учитываются.

Модули, внесенные в эти конфигурационные файлы, будут автоматически загружены при следующем старте ОС.

Черный список модулей

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

Черные списки находятся в файлах *.conf в следующих каталогах:

  • Каталог /lib/modprobe.d/ – содержит настройки, заданные при установке ОС или внесенные при установке ПО;

  • Каталог /etc/modprobe.d/ – в эту папку можно сохранять свои собственные настройки, которые потребовались вам в процессе эксплуатации системы.

localadmin@astra:~$ ls /lib/modprobe.d/
aliases.conf                             fbdev-blacklist.conf
blacklist_linux_5.15.0-33-generic.conf   systemd.conf
blacklist_linux_5.15.0-70-generic.conf

localadmin@astra:~$ ls /etc/modprobe.d/
blacklist-astra.conf    blacklist-firewire.conf      blacklist-rare-network.conf
blacklist-ath_pci.conf  blacklist-framebuffer.conf   iwlwifi.conf
blacklist.conf          blacklist.local.conf         parsec-cifs.conf

localadmin@astra:~$ cat /lib/modprobe.d/blacklist_linux_5.15.0-70-generic.conf | head
# Kernel supplied blacklist for linux 5.15.0-70-generic amd64
# modprobe.d/common.conf
# LP:1434842 -- disable OSS drivers by default to allow pulseaudio to emulate
blacklist snd-mixer-oss
blacklist snd-pcm-oss
# Autogenerated watchdog blacklist
blacklist acquirewdt
blacklist advantechwdt
blacklist alim1535_wdt
blacklist alim7101_wdt

Модули могут быть загружены как службой udev, так и на более раннем этапе из initramfs диска.

Для того чтобы запретить автозагрузку модуля, достаточно в каталоге /etc/modprobe.d/ в файле с суффиксом *.conf создать строку, которая начиналась бы с директивы blacklist, за которой следовало бы имя модуля. Однако для соблюдения соглашения об именовании крайне желательно, чтобы имя такого файла начиналось со слова blacklist.

Для запрета автозагрузки модуля, загружаемого из initramfs, необходимо пересоздать initramfs после внесения изменений в конфигурационные файлы. Это можно сделать командой sudo update-initramfs -u.

Запрет, созданный с помощью директивы blacklist, запретит автозагрузку модуля. Однако модуль может быть все равно загружен, если от него зависят другие модули. Для полного запрета загрузки модуля в дополнение к директиве blacklist необходимо добавить команду install <имя_модуля> /bin/true.

Загрузку модулей можно запретить также с помощью параметров GRUB. Это может быть полезно, если один из модулей препятствует нормальной загрузке системы. Для этого необходимо добавить текст вида module_blacklist=<имя_модуля1>,<имя_модуля2> в строку с параметрами загрузки ядра.

Создадим файл blacklist-network.conf в /etc/modprobe.d/, добавим в него строку blacklist e1000 и перезагрузим систему.

localadmin@astra:~$ sudo vim /etc/modprobe.d/blacklist-network.conf
localadmin@astra:~$ sudo cat /etc/modprobe.d/blacklist-network.conf
blacklist e1000
localadmin@astra:~$ sudo reboot

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

localadmin@astra:~$ lsmod | grep e1000
e1000                 151552  0

Дело в том, что этот драйвер загружается из initramfs. Выполним обновление образа Initrd, перезагрузим систему и убедимся, что теперь сеть нам не доступна:

localadmin@astra:~$ sudo update-initramfs -u
update-initramfs: Generating /boot/initrd.img-5.15.0-70-generic
localadmin@astra:~$ sudo reboot

После перезагрузки:

localadmin@astra:~$ lsmod | grep e1000
localadmin@astra:~$

Однако мы все еще можем загрузить этот модуль вручную командой:

localadmin@astra:~$ sudo modprobe e1000
localadmin@astra:~$ lsmod | grep e1000
e1000                 151552

При внесении дополнительной строки install e1000 /bin/true в конфигурационный файл /etc/modprobe.d/blacklist-network.conf мы полностью запретим загрузку этого модуля.

blacklist e1000
install e1000 /bin/true

Создайте файл blacklist-network.conf с содержимым, описанным выше, и перезагрузитесь:

localadmin@astra:~$ sudo vim /etc/modprobe.d/blacklist-network.conf
localadmin@astra:~$ sudo reboot

После перезагрузки проверим:

localadmin@astra:~$ sudo modprobe e1000
localadmin@astra:~$ lsmod | grep e1000
localadmin@astra:~$

Для восстановления работоспособности сети, удалим созданный нами файл черного списка /etc/modprobe.d/blacklist-network.conf, пересоздадим образ Initrd и перезагрузим систему.

localadmin@astra:~$ sudo rm /etc/modprobe.d/blacklist-network.conf
localadmin@astra:~$ sudo update-initramfs -u
update-initramfs: Generating /boot/initrd.img-5.15.0-70-generic
localadmin@astra:~$ sudo reboot

Как мы можем убедиться, сетевой адаптер снова работает, и сеть стала опять доступна:

localadmin@astra:~$ lsmod | grep e1000
e1000                 151552 0

Псевдонимы модулей

Псевдонимы модулей – это альтернативные имена модулей, которые могут быть созданы для удобства (если имя модуля, например, слишком длинное) или для нужд приложений.

Псевдонимы, как и черные списки, хранятся в файлах с суффиксом .conf в следующих каталогах:

  • Каталог /lib/modprobe.d/ - содержит настройки, заданные при установке ОС или внесенные при установке ПО.

  • Каталог /etc/modprobe.d/ - в эту папку можно сохранять свои собственные настройки, которые потребовались вам в процессе эксплуатации системы.

Однако в этом случае не нужно использовать слово blacklist в названии файлов.

Чтобы создать псевдоним, необходимо в файл с суффиксом *.conf (например, aliases.conf или aliases-<что-то>.conf) добавить строку вида:

alias <псевдоним_модуля> <имя_модуля>

В именах алиасов вам доступны также символы подстановки. Например, задав псевдоним через команду alias my-mod* module_name, к модулю можно будет обращаться через имена my-mod-1, my-mod-something и так далее.

Параметры модулей

Параметры модулей можно задавать как с помощью конфигурационных файлов, так и «на лету» с помощью утилиты modprobe:

  • Параметры модулей, как и псевдонимы, задаются в файлах *.conf в каталогах /lib/modprobe.d/ и /etc/modprobe.d/. Для этого необходимо добавить в файл строку вида:

    options <имя_модуля> <имя_параметра>=<значение параметра>

  • Для управления параметрами модулей при работе системы можно воспользоваться командой:

    modprobe <имя_модуля> <имя_параметра>=<значение параметра>.

Практика и тестирование

Заключение

В этом модуле мы познакомились с содержимым псевдофайловой системы sysfs и правилами подсистемы udev, с помощью которых можно задавать действия, которые будут автоматически выполняться в системе при подключении/отключении устройств. Мы узнали немного больше о модулях ядра и о том, как ими управлять, поэтому нам станут теперь понятны сложные инструкции по настройке какого-нибудь специфического оборудования.

В следующем модуле мы подробнее познакомимся с файловыми системами в Linux и научимся работать с блочными устройствами и LVM.

Дополнительные источники информации: