The design of the unix operating system by Maurice J
Вид материала | Реферат |
- Лекция 10. Файловые системы Unix, 116.79kb.
- Уровни рассмотрения, 314.07kb.
- Курс по операционным системам (на примере ос windows) Основан на учебном курсе Windows, 29.21kb.
- Выполнил ученик 11 «А» класса, 443.51kb.
- Ос лекция 1 (2-й семестр – временно), 101.4kb.
- Operating System, 7686.97kb.
- Unix-подобные операционные системы, характеристики, особенности, разновидности, 40.63kb.
- 1. ms sql server. Общие сведения, 66.03kb.
- Shanti ananda maurice, 89.84kb.
- Методические материалы, 3002.45kb.
точку монтирования в третьей компоненте ".." имени.
Для случая пересечения точки монтирования в направлении из
файловой системы, где производится монтирование, в файловую сис-
тему, которая монтируется, рассмотрим модификацию алгоритма iget
(Рисунок 5.25), которая идентична версии алгоритма, приведенной
на Рисунке 4.3, почти во всем, за исключением того, что в данной
модификации производится проверка, является ли индекс индексом
точки монтирования. Если индекс имеет соответствующую пометку,
ядро соглашается, что это индекс точки монтирования. Оно обнару-
живает в таблице монтирования запись с указанным индексом точки
монтирования и запоминает номер устройства монтируемой файловой
системы. Затем, используя номер устройства и номер индекса корня,
общего для всех файловых систем, ядро обращается к индексу корня
-------------------------------------------------------------┐
│ алгоритм iget │
│ входная информация: номер индекса в файловой системе │
│ выходная информация: заблокированный индекс │
│ { │
│ выполнить │
│ { │
│ если (индекс в индексном кеше) │
│ { │
│ если (индекс заблокирован) │
│ { │
│ приостановиться (до освобождения индекса); │
│ продолжить; /* цикл с условием продолжения */ │
│ } │
│ /* специальная обработка для точек монтирования */ │
│ если (индекс является индексом точки монтирования) │
│ { │
│ найти запись в таблице монтирования для точки мон- │
│ тирования; │
│ получить новый номер файловой системы из таблицы │
│ монтирования; │
│ использовать номер индекса корня для просмотра; │
│ продолжить; /* продолжение цикла */ │
│ } │
│ если (индекс в списке свободных индексов) │
│ убрать из списка свободных индексов; │
│ увеличить счетчик ссылок для индекса; │
│ возвратить (индекс); │
│ } │
│ │
│ /* индекс отсутствует в индексном кеше */ │
│ убрать новый индекс из списка свободных индексов; │
│ сбросить номер индекса и файловой системы; │
│ убрать индекс из старой хеш-очереди, поместить в новую;│
│ считать индекс с диска (алгоритм bread); │
│ инициализировать индекс (например, установив счетчик │
│ ссылок в 1); │
│ возвратить (индекс); │
│ } │
│ } │
L-------------------------------------------------------------
Рисунок 5.25. Модификация алгоритма получения доступа к ин-
дексу
монтируемого устройства и возвращает при выходе из функции этот
индекс. В первом примере смены каталога ядро обращается к индексу
каталога "/usr" из файловой системы, в которой производится мон-
тирование, обнаруживает, что этот индекс имеет пометку "точка
монтирования", находит в таблице монтирования индекс корня монти-
руемой файловой системы и обращается к этому индексу.
-------------------------------------------------------------┐
│ алгоритм namei /* превращение имени пути поиска в индекс */│
│ входная информация: имя пути поиска │
│ выходная информация: заблокированный индекс │
│ { │
│ если (путь поиска берет начало с корня) │
│ рабочий индекс = индексу корня (алгоритм iget); │
│ в противном случае │
│ рабочий индекс = индексу текущего каталога │
│ (алгоритм iget); │
│ │
│ выполнить (пока путь поиска не кончился) │
│ { │
│ считать следующую компоненту имени пути поиска; │
│ проверить соответствие рабочего индекса каталогу │
│ и права доступа; │
│ если (рабочий индекс соответствует корню и компо- │
│ нента имени "..") │
│ продолжить; /* цикл с условием продолжения */│
│ поиск компоненты: │
│ считать каталог (рабочий индекс), повторяя алго- │
│ ритмы bmap, bread и brelse; │
│ если (компонента соответствует записи в каталоге │
│ (рабочем индексе)) │
│ { │
│ получить номер индекса для совпавшей компонен-│
│ ты; │
│ если (найденный индекс является индексом кор- │
│ ня и рабочий индекс является индексом корня │
│ и имя компоненты "..") │
│ { │
│ /* пересечение точки монтирования */ │
│ получить запись в таблице монтирования для │
│ рабочего индекса; │
│ освободить рабочий индекс (алгоритм iput); │
│ рабочий индекс = индексу точки монтирования;│
│ заблокировать индекс точки монтирования; │
│ увеличить значение счетчика ссылок на рабо- │
│ чий индекс; │
│ перейти к поиску компоненты (для ".."); │
│ } │
│ освободить рабочий индекс (алгоритм iput); │
│ рабочий индекс = индексу с новым номером │
│ (алгоритм iget); │
│ } │
│ в противном случае /* компонента отсутствует в │
│ каталоге */ │
│ возвратить (нет индекса); │
│ } │
│ возвратить (рабочий индекс); │
│ } │
L-------------------------------------------------------------
Рисунок 5.26. Модификация алгоритма синтаксического анализа
имени файла
Для второго случая пересечения точки монтирования в направле-
нии из файловой системы, которая монтируется, в файловую систему,
где выполняется монтирование, рассмотрим модификацию алгоритма
namei (Рисунок 5.26). Она похожа на версию алгоритма, приведенную
на Рисунке 4.11. Однако, после обнаружения в каталоге номера ин-
декса для данной компоненты пути поиска ядро проверяет, не указы-
вает ли номер индекса на то, что это корневой индекс файловой
системы. Если это так и если текущий рабочий индекс так же явля-
ется корневым, а компонента пути поиска, в свою очередь, имеет
имя "..", ядро идентифицирует индекс как точку монтирования. Оно
находит в таблице монтирования запись, номер устройства в которой
совпадает с номером устройства для последнего из найденных индек-
сов, получает индекс для каталога, в котором производится монти-
рование, и продолжает поиск компоненты с именем "..", используя
только что полученный индекс в качестве рабочего. В корне файло-
вой системы, тем не менее, корневым каталогом является "..".
В вышеприведенном примере (cd "../../..") предполагается, что
в начале процесс имеет текущий каталог с именем "/usr/src/uts".
Когда имя пути поиска подвергается анализу в алгоритме namei, на-
чальным рабочим индексом является индекс текущего каталога. Ядро
меняет текущий рабочий индекс на индекс каталога с именем
"/usr/src" в результате расшифровки первой компоненты ".." в име-
ни пути поиска. Затем ядро анализирует вторую компоненту ".." в
имени пути поиска, находит корневой индекс смонтированной (перед
этим) файловой системы - индекс каталога "usr" - и делает его ра-
бочим индексом при анализе имени с помощью алгоритма namei. Нако-
нец, оно расшифровывает третью компоненту ".." в имени пути поис-
ка. Ядро обнаруживает, что номер индекса для ".." совпадает с но-
мером корневого индекса, рабочим индексом является корневой ин-
декс, а ".." является текущей компонентой имени пути поиска. Ядро
находит запись в таблице монтирования, соответствующую точке мон-
тирования "usr", освобождает текущий рабочий индекс (корень фай-
ловой системы, смонтированной в каталоге "usr") и назначает ин-
декс точки монтирования (каталога "usr" в корневой файловой
системе) в качестве нового рабочего индекса. Затем оно просматри-
вает записи в каталоге точки монтирования "/usr" в поисках имени
".." и находит номер индекса для корня файловой системы ("/").
После этого системная функция chdir завершается как обычно, вызы-
вающий процесс не обращает внимания на тот факт, что он пересек
точку монтирования.
5.14.2 Демонтирование файловой системы
Синтаксис вызова системной функции umount:
umount(special filename);
где special filename указывает демонтируемую файловую систему.
При демонтировании файловой системы (Рисунок 5.27) ядро обращает-
ся к индексу демонтируемого устройства, восстанавливает номер ус-
тройства для специального файла, освобождает индекс (алгоритм
iput) и находит в таблице монтирования запись с номером устройс-
тва, равным номеру устройства для специального файла. Прежде чем
ядро действительно демонтирует файловую систему, оно должно удос-
товериться в том, что в системе не осталось используемых файлов,
для этого ядро просматривает таблицу индексов в поисках всех фай-
лов, чей номер устройства совпадает с номером демонтируемой сис-
темы. Активным файлам соответствует положительное значение счет-
чика ссылок и в их число входят текущий каталог процесса, файлы с
разделяемым текстом, которые исполняются в текущий момент (глава
7), и открытые когда-то файлы, которые потом не были закрыты. Ес-
ли какие-нибудь файлы из файловой системы активны, функция umount
завершается неудачно: если бы она прошла успешно, активные файлы
сделались бы недоступными.
Буферный пул все еще содержит блоки с "отложенной записью",
не переписанные на диск, поэтому ядро "вымывает" их из буферного
пула. Ядро удаляет записи с разделяемым текстом, которые находят-
ся в таблице областей, но не являются действующими (подробности в
главе 7), записывает на диск все недавно скорректированные су-
перблоки и корректирует дисковые копии всех индексов, которые
требуют этого. Казалось, было бы достаточно откорректировать дис-
ковые блоки, суперблок и индексы только для демонтируемой файло-
вой системы, однако в целях сохранения преемственности изменений
-------------------------------------------------------------┐
│ алгоритм umount │
│ входная информация: имя специального файла, соответствую- │
│ щего демонтируемой файловой системе │
│ выходная информация: отсутствует │
│ { │
│ если (пользователь не является суперпользователем) │
│ возвратить (ошибку); │
│ получить индекс специального файла (алгоритм namei); │
│ извлечь старший и младший номера демонтируемого устрой-│
│ ства; │
│ получить в таблице монтирования запись для демонтируе- │
│ мой системы, исходя из старшего и младшего номеров; │
│ освободить индекс специального файла (алгоритм iput); │
│ удалить из таблицы областей записи с разделяемым текс- │
│ том для файлов, принадлежащих файловой │
│ системе; /* глава 7ххх */ │
│ скорректировать суперблок, индексы, выгрузить буферы │
│ на диск; │
│ если (какие-то файлы из файловой системы все еще ис- │
│ пользуются) │
│ возвратить (ошибку); │
│ получить из таблицы монтирования корневой индекс монти-│
│ рованной файловой системы; │
│ заблокировать индекс; │
│ освободить индекс (алгоритм iput); /* iget был при │
│ монтировании */ │
│ запустить процедуру закрытия для специального устрой- │
│ ства; │
│ сделать недействительными (отменить) в пуле буферы из │
│ демонтируемой файловой системы; │
│ получить из таблицы монтирования индекс точки монтиро- │
│ вания; │
│ заблокировать индекс; │
│ очистить флаг, помечающий индекс как "точку монтирова- │
│ ния"; │
│ освободить индекс (алгоритм iput); /* iget был при │
│ монтировании */ │
│ освободить буфер, используемый под суперблок; │
│ освободить в таблице монтирования место, занятое ранее;│
│ } │
L-------------------------------------------------------------
Рисунок 5.27. Алгоритм демонтирования файловой системы
ядро выполняет аналогичные действия для всей системы в целом. За-
тем ядро освобождает корневой индекс монтированной файловой сис-
темы, удерживаемый с момента первого обращения к нему во время
выполнения функции mount, и запускает из драйвера процедуру зак-
рытия устройства, содержащего файловую систему. Впоследствии ядро
просматривает буферы в буферном кеше и делает недействительными
те из них, в которых находятся блоки демонтируемой файловой сис-
темы; в хранении информации из этих блоков в кеше больше нет не-
обходимости. Делая буферы недействительными, ядро вставляет их в
начало списка свободных буферов, в то время как блоки с актуаль-
ной информацией остаются в буферном кеше. Ядро сбрасывает в ин-
дексе системы, где производилось монтирование, флаг "точки монти-
рования", установленный функцией mount, и освобождает индекс.
Пометив запись в таблице монтирования свободной для общего ис-
пользования, функция umount завершает работу.
/
│
│
usr
│
-------------+-------------┐
│ │
src include
│ │
│ -----+----┐
uts sys realfile.h
│
│
sys
│
--------+-------┐
inode.h testfile.h
Рисунок 5.28. Файлы в дереве файловой системы, связанные с
помощью функции link
5.15 LINK
Системная функция link связывает файл с новым именем в струк-
туре каталогов файловой системы, создавая для существующего ин-
декса новую запись в каталоге. Синтаксис вызова функции link:
link(source file name, target file name);
где source file name - существующее имя файла, а target file
name - новое (дополнительное) имя, присваиваемое файлу после вы-
полнения функции link. Файловая система хранит имя пути поиска
для каждой связи, имеющейся у файла, и процессы могут обращаться
к файлу по любому из этих имен. Ядро не знает, какое из имен фай-
ла является его подлинным именем, поэтому имя файла специально не
обрабатывается. Например, после выполнения набора функций:
link("/usr/src/uts/sys","/usr/include/sys");
link("/usr/include/realfile.h","/usr/src/uts/sys/testfile.h");
на один и тот же файл будут указывать три имени пути поиска:
"/usr/src/uts/sys/testfile.h", "/usr/include/sys/testfile.h" и
"/usr/include/realfile" (см. Рисунок 5.28).
Ядро позволяет суперпользователю (и только ему) связывать ка-
талоги, упрощая написание программ, требующих пересечения дерева
файловой системы. Если бы это было разрешено произвольному поль-
зователю, программам, пересекающим иерархическую структуру фай-
лов, пришлось бы заботиться о том, чтобы не попасть в бесконечный
цикл в том случае, если пользователь связал каталог с вершиной,
стоящей ниже в иерархии. Предполагается, что суперпользователи
более осторожны в указании таких связей. Возможность связывать
между собой каталоги должна была поддерживаться в ранних версиях
системы, так как эта возможность требуется для реализации команды
mkdir, которая создает новый каталог. Включение функции mkdir ус-
траняет необходимость в связывании каталогов.
-------------------------------------------------------------┐
│ алгоритм link │
│ входная информация: существующее имя файла │
│ новое имя файла │
│ выходная информация: отсутствует │
│ { │
│ получить индекс для существующего имени файла (алгоритм │
│ namei); │
│ если (у файла слишком много связей или производится │
│ связывание каталога без разрешения суперпользователя) │
│ { │
│ освободить индекс (алгоритм iput); │
│ возвратить (ошибку); │
│ } │
│ увеличить значение счетчика связей в индексе; │
│ откорректировать дисковую копию индекса; │
│ снять блокировку с индекса; │
│ получить индекс родительского каталога для включения но-│
│ вого имени файла (алгоритм namei); │
│ если (файл с новым именем уже существует или существую- │
│ щий файл и новый файл находятся в разных файловых сис- │
│ темах) │
│ { │
│ отменить корректировку, сделанную выше; │
│ возвратить (ошибку); │
│ } │
│ создать запись в родительском каталоге для файла с но- │
│ вым именем: │
│ включить в нее новое имя и номер индекса существую- │
│ щего файла; │
│ освободить индекс родительского каталога (алгоритм │
│ iput); │
│ освободить индекс существующего файла (алгоритм iput); │
│ } │
L-------------------------------------------------------------
Рисунок 5.29. Алгоритм связывания файлов
На Рисунке 5.29 показан алгоритм функции link. Сначала ядро,
используя алгоритм namei, определяет местонахождение индекса ис-
ходного файла, увеличивает значение счетчика связей в индексе,
корректирует дисковую копию индекса (для обеспечения согласован-
ности) и снимает с индекса блокировку. Затем ядро ищет файл с но-
вым именем; если он существует, функция link завершается неудачно
и ядро восстанавливает прежнее значение счетчика связей, изменен-
ное ранее. В противном случае ядро находит в родительском катало-
ге свободную запись для файла с новым именем, записывает в нее
новое имя и номер индекса исходного файла и освобождает индекс
родительского каталога, используя алгоритм iput. Поскольку файл с
новым именем ранее не существовал, освобождать еще какой-нибудь
индекс не нужно. Ядро, освобождая индекс исходного файла, делает
заключение: счетчик связей в индексе имеет значение, на 1 боль-
шее, чем то значение, которое счетчик имел перед вызовом функции,
и обращение к файлу теперь может производиться по еще одному име-
ни в файловой системе. Счетчик связей хранит количество записей
в каталогах, которые (записи) указывают на файл, и тем самым от-
личается от счетчика ссылок в индексе. Если по завершении выпол-
нения функции link к файлу нет обращений со стороны других про-
цессов, счетчик ссылок в индексе принимает значение, равное 0, а
счетчик связей - значение, большее или равное 2.
Например, выполняя функцию, вызванную как:
link("source","/dir/target");
ядро обнаруживает индекс для файла "source", увеличивает в нем
значение счетчика связей, запоминает номер индекса, скажем 74, и
снимает с индекса блокировку. Ядро также находит индекс каталога
"dir", являющегося родительским каталогом для файла "target",
ищет свободное место в каталоге "dir" и записывает в него имя
файла "target" и номер индекса 74. По окончании этих действий оно
освобождает индекс файла "source" по алгоритму iput. Если значе-
ние счетчика связей файла "source" раньше было равно 1, то теперь
оно равно 2.
Стоит упомянуть о двух тупиковых ситуациях, явившихся причи-
ной того, что процесс снимает с индекса исходного файла блокиров-
ку после увеличения значения счетчика связей. Если бы ядро не
снимало с индекса блокировку, два процесса, выполняющие одновре-
менно следующие функции:
процесс A: link("a/b/c/d","e/f/g");
процесс B: link("e/f","a/b/c/d/ee");
зашли бы в тупик (взаимная блокировка). Предположим, что процесс
A обнаружил индекс файла "a/b/c/d" в тот самый момент, когда про-
цесс B обнаружил индекс файла "e/f". Фраза "в тот же самый мо-
мент" означает, что системой достигнуто состояние, при котором
каждый процесс получил искомый индекс. (Рисунок 5.30 иллюстрирует
стадии выполнения процессов.) Когда же теперь процесс A попытает-
ся получить индекс файла "e/f", он приостановит свое выполнение
до тех пор, пока индекс файла "f" не освободится. В то же время
процесс B пытается получить индекс каталога "a/b/c/d" и приоста-
навливается в ожидании освобождения индекса файла "d". Процесс A
будет удерживать заблокированным индекс, нужный процессу B, а