Бага drivers/media/radio/si470x/radio-si470x- common.c

Баг, который тут описан, был найден в драйвере ядра linux-2.6.37 с помощью проекта Linux Driver Verification Program.

Драйвер предназначен, как в его коде написано, для работы «radios with Silicon Labs Si470x FM Radio Receivers». Но, видимо, не работает, поскольку функция read скорее всего приводит к зависанию. На операциях read и write держится большая часть полезной работы драйверов.

Сама ошибка заключается в повторной блокировки одного и того же mutex’а. Для тех, кто не знает, что такое mutex рекомендую — почитать вот это. Вкратце: если мы последовательно попытаемся захватить один и тот же мютекс два раза, то получим deadlock. Иначе говоря, программа будет бесконечно ждать сама себя, что крайне неприятно.

Проблемный кусок кода.

Мютекс нигде не освобождается между строчками 441-462. Почему сделан такой вывод? Очевидно, что явного вызова mutex_unlock в вышеописанном коде нет. Допустим даже, что мютекс может разблокироваться в функции si470_rds_on (вызывается в строчке 443). Но условие в строчке 442 вполне может не выполниться (иначе зачем его туда поставили ) и мы пойдем дальше. А дальше кроме как wait_event_interruptible никакие функции не вызываются. wait_event_interruptible — представитель API ядра. Ее задача заключается в ожидании выполнения  некоторого условия (не совсем, interruptible — говорит о том что ожидание может быть прервано) . В данном случае это условие: radio->wr_index != radio->rd_index. То есть в условии не вызываются никакие посторонние функции, которые могли бы разлочить мютекс.  Можно конечно предположить, что мютекс разлочит кто-нибудь еще. Но таких сложностей в драйвере нет и работа с мютексами там написана достаточно прозрачно.

В версии ядра 2.6.36.3 первого mutex_lock’а нет. Давайте посмотрим, что на самом деле хотели сделать разработчики. Ниже представлено сравнение участков кода нашего драйвера из двух версий ядра : 2.6.36.3 слева и справа 2.6.37.

 

code

Видно, что в версии 2.6.37 пару mutex_lock/mutex_unlock вынесли в fops_read. А убрать старый mutex_lock из fops_read забыли. Теперь все ясно. Поможем разработчикам и напишем патч.

Продолжение в Linux Kernel Mailing List или на странице багов, найденных с помощью  LDV.