Руководство по файловой системе для устройств

Sven Vermeulen  Author
Seemant Kulleen  Reviewer
Mikhail Filatov  Translator
Sergey Kuleshov  Editor

Updated 9 Сентября 2004г.

1. Что такое devfs?

Старые (добрые?) времена

Традиционная реализация Linux предоставляет пользователю абстрактный каталог устройств называемый /dev. Внутри этого каталога находятся device nodes, специальные файлы символизирующие устройства внутри системы. Например, /dev/hda символизирует первое IDE устройство в вашей системе. Файлы устройств позволяют создавать программы которые взаимодействуют с устройствами так как если бы устройства были обычными файлами, вместо использования специальных API.

Файлы устройств подразделяются на две группы называемые character devices (символьные устройства)и block devices (блочные устройства). Первая группа содержит устройства для котрых отсутствует буферизация чтения/записи. Вторая группа естественно содержит устройства для которых чтение/запись буферизируется. Из обоих типов устройств может быть прочитан за раз один символ или блок. Поэтому такой способ присваивания имён может сбивать с толку и на самом деле неправилен.

Если посмотреть на конкретное устройство вы можете обнаружить что то похожее на это:

Code Listing 1.1: Исследование информации о файле устройства

# ls -l /dev/hda
brw-rw----    1 root     disk       3,   0 Jul  5  2000 /dev/hda

В предыдущем примере мы увидели что /dev/hda это блочное устройство. Однако важнее то что ему присвоено два специальных номера 3, 0. Эта пара называется major-minor. Она используется ядром чтобы соотнести файл устройства и реальное устройство. major (старший) относится к типу устройства, minor (младший) к конкретному устройству. Выглядит запутано? Неправда ли.

Ещё два примера /dev/hda4 и /dev/tty5. Первое устройство соответствует четвёртой партиции на первом IDE устройстве. Его пара major-minor 3, 4. Другими словами minor соответствует партиции тогда как major соответствует устройству. Второй пример имеет пару major-minor 4, 5. В этом случае первое число соответствует драйверу терминала тогда как второе соответствует номеру терминала (в данном случае пятый терминал).

Проблемы

Если вы заглядывали в папку /dev, вы обнаружили что там перечислены не только все ваши устройства но и все возможные устройства которые только могут быть. Другими словами, у вас есть файлы устройств для устройств которых у вас нет. Управление такой кучей устройств по крайней мере можно назвать громоздким. Представьте, что надо поменять права на все устройства релаьно существующие в вашей системе, оствив остальные без изменений.

Затем вы добавили новое оборудование в вашу систему, для него может не оказаться уже существующего файла. Продвинутые пользователи знают что эта задача может быть выполнена с помощью команды ./MAKEDEV внутри директории /dev, но разве вы сразу знаете что за устройство вам придётся создать?

Когда у вас есть программы взаимодействующие с оборудованием при помощи файлов устройств вы не можете смонтировать корневую партицию только для чтения, в то время как в дальнейшем нет необходимости в том чтобы она была смонтирована на чтение и запись. И вы не можете иметь /dev на отдельной партиции, так как mount необходим /dev чтобы монтировать партиции.

Решения

Как вы могли себе предствить, kernel hackers нашли достаточно решений для вышеперечисленных проблем. Однако многие из этих решений имеют собственные проблемы описанные в http://www.atnf.csiro.au/people/rgooch/linux/docs/devfs.html#faq-why. Мы не будем обсуждать эти варианты а сконцентрируемся на одном способе который был реализован в официальной версии исходников ядра:

devfs как абсолютный победитель?

devfs решает все перечисленные проблемы. Она просто предоставляет пользователю доступ к существующим устройствам, добавляет новые device nodes (файлы устройств) когда найдены новые устройства, и делает возможным монтировать корневую файловую систему в режиме read only (только чтение). А также решает многие проблемы которые мы раньше не обсуждали потому что они не так интересны для пользователей...

Как пример, с devfs вам не надо беспокоится о паре major/minor. Она продолжат поддерживаться (для обратной совместимости), но в ней нет необходимости. Это позволяет Linux поддерживать ещё больше устройств, так как больше нет ограничений (числа всегда имеют границы :)

Однако у devfs есть свои проблемы, не столь очевидные для пользователей, но достаточно серьезные, чтобы разработчики ядра пометили ее как obsolete (устаревшее), порекомендовав использовать udev, которая также поддерживается Gentoo.

Чтобы узнать, почему devfs считается устаревшей, читайте udev FAQ и udev versus devfs document.

2. Навигация через дерево устройств

Директории

Одна из первых особенностей которые вы можете заметить это то что devfs использует директории для объединения устройств вместе. Это повышает читабельность так как теперь все связанные между собой устройства находятся внутри одной общей директории.

