\section{Устойчивость ФС к сбоям}\label{FaultTolerance}

\subsection{Устойчивость к сбоям питания}

Свойство \termin{устойчивости к сбоям питания}{power-fault tolerance}
является одной из важных характеристик файловой системы.
Строго говоря, имеется в виду устойчивость не только к сбоям питания,
но и к любой ситуации, при которой работа с ФС прекращается без
выполнения операции размонтирования. Поэтому правильнее было бы говорить
об устойчивости к любым сбоям системы, а не только питания.

С другой стороны, если говорить просто об <<устойчивости к сбоям>>,
возникает неприятная двусмысленность. Под устойчивостью к сбоям
можно понимать устойчивость к сбоям всей системы, например, к тем же
сбоям питания, а можно понимать устойчивость к дефектам физического носителя,
которые могут привести к потере части данных на диске.
Вторая проблема также довольно сложна, но она
обсуждается в разделе \ref{hotfixing}, а сейчас мы будем говорить
только о первой проблеме, называя ее просто <<устойчивостью>> для краткости.

На самом деле, неожиданное прекращение работы с ФС может произойти
не только при сбое питания, но и при:
\begin{itemize}
\item извлечении носителя из дисковода (подробнее об этом см. ниже);
\item нажатии кнопки \verb"RESET" нетерпеливым пользователем;
\item фатальном аппаратном сбое;
\item аппаратном сбое, который сам по себе не был фатальным,
но система не смогла правильно восстановиться, что привело к ее развалу;
\item разрушении системы из-за чисто программных проблем%
\footnote{На практике часто сложно провести границы между тремя
последними типами сбоев. В качестве примера можно привести проблему,
описанную в разделе \ref{SCOHorrorStoryPart1}}.
\end{itemize}

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

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

К тому же перед выключением системы, интегрированной в сеть,
необходимо уведомить всех клиентов и все сервера о разъединении. Только
чисто клиентская машина может быть выключена из сети без проблем.
Поэтому на сетевых серверах в любом случае необходима процедура
\termin{закрытия системы}{shutdown}.
Так почему бы не возложить на эту процедуру
еще и функцию размонтирования ФС?

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

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

{\small
Интересный альтернативный подход используется в компьютерах
\machname{Macintosh} и некоторых рабочих станциях. У этих машин
дисковод не имеет кнопки для извлечения дискеты.
Выталкивание дискеты осуществляется программно, подачей соответствующей
команды дисководу. Перед подачей такой команды ОС может выполнить
нормальное размонтирование ФС на удаляемом диске.
}

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

\note{Нужно отметить, что даже если ФС считается в этом смысле устойчивой,
некоторые сбои для нее могут быть опасны. Например, если запустить команду
\verb"DISKOPT" на <<устойчивой>> файловой системе \sysname{FAT} и в подходящий
момент нажать RESET, то значительная часть данных на диске может быть
навсегда потеряна.}

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

{\small
Характерный и очень простой пример: архиватор \progname{InfoZip}
работает над созданием архива.
Программа сформировала заголовок файла, упаковала и записала на диск
около 50 \% данных, и в этот момент произошел сбой.
В \standname{zip}-архивах каталог находится в конце архивного файла и
записывается туда после завершения упаковки всех данных.
Обрезанный в случайном месте \standname{zip}-файл не содержит каталога
и поэтому, безусловно, является безнадежно испорченным.
}

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

Поддержание целостности структур ФС обычно гораздо важнее,
чем целостность недописанных в момент сбоя пользовательских данных.
Дело в том, что если при сбое оказывается испорчен создававшийся файл,
это достаточно неприятно; если же окажется испорчена файловая система,
в худшем случае это может привести к потере {\it всех} данных на диске,
то есть к катастрофе.
Поэтому обычно обеспечению целостности ФС при сбоях уделяется гораздо
больше внимания.

