The design of the unix operating system by Maurice J
Вид материала | Реферат |
5.14 Монтирование и демонтирование файловых систем |
- Лекция 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.
│ cp2 = buf; │
│ while(*cp1) │
│ *cp2++ = *cp1++; │
│ pipe(fds); │
│ for (;;) │
│ { │
│ write(fds[1],buf,6); │
│ read(fds[0],buf,6); │
│ } │
│ } │
L----------------------------------
Рисунок 5.18. Чтение из канала и запись в канал
5.12.5 Примеры
Программа на Рисунке 5.18 иллюстрирует искусственное исполь-
зование каналов. Процесс создает канал и входит в бесконечный
цикл, записывая в канал строку символов "hello" и считывая ее из
канала. Ядру не нужно ни знать о том, что процесс, ведущий запись
в канал, является и процессом, считывающим из канала, ни прояв-
лять по этому поводу какое-либо беспокойство.
Процесс, выполняющий программу, которая приведена на Рисунке
5.19, создает поименованный канал с именем "fifo". Если этот про-
цесс запущен с указанием второго (формального) аргумента, он пос-
-------------------------------------------------------------┐
│ #include
│ char string[] = "hello"; │
│ main(argc,argv) │
│ int argc; │
│ char *argv[]; │
│ { │
│ int fd; │
│ char buf[256]; │
│ │
│ /* создание поименованного канала с разрешением чтения и │
│ записи для всех пользователей */ │
│ mknod("fifo",010777,0); │
│ if(argc == 2) │
│ fd = open("fifo",O_WRONLY); │
│ else │
│ fd = open("fifo",O_RDONLY); │
│ for (;;) │
│ if(argc == 2) │
│ write(fd,string,6); │
│ else │
│ read(fd,buf,6); │
│ } │
L-------------------------------------------------------------
Рисунок 5.19. Чтение и запись в поименованный канал
тоянно записывает в канал строку символов "hello"; будучи запущен
без второго аргумента, он ведет чтение из поименованного канала.
Два процесса запускаются по одной и той же программе, тайно дого-
ворившись взаимодействовать между собой через поименованный канал
"fifo", но им нет необходимости быть родственными процессами.
Другие пользователи могут выполнять программу и участвовать в ди-
алоге (или мешать ему).
5.13 DUP
Системная функция dup копирует дескриптор файла в первое сво-
бодное место в таблице пользовательских дескрипторов файла, возв-
ращая новый дескриптор пользователю. Она действует для всех типов
файла. Синтаксис вызова функции:
newfd = dup(fd);
где fd - дескриптор файла, копируемый функцией, а newfd - новый
дескриптор, ссылающийся на файл. Поскольку функция dup дублирует
дескриптор файла, она увеличивает значение счетчика в соответс-
твующей записи таблицы файлов - записи, на которую указывают свя-
занные с ней точки входа в таблице файловых дескрипторов, которых
теперь стало на одну больше. Например, обзор структур данных,
изображенных на Рисунке 5.20, показывает, что процесс вызывает
следующую последовательность функций: он открывает (open) файл с
именем "/etc/passwd" (файловый дескриптор 3), затем открывает
файл с именем "local" (файловый дескриптор 4), снова файл с име-
нем "/etc/passwd" (файловый дескриптор 5) и, наконец, дублирует
(dup) файловый дескриптор 3, возвращая дескриптор 6.
таблица пользова-
тельских дескрип-
торов файла таблица файлов таблица индексов
----------┐ -------------┐ ---------------┐
0│ ----+----┐ │ │ │ │
+---------+ │ │ │ │ │
1│ ----+---┐L-->│ │ │ │
+---------+ │ +------------+ │ │
2│ ----+--┐L--->│ │ │ │
+---------+ L---->│ │ │ │
3│ ----+----┐ │ │ │ │
+---------+ │ │ │ +--------------+
4│ ----+---┐│ │ │ ----->│ счет- │
+---------+ ││ │ │ │ │ чик (/etc/ │
5│ ----+--┐││ +------------+ │ --->│ 2 passwd)│
+---------+ │││ │ счет- │ │ │ +--------------+
6│ ----+┐ ││L-->│ чик +--- │ │ │
+---------+L-││--->│ 2 │ │ │ │
7│ │ ││ +------------+ │ │ │
+---------+ ││ │ │ │ │ │
│ │ ││ │ │ │ │ │
│ │ ││ │ │ │ │ │
│ │ ││ +------------+ │ │ │
L---------- ││ │ счет- │ │ │ │
│L--->│ чик +----│┐ │ │
│ │ 1 │ ││ │ │
│ +------------+ ││ │ │
│ │ │ ││ +--------------+
│ │ │ ││ │ счет- │
│ │ │ │L->│ чик (local)│
│ │ │ │ │ 1 │
│ │ │ │ +--------------+
│ │ │ │ │ │
│ +------------+ │ │ │
│ │ счет- │ │ │ │
L---->│ чик +----- │ │
│ 1 │ │ │
+------------+ │ │
│ │ │ │
│ │ L---------------
│ │
L-------------
Рисунок 5.20. Структуры данных после выполнения функции dup
Возможно, dup - функция, не отличающаяся изяществом, посколь-
ку она предполагает, что пользователь знает о том, что система
возвратит свободную точку входа в таблице пользовательских деск-
рипторов, имеющую наименьший номер. Однако, она служит важной за-
даче конструирования сложных программ из более простых конструк-
ционных блоков, что, в частности, имеет место при создании
конвейеров, составленных из командных процессоров.
Рассмотрим программу, приведенную на Рисунке 5.21. В перемен-
ной i хранится дескриптор файла, возвращаемый в результате откры-
тия файла "/etc/passwd", а в переменной j - дескриптор файла,
возвращаемый системой в результате дублирования дескриптора i с
помощью функции dup. В адресном пространстве процесса оба пользо-
вательских дескриптора, представленные переменными i и j, ссыла-
ются на одну и ту же запись в таблице файлов и поэтому используют
одно и то же значение смещения внутри файла. Таким образом, пер-
вые два вызова процессом функции read реализуют последовательное
считывание данных, и в буферах buf1 и buf2 будут располагаться
разные данные. Совсем другой результат получается, когда процесс
---------------------------------------------------------┐
│ #include
│ main() │
│ { │
│ int i,j; │
│ char buf1[512],buf2[512]; │
│ │
│ i = open("/etc/passwd",O_RDONLY); │
│ j = dup(i); │
│ read(i,buf1,sizeof(buf1)); │
│ read(j,buf2,sizeof(buf2)); │
│ close(i); │
│ read(j,buf2,sizeof(buf2)); │
│ } │
L---------------------------------------------------------
Рисунок 5.21. Программа на языке Си, иллюстрирующая использо-
вание функции dup
открывает один и тот же файл дважды и читает дважды одни и те же
данные (раздел 5.2). Процесс может освободить с помощью функции
close любой из файловых дескрипторов по своему желанию, и
ввод-вывод получит нормальное продолжение по другому дескриптору,
как показано на примере. В частности, процесс может "закрыть"
дескриптор файла стандартного вывода (файловый дескриптор 1),
снять с него копию, имеющую то же значение, и затем рассматривать
новый файл в качестве файла стандартного вывода. В главе 7 будет
представлен более реалистический пример использования функций
pipe и dup при описании особенностей реализации командного про-
цессора.
5.14 МОНТИРОВАНИЕ И ДЕМОНТИРОВАНИЕ ФАЙЛОВЫХ СИСТЕМ
Физический диск состоит из нескольких логических разделов, на
которые он разбит дисковым драйвером, причем каждому разделу со-
ответствует файл устройства, имеющий определенное имя. Процессы
обращаются к данным раздела, открывая соответствующий файл уст-
ройства и затем ведя запись и чтение из этого "файла", представ-
ляя его себе в виде последовательности дисковых блоков. Это взаи-
модействие во всех деталях рассматривается в главе 10. Раздел
диска может содержать логическую файловую систему, состоящую из
блока начальной загрузки, суперблока, списка индексов и информа-
ционных блоков (см. главу 2). Системная функция mount (монтиро-
вать) связывает файловую систему из указанного раздела на диске с
существующей иерархией файловых систем, а функция umount (демон-
тировать) выключает файловую систему из иерархии. Функция mount,
таким образом, дает пользователям возможность обращаться к данным
в дисковом разделе как к файловой системе, а не как к последова-
тельности дисковых блоков.
Синтаксис вызова функции mount:
mount(special pathname,directory pathname,options);
где special pathname - имя специального файла устройства, соот-
ветствующего дисковому разделу с монтируемой файловой системой,
directory pathname - каталог в существующей иерархии, где будет
монтироваться файловая система (другими словами, точка или место
монтирования), а options указывает, следует ли монтировать файло-
вую систему "только для чтения" (при этом не будут выполняться
- - - - - - - - - - - - - - - - - - - - - - - - - ┐
/
│ │ │
-----------------T--+-------------┐ Корневая
│ │ │ │ │ файловая
bin etc usr система
│ │ │ │
------+-----┐ -----+----┐
│ │ │ │ │ │ │
cc date sh getty passwd
L - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - ┐
/
│ │ │
Файловая -----------------T--+-------------┐
система из │ │ │ │ │
раздела с bin include src
именем │ │ │ │ │
/dev/dsk1 ------+-----┐ │ │
│ │ │ │ │ │ │
awk banner yacc stdio.h uts
L - - - - - - - - - - - - - - - - - - - - - - - - -
Рисунок 5.22. Дерево файловых систем до и после выполнения
функции mount
такие функции, как write и creat, которые производят запись в
файловую систему). Например, если процесс вызывает функцию mount
следующим образом:
mount("/dev/dsk1","/usr",0);
ядро присоединяет файловую систему, находящуюся в дисковом разде-
ле с именем "/dev/dsk1", к каталогу "/usr" в существующем дереве
файловых систем (см. Рисунок 5.22). Файл "/dev/dsk1" является
блочным специальным файлом, т.е. он носит имя устройства блочного
типа, обычно имя раздела на диске. Ядро предполагает, что раздел
на диске с указанным именем содержит файловую систему с супербло-
ком, списком индексов и корневым индексом. После выполнения функ-
ции mount к корню смонтированной файловой системы можно обращать-
ся по имени "/usr". Процессы могут обращаться к файлам в
монтированной файловой системе и игнорировать тот факт, что сис-
тема может отсоединяться. Только системная функция link контроли-
рует файловую систему, так как в версии V не разрешаются связи
между файлами, принадлежащими разным файловым системам (см. раз-
дел 5.15).
Ядро поддерживает таблицу монтирования с записями о каждой
монтированной файловой системе. В каждой записи таблицы монтиро-
вания содержатся:
* номер устройства, идентифицирующий монтированную файловую
систему (упомянутый выше логический номер файловой системы);
* указатель на буфер, где находится суперблок файловой системы;
* указатель на корневой индекс монтированной файловой системы
("/" для файловой системы с именем "/dev/dsk1" на Рисунке
5.22);
* указатель на индекс каталога, ставшего точкой монтирования
(на Рисунке 5.22 это каталог "usr", принадлежащий корневой
файловой системе).
Связь индекса точки монтирования с корневым индексом монтиро-
ванной файловой системы, возникшая в результате выполнения сис-
темной функции mount, дает ядру возможность легко двигаться по
иерархии файловых систем без получения от пользователей дополни-
тельных сведений.
-------------------------------------------------------------┐
│ алгоритм mount │
│ входная информация: имя блочного специального файла │
│ имя каталога точки монтирования │
│ опции ("только для чтения") │
│ выходная информация: отсутствует │
│ { │
│ если (пользователь не является суперпользователем) │
│ возвратить (ошибку); │
│ получить индекс для блочного специального файла (алго- │
│ ритм namei); │
│ проверить допустимость значений параметров; │
│ получить индекс для имени каталога, где производится │
│ монтирование (алгоритм namei); │
│ если (индекс не является индексом каталога или счетчик │
│ ссылок имеет значение > 1) │
│ { │
│ освободить индексы (алгоритм iput); │
│ возвратить (ошибку); │
│ } │
│ найти свободное место в таблице монтирования; │
│ запустить процедуру открытия блочного устройства для │
│ данного драйвера; │
│ получить свободный буфер из буферного кеша; │
│ считать суперблок в свободный буфер; │
│ проинициализировать поля суперблока; │
│ получить корневой индекс монтируемой системы (алгоритм │
│ iget), сохранить его в таблице монтирования; │
│ сделать пометку в индексе каталога о том, что каталог │
│ является точкой монтирования; │
│ освободить индекс специального файла (алгоритм iput); │
│ снять блокировку с индекса каталога точки монтирования;│
│ } │
L-------------------------------------------------------------
Рисунок 5.23. Алгоритм монтирования файловой системы
На Рисунке 5.23 показан алгоритм монтирования файловой систе-
мы. Ядро позволяет монтировать и демонтировать файловые системы
только тем процессам, владельцем которых является суперпользова-
тель. Предоставление возможности выполнять функции mount и umount
всем пользователям привело бы к внесению с их стороны хаоса в ра-
боту файловой системы, как умышленному, так и явившемуся резуль-
татом неосторожности. Суперпользователи могут разрушить систему
только случайно.
Ядро находит индекс специального файла, представляющего фай-
ловую систему, подлежащую монтированию, извлекает старший и млад-
ший номера, которые идентифицируют соответствующий дисковый раз-
дел, и выбирает индекс каталога, в котором файловая система будет
смонтирована. Счетчик ссылок в индексе каталога должен иметь зна-
чение, не превышающее 1 (и меньше 1 он не должен быть - почему
?), в связи с наличием потенциально опасных побочных эффектов
(см. упражнение 5.27). Затем ядро назначает свободное место в
таблице монтирования, помечает его для использования и присваива-
ет значение полю номера устройства в таблице. Вышеуказанные наз-
начения производятся немедленно, поскольку вызывающий процесс мо-
жет приостановиться, следуя процедуре открытия устройства или
считывая суперблок файловой системы, а другой процесс тем време-
нем попытался бы смонтировать файловую систему. Пометив для ис-
пользования запись в таблице монтирования, ядро не допускает ис-
пользования в двух вызовах функции mount одной и той же записи
таблицы. Запоминая номер устройства с монтируемой системой, ядро
может воспрепятствовать повторному монтированию одной и той же
системы другими процессами, которое, будь оно допущено, могло бы
привести к непредсказуемым последствиям (см. упражнение 5.26).
Ядро вызывает процедуру открытия для блочного устройства, со-
держащего файловую систему, точно так же, как оно делает это при
непосредственном открытии блочного устройства (глава 10). Проце-
дура открытия устройства обычно проверяет существование такого
устройства, иногда производя инициализацию структур данных драй-
вера и посылая команды инициализации аппаратуре. Затем ядро выде-
ляет из буферного пула свободный буфер (вариант алгоритма getblk)
для хранения суперблока монтируемой файловой системы и считывает
суперблок, используя один из вариантов алгоритма read. Ядро сох-
раняет указатель на индекс каталога, в котором монтируется систе-
ма, давая возможность маршрутам поиска файловых имен, содержащих
имя "..", пересекать точку монтирования, как мы увидим дальше.
Оно находит корневой индекс монтируемой файловой системы и запо-
минает указатель на индекс в таблице монтирования. С точки зрения
пользователя, место (точка) монтирования и корень файловой систе-
мы логически эквивалентны, и ядро упрочивает эту эквивалентность
благодаря их сосуществованию в одной записи таблицы монтирования.
Процессы больше не могут обращаться к индексу каталога - точки
монтирования.
Ядро инициализирует поля в суперблоке файловой системы, очи-
щая поля для списка свободных блоков и списка свободных индексов
и устанавливая число свободных индексов в суперблоке равным 0.
Целью инициализации (задания начальных значений полей) является
сведение к минимуму опасности разрушить файловую систему, если
монтирование осуществляется после аварийного завершения работы
системы. Если ядро заставить думать, что в суперблоке отсутствуют
свободные индексы, то это приведет к запуску алгоритма ialloc,
ведущего поиск на диске свободных индексов. К сожалению, если
список свободных дисковых блоков испорчен, ядро не исправляет
этот список изнутри (см. раздел 5.17 о сопровождении файловой
системы). Если пользователь монтирует файловую систему только для
чтения, запрещая проведение всех операций записи в системе, ядро
устанавливает в суперблоке соответствующий флаг. Наконец, ядро
помечает индекс каталога как "точку монтирования", чтобы другие
процессы позднее могли ссылаться на нее. На Рисунке 5.24 предс-
тавлен вид различных структур данных по завершении выполнения
функции mount.
5.14.1 Пересечение точек монтирования в маршрутах поиска
имен файлов
Давайте повторно рассмотрим поведение алгоритмов namei и iget
в случаях, когда маршрут поиска файлов проходит через точку мон-
тирования. Точку монтирования можно пересечь двумя способами: из
файловой системы, где производится монтирование, в файловую сис-
тему, которая монтируется (в направлении от глобального корня к
листу), и в обратном направлении. Эти способы иллюстрирует следу-
ющая последовательность команд shell'а.
Таблица индексов Таблица монтирования
-------------------┐ ---------------------┐
│ │ │ │
+------------------+ │ │
│ Индекс каталога, + - - ┐ │ │
│ где производится │ │ │
│ монтирование │ │ │ │ --------┐
│ Помечен как "точ-│<---┐ │ │-->│ Буфер │
│ ка монтирования" │ ││ │ ││ L--------
│ Счетчик ссылок =1│ │ │ ││
+------------------+ │L >+--------------------+│
│ │ │ │ Суперблок ---+-
+------------------+ L---+ Индекс точки монти-│
│ Индекс устройства│ │ рования │
│ Не используется │ ----+- Корневой индекс │
│ Счетчик ссылок =0│ │ +--------------------+
+------------------+ │ │ │
│ │ │ │ │
+------------------+<---- │ │
│ Индекс корня мон-│ │ │
│ тируемой файловой│ │ │
│ системы │ │ │
│ Счетчик ссылок =1│ L---------------------
+------------------+
│ │
L-------------------
Рисунок 5.24. Структуры данных после монтирования
mount /dev/dsk1 /usr
cd /usr/src/uts
cd ../../..
По команде mount после выполнения некоторых логических прове-
рок запускается системная функция mount, которая монтирует файло-
вую систему в дисковом разделе с именем "/dev/dsk1" под управле-
нием каталога "/usr". Первая из команд cd (сменить каталог)
побуждает командный процессор shell вызвать системную функцию
chdir, выполняя которую, ядро анализирует имя пути поиска, пере-
секающего точку монтирования в "/usr". Вторая из команд cd приво-
дит к тому, что ядро анализирует имя пути поиска и пересекает