Сторонний драйвер, собранный вручную, ломается при первом обновлении ядра: модуль остаётся в /lib/modules для старой версии, а новая загружается без него. DKMS решает эту проблему — при установке нового ядра пакет автоматически пересобирает модуль под него. Ниже полный цикл: подготовка, dkms.conf, сборка, подпись для Secure Boot и разбор типичных ошибок.
Подготовка: заголовки ядра и dkms
Для сборки нужны исходники или заголовки именно того ядра, под которое собирается модуль. В Debian и Ubuntu это пакет linux-headers-$(uname -r), в Fedora и RHEL-совместимых — kernel-devel и kernel-headers. После обновления ядра до перезагрузки заголовки могут относиться к новому ядру, а работает старое — проверяйте соответствие.
sudo apt update
sudo apt install dkms build-essential linux-headers-$(uname -r)
uname -r
dkms --version
В Fedora команда установки выглядит иначе: sudo dnf install dkms kernel-devel kernel-headers gcc make. Убедитесь, что каталог /lib/modules/$(uname -r)/build существует и указывает на корректные заголовки. Если его нет, DKMS не сможет собрать модуль, даже при правильном dkms.conf.
Структура исходников и dkms.conf
Исходники размещаются в /usr/src/имя-версия. Внутри — файлы модуля, Makefile и dkms.conf. Имя пакета и версия в конфигурации должны совпадать с каталогом, иначе команды dkms add и build будут искать не там. Минимальный набор переменных показан ниже.
PACKAGE_NAME="mydriver"
PACKAGE_VERSION="1.0.0"
BUILT_MODULE_NAME[0]="mydriver"
BUILT_MODULE_LOCATION[0]="."
DEST_MODULE_LOCATION[0]="/updates"
MAKE[0]="make -C $kernel_source_dir M=$dkms_tree/$PACKAGE_NAME/$PACKAGE_VERSION/build"
CLEAN="make -C $kernel_source_dir M=$dkms_tree/$PACKAGE_NAME/$PACKAGE_VERSION/build clean"
AUTOINSTALL="yes"
Переменная kernel_source_dir указывает на заголовки текущего ядра, а dkms_tree — на рабочую копию исходников. DEST_MODULE_LOCATION /updates кладёт модуль в отдельный каталог, чтобы он не конфликтовал с модулями ядра. AUTOINSTALL разрешает автоматическую сборку при установке нового ядра. Makefile должен поддерживать цели modules и clean — обычно это стандартный kbuild-шаблон.
Сборка и установка
Сначала добавьте пакет в базу DKMS, затем соберите и установите. Сборка без установки удобна для проверки: если компилятор ругается, вы увидите ошибку до того, как модуль попадёт в систему. Все шаги выполняются от root, потому что DKMS пишет в /var/lib/dkms и /lib/modules.
sudo dkms add -m mydriver -v 1.0.0
sudo dkms build -m mydriver -v 1.0.0
sudo dkms install -m mydriver -v 1.0.0
dkms status
После установки загрузите модуль через modprobe и проверьте, что он действительно тот: modinfo покажет версию, автора и параметры. dmesg должен содержать сообщения драйвера без ошибок. Если модуль уже был загружен, старую версию нужно выгрузить или перезагрузиться — иначе в памяти останется прежний код.
sudo modprobe mydriver
lsmod | grep mydriver
modinfo mydriver
dmesg | tail -30
Что происходит при обновлении ядра
Пакет ядра вызывает hook, который запускает dkms autoinstall для новой версии. На Debian и Ubuntu это делает /etc/kernel/postinst.d/dkms, на системах с systemd также работает dkms.service при загрузке. Если модуль нужен на этапе монтирования корня — например, драйвер дискового контроллера или файловой системы, — его нужно добавить в initramfs. Иначе система может не загрузиться после обновления.
sudo dkms autoinstall -k $(uname -r)
sudo update-initramfs -u -k all
sudo dracut --force --add-drivers mydriver
Команда update-initramfs относится к Debian и Ubuntu, dracut — к Fedora и RHEL-совместимым. Не выполняйте обе подряд «на всякий случай»: на системах с dracut update-initramfs может отсутствовать. Проверьте, какая система инициализации initramfs используется в вашем дистрибутиве.
Не удаляйте предыдущее ядро сразу после обновления. Загрузитесь в новое, проверьте dkms status, работу устройства и только потом очищайте старые пакеты. Если модуль не собрался, вы сможете вернуться в прежнее ядро и спокойно прочитать make.log, вместо того чтобы восстанавливать систему с флешки.
Secure Boot и подпись модуля
При включённом Secure Boot ядро загружает только подписанные модули. Ubuntu подписывает модули DKMS ключом из /var/lib/shim-signed/mok, но ключ нужно один раз зарегистрировать в прошивке через mokutil. Fedora использует akmods и собственный механизм подписи. Проверить режим и подпись можно командами ниже.
mokutil --sb-state
modinfo -F signer mydriver
sudo mokutil --import /var/lib/shim-signed/mok/MOK.der
dmesg | grep -i -E 'key|signature|taint'
После импорта ключа при перезагрузке появится экран MOK с подтверждением. Без этого модуль не загрузится, а в dmesg будет сообщение о rejection. Отключать Secure Boot ради драйвера не стоит: регистрация собственного ключа — штатная процедура. Помните, что сторонний модуль помечает ядро как tainted, и это нормально, но усложняет разбор отчётов об ошибках.
Типичные сбои и диагностика
Основные причины: несовпадение версии заголовков, изменения внутреннего API ядра, старый объектный файл в каталоге сборки, отсутствие подписи и конфликт с уже загруженным модулем. Начинайте с dkms status: статус built означает, что сборка прошла, installed — что модуль установлен, а ошибка видна в make.log конкретной версии.
dkms status
sudo tail -40 /var/lib/dkms/mydriver/1.0.0/build/make.log
sudo modprobe -v mydriver
sudo depmod -a
Перед пересборкой полезно выполнить sudo dkms remove и dkms add заново: это очищает служебные ссылки, если каталог исходников переименовали.
Сообщение «Invalid module format» обычно указывает на несовпадение vermagic — модуль собран под другое ядро. «Unknown symbol» означает, что изменился API или не подключён нужный экспорт. Если после обновления ядра модуль пропал, проверьте, установлены ли headers для новой версии и не завершился ли autoinstall ошибкой. Иногда помогает очистить каталог /var/lib/dkms/имя/версия/build и собрать заново.
Удаление и чистота
Удаляйте модуль через dkms remove, а не вручную: утилита уберёт записи для всех ядер и обновит зависимости. После этого можно удалить исходники из /usr/src. Если модуль прописан в /etc/modules или /etc/modules-load.d, уберите и эти записи, иначе система будет пытаться загрузить отсутствующий драйвер.
sudo dkms remove -m mydriver -v 1.0.0 --all
sudo rm -rf /usr/src/mydriver-1.0.0
sudo depmod -a
Итог
DKMS превращает ручную сборку драйвера в воспроизводимый процесс, который переживает обновления ядра. Ключевые условия: совпадающие заголовки, корректный dkms.conf с путями kbuild, проверка статуса после каждого обновления и настроенная подпись при Secure Boot. Если модуль нужен при загрузке, не забудьте про initramfs. Диагностика почти всегда начинается с dkms status и make.log, а не с переустановки драйвера наугад.