Упоминавшаяся выше <<врожденная>> устойчивость к сбоям файловой
системы \sysname{FAT} объясняется тем, что
в этой ФС удаление блока из списка свободных и выделение его файлу
производится одним действием -- модификацией элемента \verb"FAT".
Поэтому если во время этой процедуры произойдет сбой или дискета будет
вынута из дисковода, то ничего страшного не случится: просто получится файл,
которому выделено на один блок больше, чем его длина, записанная в каталоге.
При стирании этого файла все его блоки будут помечены как свободные, поэтому
вреда практически нет.

\note{
Нужно отметить, что при использовании отложенной записи \sysname{FAT}
и родственные ФС теряют это преимущество. При этом отложенная запись 
\verb"FAT" является единственным способом добиться хоть сколько-нибудь 
приемлемой производительности от ФС с 32-битовым \verb"FAT". 
Поэтому, например, хотя \sysname{Novell NetWare} и использует ФС, 
основанную на 32-битной \verb"FAT", после аварийной перезагрузки 
эта система вынуждена запускать программу аварийной починки дисковых томов.
Аналогичным образом ведет себя и 32-битная версия ДОСовской ФС
\sysname{FAT32}.
}

Если же система хранит отдельно список или карту свободных блоков,
а отдельно списки блоков, выделенных каждому файлу,
как это делают \sysname{HPFS} или ФС систем семейства \sysname{Unix},
то при прерывании операции выделения места в неподходящий момент
могут либо теряться блоки (если мы сначала удаляем блок из списка свободных),
либо получаться блоки, которые одновременно считаются и свободными,
и занятыми (если мы сначала выделяем блок файлу).

Первая ситуация достаточно неприятна, вторая же просто
недопустима: первый же файл, созданный после перевызова системы, будет
<<перекрещиваться>> с испорченным. Поэтому все ОС, использующие файловые
системы такого типа (системы семейства \sysname{Unix}, \sysname{OS/2}, 
\sysname{Windows~NT} и т.д.), после аварийной перезагрузки первым делом 
проверяют свои ФС соответствующей программой починки.

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

\subsection{Восстановление ФС после сбоя}

Чаще всего суперблок неустойчивых ФС содержит флаг
\termin{dirty}{<<грязный>>}, сигнализирующий о том, что ФС, возможно,
нуждается в починке.
Этот флаг сбрасывается при нормальном размонтировании ФС
и устанавливается при ее монтировании или при первой модификации
после монтирования. Таким образом, если ОС погибла, не успев
размонтировать свои дисковые тома, после перезагрузки на этих
томах dirty-флаг будет установлен, что и будет сигнализировать
о необходимости починки.

Починка состоит в том, что система прослеживает пространство,
выделенное всем файлам. При этом должны выполняться следующие требования:
\begin{enumerate}
\item Каждая запись в каталоге должна иметь правильный формат
и содержать осмысленные данные. Например, если запись помечена как
свободная, она не должна ссылаться на данные, помеченные как
принадлежащие файлу, или на инод. Не во всех ФС можно обнаружить
ошибки такого типа.

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

Чаще всего программа починки в этой ситуации требует вмешательства
пользователя, с тем чтобы решить, какие из файлов следует удалить или
обрезать по месту пересечения. Иногда для каждого из файлов создается
копия <<общего>> блока, но и в этом случае пользователю все равно нужно
определить, какие из файлов испорчены.

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

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

\item Все блоки, не принадлежащие файлам, должны быть помечены,
как свободные. Соответствующий тип ошибок -- потерянные блоки --
наиболее частый результат системных сбоев  как в  файловой системе
\progname{FAT}, так и в более сложных файловых системах. Сами по себе
ошибки этого типа относительно безобидны.

Обычно программа починки не помечает потерянные блоки как свободные,
а выделяет из них непрерывные цепочки и создает из этих цепочек файлы.
Например, в \sysname{OS/2} программа починки пытается найти в потерянных
блоках файловые записи, а потом создает ссылки на найденные таким образом 
файлы в каталоге \verb'\FOUND.XXX'.
В \sysname{DOS} эти файлы помещаются в корневой каталог ФС под именами
\verb"FILEXXXX.CHK" (вместо \verb"XXXX" подставляется номер).
Предполагается, что пользователь просматривает все такие файлы и
определяет, не содержит ли какой-то из них ценной информации,
например конца насильственно укороченного файла.

