lfs-ru/chapter09/udev.xml
2023-06-08 02:14:57 +05:00

324 lines
24 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sect1 PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % general-entities SYSTEM "../general.ent">
%general-entities;
]>
<sect1 id="ch-config-udev">
<?dbhtml filename="udev.html"?>
<title>Взаимодействие с устройствами и модулями</title>
<indexterm zone="ch-config-udev">
<primary sortas="a-Udev">Udev</primary>
<secondary>usage</secondary>
</indexterm>
<para>В <xref linkend="chapter-building-system"/>, мы установили пакет udev
во время сборки <phrase revision="sysv">eudev</phrase>
<phrase revision="systemd">systemd</phrase>. Прежде чем мы углубимся в детали того, как
это работает, необходимо кратко рассказать о предыдущих методах взаимодействия с устройствами.</para>
<para>Системы Linux традиционно использовали метод статического создания устройств, при котором
огромное количество узлов устройств(иногда буквально тысячи узлов) создавалось в
<filename class="directory">/dev</filename>, независимо от того, существовали ли соответствующие
аппаратные устройства на самом деле. Обычно это делалось с помощью скрипта <command>MAKEDEV</command>,
который содержал команды вызова программы <command>mknod</command> с нужным количеством устройств
для всех возможных вариантов, которые только могут существовать в мире.</para>
<para>Используя метод udev, только те устройства, которые были обнаружены ядром,
получают свой узел. Поскольку эти узлы будут создаваться каждый раз, при загрузке
системы, они будут располагаться в каталоге файловой
системы <systemitem class="filesystem">devtmpfs</systemitem> (виртуальная файловая
система, которая полностью находится в оперативной памяти). Узлы не занимают много
места в памяти и их общий размер незначителен.</para>
<sect2>
<title>История</title>
<para>В феврале 2000 года, новая файловая система <systemitem
class="filesystem">devfs</systemitem> была принята в ветку ядра 2.3.46 и была
доступна на протяжении выпуска стабильных релизов ветки 2.4. Хотя она и
присутствовала в ядре, такой способ динамического создания устройств никогда не
получал поддержки от разработчиков ядра.</para>
<para>Основная проблема с подходом, принятым <systemitem class="filesystem">devfs</systemitem>
была связана с обработкой обнаружения, создания и назначения имен устройствам. Проблема
связанная с именованием узлов была самой важной. Как правило, если имена
устройствам можно настраивать, то политика назначения имён должна быть установлена
системным администратором, а не навязываться каким-либо разработчиком. Файловая
система <systemitem class="filesystem">devfs</systemitem> также страдала от состояния гонки,
которое было присуще ее дизайну и не могло быть исправлено без существенной переработки
самого ядра. В конечном счёте, эта файловая система была помечена как устаревшая на протяжении
достаточно долгого периода времени, по причине отсутствия её ненадлежащей поддержки, и была
удалена из ветки ядра в июне 2006 года.</para>
<para>При разработке нестабильной ветки ядра 2.5, позднее, выпущенной как стабильный
релиз 2.6, появилась новая виртуальная файловая система
<systemitem class="filesystem">sysfs</systemitem>. Задача этой файловой системы
заключалась в экспорте представления об аппаратной конфигурации системы в процессы
пользовательского пространства. С помощью этого представления, видимого в пользовательском
пространстве, разработка замены для <systemitem class="filesystem">devfs</systemitem>
стала гораздо реалистичнее.</para>
</sect2>
<sect2>
<title>Реализация Udev</title>
<sect3>
<title>Sysfs</title>
<para>Краткое описание файловой системы <systemitem class="filesystem">sysfs</systemitem> было
представлено выше. Можно задаться вопросом, как <systemitem class="filesystem">sysfs</systemitem>
получает информацию об устройствах в системе, и о том, какие номера устройств должны использоваться
для них. Драйверы, скомпилированные в ядро, напрямую регистрируют объекты с помощью
<systemitem class="filesystem">sysfs</systemitem> (внутри <systemitem class="filesystem">devtmpfs</systemitem>),
по мере обнаружения ядром. Для драйверов, которые скомпилированы в виде модулей, регистрация будет
происходить при его загрузке. После того, как файловая система
<systemitem class="filesystem">sysfs</systemitem> будет примонтирована в каталог
<filename class="directory">/sys</filename>, данные, которые регистрируются драйверами, в
<systemitem class="filesystem">sysfs</systemitem>, станут доступны для пользовательского окружения
и udevd для обработки (включая изменения узлов устройств).</para>
</sect3>
<sect3>
<title>Создание узла устройства</title>
<para>Файлы устройств создаются ядром при помощи файловой
системы <systemitem class="filesystem">devtmpfs</systemitem>. Любой драйвер,
которому необходимо зарегистрировать узел устройства, будет проходить через
файловую систему <systemitem class="filesystem">devtmpfs</systemitem> (через
системный драйвер ядра). Когда экземпляр
<systemitem class="filesystem">devtmpfs</systemitem> монтируется в каталог
<filename class="directory">/dev</filename>, узел устройства будет создан с
фиксированным именем, соответствующими разрешениями и владельцем.</para>
<para>Через некоторое время, ядро отправит uevent в <command>udevd</command>.
На основе правил, которые указанны в файлах в каталогах
<filename class="directory">/etc/udev/rules.d</filename>, <filename
class="directory">/lib/udev/rules.d</filename>, и <filename
class="directory">/run/udev/rules.d</filename>, <command>
udevd</command> создаст дополнительные символические ссылки на узлы устройств,
или сменит разрешения, владельца или группу, или изменит запись (имя) во внутренней
базе данных <command>udevd</command> для этого объекта.</para>
<para>Правила в этих трёх каталогах пронумерованы и используются совместно. Если
<command>udevd</command> не может найти правило для устройства, он оставит права
доступа и владельца на <systemitem class="filesystem">devtmpfs</systemitem>, которые
были установлены изначально.</para> </sect3>
<sect3 id="module-loading">
<title>Загрузка модуля</title>
<para>Драйверы устройств, скомпилированные в виде модулей ядра могут содержать
встроенные псевдонимы. Псевдонимы можно увидеть просмотрев вывод программы
<command>modinfo</command>, обычно они связаны со специфичными для шины идентификаторами
устройств, которые поддерживается модулем. Например, драйвер <emphasis>snd-fm801</emphasis>
подерживает PCI устройства с идентификатором поставщика 0x1319 и идентификатором
устройства 0x0801, и имеет псевдоним <quote>pci:v00001319d00000801sv*sd*bc04sc01i*</quote>.
Для большинства устройств, драйвер шины экспортирует псевдонимы драйвера, которые
будет обрабатывать устройство через <systemitem class="filesystem">sysfs</systemitem>. Например,
файл <filename>/sys/bus/pci/devices/0000:00:0d.0/modalias</filename> может
содержать строку <quote>pci:v00001319d00000801sv00001319sd00001319bc04sc01i00</quote>.
Правила по умолчанию, которые предоставлены Udev, заставят <command>udevd</command>
вызвать <command>/sbin/modprobe</command> с содержимым, которое находится в значении
переменной окружения <envar>MODALIAS</envar> uevent (которое должно совпадать с
содержимым файла <filename>modalias</filename> в sysfs), тем самым загружая все
модули, чьи псевдонимы совпадают в строке после расширение подстановочных
знаков</para>
<para>В указанном примере, это означает, что в дополнение к <emphasis>snd-fm801</emphasis>
будет загружен устаревший (и нежелательный) драйвер <emphasis>forte</emphasis>, если он
будет доступен. Ниже приведены способы, как можно предотвратить загрузку нежелательных
драйверов.</para>
<para>Само ядро также способно загружать модули для сетевых протоколов, файловых систем
и поддержки NLS по запросу.</para>
</sect3>
<sect3>
<title>Работа с устройствами с горячей заменой или динамическими устройствами</title>
<para>При подключении устройства, например, MP3-плеер, к универсальной последовательной
шине (USB), ядро распознает, что устройство подключено, и генерирует событие
uevent. Затем это событие обрабатывается <command>udevd</command>, как было описано выше.</para>
</sect3>
</sect2>
<sect2>
<title>Проблемы с загрузкой модулей и созданием устройств</title>
<para>Существует несколько возможных проблем, связанных с автоматическим созданием узлов
устройств.</para>
<sect3>
<title>Модуль ядра не загружается автоматически</title>
<para>Udev загрузит модуль только в том случае, если у него есть псевдоним, специфичный
для шины, и драйвер шины правильно экспортирует необходимые псевдонимы в <systemitem
class="filesystem">sysfs</systemitem>. В других
случаях следует организовать загрузку модуля иными способами. Известно, что, начиная
с версии Linux-&linux-version;, udev, выполняет загрузку правильно написанных
драйверов для INPUT, IDE, PCI, USB, SCSI, SERIO, и FireWire устройств.</para>
<para>Чтобы определить, имеет ли требуемый драйвер устройства необходимую поддержку
Udev, запустите <command>modinfo</command> с именем модуля в качестве аргумента.
Далее, попробуйте найти каталог устройства в
<filename class="directory">/sys/bus</filename> и проверьте, есть ли там
файл <filename>modalias</filename>.</para>
<para>Если файл <filename>modalias</filename> существует в
<systemitem class="filesystem">sysfs</systemitem>, то драйвер, который поддерживает
устройство, может обращаться к нему напрямую, но не имеет псевдонима, это ошибка
в драйвере. Загрузите драйвер без помощи Udev и ожидайте, что проблема будет
исправлена позднее.</para>
<para>Если же в каталоге <filename class="directory">/sys/bus</filename> нет
файла <filename>modalias</filename>, это означает, что разработчики ядра еще не
добавили поддержку <filename>modalias</filename> к этому типу шины.
В Linux-&linux-version; это относится к шиной ISA. Ожидайте, что эта проблема
будет исправлена в более поздних версиях ядра.</para>
<para>Udev не предназначен для загрузки драйверов <quote>обёрток</quote>, таких как
<emphasis>snd-pcm-oss</emphasis>и неаппаратных драйверов, например,
<emphasis>loop</emphasis>.</para>
</sect3>
<sect3>
<title>Модуль ядра не загружается автоматически, и Udev не предназначен для его
загрузки</title>
<para>Если модуль <quote>обёртка</quote> только расширяет функциональность,
предоставляемую каким-либо другим модулем (например модуль
<emphasis>snd-pcm-oss</emphasis> расширяет функциональность модуля
<emphasis>snd-pcm</emphasis>, давая возможность звуковым картам быть доступными
для OSS приложений), настройте <command>modprobe</command> для загрузки оболочки
после того, как Udev загрузит обернутый модуль. Для этого добавьте строку
<quote>softdep</quote> в файл, который находится в каталоге
<filename>/etc/modprobe.d/<replaceable>&lt;filename&gt;</replaceable>.conf</filename>. Например:</para>
<screen role="nodump"><literal>softdep snd-pcm post: snd-pcm-oss</literal></screen>
<para>Обратите внимание, что команда <quote>softdep</quote> разрешает добавлять
<literal>pre:</literal> зависимости, или одновременно
<literal>pre:</literal> и <literal>post:</literal> зависимости. Обратитесь к документации
<filename>modprobe.d(5)</filename> для изучения синтаксиса и возможностей
<quote>softdep</quote>.</para>
<para revision="sysv">Если рассматриваемый модуль не является обёрткой, и полезен сам по
себе, настройте загрузочный скрипт <command>modules</command>, чтобы он инициализировался
при загрузке системы. Для этого добавьте имя модуля в файл <filename>/etc/sysconfig/modules</filename>
в отдельной строке. Этот способ сработает и для модулей-обёрток,но не является оптимальным.</para>
</sect3>
<sect3>
<title>Udev загружает какой-то нежелательный модуль</title>
<para>Либо не создавайте модуль, либо занесите его в черный список в файле
<filename>/etc/modprobe.d/blacklist.conf</filename>, как это сделано с
модулем <emphasis>forte</emphasis> в примере ниже:</para>
<screen role="nodump"><literal>blacklist forte</literal></screen>
<para>Модули, занесенные в черный список, можно загрузить вручную с помощью явной команды
<command>modprobe</command>.</para>
</sect3>
<sect3>
<title>Udev неправильно создает устройство или делает неправильную символическую ссылку</title>
<para>Это обычно происходит, если правило неожиданно совпадает с другим устройством.
Например, плохо написанное правило может соответствовать как диску SCSI
(искомое устройство), так и универсальному устройству SCSI (неправильно)
указанному поставщиком. Найдите ошибочное правило и исправьте его с помощью
команды <command>udevadm info</command>.</para>
</sect3>
<sect3>
<title>Правило Udev работает ненадежно</title>
<para>Это может быть проявлением предыдущей проблемы. В ином случае, если
правило использует атрибуты файловой системы
<systemitem class="filesystem">sysfs</systemitem>, то это может быть
проблемой синхронизации ядра, которая будет исправлена в более поздних
версиях ядра. Но вы можете обойти проблему, создав правило, которое
ожидает используемый атрибут <systemitem class="filesystem">sysfs</systemitem>
и добавляет его к файлу правил <filename>/etc/udev/rules.d/10-wait_for_sysfs.rules</filename>
(создайте его, если файл не существует). Пожалуйста, сообщите в списке
рассылки разработчиков LFS, если это решение вам поможет.</para>
</sect3>
<sect3>
<title>Udev не создаёт устройство</title>
<para>Дальнейший текст предполагает, что драйвер статически встроен в ядро или уже загружен
как модуль, и что вы уже проверили, что Udev не создает устройство с неправильным именем.</para>
<para>Udev не обладает информацией, необходимой для создания узла устройства,
если драйвер ядра не экспортирует свои данные в
<systemitem class="filesystem">sysfs</systemitem>. Как правило, такое происходит
с внешними драйверами, которых нет в дереве исходного кода ядра. Создайте
статический узел в каталоге <filename>/usr/lib/udev/devices</filename> с
соответствующими первичными и второстепенными номерами (смотрите файл devices.txt
в документации по ядру или документации, предоставленной сторонним поставщиком
драйвера). Статический узел будет скопирован в
<filename class="directory">/dev</filename> с помощью <command>udev</command>.</para>
</sect3>
<sect3>
<title>Порядок присвоения имен устройствам меняется случайным образом после перезагрузки</title>
<para>Это связано с тем, что udev обрабатывает события uevents и загружает модули
параллельно, а значит в непредсказуемом порядке. Это никогда не будет <quote>исправлено</quote>.
Вы не должны полагаться на то что имена устройств ядра стабильны. Вместо этого создайте
свои собственные правила, которые делают символические ссылки со стабильными именами на
основе некоторых неизменяемых атрибутов устройства, таких как серийный номер или вывод
различных утилит *_id, установленных Udev. Смотрите <xref linkend="ch-config-symlinks"/> и
<xref linkend="ch-config-network"/> для примера.</para>
</sect3>
</sect2>
<sect2>
<title>Полезная информация</title>
<para>Дополнительную документацию можно получить на следующих сайтах:</para>
<itemizedlist>
<listitem>
<para>Реализация пользовательского пространства в <systemitem class="filesystem">devfs</systemitem>
<ulink url="http://www.kroah.com/linux/talks/ols_2003_udev_paper/Reprint-Kroah-Hartman-OLS2003.pdf"/></para>
</listitem>
<listitem>
<para>Файловая система <systemitem class="filesystem">sysfs</systemitem>
<ulink url="https://www.kernel.org/pub/linux/kernel/people/mochel/doc/papers/ols-2005/mochel.pdf"/></para>
</listitem>
<!-- No longer available
<listitem>
<para>Pointers to further reading
<ulink url="http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html"/>
</para>
</listitem>
-->
</itemizedlist>
</sect2>
</sect1>