2017-01-25 8 views
1

Я работаю над драйвером 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; 
    } 
+0

Возможно, вам будет интересно прочитать книгу Роберта Лава о блокировке и др. – 0andriy

+0

Взгляните на это ядро: - https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c79041a44045a40329d9ada3f8679c4b30c5b76b - «USB: usb-skeleton.c: исправить заблокирован навсегда в skel_read "- я думаю, это может быть то, что вам нужно. У меня нет времени, чтобы взглянуть на это сейчас, надеюсь, сегодня я позабочусь и могу ответить на этот вопрос. – michaeljt

+0

Взял более пристальный взгляд на код и не мог решить, почему прерывание ожидания может не прерываться, или, как альтернатива, почему второе сообщение может не отображаться. Добавление нескольких сообщений в другие пути, в частности, завершение и непрерывные пути ожидания, может дать некоторую подсказку. – michaeljt

ответ

0

Написание этого ответа, поскольку ответа на мои комментарии не было. Ядро совершает c79041a4 [1], которое было добавлено в 3.10, исправления «заблокированы навсегда в skel_read». Посмотрев на код выше, я вижу, что первое сообщение может запускаться без отображения второго, если в файле устройства установлен флаг O_NONBLOCK. Как описано в сообщении фиксации, если завершение происходит между вызовами read(), следующий вызов read() будет завершен в ожидании без прерывания, ожидая завершения, которое уже произошло.

[1] https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c79041a4

Очевидно, что я не уверен, что это то, что вы видите, но я думаю, что есть хороший шанс. Если это правильно, вы можете применить изменение (вручную) к своему драйверу, и это должно устранить проблему.