\item В системах семейства \sysname{Unix} существует несколько
специфических ошибок, связанных с инодами:
\begin{itemize}
\item инод, внутренний счетчик ссылок которого не соответствует
реальному количеству ссылок из каталогов. Эта проблема может возникать
при системном сбое в момент удаления существовавшей связи или создания новой.
Она решается коррекцией внутреннего счетчика инода. После этого можно
обнаружить следующие две ошибки;

\item инод, не имеющий ни одной ссылки, но не помеченный
как свободный -- \termin{сирота}{orphan}. Ссылка на
такой инод создается в каталоге \verb"lost+found";

\item инод с ненулевым количеством ссылок из каталогов,
но помеченный свободным. Чаще всего это свидетельствует
о порче самого каталога. Обычно ссылки на такой инод удаляются.
\end{itemize}
\end{enumerate}

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

{\small\label{SCOHorrorStoryPart2}
В процессе эксплуатации системы \sysname{SCO Open Desktop 4.0},
у одного из авторов неоднократно возникала необходимость выполнять
холодную перезагрузку без нормального размонтирования файловых систем.
Одна из таких перезагрузок привела к катастрофе.

Дисковая подсистема машины состояла из кэширующего контроллера
дискового массива. Контроллер активно использовал отложенную запись,
что, по-видимому и послужило причиной катастрофы. Во время планового
резервного копирования драйвер лентопротяжки впал в ступор и заблокировал
процесс копирования\footnote{Механизм возникновения этой аварии
подробнее обсуждался в \ref{SCOHorrorStoryPart1}.}.
Из-за наличия зависшего процесса оказалось невозможно
размонтировать файловую систему и машина была перезагружена нажатием
кнопки \verb"RESET" без выполнения нормального закрытия, в том числе и
без выполнения операции закрытия драйвера дискового массива,
которая должна была сбросить на диски содержимое буферов контроллера.

После перезагрузки система автоматически запустила программу починки файловой
системы \verb"fsck" (File System ChecK), которая выдала радостное сообщение:
\verb"DUP in inode 2". Для незнакомых с системными утилитами \sysname{Unix}
необходимо сказать, что DUP означает ошибку перекрещивания файлов, а инод 2
-- это инод корневого каталога ФС. Таким образом, корневая директория
дискового тома объемом около 2 гигабайт оказалась испорчена.  При этом
подавляющее большинство каталогов и файлов были не затронуты катаклизмом, но
оказались недоступны. Программа починки не могла перенести ссылки на
соответствующие иноды в каталог \verb"lost+found", так как ссылка на него
также идет из корневого каталога.

Ситуация представлялась безвыходной. Катастрофа усугублялась тем,
что произошла она {\em во время} резервного копирования, а последняя
<<хорошая" копия была сделана неделю назад. Б\'{о}льшую часть пользовательских
данных можно было бы восстановить, но среди потерянных файлов оказался
журнальный файл сервера СУБД \progname{ORACLE} (сама база данных находилась
в другом разделе диска). Пришлось заняться восстановлением
ФС с использованием дискового редактора, мотивируя это тем, что
<<терять всё равно уже нечего". Собственно, в восстановлении ФС
участвовало два человека -- автор и штатный администратор системы.
Автор ни в коем случае не хочет создать у читателя впечатление, что
план восстановления был разработан лично им -- это был плод совместных
усилий, проб и ошибок.

Редактирование системных данных <<сложных" ФС с использованием
простого шестнадцатиричного дискового редактора является крайне
неблагодарным занятием. Есть основания утверждать, что это вообще
невозможно. Во всяком случае, ни одному из авторов не доводилось 
слышать об успехе такого предприятия. К счастью, системы семейства 
\sysname{Unix} предоставляют для редактирования ФС специальную 
программу \termint{\verb"fsdb"}{File System DeBugger}{отладчик 
файловой системы}. По пользовательскому интерфейсу
эта программа напоминает программу \verb"DEBUG.COM", поставляемую с
\sysname{MS DOS}; основным ее преимуществом является то, что она
<<знакома" с основными понятиями файловой системы. Так, например,
\verb"fsdb" позволяет просмотреть содержимое 10-го логического блока файла
с инодом 23456, выделить физический блок 567345 файлу с инодом 2 или
пометить инод 1245 как свободный.

Первая попытка восстановления состояла в том, что мы удалили тот инод,
с которым перекрещивался корневой каталог, смонтировали том командой
<<безусловного" монтирования (которая позволяла монтировать поврежденные
тома), создали командой \verb"mkdir" каталог \verb"lost+found" и вновь
запустили \verb"fsck". Попытка завершилась крахом. Беда была в том, что,
как оказалось, корневой каталог пересекался также и со списком свободных
блоков, то есть создание каталога, а потом его расширение командой
\verb"fsck" снова приводило к порче корневого каталога и задача
сводилась к предыдущей.

