udev - реализация devfs в пользовательском пространстве
Игорь Стародумов - Epam Systems - Минск, Беларусь
LVEE 2008
введение
ОС Linux используется на множестве различных платформ начиная от мобильных устройств и заканчивая суперкомпьютерами. Количество различного оборудования постоянно растет. Каждое устройство использует определённые ресурсы машины. Linux нужен был механизм, который бы эти ресурсы распределял.
Существует технология Plug-and-Play для распределения ресурсов устройствам. Для “горячего” подключения (без перезагрузки) используется термин «hotplug». Первоначально о hotplug можно было говорить только в применении к USB и PCMCIA/Cardbus. Потом этот список был дополнен устройствами Firewire и CompactPCI, а в настоящее время hotplug возможен для “нормальных” PCI-устройств (посредством специальных hotplug-контроллеров), IDE (некоторые контроллеры RAID), SCSI, модулей памяти и, наконец, CPU!!!
драйвера устройств
Основное условие использования устройства - это существование и загрузка соответствующего модуля ядра - драйвера. Нет модуля - нет работоспособного устройства.
/dev
Linux унаследовал от UNIX представление устройств в виде файлов, находящихся в каталоге /dev и характеризующихся уникальным идентификаторами - числами minor и major. Существование таких файлов - абсолютно необходимое условие доступности устройств. Если программист хочет предложить свой драйвер для широкого использования, то использование случайно выбранного major-номера или даже вариант с его динамическим присваиванием “не пройдет”. В таких случаях разработчик драйвера должен войти в контакт с разработчиками ядра Linux и получить для своего специфического устройства “официальный” major-номер. После этого для всех Linux пользователей устройство (и только оно) будет связано с таким major-номером.
Не так давно общепринятой практикой было “заблаговременное” создание таких файлов, зачастую без учета реального присутствия или отсутствия устройств, что делало каталог /dev необъятным. Кроме того, поскольку под номера minor/major изначально было выделено всего по байту, в скором времени резерв номеров должен был исчерпаться. Отсутствовал единый метод представления связей между драйверами (модулями ядра) и устройствами. Отсутствовал общий hotplug-механизм, единый для PnP-конфигурируемых устройств и устройств, подключаемых к независимым шинам, таким как USB или PCMCIA. Происходило загромождение виртуальной файловой системы procfs информацией, не имеющей отношения к процессам, фактически - такой, для хранения которой она изначально не предназначалась.
При загрузке ядра минорные значения для найденных устройств выдавались ядром в порядке возрастания. Возникали проблемы с устройствами одного класса когда при перезагрузках одни и те же устройства имели разные minor-значения и, соответственно, имена. Аналогичные проблемы возникали также и для устройств, которые подключались и отключались динамически. При каждом новом добавлении могло поменяться имя устройства - что осложняло работу с системой.
hotplug
При добавлении/удалении и других событиях, связанных с устройствами, ядро генерирует уведомления, которые можно перехватывать. Hotplug – это пакет, написанный на shell. При получении сообщения от ядра запускается отдельный процесс hotplug, который способен решать следующие задачи:
- связывание драйверов с новыми устройствами. (для еще не загруженных драйверов);
- специфическая конфигурация драйвера (например подкачка firmware);
- специфическая конфигурация устройства;
- специфическая конфигурация подсистем (например ifconfig);
- возможный запуск какого-либо приложения.
devfs
Devfs, или Device Filesystem, разработана с единственной целью предоставления нового (более адекватного) способа управления всеми блочными и символьными устройствами, заполнившими каталог /dev. Правильное конфигурирование подразумевает добавление поддержки devfs в ядро. Запускается ядро, и драйвера начинают регистрировать свои устройства для остальной части системы. Если это система, не использующая devfs, как и ранее, выполняются системные вызовы register_blkdev() и register_chrdev() (вместе с сопровождающими вызовы major-номерами). Однако, если devfs поддерживается, то драйвера для регистрации своих устройств используют новый, улучшенный вызов ядра, называемый devfs_register().
Devfs решает некоторые проблемы и безусловно представляет собой более продвинутое решение, однако на данный момент объявлена устаревшей. Devfs имеет следующие проблемы:
- devfs имеет жесткую политику именования устройств, которая сильно отличается от классической;
- devfs создает inod’ы в режиме ядра, что накладывает определенные ограничения на настройки из пользовательского режима (права доступа, динамическое конфигурирование, именование и др). Частично проблемы именования решаются с помощью линков; однако, по хорошему, такие вещи как политика именования устройств должны выносится из ядра;
- devfs хранит базу данных имен устройств в памяти ядра, которая не может быть перемещена - она всегда постоянна. При большом количестве устройств в системе - это может стать потенциальной проблемой;
- devfs - практически не поддерживается. Основной маинтейнер пакета похоже не проявляет серьезной активности для развития devfs. В ядрах начиная с 2.6.13 devfs по умолчанию отключена.
sysfs
sysfs – виртуальная файловая система, экспортирующая в пространство пользователя информацию ядра о присутствующих в системе устройствах и драйверах. sysfs не может быть модулем, она всегда - часть ядра.
Существует непосредственная связь между sysfs и объектами инфраструктуры ядра. Всем зарегистрированным системой объектам инфраструктуры в /sys соответствуют свои каталоги. Форма дерева каталогов, берущего своё начало в /sys, максимально точно соответствует соотношению между объектами. Если каждое устройство или драйвер - каталог, то файлы этих каталогов - атрибуты этих объектов. Операции записи/чтения атрибутов объектов ядра становятся такими же доступными, как операции записи и чтения файлов.
sysfs родилась не на пустом месте, и если информация о связях объектов ядра - это, действительно, новость, то большую часть атрибутов устройств можно было получить и в “старой” /proc/sys. Файлы атрибутов в /sys, однако, существенно отличаются от файлов procfs, парсинг содержимого которых мог быть довольно сложным.
udev
Основные задачи udev:
- работать в режиме пользователя (userspace);
- динамически обновлять каталог /dev;
- поддерживать постоянные имена для устройств (например для динамически подключаемых и отключаемых);
- предоставить удобный интерфейс для получения информации (метаинформации) об устройстве.
udev разделен на подсистемы:
- namedev - отвечает за именование устройств. Позволяет гибко формировать правила именования устройств руководствуясь серийным номером устройства, номером шины устройства, топологией на шине и др. что позволяет четко привязывать конкретное устройство к конкретному имени вне зависимости от того когда оно было обнаружено.
- libsysfs - библиотека для доступа к информации об устройстве. Эта информация полезна для прикладных программ.
- udev - динамическое формирование /dev. Используется hotplug.
Udev работает без использования значений major/minor, имея собственную систему связи и поиска устройств и драйверов.
D-bus
Проект D-bus - унифицированная технология межпроцессного взаимодействия (IPC) для прикладных программ, которые хотят в том числе и отслеживать добавление/удаление устройств.