Для монтирования файловой системы используется системный вызов mount. Монтирование файловой системы означает следующее. В имеющейся к моменту монтирования дереве каталогов и файлов должен иметься листовой узел - пустой каталог (в терминологии UNIX такой каталог, используемый для монтирования файловой системы, называется directory mount point - точка монтирования). В любой файловой системе имеется корневой каталог. Во время выполнения системного вызова mount корневой каталог монтируемой файловой системы совмещается с каталогом - точкой монтирования, в результате чего образуется новая иерархия с полными именами каталогов и файлов.
Смонтированная файловая система впоследствии может быть отсоединена от общей иерархии с использованием системного вызова umount. Для успешного выполнения этого системного вызова требуется, чтобы отсоединяемая файловая системы к этому моменту не находилась в использовании (т.е. ни один файл из этой файловой системы не был открыт). Корневая файловая система всегда является смонтированной, и к ней не применим системный вызов umount.
Как мы отмечали выше, отдельная файловая система обычно располагается на логическом диске, т.е. на разделе физического диска. Для инициализации файловой системы не поддерживаются какие-либо специальные системные вызовы. Новая файловая система образуется на отформатированном диске с использованием утилиты (команды) mkfs. Вновь созданная файловая система инициализируется в состояние, соответствующее наличию всего лишь одного пустого корневого каталога. Команда mkfs выполняет инициализацию путем прямой записи соответствующих данных на диск.
Ядро ОС UNIX поддерживает для работы с файлами несколько системных вызовов. Среди них наиболее важными являются open, creat, read, write, lseek и close.
Важно отметить, что хотя внутри подсистемы управления файлами обычный файл представляется в виде набора блоков внешней памяти, для пользователей обеспечивается представление файла как линейной последовательности байтов. Такое представление позволяет использовать абстракцию файла при работе в внешними устройствами, при организации межпроцессных взаимодействий и т.д.
Файл в системных вызовах, обеспечивающих реальный доступ к данным, идентифицируется своим дескриптором (целым значением). Дескриптор файла выдается системными вызовами open (открыть файл) и creat (создать файл). Основным параметром операций открытия и создания файла является полное или относительное имя файла. Кроме того, при открытии файла указывается также режим открытия (только чтение, только запись, запись и чтение и т.д.) и характеристика, определяющая возможности доступа к файлу:
open(pathname, oflag [,mode])Одним из признаков, могущих участвовать в параметре oflag, является признак O_CREAT, наличие которого указывает на необходимость создания файла, если при выполнении системного вызова open файл с указанным именем не существует (параметр mode имеет смысл только при наличии этого признака). Тем не менее по историческим причинам и для обеспечения совместимости с предыдущими версиями ОС UNIX отдельно поддерживается системный вызов creat, выполняющий практически те же функции.
Открытый файл может использоваться для чтения и записи последовательностей байтов. Для этого поддерживаются два системных вызова:
read(fd, buffer, count) и write(fd, buffer, count)Здесь fd - дескриптор файла (полученный при ранее выполненном системном вызове open или creat), buffer - указатель символьного массива и count - число байтов, которые должны быть прочитаны из файла или в него записаны. Значение функции read или write - целое число, которое совпадает со значением count, если операция заканчивается успешно, равно нулю при достижении конца файла и отрицательно при возникновении ошибок.
В каждом открытом файле существует текущая позиция. Сразу после открытия файл позиционируется на первый байт. Другими словами, если сразу после открытия файла выполняется системный вызов read (или write), то будут прочитаны (или записаны) первые count байт содержимого файла (конечно, они будут успешно прочитаны только в том случае, если файл реально содержит по крайней мере count байт). После выполнения системного вызова read (или write) указатель чтения/записи файла будет установлен в позицию count+1 и т.д.
Такой чисто последовательный стиль работы оказывается во многих случаях достаточным, но часто бывает необходимо читать или изменять файл с произвольной позиции (например, как без такой возможности хранить в файле прямо индексируемые массивы данных?). Для явного позиционирования файла служит системный вызов
lseek(fd, offset, origin)Как и раньше, здесь fd - дескриптор ранее открытого файла. Параметр offset задает значение относительного смещения указателя чтения/записи, а параметр origin указывает, относительно какой позиции должно применяться смещение. Возможны три значения параметра origin. Значение 0 указывает, что значение offset должно рассматриваться как смещение относительно начала файла. Значение 1 означает, что значение offset является смещением относительно текущей позиции файла. Наконец, значение 2 говорит о том, что задается смещение относительно конца файла. Заметим, что типом данных параметра offset является long int. Это значит, что, во-первых, могут задаваться достаточно длинные смещения и, во-вторых, смещения могут быть положительными и отрицательными.
Например, после выполнения системного вызова
lseek(fd, 0, 0)указатель чтения/записи соответствующего файла будет установлен на начало (на первый байт) файла. Системный вызов
lseek(fd, 0, 2)установит указатель на конец файла. Наконец, выполнение системного вызова
lseek(fd, 10, 1)приведет к увеличению текущего значения указателя на 10.
Естественно, системный вызов успешно завершается только в том случае, когда заново сформированное значение указателя не выходит за пределы существующих размеров файла.
Одним из наиболее существенных недостатков традиционных файловых систем является трудность восстановления согласованного состояния файлов после сбоев, в результате которых теряется содержимое основной памяти. Это связано с тем, что для повышения эффективности работа с внешней памятью производится через буфера основной памяти, в которых в момент сбоя могут находиться как данные (содержимое блоков файла), так и метаданные (например, содержимое i-узлов). Обычным приемом восстановления файловой системы после сбоя является применение утилиты fsck, которая, работая на уровне логического диска, обходит всю файловую систему и, по мере возможности, находит и исправляет ошибочные ситуации. Естественно, если используются большие диски, то эта работа занимает много времени, приводя к серьезным задержкам в использовании компьютера. Для устранения этого недостатка все чаще применяются файловые системы с журнализацией.
Как и в случае журнализации изменений в системах управления базами данных, основным принципом журнализующих файловых систем является поддержание специального файла-журнала, в который в последовательном и только последовательном режиме записывается информация обо всех изменениях файловой системы. Запись, как правило, производится порциями большого объема, что обеспечивает высокий уровень полезного использования дисковой памяти и высокую эффективность. При восстановлении после сбоя требуется использовать только "хвост" журнала, что позволяет производить восстановление быстро и надежно.
Файловые системы с журнализацией разделяются на две категории: системы, производящие журнализацию всех изменений, и системы, журнализующие только изменения метаданных. Среди систем второй категории выделяются те, которые журнализуют только некоторую выделенную информацию (например, не помещают в журнал информацию о смене владельца файла).
Различаются подходы с журнализацией операций и журнализацией результатов операций. Если, например, журнализуется операция изменения таблицы распределения памяти на диске, то выгоднее поместить в журнал информацию о самой операции (поскольку она изменяет только несколько бит информации на диске). В случае же журнализации операции записи блока данных выгоднее занести в журнал все содержимое блока до его изменения.
Среди файловых систем с журнализацией выделяются такие, в которых журнал используется как вспомогательное средство, а структура самой файловой системы не меняется (в частности, как и в традиционных файловых системах, поддерживаются структуры i-узлов и суперблоков). Другой класс журнализующих файловых систем составляют те, в которых журнал является единственным средством представления файлов на магнитном диске.
Имеется два типа журналов: журнал, ориентированный только на повторное выполнение операций (redo-only), и журнал, способный поддерживать как повторное выполнение операций, так и их обратное выполнение (undo-redo). В журнале "undo-redo" сохраняются как новые, так и старые значения данных. При использовании журнала типа "redo-only" операции восстановления упрощаются, но требуется ограничивать порядок записи метаданных в журнал и на место их постоянного хранения. Журнал "undo-redo" больше по объему и требует применения более сложного механизма журнализации, но использование этого типа журнализации допускает более высокий уровень параллельности.