Таким образом, нам необходимо было либо починить вручную список
свободных блоков, либо найти способ создать директорию \verb"lost+found"
без обращений к этому списку. Дополнительная сложность состояла в том,
что с каталогом \verb"lost+found" не связано фиксированного инода,
а определить инод старого \verb"lost+found" не представлялось
возможным.

Мы решили не связываться с починкой списка свободны блоков.
Вместо этого мы просмотрели листинг последней <<правильной" резервной
копии, нашли там ненужный пустой каталог и присоединили его к корневому
под названием \verb"lost+found". После этого нам оставалось лишь
уповать на то, что вновь создаваемые \verb"fsck" ссылки на файлы
не приведут к необходимости удлинить наш \verb"lost+found".
К счастью, этого не произошло: все потомки корневого каталога
благополучно получили имена в \verb"lost+found". По существу,
ФС пришла в пригодное для чтения состояние, оставалось лишь правильно
определить имена найденных каталогов. Это также оказалось относительно
несложной задачей: большая часть каталогов на томе была домашними
каталогами пользователей и их имена можно было восстановить на
основании того, кому эти каталоги принадлежали. Для остальных каталогов
имя достаточно легко определялось после сопоставления их содержимого
с листингом резервной копии.
}

Во многих современных ОС реализованы устойчивые к сбоям
файловые системы: \sysname{jfs} в \sysname{AIX}(версия \sysname{Unix},
поставляемая \entname{IBM}), \sysname{Merlin}), \sysname{Veritas} в 
\sysname{UnixWare}, \sysname{NTFS} в \sysname{Windows~NT}. 
Практически все такие ФС основаны на механизме, который 
по-английски называется
\termin{intention logging}{регистрация намерений}.

\subsection{Файловые системы с регистрацией намерений}\label{IntentionLogging}

\note{
Термин, вынесенный в заголовок этого подпункта, является дословной калькой
(возможно, не очень удачной) англоязычного термина \term{intention logging}.
В русском языке, к сожалению, еще нет общепринятого термина для этого
понятия.
}

Идея журналов регистрации намерений пришла из систем управления базами
данных. В СУБД часто возникает задача внесения согласованных изменений
в несколько разных структур данных. Например, банковская система переводит
миллион долларов с одного счета на другой. СУБД вычитает 1.000.000 из
суммы на первом счету, затем пытается добавить ту же величину ко
второму счету\ellipsis и в этот момент происходит сбой.

Для СУБД этот пример выглядит очень тривиально, но мы выбрали его потому,
что он похож на ситуацию в файловой системе: в каком бы порядке ни
производились действия по переносу объекта из одной структуры в другую,
сбой в неудачный момент приводит к крайне неприятной ситуации.
В СУБД эта проблема была осознана очень давно и была очень
острой -- ведь миллион долларов всегда был намного дороже одного
сектора на диске\ellipsis

Удовлетворительное решение проблемы заключается в следующем:

