Индекс
НазадОглавлениеВперед


Глава 7
Файловые системы

7.1. Иерархическая модель файловой системы

Файл есть именованная совокупность данных. Это определение относится к виртуальному файлу - каким он представляется пользователю. Определение виртуального файла не конкретизирует, где именно, на каких носителях находятся данные, из каких элементов эта совокупность состоит и каковы отношения между элементами. Отсутствие детализации в определении виртуального файла делает его удобной универсальной метафорой любых внешних по отношению к процессу данных. В ОС Unix впервые было введено представление всех внешних устройств, как виртуальных файлов. Это представление прочно укоренилось и в современных ОС имеется тенденция более широкого использования файловой метафоры. В таких системах, например, имена всех внешних по отношению к процессу именованных данных (семафоры, каналы-транспортеры, очереди т.д.) формируются по соглашениям именования файлов.

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

Файловой системой (ФС) называется та часть ОС, которая обеспечивает перевод виртуального представления файла в физическое. Этот перевод выполняется поэтапно, что позволяет представить ФС в виде иерархической модели, показанной на Рисунке 7.1.


Рис.7.1. Иерархическая модель файловой системы

Подсистема логической организации файлов обеспечивает API процессов в соответствии с той логической структурой, которую имеет виртуальный файл.

Логическая ФС выполняет перевод символьного имени файла в некоторый внутрисистемный идентификатор файла. Этот перевод включает в себя поиск по справочникам. Идентификатор обычно представляет собой некоторую простую структуру данных, адресующую дескриптор файла, который используется на следующем уровне иерархии.

Базовая ФС выполняет открытие и закрытие файлов и сопровождение открытых файлов. Базовая ФС находит по идентификатору дескриптор файла - системную структуру данных, содержащую информацию о местонахождении файла, его характеристиках и состоянии. При открытии файла этот уровень создает расширенный дескриптор файла, отслеживающий в ходе работы процессов с файлом его текущее состояние. Базовая ФС, возможно, также контролирует соблюдение прав доступа к файлу.

Подсистема физической организации файлов выполняет перевод виртуальных файловых адресов в реальные адреса на носителях. Этот уровень отслеживает размещение файлов на внешней памяти и управляет распределением пространства внешней памяти.

Система управления вводом-выводом (СУВВ) занимается формированием управляющих воздействий на устройства внешней памяти, их выполнением и обработкой прерываний. Этот уровень обеспечивается драйверами устройств, рассмотренными нами в предыдущем разделе, поэтому здесь мы этот уровень рассматривать не будем. Отметим только, что управление устройствами (любыми, а не только устройствами внешней памяти) является вырожденным случаем иерархической модели, в котором отсутствуют уровень логической ФС, а функции физической организации и управления вводом-выводом реализованы в драйвере.

В следующих разделах мы рассмотрим подробнее уровни ФС, двигаясь сверху вниз по иерархии.

7.2. Логическая организация файлов. Интерфейсы

Вне зависимости от логической структуры виртуального файла для получения процессом доступа к данным файла должен быть выполнен системный вызов open:

    handle = open(fileName, mode)

Здесь fileName - символьное имя, идентифицирующее файл для пользователя, соглашения об именовании файлов обсуждаются в следующем разделе. Режим - mode - задает способ обработки файла (чтение, запись, запись в конец, чтение/запись, синхронное/асинхронное выполнение операций ввода/вывода, параметры буферизации, возможность совместного использования файла процессами т.д.). Возвращаемый манипулятор handle используется процессом для идентификации файла во всех последующих операциях с ним.

Системный вызов:

    close(handle) 

закрывает файл, то есть, заканчивает работу процесса с файлом. Как правило, ОС обеспечивает при завершении процесса автоматическое закрытие всех открытых им файлов.

Синтаксис и семантика системных вызовов, связанных с чтением/ записью и поиском данных в файле, зависит от логической структуры файла. Логические структуры виртуальных файлов прежде всего можно подразделить на байториентированные и записеориентированные.

Байториентированные файлы представляются как линейная последовательность байт, без какого-либо дополнительного структурирования. API байториентированных файлов обеспечивается тремя основными системными вызовами:

    read(handle,vAddr, byteCounter)
    write(handle, vAddr, byteCounter)
    seek (handle, offset, form)

Здесь vAddr - адрес той области в виртуальном адресном пространстве процесса, с которой происходит обмен. За одну операцию обмена читается или пишется заданное byteCounter количество байт. К байториентированным файлам обеспечивается произвольный доступ, для чего вводится понятие файлового курсора - номера того байта файла, который будет читаться/записываться следующим. По умолчанию при открытии файла курсор устанавливается на начало файла и сдвигается при каждой операции read/write на byteCounter. Но системный вызов seek дает процессу возможность установить курсор в произвольную позицию, причем смещение offset может задаваться как от начала файла, так и от его конца или от текущей позиции курсора (это задается параметром from). Возможен также сервисный системный вызов, возвращающий текущее положение курсора. Системный вызов read должен адекватно реагировать на попытку чтения данных за концом файла. Стандартным решением является возврат этим вызовом числа прочитанных байт - при достижении конца файла возвращаемое значение будет меньше, чем byteCounter.

Безусловно, байториентированная организация является наиболее универсальной из всех возможных, так как на неструктурированную последовательность байт приложение может наложить любую собственную логическую структуру. Приведем пример, наверняка известный читателю: MS DOS поддерживает только байториентированную организацию файлов, но системы программирования Pascal (приложения в MS DOS) обеспечивают работу с файлами, состоящими из записей - тип данных file of ... . Байториентированные файлы являются единственной логической файловой структурой, поддерживаемой ОС Unix, и "с подачи" этой системы они включены в стандарт на переносимость ОС.

Альтернативной файловой организацией является записеориентированная. Записеориентированные файлы поддерживает фирма IBM в нескольких поколениях своих ОС для ЭВМ средней и большой мощности. В таких файлах единицей обмена является запись - порция данных, состоящая из одного или нескольких байт и, возможно, имеющая свою внутреннюю структуру. Имеется целый ряд методов логической организации записеориентированных файлов.

Последовательные файлы - файлы, ориентированные на обработку запись за записью - от первой записи до последней. Синтаксис и семантика системных вызовов read и write для таких файлов такие же, как и для байториентированных, но объем данных задается количеством записей, а не байтов. Произвольное позиционирование файлового курсора для последовательных файлов невозможно, но система может предоставлять системные вызовы для сдвига на запись вперед или назад. Последовательные файлы могут состоять из записей фиксированной или переменной длины. В последнем случае либо длина входит в состав записи, как одно из ее полей, либо запись содержит специальный код - признак конца записи.

Файлы прямого доступа - предполагается, что для каждой записи файла имеется логическая идентификация или ключ (key). Доступ производится к произвольной записи файла с указанием ее ключа. Системные вызовы для чтения записи имеют вид:

    keyRead (handle, key, vAdd)
    keyWrite (handle, key, vAdd) 

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

Файлы комбинированного доступа допускают как прямой доступ по ключу (keyRead/keyWrite), так и последовательный (read/write) в порядке возрастания ключей. Системный вызов, например, для чтения по ключу 'Коваль' обеспечит считывание записи, относящейся к сотруднику Ковалю, последующие системные вызовы последовательного чтения будут считывать записи, относящиеся к сотрудникам, следующим за Ковалем в принятом (например, в алфавитном) порядке.

Какой организации отдать предпочтение - байт- или записеориентированной? Как мы уже отмечали, байториентированная организация гибче, но при ней задача структурирования файла перекладывается на приложения - а задача эта не всегда простая. Фирма IBM, не желая с одной стороны отказываться от преимуществ записеориентированной организации, а с другой - желая обеспечить совместимость своих ОС со стандартами, обеспечивает поддержку обеих структур, и такое решение представляется нам оптимальным.

Интересной, хотя пока несколько экзотической формой являются файлы отображаемого доступа. Такие файлы при открытии отображаются в виртуальное адресное пространство процесса. Операция open может возвращать дескриптор сегмента в виртуальной памяти, и в дальнейшем все манипулирование с данными файла будет выполняться, как манипулирование с данными в памяти. Хотя такое решение является весьма элегантным, его реализация требует значительного расширения разрядности представления виртуального адреса и реализуется пока только в 64-разрядных клонах Unix.

7.3. Логическая файловая система. Каталоги

Логическая ФС рассматривает файл, как единицу хранения. Удачным нам представляется сравнение логической ФС с библиотекарем, который не должен знать содержание книги (файла), но обязан уметь быстро найти требуемую книгу в книгохранилище. Как бы продолжая это сравнение, файловые справочники ОС носят названия каталогов (catalog) или оглавлений (directory).

Файловые справочники - и это естественно - располагаются на тех же носителях, что и файлы данных. Первоначально с каждой единицей сменного носителя (пакет магнитных дисков, бобина магнитной ленты) жестко связывался свой единственный справочник и смена носителя вызывала смену справочника. Такая единица сменного носителя получила название тома (volume). Дальнейшее развитие вычислительных систем привело, с одной стороны, к увеличению объемов несменяемых носителей, так что несколько их единиц могут составлять один том, с другой, - к практике разбиения одного физического носителя на несколько логических томов. Таким образом, мы определяем том, как часть внешней памяти вычислительной системы, имеющую собственный справочник. Ниже мы рассмотрим вначале логическую структуру хранения файлов на отдельном томе, а затем - интеграцию томов.

Элемент каталога содержит, как минимум, символьное имя файла и адрес его дескриптора, иногда дескриптор файла может непосредственно входить в элемент каталога.

Прежде, чем переходить к структурам каталогов, остановимся на именовании файлов. Каждый файл имеет символьное имя, которое позволяет пользователю обращаться к данному конкретному файлу. Каждая ОС устанавливает собственные соглашения о формировании имен. Как правило, эти соглашения допускают или даже требуют разделения имени файла на составные части - компоненты. При записи символьного имени его компоненты обычно разделяются точкой. Разные ОС накладывают разные ограничения на количество и длины компонент имени - от двухкомпонентных имен с компонентами ограниченной длины до неограниченного их числа и практически неограниченной длины. Некоторые ОС резервируют одну из составляющих имени файла в качестве описателя типа информации, хранящейся в файле. Даже если ОС не предъявляет дополнительных требований к именованию, пользователи применяют составные имена файлов, как средство структурирования хранения своей информации. Для ОС, работающих с многокомпонентными именами, распространенной является практика применения "символа-джокера", обычно - "*" или "&". Употребление джокера вместо одной из компонент имени обеспечивает выполнение системных вызовов, адресованных логической ФС, как групповых операций - над всеми файлами с любыми значениями этой составляющей имени.

Каталоги файлов выполняют две функции: обеспечивают поиск файлов и структурирование хранения информации.

Простейшей структурой каталога является плоский (flat) каталог. Информация обо всех файлах сведена в одну таблицу, и поиск файла сводится к поиску в этой таблице - линейному или двоичному, если таблица упорядочена. Такая структура каталога не допускает, чтобы файлы имели одинаковые имена. Плоская структура не выполняет второй функции каталога - структурирования хранения и может быть эффективной только для ОС, работающих с томами носителей небольшого объема, когда том содержит файлы, принадлежащие одному пользователю. Если том содержит файлы, принадлежащие разным пользователям, то возможны конфликты имен - назначение разными пользователями одинаковых имен для своих файлов. Даже если такие конфликты предотвращаются (за счет многокомпонентных имен), то остается существенный недостаток: каталог открыт для чтения всем пользователям, а в некоторых случаях даже список имен файлов пользователя может быть его конфиденциальной информацией.

Простейшим решением разделения файлов между пользователями (или по другим признакам) является двухуровневая структура каталога. В этой структуре каждый пользователь имеет собственный каталог. Каталог именуется по правилам именования файлов, его имя также может быть составным. В такой структуре возникают понятия полного и локального имен файла. Полное имя файла состоит из имени каталога и имени файла в каталоге. Обычно эти имена разделяются наклонной чертой "\" или "/". Вторая часть полного имени является локальным именем файла. На томе не может быть двух файлов, имеющих одинаковые полные имена, но файлы с одинаковыми локальными именами могут находиться в разных каталогах. Для сокращения именования файлов процесс может сообщить ОС устанавливаемое по умолчанию имя каталога. Каталог, имя которого устанавливается по умолчанию называется рабочим или текущим. К файлам в текущем каталоге процесс может обращаться по локальным именам, к файлам в других каталогах - только по полным именам.

Нетрудно распространить двух- или трехуровневую структуру каталога на произвольное число уровней - каталог приобретает древовидную или иерархическую структуру. Пример такой структуры показан на Рисунке 7.2. Иерархическая структура каталогов практически исключает возможность конфликта имен. Полное имя файла складывается из перечисления через "/" всего пути (path) от корневого каталога, имеющего имя "/", до данного файла, например:

    /system/utility/disks/anti/test1


Рис.7.2. Пример иерархической структуры каталогов

Иерархические каталоги хорошо известны пользователям MS DOS, поэтому мы будем останавливаться прежде всего на тех их свойствах, которые в этой системе неизвестны или непопулярны.

Обычно в каждый узел древовидной структуры включается запись о каталоге, являющемся по отношению к данному родительским. В такой записи имя каталога-родителя обозначается каким-либо специальным символом или комбинацией символов, например: "..". Это позволяет обращаться к файлам в другом каталоге, задавая путь с отправной точкой либо из корневого каталога, либо из текущего (рабочего). Так, если рабочим является каталог /users/ivanov (рис.7.2), то возможно обращение:

    ../../petrov/pgm3.c

В каталог также включается запись о нем самом, обычно обозначаемая, как ".". Если рабочим является каталог /system/utility (рис.7.2), то возможно обращение:

    ./disks/anti/test.1

Древовидный каталог является элегантной и в большинстве случаев удобной структурой, но в некоторых случаях может быть полезно внести в идеальную древовидную структуру некоторые нарушения. Но прежде, чем обсуждать такие нарушения, рассмотрим вопрос о составе элемента каталога.

Каждый элемент каталога описывает файл или подкаталог (subdirectory). С точки зрения ниже лежащих уровней ФС подкаталог является таким же файлом, как и файлы пользователей. Выше мы уже говорили о том, что элемент каталога содержит символьное имя файла или подкаталога и указатель на файловый дескриптор. Вся остальная информация о файле содержится в дескрипторе файла. В некоторых системах сам файловый дескриптор также входит в состав элемента каталога. Но хранение дескриптора файла отдельно от каталога логически вытекает из иерархической структуры ФС, поскольку поиск файла (работа с каталогами) и обработка файла (работа с дескриптором) выполняются разными уровнями ФС. Дескрипторы файлов могут храниться вместе с данными файлов или в специально отведенной области. Раздельное хранение каталогов и дескрипторов обеспечивает ряд дополнительных возможностей в логической ФС, первая из которых - алиасы.

Алиасами (alias) или жесткими связями (hard link), или просто связями (link) называются элементы каталогов, указывающие на один и тот же файловый дескриптор. Алиасы могут находиться в одном том же подкаталоге, в этом случае альтернативные имена обязательно должны быть разными, или в разных подкаталогах, тогда имена могут быть одинаковыми. Два разных элемента каталога, таким образом, указывают на один и тот же физический файл. Если при обращении к файлу по одному из альтернативных имен в данных файла были сделаны изменения, то при чтении файла по другому имени эти изменения будут найдены в файле. Как правило, алиасы создаются для того, чтобы включить в рабочий каталог пользователя файлы, находящиеся в других каталогах, но часто используемые данным пользователем. Например, если обычным рабочим каталогом для нас является /user/petrov, но нам часто приходится обращаться к файлу /system/tools/c, то удобно создать для этого файла альтернативный элемент каталога /user/petrov/c, это позволит нам в дальнейшем обращаться к этому файлу из нашего рабочего каталога по локальному имени. Алиас для рассмотренного примера показан на Рисунке 7.3.а. Отметим, что если для файла создан алиас, то оба альтернативных имен файла - старое и новое - являются равноправными. Нельзя говорить, что файл принадлежит к тому каталогу, в котором он был создан, и только присоединен к другому каталогу - файл в равной степени принадлежит обоим каталогам. При удалении файла по одному из альтернативных имен удаляется только соответствующий элемент в каталоге, физический же файл (и его дескриптор) продолжает существовать, он будет уничтожен, когда будет удалена последняя ссылка на него.



а). алиас



б). косвенный файл
Рис.7.3. Альтернативное имя для файла

Косвенным файлом (indirect file) или символьной связью (symbolic link), или мягкой связью (soft link) называется элемент каталога, который ссылается на другой элемент каталога. Ссылка производится обычно путем указания полного символьного имени каталога. Физически символьные связи представляются файлами специального типа, содержащими ссылки. Так, в приведенном выше примере элемент каталога /users/petrov/c может содержать адрес дескриптора файла со ссылкой "/system/tools/c". Такой косвенный файл показан на Рисунке 7.3.б. При обращении к файлу по имени "/users/petrov/c" ФС в процессе поиска, дойдя до этого места, продолжит поиск по пути, который указан в ссылке. Нетрудно обеспечить и многоуровневые символьные связи. Подобно косвенным файлам, могут быть и косвенные каталоги. Принципиальное отличие косвенных файлов от алиасов - в том, что имена косвенных файлов имеют неравные права с основным именем. Только один элемент каталога (основной) ссылается на физический файл, остальные же - на элемент каталога. Поэтому удаление физического файла возможно только по основному имени, удаления же по косвенным именам удаляют только элементы каталогов. Если файл удален по основному имени, то косвенные ссылки на него, как правило, остаются в каталогах и обращения по косвенным именам приведут к ошибкам. Задача чистки каталогов от неактуальных косвенных имен может возлагаться либо на пользователей - владельцев каталогов, либо на администратора системы, в распоряжении которого должны быть соответствующие утилиты.

Раздельное хранение каталогов и дескрипторов предоставляет, как мы показали, дополнительные возможности, но и создает почву для возникновения дополнительных ошибок - "беспризорных" файлов, то есть файлов, на которые нет ссылок ни в каком каталоге. В распоряжении системного администратора должны быть утилиты, позволяющие исправлять такие ошибки (как, например, fsck и fsdb в Unix).

Внешняя память вычислительной системы может состоять из нескольких томов, каждый из которых имеет свой каталог. Если компьютер работает в составе сети, то в его пространство внешней памяти могут также включаться тома, расположенные в других узлах сети. В персональных системах пользователь при начале работы автоматически получает доступ ко всем наличным томам. В многопользовательской системе пользователю предоставляется только один определенный том (или несколько томов), а остальные должны быть подключены (mount - монтированы) пользователем явным образом. При работе с несколькими томами структура хранения информации может представлять собой "лес" или "дерево". В первом случае каждый том представляется, как отдельное дерево каталогов и полное имя файла включает в себя имя тома (OS/2, Windows, CMS). Во втором случае новый том подключается к основному и выглядит, как ветвь в общем дереве каталогов (Unix, OS/400). Если каталоги всех томов имеют одинаковую логическую структуру (а стандартной является структура иерархическая), то в одно дерево могут быть объединены даже тома, имеющие различную физическую структуру. С логической точки зрения нет разницы в том, находится ли монтируемый том на этом же компьютере или в другом узле сети. Кроме того, операция монтирования может быть реализована таким образом, чтобы давать пользователю доступ не ко всему тому (к корневому каталогу), а только к одной его ветви его дерева каталогов.

7.4. Логическая файловая система. Системные вызовы

В API ФС зачастую трудно установить, к какой части ФС адресован тот или иной системный вызов, так как большинство вызовов проходят обработку на всех уровнях ФС. Тем не менее, большинство системных вызовов мы рассматриваем именно вместе с логической ФС, так как существенной составляющей этих вызовов является именно работа с каталогами. Не следует, однако, забывать, что даже, если функции вызова ограничиваются только работой с каталогом, для его выполнения тоже требуется обращение к нижним уровням иерархии ФС, так как каталог - это тоже файл, который имеет свою физическую структуру и который тоже надо читать и записывать.

Для рассмотрения мы разобьем все системные вызовы на следующие группы:

Вызовы, работающие с каталогами.

Установить рабочий (текущий) каталог:

    setCurrentDirectory(dirName) 

При помощи этого вызова процесс сообщает ОС, какой каталог является для него рабочим. В дальнейшем допустимы обращения к файлам в этом каталоге по локальным именам. В ходе своего выполнения процесс может неоднократно менять свой рабочий каталог. Имя каталога dirName задается в виде символьной строки, содержащей путь, отправной точкой которого может быть либо корневой каталог, либо - текущий. Логическая ФС (совместно с нижними уровнями ФС) обеспечивает движение по этому пути. В API ОС может быть включен также информационный вызов getCurrentDirectory, возвращающий полное имя текущего каталога.

Создать подкаталог:

    createDirectory(dirName) 

При помощи этого вызова процесс может создать новый подкаталог. Обычно имя каталога dirName задается локальным и новый подкаталог создается в текущем каталоге, но может быть допущено и задание полного имени. Этот вызов может рассматриваться как специальный случай вызова createFile.

Удалить подкаталог:

    removeDirectory(dirName) 

Конструктор ОС должен особо определить реакцию системы на применение этого вызова к непустому каталогу - то ли завершать в этом случае вызов с ошибкой, то ли удалять каталог со всем его содержимым.

Вызовы, работающие с файлами.

Создать файл:

    createFile(fileName, parameters) 

Вызов создает новый физический файл в текущем каталоге, если имя задано в локальной форме, или в другом, если задано полное имя. Другие параметры - parameters - задают атрибуты, заносимые в дескриптор создаваемого файла.

Создать алиас:

    createAlias(fileName, aliaseName) 

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

Создать косвенный файл:

    createIndirect(fileName, indirectName) 

Вызов создает новый элемент каталога, ссылающийся на старый элемент каталога.

Удалить файл:

    deleteFile(fileName) 

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

Переместить файл:

    moveFile(oldName, newName ) 

Вызов перемещает файл в другой каталог. Одно из имен может быть локальным (то есть, исходный или целевой каталог может быть текущим), другое - обязательно должно быть полным. Данная операция не требует перемещения физического файла или его дескриптора, а только элемента каталога. Вызов может быть реализован, как комбинация двух вызовов, описанных выше: createAlias - в новом каталоге и deleteFile - в старом. Как частный случай этого вызова может рассматриваться вызов renameFile - переименовать файл - но в целях повышения эффективности его реализация может быть выполнена путем исправления данных в элементе каталога, остающемся на том же месте.

Копировать файл:

    copyFile(oldName, newName ) 

Вызов копирует файл в другой каталог или в тот же каталог под новым именем. В отличие от вызова moveFile, копируется физический файл - данные файла и файловый дескриптор, а для копии создается новый элемент каталога. Далее старый файл и копия существуют независимо друг от друга.

Вызовы, работающие с томами.

Монтировать том:

    mount(entrName, extName) 

Вызов подключает к ФС новый том. entrName задает идентификацию тома в ФС - это логическое имя тома или имя подкаталога, которым представляется том в едином дереве каталогов. extName идентифицирует том вне ФС - это может быть адрес устройства, на котором том установлен, сетевой адрес узла при удаленном доступе и т.п.

Снять том:

    unMount (entrName ) 

Вызов отключает от ФС ранее монтированный том.

7.5. Базовая файловая система.

Дескриптор файла

Выше мы уже неоднократно упоминали дескриптор файла, и читатель, наверное, уже сделал правильный вывод о том, что эта структура данных является ключевой при переводе виртуального представления файла в реальное. Дескриптор однозначно связан с физическим файлом, но храниться может как вместе с файлом, так и отдельно от него. В любом случае, однако, дескриптор файла является прозрачным для процессов пользователей, он обрабатывается только ОС. Дескриптор содержит информацию о физической природе файла и информацию о его использовании и защите. Естественно, что формат дескриптора определяется спецификациями конкретной ОС, и мы можем дать только приблизительное перечисление его полей. В общем случае в дескриптор файла могут входить следующие составляющие:

Некоторые из входящих в состав дескриптора подструктуры данных мы рассмотрим ниже более подробно. В основном содержимое дескриптора формируется при создании файла или каталога (системные вызовы createFile, createDirectory ), некоторые поля изменяются при работе с файлом. Предоставляем читателю самому проследить, как системные вызовы, описанные выше, работают с дескрипторами файлов/каталогов.

Наиболее важным для дескриптора файла является системный вызов open , он производит активизацию дескриптора. Для файлов на устройствах внешней памяти при этом производится считывание дескриптора в оперативную память и построение его расширения, называемого дескриптором открытого файла. Для устройств, представляемых в виде виртуальных файлов, файловых дескрипторов на внешней памяти не существует, но в оперативной памяти открытие такого виртуального файла вызывает построение дескриптора открытого файла, отличающегося от дескриптора открытого файла на внешней памяти, как правило, содержимым полей, но не их форматом. Для каталогов системный вызов open не выполняется явным образом, но при выполнении функций поиска по заданному пути в логической ФС активизируются дескрипторы всех каталогов, входящих в путь.

В расширение дескриптора открытого файла в оперативной памяти могут входить:

Так, например, при подключении тома к ФС в виде ветви общего дерева каталогов, в памяти создается дескриптор для псевдокаталога, которым представлен подключенный том. Этот дескриптор содержит признак, описывающий его, как "точку монтирования", и ссылку на элемент специальной системной таблицы монтирования. Элемент же таблицы содержит описание тома и указатели как на корневой каталог тома, так и обратно - на "точку монтирования", что позволяет проходить эту точку при движении по дереву в обоих направлениях.

Очевидно, что некоторые поля дескриптора должны изменяться автоматически при работе с файлом. Все изменения, выполненные в дескрипторе в ходе работы с открытым файлом, запоминаются в его копии на внешней памяти при выполнении системного вызова close .

Обычно ОС предоставляют также в составе своего API тот или иной набор системных вызовов, сводящихся к двум типам: getFileInfo, setFileInfo - получить или установить информацию о файле. Выполнение вызовов этой группы позволяет прочитать/записать значения отдельных полей файловых дескрипторов.

Управление доступом

В некоторых ОС одной из важнейших функций базовой ФС является контроль за доступом пользователей к файлам. Мы говорим "в некоторых", так как в ряде ОС проблема контроля доступа решается на общесистемном уровне, и доступ к файлам - ее частный случай. Такие ОС рассматриваются нами в главе 10, здесь же мы остановимся на случае, когда доступ к файлам контролируется базовой ФС, и рассмотрим его на примере ОС Unix.

В Unix возможны следующие режимы доступа к файлам: r - чтение, w - запись, x - выполнение. Возможны также их комбинации.

Пользователи подразделяются на следующие категории:

Для каждого файла определяется допустимый режим доступа для каждой из этих трех групп. Так, например, если для файла доступ закодирован в виде:

    rwxr-x--x, 

то это означает, что владелец имеет право читать, писать и выполнять файл (rwx), остальные члены группы владельца имеют право читать и выполнять файл (r-x), все другие пользователи - только выполнять (--x).

Идентификаторы владельца и группы владельца входят в состав файлового дескриптора. Для кодировки прав доступа достаточно трех 3-битных позиционных кодов, которые также включаются в дескриптор.

Каждая активизация файлового дескриптора базовой ФС включает в себя проверку прав доступа. В ходе проверки определяется идентификатор владельца процесса, открывающего файл. Этот идентификатор сравнивается с идентификатором владельца файла и с идентификатором группы владельца файла. В зависимости от результатов сравнения определяется категория пользователя, открывающего файл и выбирается соответствующий 3-битный код доступа. Режим доступа, запрашиваемый при открытии, сравнивается с кодом доступа, и при несоответствии их происходит отказ в доступе.

Как мы отмечали выше, с точки зрения базовой ФС каталоги практически ничем не отличаются от файлов, следовательно, все, что говорилось выше о правах доступа, относится и к каталогам.

Поскольку логическая ФС при поиске обращается к базовой ФС для чтения информации из каталогов, а базовая ФС производит при этом проверку прав доступа, то файл может быть доступен для данного пользователя только, если для него доступны все подкаталоги, входящие в путь к файлу.

Как определяется доступ к алиасам и косвенным файлам? Что касается алиасов, то ответ зависит от того, связываются ли права доступа с именем или с файлом. До сих пор мы говорили о том, что права доступа хранятся в файловом дескрипторе, поскольку физическому файлу соответствует единственный файловый дескриптор, права доступа к файлу по всем алиасам будут одинаковы. Возможно, однако, хранение прав доступа не в дескрипторе, а в элементе каталога, в этом случае разные алиасы могут обеспечивать разные права доступа к одному файлу. Возможны два варианта реализации прав доступа к косвенному файлу. В первом варианте в псевдодескрипторе, содержащем ссылку указываются права доступа, как для обычного файла, при соответствии конкретного режима доступа этим правам проверка прав доступа заканчивается. Во втором случае проверка прав доступа продолжается и для всех каталогов, входящих в путь, указанный в ссылке.

7.6. Физическая структура файлов

До этого уровня ФС оперировала с виртуальными адресами в файле - относительными номерами байт или записей. Уровень физической структуры выполняет перевод реальных адресов в физические адреса на носителе. На этот уровень ложатся все задачи, связанные с управлением распределением реальной внешней памяти. Внешняя память может включать в себя как устройства произвольного доступа (в дальнейшем - диски), так и устройства последовательного доступа (в дальнейшем - ленты). Мы сосредоточимся здесь только на дисковой памяти, имея в виду то обстоятельство, что задачи управления памятью на лентах составляют лишь узкое подмножество задач, возникающих при управлении дисками.

Несколько принципиально важных положений являются общими для любых способов управления дисковой памятью.

  1. Дисковая память состоит из блоков, являющихся единицами распределения дискового пространства (например, секторов). Каждый блок имеет уникальный номер (адрес), его идентифицирующий. В каждый блок может быть записана любая информация достаточно сложной структуры, в том числе, и содержащая ссылки на другие блоки.
  2. Каждый физический диск описывается дескриптором диска, который содержит информацию о количестве и размере блоков на диске и о свободном пространстве на диске. Дисковый дескриптор записывается на известное заранее место на диске (чаще всего - в первый блок).
  3. Каждый файл в составе своего дескриптора имеет план своего размещения (layuot) на физическом пространстве диска.
  4. Информация, записываемая на диск, может быть избыточной для обеспечения возможности ее восстановления при сбоях.
  5. Дисковое пространство распределяется блоками фиксированной длины. Даже в тех дисковых архитектурах, которые допускают чтение/запись блоками переменной длины, размер единицы распределения, как правило, все равно фиксирован, например, дорожка. Возможно объединение в единицу распределения нескольких смежных блоков, такой прием носит название кластеризации (clastering), а порции распределения, состоящие из нескольких блоков, называются кластерами. Кластеризация может быть как симметричной - с заранее установленным размером кластера, так и асимметричной - с размером кластера, выбираемым для каждого распределения.
  6. Поиск на диске управляющих структур ФС и свободных блоков может оказаться слишком времяемким. Поэтому те управляющие структуры, обращение к которым происходит наиболее часто, обычно копируются в оперативную память. Это создает дополнительные проблемы, связанные с надежностью функционирования ОС. При крахе системы изменения в управляющих структурах могут не быть перенесены из кеша на внешнюю память. Специальные системные процессы ОС обычно обеспечивают периодическое сохранение управляющих структур на внешней памяти.

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

Распределение дисковой памяти может быть классифицировано как смежное или не смежное. В первом случае файлу распределяется непрерывный участок внешней памяти, во втором - файл может быть разбросан по пространству диска. Смежное распределение весьма привлекательно по нескольким причинам. Во-первых, план размещения в этом случае получается простейшим: он состоит только из номера начального блока и количества блоков. Во-вторых, и это более важно, смежное размещение обеспечивает высокую степень локализации обращений к дорожкам при обработке файла и, следовательно, высокую эффективность обмена. Однако, и недостатки смежного распределения более чем серьезны. Во-первых, как и при распределении оперативной памяти блоками переменной длины, здесь возникают все проблемы фрагментации пространства памяти (внешних дыр). Во-вторых, такое распределение требует, чтобы необходимый размер дискового пространства указывался при создании файла - эта информация не всегда может быть предоставлена пользователем, создающим файл. В-третьих, расширение файла за пределы установленного размера невозможно - для файлов с длительным сроком существования эта проблема может стать критической. Перечисленные недостатки могут быть не радикально преодолены, но несколько сглажены, если допустить, чтобы файл занимал не один, а несколько участков дискового пространства. При создании такого файла задаются требования к размеру первичного и вторичного распределения. Файлу выделяется непрерывный участок памяти в соответствии с первичным размером. Если далее оказывается, что файл не помещается в первичный участок, ему выделяется дополнительный участок (экстент - extent), размер которого задается требованием ко вторичному распределению. Экстент занимает непрерывную область на диске, но необязательно смежную с первичным участком. Затем может быть выделен второй экстент и т.д. План файла в его дескрипторе в этом случае представляется массивом пар "начальный адрес - длина", каждый элемент которого соответствует одному экстенту. Размер этого массива в дескрипторе ограничивает допустимое число экстентов.

Очевидно, что смежное распределение является негибким. Это в первую очередь послужило причиной полного отказа от него в ОС Unix и в MS DOS. Однако, в связи с увеличением объемов дисковых накопителей вопросы повышения эффективности обмена приобретают все большее значение и локализация файлов является хорошим средством повышения этой эффективности. В последнее время наметилась тенденция к размещению файлов в смежных областях диска, пусть даже и в рамках несмежной модели распределения (см., например описание ФС HPFS, NTFS, Veritas, JFS в Части II).

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

Несмежное распределение допускает, чтобы файл состоял из большого числа участков (отдельных блоков), и план файла должен описывать размещение каждого из блоков файла. Можно выделить три основных подхода к представлению плана файла в несмежной модели:

Метод списков блоков предполагает, что в файловом дескрипторе содержится только указатель на первый выделенный файлу блок. В самом блоке на фиксированном месте содержится указатель на второй блок, во втором - на третий и т.д. Таким образом, блоки выстраиваются в односвязный линейный список. С учетом того, что список располагается на внешней памяти, этот метод может применяться только для файлов с последовательным доступом.

Метод карты размещения хорошо известен программистам в MS DOS по Таблице размещения файлов FAT. ФС для каждого диска поддерживает таблицу, каждая строка которой описывает один блок на диске. В списки связываются не сами блоки, а соответствующие им элементы карты. Карта размещения обеспечивает достаточно простой и эффективный метод управления распределением, но сосредоточение информации о размещении всех файлов в одной структуре данных делает эту структуру узким местом ФС с точки зрения безопасности.

Метод списков указателей на блоки предполагает, наличие для каждого файла перечня номеров блоков, ему распределенных. Этот перечень записывается в отдельный блок, специально выделяемый для этой цели, а файловый дескриптор содержит указатель на этот блок. Если в блоке не хватает места для всего перечня, то последний в нем номер адресует блок, содержащий продолжение перечня и т.д. При применении этого метода "в чистом виде" список блоков, как всякий линейный список, может обрабатываться только последовательно, поэтому доступ в блокам файла, имеющим большие виртуальные номера может быть значительно замедлен. Поэтому на практике применяются различные модификации этого метода. Классическим примером такого подхода является ФС s5 первых версий ОС Unix.

Учет дискового пространства, выделенного файлу (план размещения), ведется в s5 следующим образом. Как показали исследования, на любом носителе всегда есть большое число файлов, объем которых не превышает 1 Кбайт. Для таких файлов нет никакой необходимости выделять отдельные блоки для размещения плана, а тем более - увязывать эти блоки в какие-либо списки. Поэтому непосредственно в файловом дескрипторе содержится массив из 10 номеров первых блоков файла. При размере блока 512 байт первые 5 Кбайт файла адресуются непосредственно из файлового дескриптора. Одиннадцатый элемент этого массива содержит адрес блока, в котором записано еще 128 номеров следующих блоков файла. Таким образом, доступ к следующим 64 Кбайтам файла производится путем косвенной адресации из дескриптора через этот блок адресов. Двенадцатый элемент содержит адрес блока, в котором записано еще 128 номеров блоков, каждый из которых адресует еще 128 блоков данных файла - это обеспечивает доступ к следующим 8 Мбайтам путем двухуровневой косвенной адресации. Наконец, тринадцатый элемент массива в дескрипторе обеспечивает доступ через трехуровневую косвенную адресацию еще к 2 Гбайтам файла. Структура плана размещения показана на Рисунке 7.4.


Рис.7.4. Размещение файла в файловой системе s5

Другой аспект распределения дисковой памяти - учет свободного пространства на диске. Как и для учета размещения файлов, здесь применяются либо карта дискового пространства, либо списки свободных блоков.

В случае, если размещение файлов отслеживается картой размещения, на этой же карте могут быть отображены и свободные блоки. Если же используются различные механизмы отслеживания размещения и учета свободного пространства, то карта свободной памяти может состоять из однобитовых элементов со значением 0 - свободен, 1 - занят. Поиск свободного участка заданного размера сводится к поиску в карте цепочки нулевых бит заданной длины. Если для системы имеет значение выделение дисковой памяти непрерывными участками, то состояние дискового пространства может отображаться в двух или более картах разного "масштаба". Наряду с обязательной картой свободных блоков, самой "мелкомасштабной", может существовать карта свободных дорожек и карта свободных цилиндров. Наличие "крупномасштабных" карт позволяет ускорить поиск больших непрерывных свободных участков.

Списки свободных блоков организуются точно так же, как и списки блоков, принадлежащих файлу. Дескриптор диска содержит указатель на начало списка свободных блоков. Последовательная природа списка не оказывает влияния на эффективность его обработки, так как список свободных блоков может обрабатываться по дисциплине LIFO - выборка блока происходит из начала списка, и новый свободный блок также добавляется в начало списка. Изящный пример работы со свободными блоками показывает та же ФС s5, пример относится к категории "ленивых политик", свойственных этой ОС Unix.

В дескрипторе диска s5 (суперблоке) содержится массив из 10 номеров свободных блоков. Поскольку суперблок в процессе работы хранится в оперативной памяти, первые 10 свободных блоков могут быть выбраны без обращений к внешней памяти. Если этот "запас" свободных блоков исчерпан, то используется последний элемент этого массива, который ссылается на свободный блок, содержащий еще 10 номеров свободных блоков. Эти новые номера заново заполняют массив в суперблоке и т.д. При необходимости включить в список новые свободные блоки их номера сохраняются в массиве суперблока, пока в нем есть свободные места. Если же свободные места исчерпаны, массив выводится в блок на внешней памяти, добавдяемый в список, а место в суперблоке освобождается.

7.7. Пример

Мы описали работу каждого уровня ФС по отдельности. Их совместное функционирование будет удобнее всего разобрать на конкретном примере. Рассмотрим такую программу:

1 main() { 
2   filehandler xfile; 
3   xfile = open ("/ivanow/work/testfile.tst", WR_ONLY); 
4   seek (xfile,1000); 
5   write (xfile,"Example",7); 
6   close (xfile); 
7 } 

Введенный нами тип данных главе filehandler предназначен для представления манипулятора файла.

Далее мы рассматриваем выполнение программы по шагам, причем, в идентификации шагов первая цифра - собственно номер шага, а вторая - номер строки исходного текста.

Шаг 1.3. Системный вызов open переключает контекст с процесса на ядро ОС. ОС передает этот вызов подсистеме логической организации, а та после соответствующих проверок - логической ФС.

Шаг 2.3. Логическая ФС начинает поиск файла по указанному пути, для чего выполняет синтаксический разбор строки имени файла. Поиск начинается с каталога "/" - корневого. Указатель на дескриптор корневого каталога у логической ФС уже имеется: дескриптор корневого каталога может находиться на фиксированном месте на диске ли же указатель на него может храниться в дескрипторе диска и считываться в память вместе с дескриптором диска. (Также логическая ФС постоянно имеет в своем распоряжении и указатель на дескриптор рабочего каталога, так как поиск может начинаться и с него. Первоначально этот указатель указывает на дескриптор корневого каталога, а затем изменяется системными вызовами setCurrentDirectory). Теперь логическая ФС обращается к базовой ФС с запросом на активизацию дескриптора корневого каталога.

Шаг 3.3. Базовая ФС передает на следующие уровни адрес дескриптора корневого каталога. На уровне СУВВ проверяется, не считан ли уже блок, содержащий этот дескриптор в буферную память. Для корневого каталога весьма велика вероятность того, что блок, содержащий его дескриптор уже есть в памяти. Если это так, то СУВВ выбирает из кеша буфер, содержащий требуемый дескриптор. Если же такого буфера в кеше нет, то СУВВ находит в кеше свободный буфер, если нет и свободного буфера, освобождает буфер, используя для выбора, например, дисциплину LRU. Затем СУВВ формирует запрос на ввод и ставит его в очередь. На время выполнения обмена процесс, выдавший вызов, блокируется. Когда прерывание от устройства сигнализирует об окончании ввода, процесс продолжает выполнение на нижнем уровне иерархии ФС. Происходит возврат из СУВВ в верхние уровни и базовая ФС получает дескриптор корневого каталога.

Заметим, что в некоторых случаях здесь может происходить две операции обмена и две блокировки процесса. Если СУВВ выбирает в кеше буфер для освобождения, а этот буфер "грязный", то сначала содержимое этого буфера выводится на диск, а уже затем в него вводится блок.

Шаг 4.3. Базовая ФС проверяет права доступа, находит свободное место в системной таблице открытых файлов и формирует в последней дескриптор открытого файла для корневого каталога. Режим открытия в этом дескрипторе устанавливается RD_ONLY, позиция файлового курсора - 0.

Шаг 5.3. Логическая ФС далее формирует запрос на чтение первого элемента каталога. Допустим, что элемент каталога состоит из 16-байтного имени и 4-байтного адреса. Базовая ФС получает, таким образом, запрос на 20 байт. Она передает на следующий нижний уровень дескриптор открытого файла и счетчик. Система физической организации по плану размещения файла и позиции файлового курсора определяет физической адрес блока, в котором находится требуемая информация, и передает запрос СУВВ. (Это определение может потребовать обращений к СУВВ для чтения информации о размещении файла).

Шаг 6.3. СУВВ находит требуемый блок в кеше или организует его ввод с диска (на время обмена процесс блокируется) и возвращает адрес буфера. Система физической организации выделяет из буфера нужные 20 байт и они возвращаются базовой ФС и далее - логической ФС. Базовая ФС увеличивает на 20 позицию файлового курсора.

В некоторых случаях для выполнения одного запроса система физической организации может формировать два и более запросов к СУВВ - если требуемая информация переходит из блока в блок.

Шаг 7.3. Логическая ФС сравнивает поле имени в полученном элементе каталога с первой составляющей строки поиска - ivanov. Скорее всего, результат сравнения в первый раз будет отрицательным. Если имя не совпадает, логическая ФС формирует запрос на чтение следующего элемента каталога и повторяются шаги 5, 6 и 7. Поскольку файловый курсор модифицирован, будут читаться следующие 20 байт и, скорее всего, СУВВ найдет их уже в кеше.

