Я работаю над драйвером Linux для устройства USB, который, к счастью, идентичен тому, что в драйвере примера usb_skeleton, который является частью стандартного источника ядра. С ядром 4.4 это был легкий ветерок, я просто изменил VID и PID и несколько строк, а драйвер скомпилирован и отлично работал как на ядрах x64, так и на ARM.Драйвер устройства linux застрял во вращении за счет постоянного чтения при первом доступе
Но, оказывается, я должен выполнить эту работу с ядром 3.2. У меня нет выбора в этом. Я сделал те же самые изменения для драйвера скелета в источнике 3.2. Опять же, мне не нужно было менять фактический код, просто VID, PID и некоторые строки. Хотя он компилируется и загружается нормально (и отображается в/dev), он постоянно зависает при первой попытке выполнить чтение из/dev/myusbdev0.
Следующий код является функцией чтения, которая должна считываться из основной конечной точки. Когда я пытаюсь прочитать устройство, я вижу первое сообщение, которое он собирается заблокировать из-за текущей io. Тогда ничего. Программа пользователя, пытающаяся прочитать это, висит и не может быть убита с kill -9. Линейная машина не может даже перезагрузиться - я должен задействовать цикл. Нет сообщений об ошибках, исключений или чего-либо подобного. Кажется довольно уверенным, что он висит в части, которая прокомментирована «IO May Take Forever».
Мой вопрос: почему будет продолжаться IO, когда никакая программа не сделала ни одного ввода-вывода с драйвером? Могу ли я исправить это в коде драйвера, или пользовательская программа должна что-то сделать, прежде чем начать чтение с/dev/myusbdev0?
В этом случае целевая машина представляет собой встроенное устройство ARM, похожее на Beaglebone Black. Напротив, версия ядра 4,4 этого драйвера отлично работает на Beaglebone с той же тестовой программой пользовательского режима.
/* if IO is under way, we must not touch things */
retry:
spin_lock_irq(&dev->err_lock);
ongoing_io = dev->ongoing_read;
spin_unlock_irq(&dev->err_lock);
if (ongoing_io) {
dev_info(&interface->dev,
"USB PureView Pulser Receiver device blocking due to ongoing io -%d",
interface->minor);
/* nonblocking IO shall not wait */
if (file->f_flags & O_NONBLOCK) {
rv = -EAGAIN;
goto exit;
}
/*
* IO may take forever
* hence wait in an interruptible state
*/
rv = wait_for_completion_interruptible(&dev->bulk_in_completion);
dev_info(&interface->dev,
"USB PureView Pulser Receiver device completion wait done io -%d",
interface->minor);
if (rv < 0)
goto exit;
/*
* by waiting we also semiprocessed the urb
* we must finish now
*/
dev->bulk_in_copied = 0;
dev->processed_urb = 1;
}
Возможно, вам будет интересно прочитать книгу Роберта Лава о блокировке и др. – 0andriy
Взгляните на это ядро: - https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c79041a44045a40329d9ada3f8679c4b30c5b76b - «USB: usb-skeleton.c: исправить заблокирован навсегда в skel_read "- я думаю, это может быть то, что вам нужно. У меня нет времени, чтобы взглянуть на это сейчас, надеюсь, сегодня я позабочусь и могу ответить на этот вопрос. – michaeljt
Взял более пристальный взгляд на код и не мог решить, почему прерывание ожидания может не прерываться, или, как альтернатива, почему второе сообщение может не отображаться. Добавление нескольких сообщений в другие пути, в частности, завершение и непрерывные пути ожидания, может дать некоторую подсказку. – michaeljt