Во-первых, все согласованные изменения в СУБД организуются в блоки,
называемые \termin{транзакциями}{transaction}. Каждая транзакция
осуществляется как неделимая (\term{атомарная}) операция, во время
которой никакие другие операции над изменяемыми данными не разрешены.

Во-вторых, каждая транзакция осуществляется в три этапа. 
\begin{enumerate}
\item Система записывает в специальный журнальный файл, что же она 
собирается делать.
\item Если запись в журнал была успешной, система выполняет транзакцию.
\item Если транзакция завершилась нормально, система помечает в журнале,
что намерение было успешно реализовано.
\end{enumerate}

Журнал часто называют \termin{журналом регистрации намерений}{intention
log}, что очень хорошо отражает суть дела, потому что в этот журнал
записываются именно \termin{намерения}{intentions}.

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

Если произошел сбой системы, после перезагрузки запускается программа
починки базы данных. Эта программа просматривает конец журнала.
\begin{itemize}
\item Если она видит там испорченную
запись, то игнорирует ее: сбой произошел во время записи в журнал.
\item Если все записи помечены как успешно выполненные транзакции,
то сбой произошел между транзакциями: ничего особенно страшного
не случилось; во всяком случае, ничего чинить не надо.
\item Если найдена запись, которая отмечает начатую, но невыполненную
транзакцию, то сбой произошел {\it во время} этой транзакции.
Это наиболее неприятная ситуация,
но журнал содержит достаточно информации, чтобы или восстановить состояние
базы данных до начала транзакции (выполнить \termin{откат назад}{rollback}),
или же доделать предполагавшиеся изменения.
\end{itemize}

Нужно отметить, что данные, необходимые для выполнения отката,
могут иметь большой объем. Фактически это копия всех данных,
подвергающихся изменению в ходе транзакции. Многие СУБД, такие как
\progname{ORACLE}, хранят эти данные не в самом журнале, а в специальной
области данных, называемой \termin{сегмент отката}{rollback segment}.

Более подробная информация о работе журналов намерений в базах данных
может быть найдена в соответствующей литературе (\cite{dbms1} и др.).
Необходимо только отметить, что книги и даже фирменная
документация по простым СУБД типа \progname{dBase} или \progname{FoxPro}
здесь не помогут, поскольку эти пакеты не содержат средств журналирования.

Легко понять, что идея журнала намерений достаточно естественно переносится в
программу управления файловой системой. Но здесь возникает интересный
вопрос -- что же считать транзакцией: только операции по распределению
пространства на диске или также все операции по изменению данных?

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

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

Ряд современных ФС с регистрацией намерений поддерживают оба режима работы
и предоставляют выбор между этими вариантами администратору системы.
Например, у файловой системы \verb"vxfs" или \progname{Veritas},
входящей в пакет \sysname{UnixWare} (версия \sysname{Unix SVR4},
поставляемая фирмой \entname{Novell}), существует две версии.
Одна версия, поставляемая вместе с системой по умолчанию,
включает в транзакцию только системные данные. Другая, <<advanced>>,
версия, которая поставляется за отдельные деньги, осуществляет
регистрацию намерений как для системных, так и для пользовательских данных.

{\small
В \sysname{Veritas 2} дисковый том разбит на области, называемые
\termin{группами цилиндров}{термин, унаследованный из \sysname{UFS} --
файловой системы \sysname{BSD Unix}}. Каждая группа цилиндров имеет свою
карту свободных блоков, участок динамической таблицы инодов и
журнал намерений. Журнал намерений организован в виде кольцевого
буфера записей о транзакциях. В журнал пишутся данные только о
транзакциях над инодами, принадлежащими к этой группе цилиндров.
При этом в каждой группе может исполняться одновременно несколько
транзакций и окончанием транзакции считается физическое завершение записи
модифицированны данных. Количество одновременно исполняющихся транзакций
ограничено  объемом журнала, но поскольку каждая группа цилиндров имеет
свой журнал, это ограничение не играет большой роли.
}

