Литмир - Электронная Библиотека
Содержание  
A
A

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

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

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

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

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

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

5.19 ВЫВОДЫ

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

5.20 УПРАЖНЕНИЯ

1. Рассмотрим программу, приведенную на Рисунке 5.35. Какое значение возвращает каждая операция read и что при этом содержится в буфере? Опишите, что происходит в ядре во время выполнения каждого вызова read.

2. Вновь вернемся к программе на Рисунке 5.35 и предположим, что оператор lseek(fd, 9000L, 0); стоит перед первым обращением к функции read. Что ищет процесс и что при этом происходит в ядре?

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

4. Библиотека стандартных подпрограмм ввода-вывода повышает эффективность выполнения пользователем операций чтения и записи благодаря буферизации данных в библиотеке и сохранению большого количества модулей обращения к операционной системе, необходимых пользователю. Как бы вы реализовали библиотечные функции fread и fwrite? Что должны делать библиотечные функции fopen и fclose?

#include ‹fcntl.h›

main()
{

 int fd;

 char buf[1024];

 fd = creat("junk", 0666);

 lseek(fd, 2000L, 2); /* ищется байт с номером 2000 */

 write(fd, "hello", 5);

 close(fd);

 fd = open("junk", O_RDONLY);

 read(fd, buf, 1024); /* читает нули */

 read(fd, buf, 1024); /* считывает нечто, отличное от 0 */

 read(fd, buf, 1024);

}

Рисунок 5.35. Считывание нулей и конца файла

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

#include ‹fcntl.h›

main()
{

 int fd;

 char buf[256];

 fd = open("/etc/passwd", O_RDONLY);

 if (read(fd, buf, 1024) ‹ 0)
 printf("чтение завершается неудачно\n");

}

Рисунок 5.36. Чтение большой порции данных в маленький буфер

6. Рассмотрим программу, приведенную на Рисунке 5.36. Что произойдет в результате выполнения программы? Обоснуйте ответ. Что произошло бы, если бы объявление массива buf было вставлено между объявлениями двух других массивов размером 1024 элемента каждый? Каким образом ядро устанавливает, что прочитанная порция данных слишком велика для буфера?

46
{"b":"96903","o":1}