Сделаем код чище: нюансы вывода отладочных сообщений в драйверах Linux

от автора

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

Для начала посмотрим, какие известные функции вывода сообщений предоставлены во внутреннем API ядра.

Базовая функция

printk(LEVEL "message\n"); 

От неё есть набор макросов (наиболее часто используемые):

pr_err("message\n"); pr_warn("message\n"); pr_info("message\n"); pr_debug("message\n"); 

И так далее.

Для драйверов же используется набор функций с префиксом dev_* с соответствющими уровнями вывода, и отдельно для драйверов сетевых карт c префиксом netdev_*. И вообще, общее правило, что подсистема ядра или драйвер использует свой префикс и суффиксом уровня вывода сообщения.

Все они являются полноценными аналогами записи printk(LEVEL …) для pr_* и таким же образом для dev_* и netdev_* за исключением pr_debug(), dev_dbg() и, как уже все догадались, netdev_dbg().

Итак, при каких условиях мы увидим сообщение, выводимое разными вариантами?

С помощью printk(KERN_DEBUG "message\n"):

  • уровень вывода в командной строке ядра выставлен равным или более 7 ИЛИ передан параметр ignore_loglevel

и pr_debug("message\n"):

  • уровень вывода в командной строке ядра выставлен равным или более 7 ИЛИ передан параметр ignore_loglevel
  • интересуемый нас модуль собран с опцией DEBUG ИЛИ включена опция конфигурации ядра CONFIG_DYNAMIC_DEBUG, а соответствующие сообщения (например, указанием имя модуля: номер строки) включены в список выводимых

То же самое и для dev_dbg(), и для netdev_dbg().

Помимо этого особое внимание стоит уделить полезной опции CONFIG_DYNAMIC_DEBUG. При всей её динамичности работать она начинает не самой загрузки ядра, поэтому не во всех модулях можно полагаться на неё.

Ещё одна дилемма о том, что использовать в продуктовой версии: CONFIG_DYNAMIC_DEBUG или стандартный вывод, префиксируемый условием типа:

#define mydbg(mydev, format, arg…) \ do { \   if (mycooldriver->debug > 0) \     dev_printk(KERN_DEBUG, dev,  format, ##arg); \ } while (0) 

Так вот разница здесь вполне очевидна, если копнуть в недра исходного кода ядра, а именно в первом случае вывод будет приравнен к no-op (пустой операции), что не так во втором случае. Соответственно критичные по времени исполнения модули не стоит заполнять кодом, показанным выше. Более того, лучшим вариантом будет применение трассировочных точек в таких местах, но об этом я расскажу когда-нибудь в будущем.

Бонусом добавлю, что функция print_hex_dump_bytes() относительно недавно обзавелась поддержкой со стороны Dynamic Debug.

ссылка на оригинал статьи http://habrahabr.ru/post/262791/