Daniel Robbins (drobbins@gentoo.org)
President/CEO,
Gentoo Technologies, Inc.
September 2001
С выходом релиза 2.4 Linux появилась возможность использования filesystem с новыми свойствами, таких как Reiserfs, XFS, GFS и других. Эти filesystems еще не достаточно опробованы и имеются вопросы, что именно они могут делать, насколько они хороши и насколько оправдано их использование в промышленной Linux среде. В этой статье Daniel объясняет назначение и преимущества использования devfs, файловой системы управления устройствами и подготавливает к пониманию своей следующей статьи, где будет рассказано об оптимальной установке devfs на вашей системе.
Устройства, устройства повсюду.
Devfs, или Device Filesystem, разработана с единственной целью предоставления нового (более "нормального") способа управления всеми блочными и символьными устройствами, заполнившими каталог /dev. Вероятно, вам известно, что обычное /dev дерево содержит сотни блочных и символьных специальных файлов-устройств, которые располагаются на корневой файловой системе. Каждый такой специальный файл доступен для user-space процессов и обеспечивает легкость взаимодействия с kernel devices. Выполняя операции с такими специальными файлами, X server способен обращаться к video hardware, fsck способен выполнять filesystem checks, а lpd передает данные через параллельный порт на принтер и т.д.
Фактически, одна из "приятных" черт Linux и Unix заключается в том, что devices
не скрыты за некоторым непонятным и специфическим API, а сосуществуют на
файловой системе рядом с "нормальными" файлами, каталогами и символическими
ссылками. Поскольку символьные и блочные devices отображаются в привычное
filesystem namespace, имеется дополнительная возможность более простого
взаимодействия с hardware через стандартные Unix команды, например
cat
или dd
. И это не просто фокус. "Стандартное"
взаимодействие более выразительно и способствует быстрому освоению нового
оборудования.
В то время как сама идея отображения устройств как специальных файлов хороша, следует заметить, что обычные Linux системы управляют ими далеко не оптимальным и громоздким способом. В наши дни в Linux поддерживается много самого разного hardware. При "классическом" подходе это означает, что в каталоге /dev "обитают" сотни специальных файлов для "презентации" соответствующих hardware. Большинство таких специальных файлов "don't even map" на реально существующее на вашей машине устройство (но в каталоге /dev такой специальный файл все равно должен присутствовать на случай добавления нового hardware/drivers). Такой подход вносит много путаницы.
Только одного такого аргумента достаточно, чтобы осознать необходимость "перестройки" каталога /dev, конечно, при соблюдении принципа "обратной совместимости". Чтобы хорошо понять, как именно devfs решает большинство проблем связанных с "классическим" каталогом /dev, посмотрим на devfs с позиции разработки нового драйвера для устройства.
Внутренняя организация device management
Чтобы получить ясное представление о devfs, давайте разберемся, как devfs
меняет традиционный подход для случая добавления нового драйвера. Традиционный
(без devfs) kernel-based device driver "прописывает" устройство в остальной
части системы через системные вызовы register_blkdev()
или
register_chrdev()
(зависит от того, регистрируется блочное или
символьное устройство).
Major номер (unsigned 8-bit integer) передается как параметр либо
register_blkdev()
, либо register_chrdev()
. После
регистрации устройства ядро знает, что этот конкретный major номер соответствует
конкретному драйверу для устройства, которое выполнило вызов
register_???dev()
.
Вопрос, а какой major номер разработчик драйвера должен использовать для
передачи с запросом register_???dev()
? Проблемы нет, если developer
драйвера не планирует его использования "внешним миром". В этом случае сгодится
любой major номер, лишь бы он не конфликтовал с другими major номерами,
используемыми в конкретном частном случае. Как альтернатива, разработчик может
"динамически" ассигновать major номер перед register_???dev()
.
Однако, "по большому счету", такое решение приемлемо только в случае, если
драйвер не предназначен для широкого использования.
Если developer хочет предложить свой драйвер для широкого использования (а большинство Linux developers имеет тенденцию делать именно так), то использование major номера "от балды" или даже вариант с его динамическим ассигнованием "не пройдет". В таких случаях разработчик драйвера должен войти в контакт с Linux kernel developers и получить для своего специфического устройства "официальный" major номер. После этого, для всех Linux пользователей это устройство (и только оно) будет связано с таким major номером.
Важно иметь "официальный" major номер, так как для взаимодействия с этим специфическим устройством, администратор должен в каталоге /dev создать специальный файл. Когда device node (специальный файл) создается, он должен получить тот же major, как зарегистрирован во внутренних структурах ядра. После этого, когда пользовательский процесс выполняет операцию над файлом-устройством, ядро знает, с каким драйвером нужно связаться. Иначе, mapping от специального файла на kernel driver сделано по major номером, а не по именам устройств. Такое "непонимание" device name - особенность non-devfs систем.
Как только device driver получает официальный major, он может использоваться
публично, а device node можно включать в дерево /dev разных дистрибутивов
через официальный сценарий /dev/MAKEDEV
. Такой сценарий помогает
суперпользователю автоматизировать процесс создания device nodes с правильными
major и minor номерами, правами и владельцами.
К сожалению, при таком подходе имеется много проблем. У разработчика драйвера появляется "головная боль" от необходимости согласования действий с kernel developers для получения "официального" major. То же относится к самим kernel developers. Возникает потребность отслеживания процедуры ассигнования всех major номеров. Во многом это похоже на проблемы системного администратора при использовании статического ассигнования IP адресов в локальной сети, когда сеть начинает "разрастаться". Точно так же, как системный администратор может "разрубить узел", воспользовавшись DHCP, можно было бы использовать подобный подход для регистрации devices.
Проблема не только в этом. Linux подошел к границе, когда все "официальные" major и minor номера будут исчерпаны. Конечно, можно просто увеличить разрядность номеров, но при этом станет еще сложнее отслеживать уникальность major для драйверов. Имеется и более радикальный способ решения проблемы. Это переход на devfs.
Подход devfs.
devfs_register()
Имеется быстрое описание того, как devfs функционирует и снимает многие
проблемы. После правильного конфигурирования devfs, что подразумевает
добавление поддержки devfs в ядро и выполнение множества достаточно хитрых
изменений в сценариях запуска, суперпользователь перезагружает систему.
Стартует ядро и device drivers начинают регистрировать свои устройства для
остальной части системы. Если это non-devfs система, как и ранее, выполняются
системные вызовы register_blkdev()
и register_chrdev()
(вместе с сопровождающими вызовы major номерами). Однако, если enabled devfs,
то device drivers для регистрации своих устройств используют новый, улучшенный
kernel call, называемый devfs_register()
.
Об этом devfs_register()
вызове можно много рассказать. Хотя можно
указать major и minor номера для обратной совместимости, жесткого требования,
делать именно так, не существует. Вместо этого вызов devfs_register()
передает path на устройство как параметр, и именно так оно впоследствии
появиться под /dev. Например, драйвер устройства foo регистрирует свое
устройство в devfs. При этом драйвер передает параметр foo0 с вызовом
devfs_register()
, сообщая ядру, что в корне devfs namespace
должен быть создан новый файл-устройство foo0. В ответ на вызов
devfs_register()
добавляется foo0 device node к корню devfs
namespace и запись о том, что этот новый foo0 node должен отобразится на
foo device driver в ядре.
После того, как все device drivers стартовали и зарегистрировали соответствующие
им устройства в ядре, ядро запускает /sbin/init
и начинается
отработка сценариев системной инициализации. На ранней фазе процесса начальной
загрузки (еще до filesystem checks), из rc scripts монтируется devfs filesystem
к точке /dev, которая содержит representation для devfs namespace. После такого
монтирования ко всем зарегистрированным устройствам (например, /dev/foo0)
можно обращаться как на обычной non-devfs системе. Отличие в том, что при
обращении к устройствам, kernel maps на соответствующий device driver
devfs отрабатываются по именам устройств, а не по major номерам.
Красота такого подхода в том, что все требующиеся device nodes (и ничего
лишнего) создаются автоматически ядром. Соответственно, отпадает необходимость
в погоне за последним сценарием MAKEDEV
(так как все
зарегистрированные устройства сами "по волшебству" появляются в /dev). Еще сие
означает, что каталог /dev не загроможден сотнями "фиктивных" device nodes.
Фактически, используя devfs, можно зайти в /dev и узнать, какие устройства у
вас "реально" присутствуют. Например, если у вас laptop с поддержкой "горячей"
замены hardware, то устройства будут появляться и исчезать в /dev по мере того,
как вы вставляете или удаляете PC Cards. Это делает devfs очень "чистым" и
"функциональным" после всего того, что когда-то было.
Devfs делает многие вещи проще. Рассмотрим старт Linux bootable CD-ROM,
который состоит из boot loader, initrd, ядра и loopback filesystem на CD.
Когда BIOS передает управление CD, boot loader грузит ядро и initrd, а затем
стартует /linuxrc
script из "развернувшегося" initrd.
Первоочередная задача /linuxrc
заключается в том, чтобы
смонтировать CD таким образом, чтобы loopback filesystem могла самостоятельно
mounted и accessed.
Без devfs сценарий /linuxrc
должен опробовать множество специальных
файлов в /dev, которые либо "представляют", либо "не представляют" реальное
hardware в системе. Например, /linuxrc
должен просканировать
/dev/hdc, /dev/scd0, /dev/hdb и прочие для обнаружения "живого"
устройства CD-ROM. По мере сканирования будут впустую опробованы несколько
"фиктивных" device nodes.
В том случае, если используется devfs, сценарий /linuxrc
просто
заходит в /dev/cdroms, в котором находятся все специальные файлы,
ассоциированные с "реальными" для данной машины CD-ROM, причем независимо,
IDE или SCSI. Благодаря такому devfs соглашению, выбор очень
конкретный; в подкаталоге перечислены только активные устройства, а
"исследующему коду" даже не требуется знать о подробностях основного CDROM,
например, сидит он на IDE channel или использует SCSI ID. Фактически, это уже
другое достоинство devfs. Как будет видно из следующей статьи этого цикла,
devfs имеет совершенно иные, заданные по умолчанию местоположения для устройств
в /dev.
Если необходимо обратится к конкретному блочному устройству (диск, partition,
CD-ROM и т.д), доступ можно сделать через несколько специальных файлов.
Например, на моем сервере имеется единственный SCSI CD-ROM. При devfs enabled,
я могу работать с ним переместившись либо в /dev/cdroms/cdrom0, либо
в /dev/scsi/host0/bus0/target4/lun0/cd. При этом доступ произойдет к
одному и тому же устройству. Просто у меня есть выбор, через какой именно файл
я это сделаю. Кроме этого, как альтернатива, к своему CD-ROM я могу получить
доступ "в старом стиле" как /dev/sr0, если мне так хочется и
инсталлирована удобная и небольшая программка devfsd
. Версии
devfsd
меняются очень быстро, но, в общем, это программа, которая
заботится об "обратной совместимости" специальных файлов и позволяет
настраивать /dev разными способами. Программа devfsd
будет
рассмотрена в следующей статье при описании процесса перехода на devfs в вашей
системе. А теперь некоторые ресурсы по devfs:
Residing in Albuquerque, New Mexico,
Daniel Robbins is the President/CEO of Gentoo Technologies,
Inc., the creator of Gentoo Linux, an advanced Linux for the
PC, and the Portage system, a next-generation ports system for Linux.
He has also served as a contributing author for the Macmillan books
Caldera OpenLinux Unleashed, SuSE Linux Unleashed, and Samba Unleashed.
Daniel has been involved with computers in some fashion since the
second grade, when he was first exposed to the Logo programming
language as well as a potentially dangerous dose of Pac Man. This
probably explains why he has since served as a Lead Graphic Artist at
SONY Electronic Publishing/Psygnosis. Daniel enjoys spending
time with his wife, Mary, and his daughter, Hadassah. You can contact Daniel at drobbins@gentoo.org.
Перевод: Владимир Холманов