"Сложные" файловые системы
Структуры "сложных" файловых систем отличаются
большим разнообразием, однако можно выделить несколько общих принципов.
Обычно файловая система начинается с заголовка, или, как это называется
в системах семейства Unix, суперблока (superblock).
Суперблок хранит информацию о размерах дискового тома, отведенного под
ФС, указатели на начало системных структур данных и другую информацию,
зависящую от типа ФС. Например, для статических структур может храниться
их размер. Часто суперблок содержит также магическое число — идентификатор
типа файловой системы. Аналог суперблока существует даже в FAT — это так
называемая загрузочная запись (boot record).
Практически все современные ФС разделяют список свободных блоков и структуры,
отслеживающие размещение файлов. Чаще всего вместо списка свободных блоков
используется битовая карта, в которой каждому блоку соответствует один
бит: занят/свободен. В свою очередь, список блоков для каждого файла обычно
связан с описателем файла. На первый взгляд, эти описатели кажется естественным
хранить в каталоге, но их, как правило, выносят в отдельные области, часто
собранные в специальные области диска — таблицу инодов, метафайл и т.
д. Такое решение уменьшает объем каталога и, соответственно, ускоряет
поиск файла по имени. К тому же многие ФС сортируют записи в каталоге
по имени файла, также с целью ускорения поиска. Понятно, что сортировка
записей меньшего размера происходит быстрее.
В файловой системе HPFS, используемой в OS/2 и Windows NT, каждая запись
в каталоге содержит имя файла и указатель vtajhode (файловую запись).
Каталоги в этой ФС организованы в виде В-деревьев и отсортированы по именам
файлов.
Файловая запись занимает один блок на диске и содержит список так называемых
extent ("расширений") — (у этого
термина нет приемлемого русского аналога. В переводах документации по
OS/360 (ОС ЕС) так и писали: экстент.). Каждый экстент описывает непрерывную
последовательность дисковых блоков, выделенных файлу. Он задает начальный
блок такой последовательности и ее длину. Вместо списка свободных блоков
используется битовая карта диска, в которой каждому блоку соответствует
один бит: занят/свободен.
Нужно отметить, что идея экстентов далеко не нова: аншюгичная структура
используется в некоторых версиях Unix с начала 80-х годов, а истоки этой
идеи теряются в глубине 60-х.
Файловая запись обычно размещается перед началом первого экстента файла,
хотя это и не обязательно. Она занимает один блок (512 байт) и может содержать
до десяти описателей экстентов (рис. 11.11). Кроме того, она содержит
информацию о времени создания файла, его имени и расширенных атрибутах
(см. разд. Тип файла). Если для списка экстентов
или расширенных атрибутов места не хватает, то для них также выделяются
экстенты. В этом случае экстенты размещаются в виде В-дерева для ускорения
поиска. Максимальное количество экстентов в файле не ограничено ничем,
кроме размера диска.
Пользовательская программа может указать размер файла при его создании.
В этом случае система сразу попытается выделить место под файл так, чтобы
он занимал как можно меньше экстентов. Если программа не сообщила размера
файла, используется значение по умолчанию. Фактически, HPFS размещает
место под файл по принципу worst fit (наименее подходящего), начиная выделение
с наибольшего непрерывного участка свободного пространства. В результате
фрагментированными оказываются только файлы, длина которых увеличивалась
многократно или же те, которые создавались при почти заполненном диске.
При нормальной работе файл редко занимает больше 3—4 экстентов.
Рис. 11.11. Каталог и файловая запись в HPFS
Еще одно любопытное следствие применения стратегии worst
fit заключается в том, что пространство, освобожденное стертым файлом,
обычно используется не сразу. Отмечались случаи, когда файл на активно
используемом диске удавалось восстановить через несколько дней после стирания.
Экстенты открытых файлов и карта свободных блоков во время работы размещаются
в ОЗУ, поэтому производительность такой ФС в большинстве ситуаций намного
(в 1,5—2 раза и более) выше, чем у FAT с тем же объемом кэша, при вполне
приемлемых потребностях в памяти и размере кластера 512 байт.
Видно также, что структура HPFS упрощает произвольный доступ к файлу:
вместо прослеживания цепочки блоков нам нужно проследить цепочку экстентов,
которая гораздо короче.
Более подробное описание структуры HPFS можно найти в статье [PC Magazine
1995|. Пользователи OS/2 считают целесообразным форматировать все разделы
емкостью более 12SM под HPFS, поскольку при этом выигрывается скорость
и увеличивается эффективность использования дискового пространства; кроме
того, исчезает необходимость в дефрагментацин и появляется возможность
создавать файлы и каталоги с длинными именами, не укладывающимися в модель
8.3, принятую в MS DOS.
За эти преимущества приходится платить неустойчивостью к сбоям (проблема
устойчивости к системным сбоям обсуждается в разд. Устойчивость
ФС к сбоям). В отличие от ДОС, спонтанные разрушения системы с последующим
зависанием в OS/2 случаются относительно редко, даже при запуске программ,
заведомо содержащих ошибки (как при разработке или тестировании прикладного
программного обеспечения). С другой стороны, на практике "неустойчивость"
приводит лишь к тому, что после аварийной перезагрузки автоматически запускается
программа восстановления ФС, что увеличивает время перезагрузки в несколько
раз; реальный же риск потерять данные при сбое не выше, а как показывает
практика, даже существенно ниже, чем при использовании FAT, поэтому игра
явно стоит свеч.
Наиболее интересна структура файловых систем в ОС семейства Unix. В этих
ФС каталог не содержит почти никакой информации о файле. Там хранится
только имя файла и номер его инода (i-node — по-видимому, сокращение от
index node: индексная запись). Иноды всех файлов в данной ФС собраны в
таблицу, которая так и называется: таблица инодов. В ранних версиях Unix
таблица инодов занимала фиксированное пространство в начале устройства;
в современных файловых системах эта таблица разбита на участки, распределенные
по диску.
Например, в файловой системе BSD Unix FFS (Fast File System — быстрая
файловая система), которая в Unix SVR4 называется просто UFS (Unix File
System), диск разбит на группы цилиндров. Каждая группа цилиндров содержит
копию суперблока, битовую карту свободных блоков для данного участка и
таблицу инодов для файлов, расположенных в пределах этого участка (рис.
11.12). Такая распределенная структура имеет два преимущества.
- Ускорение доступа к системным структурам данных. Когда
системные данные расположены вблизи от блоков пользовательских данных,
уменьшается расстояние, на которое перемещаются головки дисковода.
- Повышенная устойчивость к сбоям носителя. При повреждении
участка поверхности диска теряется только небольшая часть системных
данных. Даже потеря суперблока не приводит к потере структуры файловой
системы.
Рис. 11.12. Блоки цилиндров FFS
Инод хранит информацию о самом файле и его размещении
на диске (рис. 11.13, пример 11.2). Информационная часть инода может быть
получена системным вызовом
int stat(const char * fname, struct stat * buf) ;
Формат структуры stat описан во многих руководствах
по языку С. ОС UNIX и стандарту POSIX, например, в работе (Керниган-Ритчи
2000|. Эта структура содержит следующую информацию.
- Тип файла. Исследуя это поле, можно понять, является
данный объект файлом данных или специальным файлом. В этом же поле закодированы
права доступа к файлу.
- Идентификаторы владельца файла и группы. Вместе с правами
доступа эти два идентификатора образуют список контроля доступа файла
(см разд. Списки контроля доступа).
- Время:
- создания файла;
- последней модификации файла;
- последнего доступа к файлу.
- Длина файла. Для специальных файлов это поле часто
имеет другой смысл.
- Идентификатор файловой системы, в которой расположен
файл.
- Количество связей файла. Это поле заслуживает отдельного
обсуждения.
Рис. 11.13. Каталоги и иноды файловых систем семейства
Unix
Пример 11.2. Структура инода файловой системы ext2fs
/* * Структура данных инода second extended file system,
считанная в память
*/
i- struct ext2_inode_info { _u32 i_data[15]; _ u32 i_flags; _u32 i^faddr;
_ u8 i_frag_no; _ u8 i_f rag_size; _ u!6 i_osync; _ u32 i_file_acl; _
u32 i_dir_acl; _ u32 i_dtime;
_ u32 not_used_l; /* FIX: не используется/зарезервировано для 2.2 */ _
u32 i_block_group; _ u32 i_next_alioc_block;
u32 i next alloc goal; _ u32 i_prealloc_block;
u32 i prealloc count; __ u32 i_high_size;
int i_new _inode : 1 ; /* Этот инод только что вьделен */
Структура, описывающая физическое размещение файла на
диске, недоступна пользовательским программам. Собственно, формат этой
структуры может быть не очень элегантен. Например, в файловой системе
Veritas это список экстентов, похожий на HPFS; в файловых системах s5,
Xenix и FFS это массив из 13 чисел, задающих номера физических блоков
файла. Если файл в s5 содержит более десяти блоков (т. е. его длина больше
5 Кбайт), то предпоследние три указателя обозначают не блоки данных, а
так называемые косвенные блоки (indirection blocks),
в которых хранятся указатели на следующие блоки данных и, возможно, на
следующие косвенные блоки.
Наиболее интересная особенность ФС семейства Unix состоит не в этом. Внимательный
читатель, возможно, заметил, что инод не содержит имени файла. С другой
стороны, он содержит счетчик связей (link) — ссылок на этот файл из каталогов.
Таким образом, на один и тот же инод можно ссылаться из различных каталогов
или из одного каталога под разными именами (рис. 11.14). Иными словами,
один и тот же файл в этих ФС может иметь несколько различных имен. Именно
это и имелось в виду, когда го верилось, что структура каталогов в ОС
UNIX не обязана быть деревом.
Это свойство предоставляет неоценимые возможности для организации не рархии
каталогов, но имеет и некоторые оборотные стороны.
- 1. Создание нескольких связей для каталога потенциально опасно— оно
может привести к возникновению кольца, в котором каталог является своим
собственным подкаталогом. Отслеживать такую ситуацию сложно поэтому
разработчики ОС UNIX запретили создавать дополнительные имена для каталогов.
- 2. Удаление файла превращается в проблему: чтобы удалить файл, нужно
проследить все его связи. Поэтому UNIX не имеет средств для удатсния
файла, а обладает только системным вызовом unlink — удалить связь. Когда
у файла не остается связей, он действительно удаляется. Этот подход
вполне разумен, но также имеет неожиданную оборотную сторону: поскольку
теперь стирание файла — это операция не над файлом, а над каталогом,
то для удаления файла не нужно иметь никаких прав доступа к нему. Достаточно
иметь право записи в каталог.
На практике, механизм защиты от стирания отдельных файлов предусмотрен
— при установке в атрибутах каталога так называемого sticky bit ("липкий
бит"), система запрещает стирать файлы, для которых вы не имеете
права записи, но и этот механизм не лишен недостатков.
- 3. Такие связи (называемые еще жесткими (hard) связями), как легко
понять, могут создаваться только в пределах одной файловой системы,
поскольку каждая ФС имеет собственную таблицу инодов, и соответственно
собственную их нумерацию.
Рис. 11.14. Жесткие связи в Unix
Последнее обстоятельство резко уменьшает полезность
жестких связей для организации иерархии каталогов. Эта проблема была осознана
еще в 70-е годы, и программисты из группы BSD придумали интересное новое
понятие - символическую связь (symbolic link)
илиsymlink.
Символическая связь представляет собой специальный файл. Вместо блоков
данных инод такого файла содержит текстовую строку — имя того файла, с
которым создана связь (рис. 11.15). Это может быть файл из другой файловой
системы, в том числе и из такой, которая сама по себе не поддерживает
ни жестких, ни символических связей, например, FAT, HPFS или файловый
сервер Novell Netware. Такого файла может и вообще не существовать, например,
потому, что его уже удалили, или потому, что файловая система, в которой
он находится, не смонтирована, или просто потому, что имя было задано
неправильно. Тогда попытки открыть символическую связь будут завершаться
неудачей с кодом ошибки "файла не существует".
Рис. 11.15. Символическая связь
Единственным недостатком символических связей является
их относительно низкая "дуракоустойчивость" (fool-tolerance):
глупый пользователь может не распознать ситуации, когда символическая
связь указывает в никуда. Зато они обеспечивают полную свободу в размещении
и именовании файлов.
Пример из жизни
На двух Unix-системах с именами orasrv и Indy установлен один и тот же
программный продукт: редакторная система GNU Emacs. Бинарные загрузочные
модули для этих систем различаются, но большая часть Emacs — это файлы
на языке Emacs Lisp, которые с одинаковым успехом могут использоваться
обеими системами. Поэтому у администратора системы возникает желание использовать
одну копию lisp-файлов. При этом Emacs установлена таким обра зом, что
она ищет все свои lisp-файлы в каталоге /usr/local/lib/emacs/19.27/lisp
Изменение этого каталога потребовало бы частичной переустановки продукта
Но его не надо менять! Мы просто подмонтируем на машине orasrv каталог
/ машины Indy как /fs/lndy и исполняем следующие команды примера 11.3.
Пример 11.3. Перенос каталога без изменения его путевого
имени
cd /usr/local/lib/emacs/19.27 # перейти в заданный каталог
rm -Rf lisp
# стереть каталог lisp со всем содержимым
In -s /fs/Indy/usr/local/lib/emacs/19.27/lisp lisp
# создать символическую связь с именем lisp с соответствующим
# каталогом на машине Indy
Вся операция вместе с ее планированием занимает около двух
минут. Освобождается около 9 Мбайт дискового пространства. Emacs ничего
не замечает, и работает без всяких проблем.
Через неделю у администратора возникает идея, что для удобства администрирования
неплохо было бы монтировать с orasrv не всю файловую систему Indy, а только
ее каталог /home. За чем дело стало: переносим на Indy каталог lisp в
каталог /home/emacs/19.27/lisp; создаем в старом каталоге символическую
связь с новой; редактируем файл /etc/mnttab на-машине orasrv так, чтобы
с Indy монтировался только /home; меняем символическую связь каталога
lisp на машине orasrv. Заставляем orasrv подмонтировать диски в соответствии
с новым /etc/mnttab. Готово.
Операция занимает чуть больше двух минут, потому что нужно переносить
9 Мбайт из одной файловой системы в другую. Emacs опять ничего не замечает
и снова работает без всяких проблем. Администратор счастлив. Все довольны.
Сравните это описание с впечатлениями пользователя, который пытается переместить
с одного ДОС-вского драйва на другой типичную программу для Win32, которая
при установке записывает во многие места своей конфигурации и системного
реестра полное имя каталога, в который ее ставили...
Символические связи присущи только системам семейства
Unix. Напротив, эквиваленты жестких связей есть в других ОС. Фактически
жесткие связи можно создавать в любой ФС, где каталоги содержат ссылки
на централизованную базу данных вместо самого дескриптора файла.
Жесткие связи в VMS и Windows NT/2000/XP
Например, в файловой системе VAX/VMS данные о размещении файлов на диске
хранятся в специальном индексном (index) файле; каталоги же хранят только
индексы записей в этом файле. Основное отличие этой структуры от принятой
в Unix состоит в том, что вместо статической таблицы или набора таблиц
используется динамическая таблица, пространство для которой выделяется
тем же методом, что и для пользовательских файлов. Этот же подход реализован
в файловой системе NTFS, используемой в Windows NT/2000/XP, но в ней индексный
файл называется MFT (Main File Table — главная таблица файлов). Более
подробное описание структуры NTFS приводится в статье [www.digit-life.com
NTFS].
VAX/VMS и Windows NT позволяют создавать дополнительные имена для файлов,
хотя в VMS утилиты восстановления ФС выдают предупреждение, обнаружив
такое дополнительное имя. Все имена файла в этих ФС обязаны находиться
в одной файловой системе. Кроме того, операция удаления файла в VMS ведет
себя не так, как в Unix: применение операции удаления к любому из имен
приводит к удалению самого файла, даже если существовали и другие имена. |