Например все устройства относящиеся к IDE находятся в директории /dev/ide/, а все относящиеся к SCSI в директории /dev/scsi/. SCSI и IDE диски во многом похожи, у них одинаковая структура поддиректорий.

IDE и SCSI диски управляются при помощи адаптера (встроенным или отдельной платой), называемым host. Каждый адаптер может иметь несколько каналов. Канал называется bus. На каждом канале может быть несколько IDs (индентификаторов). ID служит для индентификации диска. Этот ID называется target. Многие SCSI устройства могут иметь множество LUN (Logical Unit Numbers (Номер Логического Устройства)), Например устройства которые управляют несколькими носителями одновременно (hi-end tapedrives). У вас скорее всего будет только один lun, lun0/.

Итак несмотря на то что раньше использовался /dev/hda4, теперь появился /dev/ide/host0/bus0/target0/lun0/part4. Это намного проще... нет, не спорьте со мной... это проще... как бы то ни было! :)

Note: Вы также можете использовать более похожие на Unix названия для жёстких дисков, такие как c0b0t0u0p2. Они могут быть найдены в /dev/ide/hd, /dev/scsi/hd и.т.д.

Чтобы дать вам лучше понять идею с директориями, вот листинг директорий которые есть у меня:

Code Listing 2.1: Дирректории в /dev

cdroms/     cpu/        discs/          floppy/
ide/        input/      loop/           misc/
netlink/    printers/   pts/            pty/
scsi/       sg/         shm/            sound/
sr/         usb/        vc/             vcc/

Обратная совместимость при помoщи devfsd

Использование этой новой структуры выглядит здорово но многие утилиты и программы используют предыдущую, старую структуру. Для уверенности что система не будет нарушена был создан devfsd. Этот демон создаёт символьные ссылки на новые файлы устройств но со старыми именами (compatibility symlinks).

Code Listing 2.2: Созданные символьные ссылки

$ ls -l /dev/hda4
lr-xr-xr-x    1 root     root           33 Aug 25 12:08 /dev/hda4 -> ide/host0/bus0/target0/lun0/part4

При помощи devfsd, вы можете устанавливать права доступа, создавать новые файлы устройств и т.д. Всё это описывается в следующей главе.

3. Администрирование дерева устройств

Перезагрузка devfsd

Если вы изменили файл /etc/devfsd.conf, и хотите чтобы изменения вступили в силу, вым не обязательно перезагружаться. В зависимости от того что вы хотите, вы можете использовать любой из следующих сигналов:

SIGHUP заставит devfsd перечитать конфигурационный файл, перегрузить разделяемые объекты (shared objects) и сгенерировать событие REGISTER для каждого листа в дереве устройств.

SIGUSR1 сделает то же самое, но не будет событий REGISTER.

Чтобы послать сигнал, просто используйте kill или killall:

Code Listing 3.1: Посылка сигнала SIGHUP демону devfsd

# kill -s SIGHUP `pidof devfsd`
или
# killall -s SIGHUP devfsd

Удаление compatibility symlinks

Warning: В настоящее время Gentoo не может существовать без этих ссылок.

Если вы хотите удалить из вашей системы ссылки которые засоряют /dev (в Gentoo они используются по умолчанию), отредактируйте /etc/devfsd.conf и удалите следующие две строчки:

Code Listing 3.2: /etc/devfsd.conf для обратной совместимости

# Закоментируйте эти две строчки для удаления симлинков
REGISTER        .*  MKOLDCOMPAT
UNREGISTER      .*  RMOLDCOMPAT

Вам придётся перезагрузится чтобы изменения пришли в силу.

Удаление возможности автосоздания файлов устройств

Когда вы загружаете модуль, devfs автоматически создаёт файлы устройств. Если вы не хотите чтоб он так делал, удалите эту строчку из /etc/devfsd.conf:

Code Listing 3.3: /etc/devfsd.conf, autoload functionality

LOOKUP      .*  MODLOAD

4. Вопросы относящиеся к правам доступа

Установка/изменение прав доступа при помощи PAM

