Некоторые из наших читателей, возможно, знакомы с пособием В.Г. Олифер и Н.А. Олифер «Компьютерные сети». Только что вышла из типографии новая книга этих авторов «Сетевые операционные системы» (СПб., Питер, 2001. — 544, ISBN: 5-272-00120-6).

Эта книга — не о конкретной операционной системе, и даже не о конкретном типе операционных систем. Она рассматривает фундаментальные концепции и принципы построения, справедливые для большинства ОС.

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

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

Ниже публикуется отрывок из книги Виктора и Натальи Олифер «Сетевые операционные системы», посвященный восстанавливаемым файловым системам. Кроме того, в этом выпуске журнала читатели найдут статьи, посвященные файловым системам с журналированием.

Причины нарушения целостности

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

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

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

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

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

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

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

Несмотря на то что период полного сброса кэша на диск обычно выбирается весьма коротким (порядка 10-30 секунд), все равно остается высокая вероятность того, что при возникновении сбоя содержимое диска не в полной мере будет соответствовать действительному состоянию файловой системы — копии некоторых блоков, с обновленным содержимым, система может не успеть переписать на диск. Для восстановления некорректных файловых систем, использующих кэширование диска, в операционных системах предусматриваются специальные утилиты, такие как fsck для файловых систем s5/uf, ScanDisk для FAT или Chkdsk для файловой системы HPFS. Однако объем несоответствий может быть настолько большим, что восстановление файловой системы после сбоя с помощью стандартных системных средств становится невозможным.

Протоколирование транзакций

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

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

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

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

Незавершенная операция с диском несет угрозу целостности файловой системы. Каким же образом файловая система может реализовать свойство транзакций «все или ничего»? Очевидно, что решение в этом случае может быть одно — необходимо протоколировать (запоминать) все изменения, происходящие в рамках транзакции, чтобы на основе этой информации в случае прерывания транзакции можно было отменить все уже выполненные подоперации, т. е. сделать так называемый откат транзакции.

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

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

Восстанавливаемость файловой системы NTFS

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

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

Журнал регистрации транзакций в NTFS делится на две части: область рестарта и область протоколирования (рис. 1).

  • Область рестарта содержит информацию о том, с какого места необходимо будет начать читать журнал транзакций для проведения процедуры восстановления системы после сбоя или краха ОС. Эта информация представляет собой указатель на определенную запись в области протоколирования. Для надежности в файле журнала регистрации хранятся две копии области рестарта.
  • Область протоколирования содержит записи обо всех изменениях в системных данных файловой системы, произошедших в результате выполнения транзакций в течение некоторого, достаточно большого периода. Все записи идентифицируются логическим последовательным номером LSN (Logical Sequence Number). Записи о подоперациях, принадлежащих одной транзакции, образуют связанный список: каждая последующая запись содержит номер предыдущей записи. Заполнение области протоколирования идет циклически: после исчерпания всей памяти, отведенной под область протоколирования, новые записи помещаются на место самых старых.

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

Запись модификации заносится в журнал транзакций относительно каждой подоперации, которая модифицирует системные данные файловой системы. Эта запись состоит из двух частей: одна содержит информацию, необходимую системе для повторения этого действия, а другая — информацию для его отмены. Информация о модификации хранится в двух формах — в физическом и в логическом описаниях. Логическое описание используется программным обеспечением уровня приложений и формулируется в терминах операций, например, «выделить файловую запись в MFT» или «удалить имя из корневого индекса». На нижнем уровне программного обеспечения, к которому относятся модули самой NTFS, используется менее компактное, но более простое физическое описание, сводящееся к указанию диапазона байт на диске, в которые необходимо поместить определенные значения.

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

Журнал транзакций, как и все остальные файлы, кэшируется в буферах оперативной памяти и периодически сбрасывается на диск.

NTFS все действия с журналом транзакций выполняет только путем запросов к специальной службе LFS (Log File Service). Эта служба размещает в журнале новые записи, сбрасывает на диск все записи до некоторого заданного номера, считывает записи в прямом и обратном порядке и выполняет некоторые другие действия над записями журнала.

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

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

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

Какие же дефекты может иметь файловая система после сбоя?