\subsection{Устойчивость ФС к сбоям диска}\label{hotfixing}

Кроме общесистемных сбоев, ФС должна обеспечивать  средства
восстановления при физических сбоях диска. Наиболее распространенным
видом таких сбоев являются нечитаемые -- \termin{<<плохие>>}{bad} -- блоки,
появление которых обычно связано с физическими дефектами магнитного
носителя.

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

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

Еще одной причиной порчи жестких дисков является соприкосновение
головок чтения/записи с поверхностью вращающегося диска (\term{head crash}).
Обычно это приводит к повреждению целой дорожки или нескольких дорожек
диска, а зачастую и самой головки. Для несъемных жестких дисков в
герметичных корпусах (т.наз. винчестерских дисков) это означает потерю
целой рабочей поверхности.
}

Обычно ошибки данных обнаруживаются при чтении. Дисковые контроллеры
используют при записи кодировку с исправлением ошибок, чаще всего,
коды типа \termint{CRC}{Cyclic Redundancy Code}{циклический избыточный
код}, которые позволяют обнаруживать и исправлять множественные ошибки.
Тем не менее, если при чтении была обнаружена ошибка, большинство
ОС отмечают такой блок как плохой, даже если данные удалось восстановить
на основании избыточного кода.

В файловой системе \sysname{FAT} плохой блок или кластер, содержащий
такой блок, отмечается кодом \verb"0xFFB" или \verb"0xFFFB" для дисков
с 16-разрядной \verb"FAT". Эта файловая система не способна компенсировать
плохие блоки в самой \verb"FAT" или в корневом каталоге диска. Такие диски
просто считаются непригодными для использования.

В <<сложных>> файловых системах обычно используется более сложный,
но зато и более удобный способ обхода плохих блоков, называемый
\termin{горячей заменой}{hotfixing}.
При создании файловой системы отводится небольшой пул блоков,
предназначенных для горячей замены. В файловой системе хранится список
всех обнаруженных плохих блоков, и каждому такому блоку поставлен
в соответствие блок из пула горячей замены. При этом плохие блоки,
на которые оказались отображены системные структуры данных, например
участок таблицы инодов, также подвергаются горячей замене.
Таблица горячей замены может быть как статической, так и динамической.

На первый взгляд, динамическая таблица горячей замены предпочтительна,
однако не нужно забывать о двух немаловажных факторах.
\begin{itemize}
\item Файловая система вынуждена справляться с таблицей горячей замены
при всех обращениях к диску, поэтому увеличение таблицы приводит к
замедлению работы.
\item Множественные плохие блоки на жестком диске свидетельствуют либо
о том, что диск дефектный, либо о том, что магнитный слой начал
разрушаться от старости (иными словами, что этот диск пора выкидывать),
либо о каких-то других не менее серьезных проблемах, вроде разгерметизации
корпуса и проникновения в него пыли.
\end{itemize}

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

\section{Драйверы файловых систем}

При эксплуатации ОС может возникнуть необходимость монтировать файловые
системы, отличающиеся от <<родной>> ФС. Особенно часто она возникает в
организациях, где используются ОС нескольких разных типов.
Да и в организациях, работающих с монокультурой \sysname{MS~DOS/MS~Windows},
такая потребность возникает все чаще. Во-первых, доступ к файлам на файловом
сервере осуществляется существенно иными способами, чем к файлам на локальном
диске, даже если на сервере стоит та же  ДОС с той же ФС типа
\sysname{FAT}. Во-вторых, дисководы для CD-ROM становятся все дешевле и
распространяются все шире. При этом стандартная ФС на CD-ROM -- вовсе не
\sysname{FAT}.

