Как узнать версию ядра Linux для изменения API?

Вопрос или проблема

Как мне узнать, начиная с какой версии ядра 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.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. Давайте рассмотрим шаги, которые вам помогли это выяснить:

  1. Git Blame:
    Этот инструмент позволяет определить, какой коммит и кто ввёл изменение в указанный файл. Использование команды git blame на файле scatterlist.c помогло выяснить, что функция была добавлена в коммите 90e7a6d. Это предоставило точку отсчета для дальнейшего анализа.

  2. Git Tag:
    Использование команды git tag --contains <коммит> позволило определить, в какой версии ядра эти изменения появились. Таким образом, было определено, что функция была включена в релиз-кандидат v5.15-rc1.

  3. Электронные ресурсы:
    Дополнительное подтверждение было получено через использование сервисов, таких как Elixir Cross Referencer, для просмотра исходного кода предыдущих релизов ядра.

Применение

Теперь, зная версию ядра, начиная с которой функция доступна (v5.15-rc1), вы можете адаптировать ваш код следующим образом:

  1. Управление версии с помощью препроцессора:
    Используйте конструкции препроцессора, чтобы описать разную логику для разных версий ядра. Например:

    #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
    /* Реализация для версии ядра начиная с 5.15 */
    #else
    /* Альтернативная реализация или решение для более старой версии */
    #endif
  2. Поддержка разных версий ядра:
    Убедитесь, что в вашем модуле используются только те функции, которые доступны для всех поддерживаемых вами версий ядра. Если функция отсутствует в более старых версиях, необходимо разработать обходные решения.

  3. Отслеживание изменений:
    Рекомендуется регулярно отслеживать изменения в основных файлах ядра и вести журнал изменений вашего кода, чтобы быть готовым к возможным будущим обновлениям ядра.

Также важно помнить, что могут существовать дистрибутивы ядра Linux с backport-ами функций в более старые версии. Например, в вашем случае функция была backport-интегрирована в RHEL-базированный ядро версии 4.18.0-553.33.1.el8_10.x86_64. Это обязывает вас учитывать поведение отдельных дистрибутивов и предоставлять адекватную поддержку для них, если они находятся в области вашего интереса.

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

Оцените материал
Добавить комментарий

Капча загружается...