Добавлен: 29.10.2018
Просмотров: 48072
Скачиваний: 190
856
Глава 10. Изучение конкретных примеров: Unix, Linux и Android
Идентификатор владельца файла
Группа, к которой принадлежит файл
Размер файла в байтах
Время создания
Время последнего доступа
Время последней модификации
Системный вызов pipe используется для создания каналов оболочки. Он создает
псевдофайл для буферизации данных, которыми обмениваются компоненты канала,
и возвращает дескрипторы файлов для чтения и записи буфера. В канале
sort <in | head -30
дескриптор файла 1 (стандартный вывод) в процессе, выполняющем программу sort,
будет настроен оболочкой на запись в канал, а дескриптор файла 0 (стандартный ввод)
в процессе, выполняющем программу head, будет настроен на чтение из канала. Про-
грамма sort просто читает из файла с дескриптором 0 (установлен на файл
in
) и пишет
в файл с дескриптором 1 (канал), даже не зная о том, что оба этих файла перенаправ-
лены. Если бы ввод и вывод не были перенаправлены, программа sort автоматически
читала бы данные с клавиатуры и выводила их на экран (устройства по умолчанию).
Подобным образом, когда программа head считывает входные данные из файла с де-
скриптором 0, она получает данные, которые программа sort поместила в буфер канала
(даже не зная о том, что используется канал). Вот хороший пример того, как простая
концепция (перенаправление) плюс простая реализация (файлы с дескрипторами 0
и 1) дают мощный инструмент (обмен между программами произвольным образом без
необходимости их модификации).
Последний системный вызов в табл. 10.9 — это fcntl. Он используется для блокировки
и разблокирования файлов, а также некоторых других специфических для файлов
операций.
Рассмотрим теперь некоторые системные вызовы, относящиеся скорее к каталогам
или файловой системе в целом, нежели к одному конкретному файлу. Наиболее часто
употребляемые системные вызовы перечислены в табл. 10.11. Каталоги создаются
и удаляются при помощи системных вызовов mkdir и rmdir соответственно. Каталог
может быть уничтожен, только когда он пуст.
Таблица 10.11. Некоторые системные вызовы, относящиеся к работе с каталогами.
В случае ошибки возвращаемое значение s равно –1; dir идентифицирует каталог;
а dirent представляет собой запись каталога. Параметры должны быть понятны без
пояснений
Системный вызов
Описание
s=mkdir(path, mode)
Создать новый каталог
s=rmdir(path)
Удалить каталог
s=link(oldpath, newpath)
Создать ссылку на существующий файл
Таблица 10.10 (продолжение)
10.6. Файловая система UNIX
857
Системный вызов
Описание
s=unlink(path)
Удалить ссылку
s=chdir(path)
Изменить рабочий каталог
dir=opendir(path)
Открыть каталог для чтения
s=closedir(dir)
Закрыть каталог
dirent=readdir(dir)
Прочитать одну запись каталога
rewinddir(dir)
Установить указатель в каталоге на первую запись
Как было показано на рис. 10.14, при создании ссылки на файл создается новая запись
в каталоге, указывающая на существующий файл. Ссылка создается при помощи си-
стемного вызова link. В параметрах этого системного вызова указываются исходное
и новое имя. Записи в каталоге удаляются системным вызовом unlink. Когда удаляется
последняя ссылка на файл, файл также автоматически удаляется. Если для файла не
было создано ни одной ссылки, то при первом же обращении к системному вызову
unlink файл исчезнет.
Рабочий каталог можно изменить при помощи системного вызова chdir. После выпол-
нения этого системного вызова будут по-другому интерпретироваться относительные
имена путей.
Последние четыре системных вызова в табл. 10.11 предназначены для чтения каталогов.
Каталоги могут открываться, закрываться и читаться аналогично обычным файлам.
Каждое обращение к системному вызову readdir возвращает ровно одну запись ката-
лога (в фиксированном формате). Пользователям запрещено писать в каталоги (это
делается, чтобы пользователи случайно не нарушили целостности системы). Файлы
могут добавляться к каталогу при помощи системных вызовов creat и link, а удаляться
с помощью системного вызова unlink. В операционной системе Linux нет способа перей-
ти к конкретному файлу в каталоге, но есть системный вызов rewinddir, позволяющий
начать читать открытый каталог с начала.
10.6.3. Реализация файловой системы Linux
В этом разделе мы сначала рассмотрим поддерживаемые уровнем виртуальной фай-
ловой системы (Virtual File System (VFS)) абстракции. VFS скрывает (от процессов
и приложений верхнего уровня) отличия поддерживаемых в Linux файловых систем
(находятся они на локальных устройствах или удаленно — с доступом по сети). Доступ
к устройствам и другим специальным файлам также получаем через уровень VFS. За-
тем мы опишем реализацию первой получившей широкое распространение файловой
системы Linux под названием ext2 (вторая расширенная файловая система). После
этого обсудим улучшения файловой системы ext4. Используется также множество
других файловых систем. Все Linux-системы могут работать с большим количеством
дисковых разделов, причем в каждом может быть своя файловая система.
Виртуальная файловая система Linux
Для того чтобы приложения могли взаимодействовать с разными файловыми систе-
мами, реализованными на разных типах локальных или удаленных устройств, в Linux
858
Глава 10. Изучение конкретных примеров: Unix, Linux и Android
принят использованный в других UNIX-системах подход — VFS. VFS определяет набор
основных абстракций файловой системы и разрешенные с этими абстракциями опера-
ции. Описанные в предыдущем разделе системные вызовы обращаются к структурам
данных VFS, определяют тип файловой системы (к которой принадлежит нужный
файл) и при помощи хранящихся в структурах данных VFS указателей на функции
запускают соответствующую операцию в указанной файловой системе.
В табл. 10.12 даны четыре основные структуры файловой системы, поддерживаемые
VFS. Суперблок содержит критичную информацию о компоновке файловой системы.
Разрушение суперблока делает файловую систему нечитаемой. i-узел (сокращение от
«индекс-узлы», никто их так не называет) описывает один файл. Обратите внимание
на то, что в Linux каталоги и устройства также представлены файлами, так что они
тоже имеют соответствующие i-узлы. И суперблок, и i-узлы имеют соответствующие
структуры на том физическом диске, где находится файловая система.
Таблица 10.12. Поддерживаемые в VFS абстракции файловой системы
Объект
Описание
Операция
Суперблок
Конкретная файловая система
read_inode, sync_fs
Элемент каталога (dentry)
Элемент каталога, компонент пути
create, link
i-узел
Конкретный файл
d_compare, d_delete
Файл (file)
Открыть связанный с процессом файл
read, write
Чтобы улучшить некоторые операции с каталогами и перемещение по путям (таким,
как
/usr/ast/bin
), VFS поддерживает структуру данных dentry, которая представляет
элемент каталога. Эта структура данных создается файловой системой на ходу. Эле-
менты каталога кэшируются в так называемом dentry_cache. Например, dentry_cache
будет содержать элементы для
/
,
/usr
,
/usr/ast
и т. д. Если несколько процессов обраща-
ются к одному и тому же файлу при помощи одной и той же жесткой ссылки (то есть
одного и того же пути), то их объект файла будет указывать на один и тот же элемент
в этом кэше.
И наконец, структура данных file является представлением открытого файла в памяти,
она создается в ответ на системный вызов open. Она поддерживает такие операции,
как read, write, sendfile, lock (и прочие описанные в предыдущем разделе системные
вызовы).
Реализованные под уровнем VFS реальные файловые системы не обязаны исполь-
зовать внутри себя точно такие же абстракции и операции. Однако они должны реа-
лизовать семантически эквивалентные операции файловой системы (такие же, как
указанные для объектов VFS). Элементы структур данных operations для каждого из
четырех объектов VFS — это указатели на функции в нижележащей файловой системе.
Файловая система Ext2 в Linux
Теперь мы опишем наиболее популярную дисковую файловую систему Linux — ext2.
Первый выпуск Linux использовал файловую систему MINIX 1, которая имела ко-
роткие имена файлов и максимальный размер файла 64 Мбайт. Файловая система
MINIX 1 была в итоге заменена первой расширенной файловой системой ext, кото-
10.6. Файловая система UNIX
859
рая позволяла использовать более длинные имена файлов и более крупные размеры
файлов. Вследствие своей низкой эффективности (в смысле производительности)
система ext была заменена своей последовательницей ext2, которая до сих пор ши-
роко используется.
Дисковый раздел с ext2 содержит файловую систему с показанной на рис. 10.17 компо-
новкой. Блок 0 не используется системой Linux и содержит код загрузки компьютера.
Следом за блоком 0 дисковый раздел разделен на группы блоков (без учета границ
цилиндров диска). Каждая группа организована следующим образом.
Рис. 10.17. Размещение файловой системы ext2 на диске
Первый блок — это суперблок (superblock), в котором хранится информация о компо-
новке файловой системы, включая количество i-узлов, количество дисковых блоков,
начало списка свободных дисковых блоков (это обычно несколько сотен элементов).
Затем следует дескриптор группы, содержащий информацию о расположении бито-
вых массивов, количестве свободных блоков и i-узлов в группе, а также количестве
каталогов в группе. Эта информация важна, так как файловая система ext2 пытается
распределить каталоги равномерно по всему диску.
В двух битовых массивах ведется учет свободных блоков и свободных i-узлов (это тоже
унаследовано из файловой системы MINIX 1 и отличает ее от большинства файловых
систем UNIX, в которых для свободных блоков используется список). Размер каждого
битового массива равен одному блоку. При размере блока 1 Кбайт такая схема ограни-
чивает размер группы блоков 8192 блоками и 8192 i-узлами. Первое число является
реальным ограничением, а второе — практически нет. При блоках размером 4 Кбайт
числа в четыре раза больше.
Затем располагаются сами i-узлы. Они нумеруются от 1 до некоторого максимума.
Размер каждого i-узла — 128 байт, и описывает он ровно один файл. i-узел содержит
учетную информацию (в том числе всю возвращаемую вызовом stat, который просто
берет ее из i-узла), а также достаточное количество информации для определения ме-
стоположения всех дисковых блоков, которые содержат данные файла.
Следом за i-узлами идут блоки данных. Здесь хранятся все файлы и каталоги. Если
файл или каталог состоит более чем из одного блока, то эти блоки не обязаны быть не-
прерывными на диске. В действительности блоки большого файла, скорее всего, будут
разбросаны по всему диску.
Соответствующие каталогам i-узлы разбросаны по всем группам дисковых блоков.
Ext2 пытается расположить обычные файлы в той же самой группе блоков, что и ро-
дительский каталог, а файлы данных — в том же блоке, что и i-узел исходного файла
(при условии, что там имеется достаточно места). Эта идея была позаимствована из
файловой системы Berkeley Fast File System (McKusick et al., 1984). Битовые массивы
используются для того, чтобы принимать быстрые решения относительно выделения
860
Глава 10. Изучение конкретных примеров: Unix, Linux и Android
места для новых данных файловой системы. Когда выделяются новые блоки файлов,
то ext2 также делает упреждающее выделение (preallocates) нескольких (восьми) до-
полнительных блоков для этого же файла (чтобы минимизировать фрагментацию
файла из-за будущих операций записи). Эта схема распределяет файловую систему по
всему диску. Она также имеет хорошую производительность (благодаря ее тенденции
к смежному расположению и пониженной фрагментации).
Для доступа к файлу нужно сначала использовать один из системных вызовов Linux
(такой, как open), для которого нужно указать путь к файлу. Этот путь разбирается,
и из него извлекаются составляющие его каталоги. Если указан относительный путь,
то поиск начинается с текущего каталога процесса, в противном случае — с корневого
каталога. В любом случае, i-узел для первого каталога найти легко: в дескрипторе про-
цесса есть указатель на него либо (в случае корневого каталога) он хранится в опреде-
ленном блоке на диске.
Каталог позволяет использовать имена файлов длиной до 255 символов (рис. 10.18).
Каждый каталог состоит из некоторого количества дисковых блоков (чтобы каталог
можно было записать на диск атомарно). В каталоге элементы для файлов и каталогов
находятся в несортированном порядке (каждый элемент непосредственно следует за
предыдущим). Элементы не могут пересекать границы блоков, поэтому в конце каж-
дого дискового блока обычно имеется некоторое количество неиспользуемых байтов.
Рис. 10.18. Каталог Linux: а — с тремя файлами; б — после удаления файла voluminous
Каждая запись каталога на рис. 10.18 состоит из четырех полей фиксированной длины
и одного поля переменной длины. Первое поле представляет собой номер i-узла, рав-
ный 19 для файла
colossal
, 42 для файла
voluminous
и 88 для каталога
bigdir
. Следом
идет поле rec_len, сообщающее размер всей записи каталога в байтах (возможно, вместе
с дополнительными байтами-заполнителями после имени). Это поле необходимо, что-
бы найти следующую запись (в том случае, когда имя файла дополнено неизвестным