Решение этой проблемы приходит в голову сразу -- необходим драйвер файловой
системы со стандартным интерфейсом, подобный драйверу внешнего устройства.
Естественно, набор функций такого драйвера должен быть существенно иным:
\begin{description}
\item[mount] -- монтирование ФС.
В зависимости от типа ФС параметры этой функции должны различаться.
Для ФС на локальных дисках достаточно передать системный идентификатор
монтируемого диска. Для ФС на удаленной машине мы должны
передать сетевой адрес этой машины и имя требуемой файловой системы.
Во многих случаях проводится различие между монтированием ФС для
чтения/модификации или только для чтения: при монтировании с модификацией
устанавливается флаг загрязнения (dirty flag) ФС);
\item[umount] -- размонтирование ФС;
\item[GetFreeSpace или df] -- получение информации о ФС: общее пространство,
свободное пространство, количество файлов и~т.д;
\item[FindFirst/FindNext или opendir/readdir] -- функции для чтения из
каталога. Считанную информацию необходимо привести
к формату, принятому в данной ОС. В частности, может оказаться необходимым
сократить и/или преобразовать считанные имена файлов. Например, драйвер
\sysname{HPFS}, используемый в эмуляторе \sysname{MS~DOS},  в системе
\sysname{OS/2} не выполняет такого преобразования. В результате
\sysname{DOS}-овские программы не видят файлов и каталогов с длинными именами;
\item[access] -- проверить существование файла
и возможность доступа к нему в заданном режиме, например, для чтения или для
записи;
\item[stat] -- функция для получения информации
о файле с заданным именем. Драйвер ФС должен считать доступную информацию о
файле и привести ее к принятому в ОС формату. При этом, возможно,
придется проигнорировать часть считанной информации, а другую часть, напротив,
драйвер вынужден сочинять сам. Так драйвер файловой системы \sysname{FAT}
в ОС семейства \sysname{Unix} вынужден сочинять идентификатор хозяина файла,
права доступа и т.д.;
\item[open] -- открыть существующий или создать новый файл с заданным именем;
\item[read и write] -- функции считывания данных из файла и записи
в него;
\item[lseek] -- позиционирование в файле;
\item[lock] -- функция (в действительности, набор функций) блокировки для
синхронизации доступа к файлу или его участкам. Подробнее о них см. в
п. \ref{filelock}. При работе с локальными ФС операции блокировки могут
прослеживаться ядром системы и не доходить до драйвера ФС, но при работе
с разделяемыми по сети ФС блокировки необходимо отслеживать на уровне
протокола разделения файлов, поэтому драйвер сетевой ФС обязан
знать о блокировках.
\item[close] -- закрыть файл;
\item[delete или unlink] -- удалить файл или его имя;
\item[link] -- создать связь с файлом (новое имя). Далеко не все ОС и
ФС поддерживают эту операцию;
\item[mkdir] -- создать каталог;
\item[rmdir] -- удалить каталог. Обычно разрешено удаление только пустых
каталогов.
\end{description}

Кроме собственно драйвера ФС, для ее полноценной поддержки нужны следующие
программы:
\begin{itemize}
\item программа создания ФС -- \verb"mkfs" или \verb"FORMAT";
\item программа контроля и починки ФС -- \verb"fsck" или \verb"CHKDSK";
\item программа fstyp, которая смотрит на диск и пытается определить,
<<её это диск или не её. Она полезна при монтировании ФС с
автоматическим
определением ее типа;
\item программа mount, которая принимает из командной строки зависящие
от типа ФС параметры, проверяет их допустимость и инициализирует
драйвер ФС.
\end{itemize}

