Работа с внешними устройствами
Файловая система
Из лекции 3 Мефодий узнал, как пользоваться файловой системой и какую структуру она имеет с точки зрения программы, работающей с файлами в ней. О том, как огранизована файловая система изнутри, написан ряд больших статей, защищено немало кандидатских (и несколько докторских) диссертаций. Разработка файловой системы - сложный и интересный процесс, требующий одновременно владения высшей математикой, статистикой, умения безошибочно программировать и досконального знания того, как работает то или иное дисковое устройство. Поэтому файловых систем не так много, и каждая из них устроена по-своему, в соответствии с тем, как решал тот или иной коллектив разработчиков задачу быстрого и надежного доступа к файлам.
Принципы организации данных на диске
Во всех файловых системах есть немало общего. Например, в каждой из них решается вопрос метаданных, то есть информации, не имеющей прямого отношения к содержимому, допустим, файла, но описывающей, как до этого содержимого добраться. В файловой системе обычно различается системная область, в которой записываются метаданные, и область данных, где хранятся собственно файлы. Системная область может составлять заметную долю общего дискового пространства, и вот почему.
Различают устройство последовательного доступа (например, накопители на магнитных лентах) и устройства прямого доступа (например, жесткие диски). Чтение (и запись) данных на устройства последовательного доступа идет последовательно: если сейчас записан первый блок носителя, то следующим будет доступен второй, за ним - третий и т.д. Если доступен пятый блок, а нужен первый или тысячный, выполняется длительная операция позиционирования, причем она тем длиннее, чем дальше отстоит нужный блок от текущего: лента перематывается. Работать с устройствами прямого доступа легче: каков бы ни был текущий прочитанный блок, время, за которое будет прочитан любой другой, примерно одинаковое.
Файлы на магнитной ленте удобнее хранить целиком, каждый файл - одним длинным куском. У такого способа есть один существенный недостаток: если на ленту объемом в один гигабайт записать 1024 мегабайтных файла, а потом удалить каждый второй, то образуется полгигабайта свободного места, но кусочками по мегабайту каждый. Тогда запись, скажем, двухмегабайтного файла потребует трех операций: сначала надо переписать какой-нибудь мегабайтный файл на свободное место, затем удалить старую его копию, и только затем записать на образовавшееся место большой файл.
На устройстве прямого доступа можно избежать этой неприятной ситуации, если постановить, что файл может размещаться на нем в области данных по частям, а карта размещения этих частей будет записана в системную область. Если, не мудрствуя, предположить, что в системную область записываются номера полукилобайтных секторов, в которых лежит файл (по 32 бита каждый номер), то выходит, что размер системной области, который может потребоваться, всего в 16 раз меньше файловой. Но в Linux в системную область записываются индексные дескрипторы, размер которых существенно больше. Количество индексных дескрипторов может быть намного меньше количества блоков, но все же системная область занимает примерно такую же (от пяти до десяти процентов) долю общего дискового пространства.
Индексный дескриптор, inode. Внутренний объект файловой системы Linux, однозначно определяющий принадлежащий ей файл. Индексный дескриптор содержит атрибуты файла, размер, указывает расположение файла на диске и т.п. Каждому индексному дескриптору соответствует единственный в данной файловой системе идентификатор - целое число.
На самом деле, даже на жестком диске блоки, расположенные подряд, считываются (и записываются) быстрее, чем блоки, расположенные как попало. Эффект связан с механическим устройством жестких дисков, пояснять которое Мефодию Гуревич не стал, ссылаясь на общеизвестность. Суть его в том, что задержки при чтении данных, находящихся на разных цилиндрах диска, растут линейно, как для ленты (чем дальше, тем дольше). Один из остроумных способов оптимизировать работу с диском состоит в том, чтобы разбить все цилиндры на группы, а внутри каждой группы выделить свою системную область и область данных. Тогда сами файлы и их индексные дескрипторы будут лежать, если это возможно, на соседних цилиндрах, и доступ ускорится.
Другое, более общее решение - использование кеширования, при котором данные с диска частично дублируются в памяти. Если какой-то процесс прочитал данные из файла, эти данные некоторое время находятся в памяти, на случай, если они ему (или кому-нибудь другому) опять понадобятся. Повторное обращение уже не дойдет до диска, система вернет процессу данные из кеша, раз уж они ничем не отличаются от тех, что на диске. Если процесс записал данные на диск, содержимое кеша обновляется, оставаясь актуальным.
Еще эффективней кеш на запись: операции записи накапливаются в памяти, а до диска добираются не сразу, и в том порядке, в каком быстрее пройдет запись, а не в том, в каком были выполнены. Если запись шла во временный файл, который, в конце концов, удалили, обращений к диску может вообще не случиться. Однако с кешированием операций записи следует обращаться бережно: а вдруг сбой в электропитании произойдет именно тогда, когда часть данных уже записана, а часть - еще нет? А если не полностью, кусочками, обновилась системная область, состояние файловой системы после того, как питание опять включат, может оказаться совсем плачевным - настолько, что даже утилита восстановления fsck может оказаться бессильной. Поэтому системные области либо вообще не кешируются на запись, либо делают это исключительно с помощью будущих кандидатов и докторов наук, которые рассчитывают безопасные алгоритмы обновления файловой системы из кеша на запись...
Работа с файловыми системами
Итак, Linux свободно работает (и даже предпочитает работать) с несколькими разделами диска, содержащими, возможно, разные типы файловых систем.
Монтирование и размонтирование
В лекции 3 было рассказано о том, что файловые системы на различных разделах "прививаются" в виде ветвей общего дерева каталогов, растущего из " / ". Делается это при помощи команды mount -o настройки_монтирования устройство точка_монтирования, где устройство - это имя блочного файла-дырки, точка_монтирования (mountpoint) - полный путь к каталогу, а настройки_монтирования определяют особые параметры, разные для разных файловых систем. После выполнения этой команды содержимое файловой системы, размещенной на устройстве (как правило, дисковом разделе ), становится доступным в виде дерева подкаталогов точки_монтирования. Посмотреть список всех смонтированных файловых систем можно с помощью команды mount без параметров:
root@localhost root]# mount /dev/hda5 on / type ext3 (rw) /dev/hda7 on /home type ext3 (rw) /dev/fd0 on /mnt/floppy type subfs (rw,nosuid,nodev,sync) /dev/hdc on /mnt/cdrom type subfs (ro,nosuid,nodev) proc on /proc type proc (rw,gid=19) devpts on /dev/pts type devpts (rw,gid=5,mode=0620) [root@localhost root]# umount /home [root@localhost root]# ls /home [root@localhost root]# mount /dev/hda7 /home [root@localhost root]# ls /home methody shogun tmpuserПример 11.7. Просмотр списка смонтированных файловых систем
Оба Linux- раздела смонтированы при старте системы: /dev/hda5 образует корневую файловую систему, а /dev/hda7 используется для хранения пользовательских домашних каталогов6Мефодий заметил, что /tmp и /var не смонтированы никуда, и, следовательно, корневая файловая система, вопреки рекомендациям FHS, слишком часто используется на запись. . Суперпользователь может размонтировать файловую систему вручную с помощью команды umount точка_монтирования, если на ней не открыто никаких файлов и никто не использует какой-либо ее каталог в качестве текущего.
Для того чтобы файловые системы монтировались при старте, их описывают в файле /etc/fstab:
/dev/hda5 / ext3 defaults 1 1 devpts /dev/pts devpts gid=5,mode=0620 0 0 /dev/hda7 /home ext3 defaults 1 2 proc /proc proc gid=19 0 0 /dev/hda6 swap swap defaults 0 0 /dev/fd0 /mnt/floppy subfs fs=floppyfss,sync,nodev,nosuid /dev/cdrom /mnt/cdrom subfs fs=cdfss,nodev,nosuidПример 11.8. Содержимое /etc/fstab
Первое поле каждой строки этого файла - устройство или название виртуальной файловой системы, второе - точка монтирования, третье - тип файловой системы, четвертое - настройки монтирования, а пятое и шестое относятся к организации резервного копирования и процедуре проверки цельности. Содержимое fstab практически повторяет выдачу mount (dev/cdrom на этой машине - ссылка на /dev/hdc). Здесь указывается и область подкачки, которую ядро не монтирует, а использует напрямую. Утилита mount поддерживает усеченный вариант командной строки mount точка_монтирования, при котором она самостоятельно ищет в /etc/fstab, каким способом должна быть смонтирована точка_монтирования. Для того чтобы при старте системы какое-либо устройство не монтировалось, а усеченным mount его можно было смонтировать вручную, в поле "настройки монтирования" добавляется ключевое слово noauto.
Две последних строки относятся к монтированию съемных (removable) носителей: лазерного и гибкого дисков. Съемные носители приходится монтировать гораздо чаще несъемных - не во время старта системы, а всякий раз, когда носитель сменился, и содержимое нового необходимо пользователю. Мало того, надо разрешить выполнять операцию mount пользователю, который принес дискету и желает поработать с ней. С другой стороны, нельзя всем и каждому давать право запускать mount и особенно umount с любыми параметрами! Существует четыре способа разрешить возникающее противоречие:
- Воспользоваться усеченным вариантом mount (запись с настройкой noauto в fstab ) и утилитой sudo, при помощи которой позволить пользователю выполнять, скажем, только команды mount /cdrom и umount /cdrom.
- Воспользоваться усеченным вариантом mount и настройкой owner в fstab, которая позволяет выполнять операцию монтирования хозяину устройства; при этом /dev/hdc отдается во владение первому зарегистрированному пользователю так же, как /dev/audio и прочие устройства персонального использования. Этот способ лучше предыдущего тем, что исключает ситуацию, когда один пользователь смонтирует диск, а другой немедленно его размонтирует.
- Воспользоваться специальным демоном из пакета autofs, который отслеживает обращения пользователей к некоторому каталогу (например, /mnt/cdrom/auto ) и самостоятельно выполняет операцию mount, а если к содержимому носителя долгое время никто не обращался - umount. Этот способ лучше предыдущего тем, что пользователю вообще никаких дополнительных команд подавать не приходится.
- Воспользоваться специализированным модулем ядра (в примере - subfs ), который всегда сообщает программе пользователя, что устройство смонтировано и готово к работе, а поменялся ли носитель, разбирается самостоятельно. Этот способ лучше предыдущего тем, что пользователю не приходится ждать, пока система соизволит размонтировать и "отдать" лазерный диск. Кроме того, subfs может снабжать пользователя данными из кеша, даже если диск давно уже вынут (речь идет, разумеется, об операциях чтения).
Во всех случаях, когда диск монтирует не системный администратор, стоит предпринять некоторые дополнительные действия. Например, диск должен монтироваться так, чтобы с него не работал запуск с подменой идентификатора (setUID), и чтобы на нем нельзя было создавать файлы-дырки (чтобы не потворствовать хулиганству, вроде запуска setUID-оболочки или записи прямо в устройство, соответствующее hda ). За это отвечают настройки nosuid и nodev, упомянутые в /etc/fstab.
Кроме того, лазерные приводы имеют "защелку", не позволяющую извлечь диск, пока он используется, а дисководы или устройства USB Flash - нет (хотя, казалось бы, она как раз нужнее там, где происходит запись). Единственная надежда - на то, что пользователь не будет выдергивать дискету из дисковода, пока он занимается записью, и на нем горит зеленая лампочка. Чтобы каждая операция записи немедленно приводила к передаче данных, необходимо полностью отключить кеш записи, то есть использовать синхронный режим работы файловой системы. Это делается при помощи настройки sync.