Вопрос или проблема
Как мне узнать, начиная с какой версии ядра Linux доступен API функции/макроса ядра или произошли ли в нем изменения, нарушающие совместимость (был удалён, изменился тип или количество аргументов).
Например, просматривая недавнюю версию scatterlist.h
, я наткнулся на sg_alloc_table_from_pages_segment
, которая имеет именно ту функциональность, которая нужна для моего модуля ядра (драйвера). Однако, к моему разочарованию, эта функция еще недоступна в версии 5.10, для которой разрабатывается модуль ядра, и мне придется найти обходной путь. Тем не менее, я хочу поддерживать будущие версии ядра на случай, если мы совершим обновление.
Обычно такие случаи решаются с помощью предпроцессорных ограждений
#if LINUX_VERSION_CODE >= KERNEL_VERSION(...)
/*Версия-специфическая реализация*/
#endif
Но для того, чтобы применить эту схему, мне нужно найти версию ядра, в которой функция была добавлена. Ручное сканирование всех промежуточных версий заголовочного файла было бы сизифовой работой.
Запуск git blame
на соответствующем файле показывает, что функция была добавлена в коммите 90e7a6de62781c27d6a111fccfb19b807f9b6887. Запуск git tag --contains 90e7a6de62781c27d6a111fccfb19b807f9b6887
затем показывает, что функция доступна с версии v5.15 (игнорируя потенциальные обратные портирования).
Выяснив, что функция sg_alloc_table_from_pages_segment
находится в исходном файле scatterlist.c, при просмотре blame для исходного файла указывает, что последний раз он был изменён коммитом 90e7a6d, который показывается в тегах:
v6.14-rc5 … v5.15-rc1
Обращаясь к Elixir Cross Referencer:
- v5.14.21/source/lib/scatterlist.c не содержит
sg_alloc_table_from_pages_segment
. - v5.15-rc1/source/lib/scatterlist.c содержит
sg_alloc_table_from_pages_segment
.
Это подтверждает, что основное ядро v5.15-rc1 впервые представило эту функцию.
Исследуя установку AlmaLinux 8.10 с установленным исходным кодом ядра, можно увидеть, что sg_alloc_table_from_pages_segment
был обратно портирован в ядро на базе RHEL linux-4.18.0-553.33.1.el8_10.x86_64
.
Ответ или решение
Определение, с какой версии Linux доступен API ядра, или выяснение изменения в таком API требует систематического подхода. Это важно для разработчиков ядра и модулей, поскольку позволяет адаптировать их программное обеспечение к разным версиям ядра Linux, избегая проблем несовместимости. Давайте разберёмся в этом вопросе более подробно, опираясь на ситуацию с функцией sg_alloc_table_from_pages_segment
.
Теория
Поддержка совместимости с ядром Linux разных версий является важной задачей для каждого разработчика модулей или драйверов. В ядре Linux регулярно происходят изменения, которые могут включать добавление новых функций, изменение существующих или их удаление. Эти изменения часто фиксируются в системе контроля версий Git, которой управляется развитие ядра.
Часто возникает проблема, когда основная функция или макрос, essential для вашего модуля, была добавлена в более новых версиях ядра или подверглась изменениям. В этой связи становится критически важным определить, начиная с какой версии ядра данная функция доступна, чтобы адекватно адаптировать код.
Пример
В рассмотренном вами случае, функция sg_alloc_table_from_pages_segment
отсутствует в версии ядра 5.10, но она необходима для вашего драйвера. Вы обнаружили, что функция была добавлена в ядро в версии 5.15. Давайте рассмотрим шаги, которые вам помогли это выяснить:
-
Git Blame:
Этот инструмент позволяет определить, какой коммит и кто ввёл изменение в указанный файл. Использование командыgit blame
на файлеscatterlist.c
помогло выяснить, что функция была добавлена в коммите 90e7a6d. Это предоставило точку отсчета для дальнейшего анализа. -
Git Tag:
Использование командыgit tag --contains <коммит>
позволило определить, в какой версии ядра эти изменения появились. Таким образом, было определено, что функция была включена в релиз-кандидат v5.15-rc1. -
Электронные ресурсы:
Дополнительное подтверждение было получено через использование сервисов, таких как Elixir Cross Referencer, для просмотра исходного кода предыдущих релизов ядра.
Применение
Теперь, зная версию ядра, начиная с которой функция доступна (v5.15-rc1
), вы можете адаптировать ваш код следующим образом:
-
Управление версии с помощью препроцессора:
Используйте конструкции препроцессора, чтобы описать разную логику для разных версий ядра. Например:#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) /* Реализация для версии ядра начиная с 5.15 */ #else /* Альтернативная реализация или решение для более старой версии */ #endif
-
Поддержка разных версий ядра:
Убедитесь, что в вашем модуле используются только те функции, которые доступны для всех поддерживаемых вами версий ядра. Если функция отсутствует в более старых версиях, необходимо разработать обходные решения. -
Отслеживание изменений:
Рекомендуется регулярно отслеживать изменения в основных файлах ядра и вести журнал изменений вашего кода, чтобы быть готовым к возможным будущим обновлениям ядра.
Также важно помнить, что могут существовать дистрибутивы ядра Linux с backport-ами функций в более старые версии. Например, в вашем случае функция была backport-интегрирована в RHEL-базированный ядро версии 4.18.0-553.33.1.el8_10.x86_64
. Это обязывает вас учитывать поведение отдельных дистрибутивов и предоставлять адекватную поддержку для них, если они находятся в области вашего интереса.
Таким образом, даже если поддержка специфических версий ядра может показаться излишне сложной задачей, стратегическое использование инструментов, таких как Git и специализированные ресурсы, существенно упрощает вашу работу. Навигация по изменениям ядра становится легче, если вы систематически отслеживаете изменения и используете соответствующие инструменты и методы.