Шаг 8.3. Когда элемент с именем ivanov будет найден, логическая ФС дает команды базовой ФС освободить дескриптор открытого файла для корневого каталога и открыть подкаталог ivanov. Указатель на дескриптор подкаталога уже выбран логической ФС, далее открытие подкаталога происходит по тому же сценарию, что и корневого каталога.

Шаг 9.3. Когда наконец активизируется файловый дескриптор для последней составляющей пути - файла testfile.tst, режим открытия устанавливается WR_ONLY. К этому моменту все каталоги, открывавшиеся в процессе поиска, уже закрыты. Указатель на элемент системной таблицы открытых файлов помещается в контекст процесса - в таблицу файлов процесса. Индекс элемента в этой таблице возвращается процессу в качестве манипулятора открытого файла и сохраняется в переменной xFile.

Шаг 10.4. Следующий системный вызов из программы - seek. По манипулятору файла ядро выбирает дескриптор открытого файла. Выполнение системного вызова ограничивается уровнем базовой ФС. Последняя устанавливает файловый курсор в позицию 1000, определяемую параметром вызова. Если это определяется спецификациями ФС, то позиция курсора сравнивается с размером файла и ограничивается этим размером. На более низкие уровни этот вызов не передается.

Шаг 11.5. Следующий системный вызов - write. По манипулятору выбирается дескриптор открытого файла. Базовая ФС передает на следующий уровень запрос на запись. Подсистема физической структуры вычисляет номер блока, в который должна быть произведена запись. Последующие действия, выполняемые этой подсистемой, зависят от того, выделен уже файлу этот блок или нет. В первом случае формируется запрос для СУВВ на чтение этого блока, СУВВ читает блок или находит соответствующий буфер в кеше. Во втором случае подсистема физической структуры находит свободный блок на диске. (Поиск свободного блока может потребовать обращений к СУВВ для чтения информации о распределении свободного пространства.) СУВВ выделяет свободный буфер в кеше и связывает его с выделенным блоком. Подсистема физической структуры записывает на определенное место в буфер заданные 8 байт и формирует для СУВВ запрос на вывод блока. СУВВ пока только помечает буфер, как "грязный".

Шаг 12.6. При выполнении системного вызова close базовая ФС копирует часть дескриптора открытого файла на диск (обращаясь для этого к нижним уровням ФС) и освобождает его место в таблице открытых файлов. Дальнейшие действия ФС зависят от того, придерживается она "активной" или "ленивой" дисциплины. "Активная" ФС просматривает весь план размещения файла и формирует для СУВВ запросы на поиск в буферном кеше блоков, принадлежащих файлу. Если такие блоки найдены в кеше и они помечены, как "грязные", СУВВ выводит их на диск и снимает с них пометку. Таким образом, при закрытии файла все обновления его данных записываются на диск. "Ленивая" ФС оставляет "грязные" блоки файла в кеше. Эти блоки попадут на диск, когда потребуется освободить занятые ими буферы кеша.

7.8. Целостность данных и файловой системы

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

Избыточность, поддерживаемая программно, на уровне ОС, обеспечивается, как правило, только для особо важной системной информации: дескрипторов дисков и файлов, таблиц размещения, каталогов и т.п. При записи одной и той же информации в два разных блока на диске даже, если сбой произойдет во время записи, один из блоков будет содержать корректный вариант информации - то ли до ее изменения, то ли после. Избыточность может вноситься как простым дублированием управляющих структур данных, так и внесением избыточности в сами эти структуры. Так, в структуры данных, которые связываются в списки, часто вводятся дополнительные указатели, позволяющие получить доступ к одной и той же структуре данных разными путями. Причем, при штатной работе используется только один путь, а остальные могут быть использованы для восстановления списка при нарушении указателей основного пути. Например, если сделать список свободных блоков на диске двунаправленным, то по обратным прошивкам можно восстановить этот список при потере указателя на его начало в дескрипторе диска. Другой пример: алгоритмы функционирования логической и базовой ФС не нуждаются в том, чтобы имя файла, имеющееся в элементе каталога, дублировалось в дескрипторе файла. Однако, такое дублирование чрезвычайно облегчит задачу восстановления доступа к файлам при разрушении системы каталогов.

Начнем с того, что весьма часто нарушение целостности происходит по вине пользователя - ошибочное удаление файлов или внесение в них неправильных изменений. Профилактикой этих ошибок является создание обратных копий (backup) файлов, к которым можно вернуться, если испорчена или уничтожена текущая копия. Концепция обратных копий может быть расширена до сохранения нескольких поколений версий файлов: при изменении файла создается его новая версия, а старая версия сохраняется. Создание новых версий может производиться разными способами:

Множественность версий может быть прозрачна для пользователя: все версии могут иметь одинаковое имя. Один элемент каталога может содержать массив ссылок на дескрипторы разных версий, или дескрипторы версий могут быть увязаны в список. Естественно, что по умолчанию всегда выбирается последняя версия и только специальным системным вызовом обеспечивается возврат к предыдущим версиям. Количество сохраняемых версий должно ограничиваться: это может быть либо общее для всех файлов ограничение, либо устанавливаемое индивидуально для каждого файла. При превышении числом версий файла установленного предела ОС автоматически выполняет удаление самой старой версии.

Профилактикой случайного удаления файла может быть неполное удаление. Такое удаление предполагает сохранение физического файла на диске, а следовательно, и возможность его последующего восстановления. Элемент каталога, соответствующий не полностью удаленному файлу, может помечаться специальным признаком или файл может переноситься в специальный каталог для удаленных файлов. Такой подход должен обеспечиваться двумя системными вызовами - deleteFile для неполного удаления и purgeFile - для полного. Неполное удаление создает, однако, проблему дискового пространства: неполное удаление файла не освобождает места на диске. ОС может периодически проверять срок хранения не полностью удаленных файлов и физически удалять те из них, которые не были восстановлены за установленный срок, или же выполнять такую проверку только, когда дает о себе знать нехватка дискового пространства.

Средством, практически гарантирующим минимизацию потерь при порче информации, является восстановление по резервной копии. Без рекомендаций о сохранении копий своих файлов на дискетах не обходится ни одно руководство по работе на персональных компьютерах, но выполнение этих рекомендаций требует от пользователя некоторой самодисциплины, которая в массе пользователям персональных ЭВМ, увы, не свойственна. В любых неперсональных системах и при работе над любыми неперсональными проектами копирование информации является не возможностью по выбору, а необходимостью. Для хранения резервных копий применяются магнитные ленты - носители, отличающиеся большим временем доступа, но и большой емкостью и малой стоимостью. Отчасти забытые по времена "персонального бума", они сейчас опять восстанавливают свои позиции архивных носителей.

Схема копирования должна обеспечивать минимизацию времени поиска и восстановления информации как при локальных (в пределах одного или нескольких файлов) потерях, так и при полном разрушении структур ФС. Рекомендуемая схема включает в себя несколько уровней выгрузки (dump), обычно - три: полные, повторные и инкрементные выгрузки. Полная выгрузка выполняется редко (например, раз в год) и включает в себя все имеющиеся на диске файлы. Повторные выгрузки производятся несколько чаще (например, ежемесячно) в них включаются только файлы, изменившиеся со времени предыдущей повторной или полной выгрузки. Инкрементные выгрузки выполняются часто (ежедневно) и включают в себя файлы, изменившиеся со времени предыдущей инкрементной или повторной. Для возможности восстановления состояния информации на начало текущего дня при полном крахе системы необходимо сохранять:

В таком порядке и используются носители при выполнении восстановления.

Создание архивных копий должно выполняться системными утилитами, которые могут также вести учет архивированных файлов: поддерживать на внешней памяти (и сохранять на отдельных архивных носителях) таблицу файлов с указанием для каждого файла сведений о том, когда сделана его архивная копия, и на каком носителе она находится. Наличие такой таблицы позволяет выполнить быстрое восстановление при локальных сбоях.

При наличии аппаратной избыточности в дисковой памяти ФС может (как правило, в качестве дополнительной возможности) поддерживать правила чтения/записи, обеспечивающие отказоустойчивость и возможность восстановления информации, а также повышение быстродействия дискового ввода-вывода за счет параллельной работы двух и более дисков.. Эти правила известны как технологии RAID (Redundant array of inexpensive disks - избыточный массив недорогих дисков). Определены 5 уровней технологии RAID:


Рис.7.5. Технология RAID 5

Промышленное применение в настоящее время имеют технологии RAID 0, 1 и 5.

Резервное копирование и даже аппаратная избыточность позволяют уменьшить потери, но не избежать их полностью. В предыдущей главе мы упоминали о том, что все современные файловые системы используют кеширование дискового ввода-вывода, а, следовательно, в них возникает ситуация отложенной или ленивой записи (lazy write), когда данные, уже записанные процессом в файл, на самом деле находятся в буферной оперативной памяти. При сбое системы такие данные могут быть потеряны. Наиболее опасно то, что отложенной записи подвергаются не только данные, но и метаданные файловой системы - дескрипторы дисков и файлов, каталоги и т.п. При потере изменений в метаданных недоступными могут стать все данные на диске. Поэтому в тех ФС, к целостности которых предъявляются высокие требования, ведется протоколирование операций над метаданными - запись информации по повторению или откату операции над метаданными в файл протокола (log) или журнала (journal). При сбое системы восстановление или откат операций производится по журналу. Поскольку журнал также подвергается отложенной записи, периодически производится фиксация контрольной точки - принудительная запись журнала на диск. При сбое системы, таким образом, гарантируется восстановление до последней контрольной точки.

Причиной нарушения целостности может являться одновременный доступ к файлу двух и более процессов. Для предотвращения таких нарушений ОС накладывает "замки" (lock) на файлы: замок разделяемого доступа для файла, открытого для чтения, и замок монопольного доступа для файла, открытого для записи. Замок может входить в дескриптор открытого файла. Если новый замок конфликтует с замком, наложенным ранее начавшейся операцией, то новая операция должна быть заблокирована. Обычно ОС не поддерживает сложного управления синхронизацией операций, ограничиваясь замками файлов. Наиболее часто в ОС применяется, так называемая, двухфазная дисциплина, требующая, чтобы замок на файл накладывался при его открытии и снимался при его закрытии. Замыкаться могут не только файлы, но и целые диски или каталоги или наоборот - отдельные записи или байты файла. Задача обеспечения синхронизации является частным случаем задачи взаимного исключения, подробно рассматриваемой в главе 8.

Большинство ОС обеспечивает только разделение доступа к каждому отдельному файлу и восстановление целостности метаданных ФС, перепоручая управление сложными транзакциями и целостностью пользовательских данных промежуточному программному обеспечению - менеджерам транзакций (IBM CICS, MS Transaction Server и др.) и системам управления базами данных (Oracle, IBM DB2 и др.). В распоряжении процессов должны быть средства API для формирования структуры транзакций - системные вызовы или обращения к тому программному пакету, в среде которого функционирует процесс. Примером такого средства могут быть предложения языка SQL: COMMIT (фиксация) и ROLLBACK (откат).

7.9. Загружаемая файловая система

Задачи переносимости программного обеспечения, в том числе, и системного, и функционирования программных изделий в среде распределенной обработки данных включают в себя требования к обеспечению единого пользовательского интерфейса различных ФС. Вытекающим отсюда следствием может быть совместное использование в одной операционной среде томов данных, обслуживаемых различными файловыми системами.

Иерархическая структура ФС дает возможность провести в иерархии уровней некоторую разграничительную линию, выше которой будут располагаться абстрактная ФС - структуры данных и алгоритмы, общие для любых ФС, а ниже - конкретная ФС со специфическими структурами и алгоритмами. Наиболее вероятно эта граница может проходить в базовой ФС, связывающей логическое представление файла с его физическим представлением. Такой подход был впервые применен в ОС Unix в связи с концепцией сетевых файловых систем. Проведение разграничительной линии на уровне базовой ФС вызывает расщепление дескриптора открытого файла на две части. Первая часть имеет общий для всех файлов формат и содержит общие для всех файлов поля, обработка которых не зависит от конкретной ФС. Это могут быть поля типа файла, размера, временные отметки и другие данные. Вторая часть - частный дескриптор - для конкретной ФС. В ней содержится план размещения файла, сведения об организации и т.д. Общая таблица томов в ядре указывает для каждого тома тип конкретной ФС, управляющей этим томом. Для каждого типа конкретной ФС ядро хранит таблицу операций - таблицу входных точек процедур, выполняющих для данной ФС стандартные функции (open, close, read и т.д.). При обращении к ФС абстрактная ФС, выполнив общие операции, определяет том и тип конкретной ФС на этом томе, выбирает соответствующую конкретной ФС таблицу входных точек и вызывает требуемую процедуру для конкретной ФС.

В системах с многоуровневыми драйверами драйвер ФС является одним из уровней, которые проходят данные на пути от процесса к устройству. При этом драйвер ФС не зависит не только от верхнего уровня - абстрактной ФС, но и от нижнего уровня - аппаратных драйверов.

Если конкретная ФС удовлетворяет спецификациям, диктуемым общей ФС, то конкретная ФС может быть загружаемой - включаемой в ядро при установке тома, управляемого конкретной ФС. Драйверы конкретной ФС могут даже и загружаться с этого же тома.

Контрольные вопросы

  1. Поясните различие между виртуальным и физическим файлом.
  2. Охарактеризуйте основные компоненты иерархической модели файловой системы. Какие преимущества дает иерархическая модель?
  3. В чем различие между байториентированными и записеориентированными файлами? Назовите достоинства и недостатки той и другой модели.
  4. В чем отличие логической структуры каталогов в MD DOS - Windows - OS/2 от структуры каталогов в Unix?
  5. В чем достоинства и недостатки отделения дескриптора файла от элемента каталога?
  6. Какую информацию о файле должен содержать его дескриптор, хранимый в файловой системе? Какую информацию должен содержать дескриптор открытого файла?
  7. В чем сходство и различие каталогов и файлов (на логическом и на физическом уровнях)?
  8. В чем сходство и различие алиасов и косвенных файлов?
  9. Обязательно ли закрытие файла при завершении открывшего его процесса? Обязательна ли запись данных файла на диск при закрытии файла?
  10. В чем отличие смежного размещения файлов в современных файловых системах от смежного размещения файлов в старых файловых системах?
  11. Какими методами может быть обеспечено преимущественно смежное размещение файла на внешней памяти?
  12. В чем отличие целостности файловой системы от целостности данных? Какую целостность и какими методами обеспечивают современные файловые системы?

НазадОглавлениеВперед
Индекс