Хотя вы можите установит права доступа в /etc/devfsd.conf, мы советуем использовать PAM (Pluggable Authentification Modules (). Так как PAM имеет решающий голос при установке прав доступа и может проигнорировать изменения которые вы сделали в /etc/devfsd.conf.

PAM использует /etc/security/console.perms для установки прав доступа. Файл состоит из двух частей: в первой описываются группы, а во второй права.

Давайте сначала взглянем на часть с группами. Как пример мы рассмотрим sound-group:

Code Listing 4.1: Sound group в /etc/security/console.perms

<sound>=/dev/dsp* /dev/audio* /dev/midi* \
    /dev/mixer* /dev/sequencer* \
    /dev/sound/* /dev/snd/* /dev/beep \
    /dev/admm* \
    /dev/adsp* /dev/aload* /dev/amidi* /dev/dmfm* \
    /dev/dmmidi* /dev/sndstat

Синтакс достаточно прост: вы начинаете с имени группы, и заканчиваете списком устройств принадлежащих этой группе.

Теперь для того чтобы с группами можно было что нибудь сделать рассмотрим следующую часть описывающую как управлять правами.

Code Listing 4.2: Права доступа для sound group в /etc/security/console.perms

<console>  0600 <sound>      0600 root.audio

Первое поле это проверка терминала. На большинстве систем, это console-group. PAM будет проверять это поле при каждом логине. Если логин произошёл на устройстве содержащемся в console-group, PAM проверит и возможно сменит права на некоторые файлы устройств.

Второе поле содержит права которые установятся на файл устройства после удачного логина. Когда человек залогинится в систему а файлы устройств принадлежат пользователю и группе по умолчанию, PAM сменит владельца на залогиневшегося пользователя и установит на них права из второго поля. В данном случае используется 0600 (пользователь имеет право на чтение/запись, все остальные нет).

В третьем поле содержатся группы устройств чьи права будут изменены. В данном случае, вторая группа (все устройства относящиеся к звуку) будут изменены.

Четвёртое поле определяет права которые будут установлены на файлы устройств после возврата в состояние по умолчанию. Другими словами, если человек который владеет правами на все файлы устройств разлогинится, PAM установит права обратно в состояние по умолчанию, описанному в этом четвёртом поле.

Пятое поле определяет собственника (с группой если вам надо) к котрому будут установлены атрибуты устройства после возврата в состояние по умолчанию Другими словами, если человек владеет правами на все файлы устройств разлогинится, PAM установит собственника обратно в состояние по умолчанию, описанному в пятом поле.

Установка/изменение прав доступа при помощи devfsd

Если вы действительно хотите установить права используя /etc/devfsd.conf, тогда используйте синтекс приведённый в этом примере:

Code Listing 4.3: Права в /etc/devfsd.conf

REGISTER    ^cdroms/.*  PERMISSIONS root.cdrom 0660

Второе поле это группа устройств, начиная с /dev. Это регулярное выражение, означающее что вы можете выбрать несколько файлов устройств с одним правилом.

Четвёртое поле - это владелец файла устройства. В отличие от PAM он не изменяется (если он не упоминается в console.perms, так как PAM главнее).

Пятое поле содержит права на файлы устройств.

Ручная установка прав и их сохранение devfsd

Это обычная ситуация для Gentoo: если вы делаете chown (CHange OWNer (Смена владельца)) и chmod (CHange MODe (Смена вида)) некоторым файлам устройств, то devfsd сохраняют информацию когда вы вы выключаете систему. Это происходит из-за того что файл /etc/devfsd.conf содержит следующие строчки:

Code Listing 4.4: /etc/devfsd.conf для сохранения прав доступа

REGISTER        ^pt[sy]/.*   IGNORE
CHANGE          ^pt[sy]/.*   IGNORE
CREATE          ^pt[sy]/.*   IGNORE
DELETE          ^pt[sy]      IGNORE
REGISTER        ^log         IGNORE
CHANGE          ^log         IGNORE
CREATE          ^log         IGNORE
DELETE          ^log         IGNORE
REGISTER        .*           COPY    /lib/dev-state/$devname $devpath
CHANGE          .*           COPY    $devpath /lib/dev-state/$devname
CREATE          .*           COPY    $devpath /lib/dev-state/$devname
DELETE          .*           CFUNCTION GLOBAL unlink
/lib/dev-state/$devname
RESTORE         /lib/dev-state

Другими словами, изменённые файлы усройств копируются в /lib/dev-state когда выключается система, и копируются в /dev когда система грузится.

Другая возможность - монтировать /lib/dev-state в /dev во время загрузки. Чтобы это зделать,вы должны быть уверены что devfs не монтируется автоматически (это значит, что вы должны перекомпилировать ядро) и что /dev/console существует. Затем, где-то в начале bootscripts (загрузочных скриптов) вашей системы, вы должны разместить:

Code Listing 4.5: Монтирование /lib/dev-state в /dev

mount --bind /dev /lib/dev-state
mount -t devfs none /dev
devfsd /dev

5. Ссылки

По этим ссылкам вы можете найти дополнительную документацию:

devfsd.conf manpage описывает синтаксис файла /etc/devfsd.conf. Чтобы просмотреть его напишите man devfsd.conf.

devfs FAQ описывает всё что касается devfs. Также содержит информацию о внутренней структуре devfs и о том как устройства могут подерживать devfs.

На LinuxJournal интересная статья devfs for Management and Administration.

Daniel Robbins написал серию статей для IBM's DeveloperWorks о Advanced filesystems. Три из них о devfs: