Ядро, модули, /proc и /sys

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

Модуль ядра — кусок кода (драйвер, файловая система, сетевой протокол), который можно загружать и выгружать в работающее ядро без перезагрузки. /proc и /sys — виртуальные ФС-окна в состояние ядра.

Зачем это на практике

Подключили USB-адаптер, а драйвера нет; нужно включить форвардинг пакетов для контейнеров; сервер «тормозит», и хочется узнать, что ядро думает об оборудовании. Всё это — работа с модулями и псевдо-файловыми системами /proc//sys. Это не «магия для ядерных разработчиков», а ежедневный инструмент админа и DevOps.

Идентификация ядра

uname -r            # версия ядра, напр. 6.8.0-40-generic
uname -a            # всё: ядро, хост, архитектура
uname -m            # архитектура (x86_64, aarch64)
cat /proc/version   # подробно: компилятор, дата сборки

Версия ядра (uname -r) критична: пути модулей лежат в /lib/modules/$(uname -r)/, и собранный под другую версию модуль не загрузится.

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

Четыре основные команды. Запомните: используйте modprobe, а не insmod — modprobe сам разрешает зависимости.

lsmodсписок загруженных модулей и кто их использует
modprobe ИМЯзагрузить модуль с зависимостями
modprobe -r ИМЯвыгрузить модуль
modinfo ИМЯописание, параметры, зависимости модуля
insmod ФАЙЛ.koзагрузить ровно один файл без зависимостей (низкоуровнево)
lsmod | head
sudo modprobe v4l2loopback           # загрузить (со всеми зависимостями)
modinfo v4l2loopback | head
sudo modprobe -r v4l2loopback        # выгрузить

# параметр модулю при загрузке
sudo modprobe v4l2loopback devices=2 video_nr=10

Чтобы модуль грузился автоматически при старте — добавьте его имя в /etc/modules-load.d/имя.conf, а параметры — в /etc/modprobe.d/имя.conf (options ИМЯ ключ=значение). Чтобы наоборот запретить — blacklist ИМЯ там же.

/proc — окно в процессы и ядро

/proc — виртуальная ФС: файлов в ней нет на диске, ядро генерирует их содержимое на лету при чтении. Здесь каждая запущенная программа имеет каталог по своему PID, а также есть системная информация:

cat /proc/cpuinfo | grep "model name" | head -1
cat /proc/meminfo | head -3
cat /proc/loadavg          # средняя нагрузка
cat /proc/mounts           # смонтированные ФС

# каталог конкретного процесса
ls -l /proc/$$/            # $$ = PID текущего shell
cat /proc/$$/cmdline | tr "\0" " "; echo   # командная строка процесса
ls -l /proc/$$/fd          # открытые файловые дескрипторы

/sys — устройства и драйверы

/sys (sysfs) появилась позже и структурирована аккуратнее: это иерархия устройств, шин и драйверов, как их видит ядро. Многие параметры устройств можно не только читать, но и менять записью в файл:

# включить/выключить функцию устройства простой записью в файл
cat /sys/class/net/eth0/operstate         # up или down
cat /sys/block/sda/queue/rotational       # 1 = HDD, 0 = SSD

# пример управления (нужны права): сменить планировщик ввода-вывода
echo mq-deadline | sudo tee /sys/block/sda/queue/scheduler

sysctl — параметры ядра

Часть настроек ядра живёт под /proc/sys/, и удобная обёртка для них — sysctl. Это способ менять поведение сети, памяти, безопасности на лету и навсегда:

sysctl net.ipv4.ip_forward            # прочитать значение
sudo sysctl -w net.ipv4.ip_forward=1  # включить форвардинг СЕЙЧАС (до перезагрузки)

# чтобы пережило ребут — в файл:
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-forward.conf
sudo sysctl --system                  # применить все *.conf

sysctl -a | grep swappiness           # поиск нужного параметра

Запись через sysctl -w и прямой echo 1 > /proc/sys/net/ipv4/ip_forward — одно и то же, но первый способ переносимее.

dmesg — кольцевой буфер ядра

Ядро пишет диагностику в кольцевой буфер; dmesg его показывает. Это первое место, куда смотрят при проблемах с железом, драйверами, OOM-killer:

sudo dmesg -T | tail -20          # -T = человекочитаемое время
sudo dmesg -w                     # следить в реальном времени
sudo dmesg --level=err,warn       # только ошибки и предупреждения
sudo dmesg | grep -i "out of memory"   # сработал ли OOM-killer

То же самое доступно через journalctl -k (ядерные сообщения) или journalctl --dmesg.

Как это работает под капотом

/proc и /sys — это не файлы, а интерфейс: они смонтированы как файловые системы типов proc и sysfs, но за каждым «файлом» стоит функция ядра. Когда вы делаете cat /proc/meminfo, ядро в этот момент формирует актуальную статистику памяти — поэтому значения всегда свежие, а размер файла часто показан как 0. Модули — это объектные файлы .ko, которые линкуются прямо в адресное пространство ядра; modprobe читает карту зависимостей modules.dep (её строит depmod) и грузит всё в правильном порядке, тогда как insmod вставляет один файл вслепую. Запись в /sys и /proc/sys вызывает обработчик ядра, который тут же меняет соответствующую переменную в работающем ядре — без перекомпиляции и без перезагрузки.

Частые ошибки

  • Используют insmod и получают «Unknown symbol» — забыли, что не подгрузились зависимости; почти всегда нужен modprobe.
  • Меняют параметр через sysctl -w и удивляются, что после ребута он сбросился — нет записи в /etc/sysctl.d/.
  • Пытаются изменить файл в /proc обычным редактором — многие из них только для чтения или требуют echo ... | tee с правами root.
  • Собрали модуль под одну версию ядра, обновили ядро — модуль перестал грузиться; нужна пересборка (часто через DKMS).
  • Смотрят dmesg без -T и не могут соотнести событие со временем из логов.

Итоги

  • modprobe (с зависимостями) предпочтительнее insmod; lsmod/modinfo для осмотра.
  • Автозагрузка модуля — /etc/modules-load.d/, параметры и blacklist — /etc/modprobe.d/.
  • /proc и /sys — виртуальные ФС, генерируемые ядром на лету; запись в них меняет ядро мгновенно.
  • sysctl -w — сейчас, файл в /etc/sysctl.d/ — навсегда.
  • dmesg -T / journalctl -k — первый взгляд при проблемах с железом и OOM.
Проверьте себя
1. Почему для загрузки драйвера обычно используют modprobe, а не insmod?
Amodprobe работает быстрее, потому что не проверяет подпись
Bmodprobe автоматически загружает зависимости модуля, а insmod вставляет один файл без них
Cinsmod устарел и удалён из современных ядер
Dmodprobe не требует прав root, а insmod требует
2. Вы включили net.ipv4.ip_forward командой sysctl -w, но после перезагрузки он снова 0. Что нужно сделать, чтобы значение сохранялось?
AПерезапустить службу networking
BЗаписать параметр в файл /etc/sysctl.d/*.conf (и применить sysctl --system)
CИспользовать insmod вместо sysctl
DИзменить /boot/grub/grub.cfg