Например, дистрибутив ОС \sysname{UnxiWare 2.0} фирмы \entname{SCO},
основанной на \sysname{UNIX System V R4.2},
содержит драйверы следующих файловых систем:
\begin{description}
\item[memfs] -- файловая система, размещающая файлы в оперативной памяти.
Может рассматриваться как эквивалент виртуального диска в \sysname{MS DOS}.
\item[dosfs] -- файловая система \sysname{FAT}.
\item[XENIX] -- файловая система, используемая ОС \sysname{Xenix}.
Эта ФС по структуре похожа на остальные ФС ОС семейства \sysname{Unix},
но не поддерживает символических связей и ограничивает длину имени файла
12 символами. Неустойчива к сбоям.
\item[s5] -- <<классическая>> ФС, сохранившаяся почти без изменений
с самых ранних версий системы -- \progname{s5}, по-видимому, означает
\sysname{Unix System 5}. Ограничивает имя файла 14 символами.
Неустойчива к сбоям.
\item[ufs] -- файловая система, разработанная в университете Беркли,
известная также как \sysname{FFS} (Fast File System) и \sysname{Berkley FS}.
Является основной ФС в большинстве версий \sysname{BSD UNIX} и поддерживается
многими другими ОС семейства \sysname{Unix}.
Имеет более высокую производительность, чем s5, в первую очередь
за счет разбиения таблицы инодов и списка свободных блоков
на участки (\term{группы цилиндров}). Такое разбиение уменьшает
перемещение головки дисковода при обращении к системным и
пользовательским данным. Поддерживает \term{дисковые квоты} --
ограничения на объем дискового пространства, занятого файлами
того или иного пользователя.
Ограничивает имя файла размером блока (обычно 512 символов).
Неустойчива к сбоям.
\item[bfs] -- Boot File System -- загрузочная файловая система.
Эта ФС имеет очень простую структуру, отчасти похожую на файловую систему
\sysname{RT-11}: все файлы в ней обязаны занимать непрерывное
пространство. Такая структура упрощает первичный загрузчик системы,
которому теперь не нужно разбираться в каталогах и инодах.
\sysname{bfs} имеет довольно низкую производительность и требует длительной
процедуры размонтирования, если в нее были записаны новые данные.
Фактически, при таком размонтировании происходит операция сжатия ФС,
эквивалентная команде \verb"SQEESE" в \sysname{RT-11}. Используется для
хранения ядра системы, и нескольких конфигурационных файлов, используемых
при загрузке. Все эти данные считываются только при загрузке системы и
перезаписываются только при изменениях конфигурации ядра, поэтому высокая
производительность от этой ФС не требуется.
\item[vxfs] -- устойчивая к сбоям ФС \progname{Veritas} с регистрацией
намерений.
Версия, входящая в стандартную поставку системы, журналирует только
системные структуры данных.
За отдельную плату можно приобрести <<продвинутую>> версию
\progname{Veritas}, которая обеспечивает журналирование пользовательских
данных.
\item[cdfs] -- Файловая система ???, используемая на CD-ROM.
\item[nfs] -- Network File System -- драйвер файловой системы, обеспечивающий
разделение файлов с использованием сетевого протокола \protname{TCP/IP}.
Протокол \protname{NFS} был предложен фирмой \entname{Sun Microsystems}
в середине 80-х гг. и в настоящее время поддерживается практически всеми
членами семейства \sysname{Unix}.
\protname{NFS}-клиенты и \protname{NFS}-серверы реализованы также для
\sysname{VMS}, \sysname{Windows~NT}, \sysname{Novell Netware},
\sysname{OS/2}, \sysname{MacOS}, \sysname{MS/DR~DOS} и
\sysname{Windows 3.x/95}.

\item[rfs] -- Remote File Sharing -- использование удаленной UNIX-системы в
качестве файлового сервера. Этот протокол был разработан фирмой
\entname{AT\&T} в 80-е гг. и пригоден только для соединения систем
\sysname{UNIX System V}.
\item[nucfs] NetWare Unix Client File System. Этот драйвер предназначен
для присоединения к файловым серверам \sysname{Novell Netware}. Он входит
в состав системы \sysname{UnixWare}, поставляемой фирмой \entname{SCO},
но не в остальные версии \sysname{UNIX SVR4}.
\end{description}.

Любопытно, что даже \sysname{MS/DR~DOS} версий выше 3.30 имеют возможность
устанавливать драйвер файловой системы. Такой драйвер может быть реализован
путем перехвата недокументированных функций прерывания \verb"0x2F" --
группы функций <<Network Redirector>> и <<IFS>>. Таким образом реализован
ряд сетевых клиентов для \sysname{MS/DR~DOS}.
К сожалению, авторы не смогли найти полноценного описания этих функций.