Во-первых, это несогласованность системных данных, возникшая в результате незавершенности транзакций, которые были начаты еще до момента последнего сброса данных из кэша на диск. На рис. 2 показана транзакция A, две подоперации которой a1 и a2 были сделаны до сброса кэша, а еще две — a3 и a4 — после сброса кэша. К моменту сбоя результаты первых двух подопераций могли быть записаны на диск, в то время как изменения, вызванные подоперациями a3 и a4, отразились только на копиях блоков файловой системы в кэше и были потеряны в результате сбоя. Чтобы устранить несогласованность, вызванную этой причиной, требуется сделать откат для всех транзакций, незафиксированных к моменту последнего сброса кэша. Для примера, изображенного на рисунке, такими транзакциями являются транзакции A и C. В каждый момент времени NTFS располагает списком, называемым таблицей незавершенных транзакций. Для каждой незавершенной транзакции эта таблица содержит последовательный номер LSN последней по времени подоперации, выполненной в рамках данной транзакции. По этому номеру может быть найдена вся цепочка подопераций транзакции.

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

Таблицы модифицированных страниц и незавершенных транзакций создаются NTFS на основании записей журнала транзакций и поддерживаются в оперативной памяти. Следует подчеркнуть, что обе эти таблицы не добавляют новой информации в журнал транзакций, они лишь представляют информацию, содержащуюся в записях журнала, в концентрированном виде, более удобном для использования при восстановлении. Содержимое таблиц фиксируется в журнале транзакций во время выполнения операции «контрольная точка».

Операция выполняется каждые 5 секунд и включает выполнение следующих действий (рис. 3). Сначала в области протоколирования журнала транзакций создаются две записи — запись таблицы незавершенных транзакций и запись таблицы модифицированных страниц, содержащие копии соответствующих таблиц. Затем номера этих записей включаются в запись контрольной точки, которая также создается в области протоколирования журнала транзакций. Сделав запись, NTFS помещает ее номер LSN в область рестарта.

Заметим, что процессы создания контрольных точек и сброса блоков данных из кэша на диск протекают асинхронно. Когда в результате сбоя из оперативной памяти исчезает вся информация, в том числе из таблиц незавершенных транзакций и модифицированных страниц, состояние этих таблиц, хотя и несколько устаревшее, сохраняется на диске в файле журнала транзакций. Кроме того, здесь же имеется несколько более поздних записей, которые были сделаны в период между сохранением таблиц и сбросом кэша (на рисунке это записи М1, М2, М3). При восстановлении файловая система обрабатывает эти записи и вносит изменения в таблицы незавершенных транзакций и модифицированных страниц, сохраненные в журнале. Так, например, если запись М1 является записью фиксации транзакции, то соответствующая транзакция исключается из таблицы незавершенных транзакций, а если это запись модификации, то в таблицу модифицированных страниц заносится информация об еще одной странице.

Процесс восстановления файловой системы включает следующие шаги.

  1. Чтение области рестарта из файла журнала транзакций и определение номера самой последней по времени записи о контрольной точке.
  2. Чтение записи контрольной точки и определение номеров записей таблицы незавершенных транзакций и таблицы модифицированных страниц.
  3. Чтение и корректировка таблиц незавершенных транзакций и модифицированных страниц на основании записей, сделанных в журнале транзакций уже после сохранения таблиц в журнале, но еще до записи журнала на диск (рис. 4).
  4. Анализ таблицы модифицированных страниц, определение номера самой ранней записи модификации страницы.
  5. Чтение журнала транзакций в прямом направлении, начиная с самой ранней записи модификации, найденной при анализе таблицы модифицированных страниц. При этом система выполняет повторение завершенных транзакций, в результате которого устраняются все несоответствия файловой системы, вызванные потерями модифицированных страниц в кэше во время сбоя или краха операционной системы.
  6. Анализ таблицы незавершенных транзакций, определение номера самой поздней подоперации, выполненной в рамках незавершенной транзакции.
  7. Чтение журнала транзакций в обратном направлении. Учитывая, что все подоперации каждой транзакции связаны в список, система легко переходит от одной записи модификации к другой, извлекает из них информацию, необходимую для отмены, и выполняет откат незавершенных транзакций.

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


Дисковый кэш в Windows NT основан на использовании виртуальной памяти, поэтому он оперирует не блоками, а страницами.

назад