| - системной функции
| - Посылает ответ пери-
| - ферийному процессу:
| - выполнение функции
| - прервано
| Выходит из состояния приостанова
| Анализирует ответ
v Обрабатывает сигнал

Рисунок 13.8. Прерывание во время выполнения системной функции

388


Предположим, например, что периферийный процесс вызывает функцию чтения
с терминала, связанного с центральным процессором, и приостанавливает свою
работу на время выполнения функции процессом-спутником (Рисунок 13.8). Если
пользователь нажимает клавишу прерывания (break), ядро ЦП посылает процес-
су-спутнику соответствующий сигнал. Если спутник находился в состоянии при-
останова в ожидании ввода с терминала порции данных, он немедленно выходит
из этого состояния и прекращает выполнение функции read. В своем ответе на
запрос периферийного процесса спутник сообщает код ошибки и номер сигнала,
соответствующий прерыванию. Периферийный процесс анализирует ответ и, пос-
кольку в сообщении говорится о поступлении сигнала прерывания, отправляет
сигнал самому себе. Перед выходом из функции read периферийное ядро осущест-
вляет проверку поступления сигналов, обнаруживает сигнал прерывания, посту-
пивший от процесса-спутника, и обрабатывает его обычным порядком. Если в ре-
зультате получения сигнала прерывания периферийный процесс завершает свою
работу с помощью функции exit, данная функция берет на себя заботу об унич-
тожении процесса-спутника. Если периферийный процесс перехватывает сигналы о
прерывании, он вызывает пользовательскую функцию обработки сигналов и по вы-
ходе из функции read возвращает пользователю код ошибки. С другой стороны,
если спутник исполняет от имени периферийного процесса системную функцию
stat, он не будет прерывать ее выполнение при получении сигнала (функции
stat гарантирован выход из любого приостанова, поскольку для нее время ожи-
дания ресурса ограничено). Спутник доводит выполнение функции до конца и
возвращает периферийному процессу номер сигнала. Периферийный процесс посы-
лает сигнал самому себе и получает его на выходе из системной функции.
Если сигнал возник на периферийном процессоре во время выполнения сис-
темной функции, периферийный процесс будет находиться в неведении относи-
тельно того, вернется ли к нему вскоре управление от процесса-спутника или
же последний перейдет в состояние приостанова на неопределенное время. Пери-
ферийный процесс посылает спутнику специальное сообщение, информируя его о
возникновении сигнала. Ядро на ЦП расшифровывает сообщение и посылает сигнал
спутнику, реакция которого на получение сигнала описана в предыдущих параг-
рафах (аварийное завершение выполнения функции или доведение его до конца).
Периферийный процесс не может послать сообщение спутнику непосредственно,
поскольку спутник занят исполнением системной функции и не считывает данные
из линии связи.
Если обратиться к примеру с функцией read, следует отметить, что перифе-
рийный процесс не имеет представления о том, ждет ли его спутник ввода дан-
ных с терминала или же выполняет другие действия. Периферийный процесс посы-
лает спутнику сообщение о сигнале: если спутник находится в состоянии приос-
танова с приоритетом, допускающим прерывания, он немедленно выходит из этого
состояния и прекращает выполнение системной функции; в противном случае вы-
полнение функции доводится до успешного завершения.
Рассмотрим, наконец, случай поступления сигнала во время, не связанное с
выполнением системной функции. Если сигнал возник на другом процессоре,
спутник получает его первым и посылает сообщение о сигнале периферийному
процессу, независимо от того, касается ли этот сигнал периферийного процесса
или нет. Периферийное ядро расшифровывает сообщение и посылает сигнал про-
цессу, который реагирует на него обычным порядком. Если сигнал возник на пе-
риферийном процессоре, процесс выполняет стандартные действия, не прибегая к
услугам своего спутника.
Когда периферийный процесс посылает сигнал другим периферийным процес-
сам, он кодирует сообщение о вызове функции kill и посылает его процес-
су-спутнику, который исполняет вызываемую функцию локально. Если часть про-
цессов, для которых предназначен сигнал, имеет местонахождение на других пе-
риферийных процессорах, сигнал получат (и прореагируют на его получение вы-
шеописанным образом) их спутники.



389

    13.2 СВЯЗЬ ТИПА NEWCASTLЕ



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

"sftig!/fs1/mjb/rje"

идентифицирует файл "/fs1/mjb/rje", находящийся на машине "sftig". Такая
схема идентифицирования файла соответствует соглашению, установленному прог-
раммой uucp относительно передачи файлов между системами типа UNIX. В другой
схеме удаленные файлы идентифицируются добавлением к имени специального пре-
фикса, например:

/../sftig/fs1/mjb/rje

где "/../" - префикс, свидетельствующий о том, что файл удаленный; вторая
компонента имени файла является именем удаленной машины. В данной схеме ис-


Процесс-клиент Процесс-сервер
+-----------------------------+ +----------------------------+
| Таблица | | Процесс- |
| Си-библиотека открытых | | спутник Запрос |
| файлов | | (пользо- на чтение |
| +------+ | | вательский | | |
| +--------------+--- | | | уровень) | | |
| | +------+ | | | | |
| | локальный | | | | +-------------+ | |
| | +------+ | | | | |
| | +----+--- | | | | | |
| | | +------+ | | | | |
| | | | | | | | | |
| | | +------+ | | | | |
| | +-----+ | | | | |
+----+---------------+--------+ +----+-----------------+-----+
| | удаленный | |
+----+---------------+--------+ +----+-----------------+-----+
| | Сетевой | | | Сетевой |
| Ядро интерфейс | | Ядро интерфейс |
| | | | | |
+--------------------+--------+ +----------------------+-----+
| с е т ь |
+-------------------------------------+

Рисунок 13.9. Формулирование запросов к файловому серверу (процессору)

390



пользуется привычный синтаксис имен файлов в системе UNIX, поэтому в отличие
от первой схемы здесь пользовательским программам нет необходимости прино-
равливаться к использованию имен, имеющих необычную конструкцию (см. [Pike
85]).
Всю оставшуюся часть раздела мы посвятим рассмотрению модели системы,
использующей связь типа Newcastle, в которой ядро не занимается распознава-
нием удаленных файлов; эта функция полностью возлагается на подпрограммы из
стандартной Си-библиотеки, выполняющие в данном случае роль системного ин-
терфейса. Эти подпрограммы анализируют первую компоненту имени файла, в обо-
их описанных способах идентифицирования содержащую признак удаленности фай-
ла. В этом состоит отступление от заведенного порядка, при котором библио-
течные подпрограммы не занимаются синтаксическим разбором имен файлов. На
Рисунке 13.9 показано, каким образом формулируются запросы к файловому сер-
веру. Если файл локальный, ядро локальной системы обрабатывает запрос обыч-
ным способом. Рассмотрим обратный случай:

open("/../sftig/fs1/mjb/rje/file",O_RDONLY);

Подпрограмма open из Си-библиотеки анализирует первые две компоненты состав-
ного имени файла и узнает, что файл следует искать на удаленной машине
"sftig". Чтобы иметь информацию о том, была ли ранее у процесса связь с дан-
ной машиной, подпрограмма заводит специальную структуру, в которой запомина-
ет этот факт, и в случае отрицательного ответа устанавливает связь с файло-
вым сервером, работающим на удаленной машине. Когда процесс формулирует свой
первый запрос на дистанционную обработку, удаленный сервер подтверждает зап-
рос, в случае необходимости ведет запись в поля пользовательского и группо-
вого кодов идентификации и создает процессспутник, который будет выступать
от имени процесса-клиента.
Чтобы выполнять запросы клиента, спутник должен иметь на удаленной маши-
не те же права доступа к файлам, что и клиент. Другими словами, пользователь
"mjb" должен иметь и к удаленным, и к локальным файлам одинаковые права дос-
тупа. К сожалению, не исключена возможность того, что код идентификации кли-
ента "mjb" может совпасть с кодом идентификации другого клиента удаленной
машины. Таким образом, администраторам систем на работающих в сети машинах
следует либо следить за назначением каждому пользователю кода идентификации,
уникального для всей сети, либо в момент формулирования запроса на сетевое
обслуживание выполнять преобразование кодов. Если это не будет сделано, про-
цесс-спутник будет иметь на удаленной машине права другого клиента.
Более деликатным вопросом является получение в отношении работы с уда-
ленными файлами прав суперпользователя. С одной стороны, клиент-суперпользо-
ватель не должен иметь те же права в отношении удаленной системы, чтобы не
вводить в заблуждение средства защиты удаленной системы. С другой стороны,
некоторые из программ, если им не предоставить права суперпользователя,
просто не смогут работать. Примером такой программы является программа mkdir
(см. главу 7), создающая новый каталог. Удаленная система не разрешила бы
клиенту создавать новый каталог, поскольку на удалении права суперпользова-
теля не действуют. Проблема создания удаленных каталогов служит серьезным
основанием для пересмотра системной функции mkdir в сторону расширения ее
возможностей в автоматическом установлении всех необходимых пользователю
связей. Тем не менее, получение setuid-программами (к которым относится и
программа mkdir) прав суперпользователя по отношению к удаленным файлам все
еще остается общей проблемой, требующей своего решения. Возможно, что наи-
лучшим решением этой проблемы было бы установление для файлов дополнительных
характеристик, описывающих доступ к ним со стороны удаленных суперпользова-
телей; к сожалению, это потребовало бы внесения изменений в структуру диско-
вого индекса (в части добавления новых полей) и породило бы слишком большой
беспорядок в существующих системах.

391

Если подпрограмма open завершается успешно, локальная библиотека остав-
ляет об этом соответствующую отметку в доступной для пользователя структуре,
содержащей адрес сетевого узла, идентификатор процесса-спутника, дескриптор
файла и другую аналогичную информацию. Библиотечные подпрограммы read и
write устанавливают, исходя из дескриптора, является ли файл удаленным, и в
случае положительного ответа посылают спутнику сообщение. Процесс-клиент
взаимодействует со своим спутником во всех случаях обращения к системным
функциям, нуждающимся в услугах удаленной машины. Если процесс обращается к
двум файлам, расположенным на одной и той же удаленной машине, он пользуется
одним спутником, но если файлы расположены на разных машинах, используются
уже два спутника: по одному на каждой машине. Два спутника используются и в
том случае, когда к файлу на удаленной машине обращаются два процесса. Вызы-
вая системную функцию через спутника, процесс формирует сообщение, включаю-
щее в себя номер функции, имя пути поиска и другую необходимую информацию,
аналогичную той, которая входит в структуру сообщения в системе с периферий-
ными процессорами.
Механизм выполнения операций над текущим каталогом более сложен. Когда
процесс выбирает в качестве текущего удаленный каталог, библиотечная подп-
рограмма посылает соответствующее сообщение спутнику, который изменяет теку-
щий каталог, при этом подпрограмма запоминает, что каталог удаленный. Во
всех случаях, когда имя пути поиска начинается с символа, отличного от нак-
лонной черты (/), подпрограмма посылает это имя на удаленную машину, где
процесс-спутник прокладывает маршрут, начиная с текущего каталога. Если те-
кущий каталог - локальный, подпрограмма просто передает имя пути поиска ядру
локальной системы. Системная функция chroot в отношении удаленного каталога
выполняется похоже, но при этом ее выполнение для ядра локальной системы
проходит незамеченным; строго говоря, процесс может оставить эту операцию
без внимания, поскольку только библиотека фиксирует ее выполнение.
Когда процесс вызывает функцию fork, соответствующая библиотечная подп-
рограмма посылает сообщения каждому спутнику. Процессы -спутники выполняют
операцию ветвления и посылают идентификаторы своих потомков клиенту-родите-
лю. Процесс-клиент запускает системную функцию fork, которая передает управ-
ление порождаемому потомку; локальный потомок ведет диалог с удаленным по-
томком-спутником, адреса которого сохранила библиотечная подпрограмма. Такая
трактовка функции fork облегчает процессам-спутникам контроль над открытыми
файлами и текущими каталогами. Когда процесс, работающий с удаленными файла-
ми, завершается (вызывая функцию exit), подпрограмма посылает сообщения всем
его удаленным спутникам, чтобы они по получении сообщения проделали то же
самое. Отдельные моменты реализации системных функций exec и exit затрагива-
ются в упражнениях.
Преимущество связи типа Newcastle состоит в том, что обращение процесса
к удаленным файлам становится "прозрачным" (незаметным для пользователя),
при этом в ядро системы никаких изменений вносить не нужно. Однако, данной
разработке присущ и ряд недостатков. Прежде всего, при ее реализации возмож-
но снижение производительности системы. В связи с использованием расширенной
Си-библиотеки размер используемой каждым процессом памяти увеличивается, да-
же если процесс не обращается к удаленным файлам; библиотека дублирует функ-
ции ядра и требует для себя больше места в памяти. Увеличение размера про-
цессов приводит к удлинению продолжительности периода запуска и может выз-
вать большую конкуренцию за ресурсы памяти, создавая условия для более час-
той выгрузки и подкачки задач. Локальные запросы будут исполняться медленнее
из-за увеличения продолжительности каждого обращения к ядру, замедление мо-
жет грозить и обработке удаленных запросов, затраты по пересылке которых по
сети увеличиваются. Дополнительная обработка удаленных запросов на пользова-
тельском уровне увеличивает количество переключений контекста, операций по
выгрузке и подкачке процессов. Наконец, для того, чтобы обращаться к удален-
ным файлам, программы должны быть перекомпилированы с использованием новых
библиотек; старые программы и поставленные объектные модули без этого рабо-
тать с удаленными файлами не смогут. Все эти недостатки отсутствуют в систе-

392

ме, описываемой в следующем разделе.


    13.3 "ПРОЗРАЧНЫЕ" РАСПРЕДЕЛЕННЫЕ ФАЙЛОВЫЕ СИСТЕМЫ




Термин "прозрачное распределение" означает, что пользователи, работающие
на одной машине, могут обращаться к файлам, находящимся на другой машине, не
осознавая того, что тем самым они пересекают машинные границы, подобно тому,
как на своей машине они при переходе от одной файловой системе к другой пе-
ресекают точки монтирования. Имена, по которым процессы обращаются к файлам,
находящимся на удаленных машинах, похожи на имена локальных файлов: отличи-
тельные символы в них отсутствуют. В конфигурации, показанной на Рисунке
13.10, каталог "/usr/src", принадлежащий машине B, "вмонтирован" в каталог
"/usr/src", принадлежащий машине A. Такая конфигурация представляется удоб-
ной в том случае, если в разных системах предполагается использовать один и
тот же исходный код системы, традиционно находящийся в каталоге "/usr/src".
Пользователи, работающие на машине A, могут обращаться к файлам, расположен-
ным на машине B, используя привычный синтаксис написания имен файлов (напри-
мер: "/usr/src/cmd/login.c"), и ядро уже само решает вопрос, является файл
удаленным или же локальным. Пользователи, работающие на машине B, имеют дос-
туп к своим локальным файлам (не подозревая о том, что к этим же файлам мо-
гут обращаться и пользователи машины A), но, в свою очередь, не имеют досту-
па к файлам, находящимся на машине A. Конечно, возможны и другие варианты, в
частности, такие, в которых все удаленные системы монтируются в корне ло-
кальной системы, благодаря чему пользователи получают доступ ко всем файлам
во всех системах.


Машина A Машина B
+-----------------------------+ +-----------------------------+
| / | | / |
| | | | | |
| +--------+--------+ | | +-----------+-----------+ |
| | | | | | | | |
| bin usr | | usr bin etc |
| | | | | | |
| +----+----+ +----+--+ | | +-------+ |
| | | | | | | | | |
|login mail bin src| +--->src bin |
| | | | | | | |
| +---+---+ | | | | +------+-----+ |
| | | | | | | | | | |
| troff vi | | | | lib cmd uts |
| | | | | | |
| | | | | +---+---+ |
| | | | | | | |
| | | | | login.c mail.c |
+---------------------------|-+ | +-----------------------------+
+---+

Рисунок 13.10. Файловые системы после удаленного монтирования


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

393

сохраняет в таблице монтирования информацию, характеризующую данную связь.
Интересная проблема связана с именами путей, включающих "..". Если про-
цесс делает текущим каталог из удаленной файловой системы, последующее ис-
пользование в имени символов ".." скорее вернет процесс в локальную файловую
систему, чем позволит обращаться к файлам, расположенным выше текущего ката-
лога. Возвращаясь вновь к Рисунку 13.10, отметим, что когда процесс, принад-
лежащий машине A, выбрав предварительно в качестве текущего каталог
"/usr/src/cmd", расположенный в удаленной файловой системе, исполнит команду

cd ../../..

текущим каталогом станет корневой каталог, принадлежащий машине A, а не ма-
шине B. Алгоритм namei, работающий в ядре удаленной системы, получив после-
довательность символов "..", проверяет, является ли вызывающий процесс аген-
том процесса-клиента, и в случае положительного ответа устанавливает, трак-
тует ли клиент текущий рабочий каталог в качестве корня удаленной файловой
системы.
Связь с удаленной машиной принимает одну из двух форм: вызов удаленной
процедуры или вызов удаленной системной функции. В первой форме каждая про-
цедура ядра, имеющая дело с индексами, проверяет, указывает ли индекс на
удаленный файл, и если это так, посылает на удаленную машину запрос на вы-
полнение указанной операции. Данная схема естественным образом вписывается в
абстрактную структуру поддержки файловых систем различных типов, описанную в
заключительной части главы 5. Таким образом, обращение к удаленному файлу
может инициировать пересылку по сети нескольких сообщений, количество кото-
рых определяется количеством подразумеваемых операций над файлом, с соответ-
ствующим увеличением времени ответа на запрос с учетом принятого в сети вре-
мени ожидания. Каждый набор удаленных операций включает в себя, по крайней
мере, действия по блокированию индекса, подсчету ссылок и т.п. В целях усо-
вершенствования модели предлагались различные оптимизационные решения, свя-
занные с объединением нескольких операций в один запрос (сообщение) и с бу-
феризацией наиболее важных данных (см. [Sandberg 85]).


Сервер Клиент (процесс/процессор)
+--------------------+ +----------------------------------------+
| таблица | | таблица таблица таблица |
| индексов +-------+ | | индексов файлов пользо- |
| +-----+ |Спутник|-| | +-----+ +-----+ ватель- |
| | | +-+-----+ |- | | | | | ских |
| +-----+ | | - +-----+ +-----+ дескрип- +-------+|
| | | | +------+- -+-+ | | торов +--+Процесс||
| +-----+ | | | | +-----+ | +-----+ файла | +-------+|
| | | | | | | | | +-+- -++ +-----+ | |
| +-----+ | | | | +-----+ +-----+| | | | |
| | | | | | | | | | || +-----+ |дескриптор |
| +-----+ | | | | +-----+ +-----++-+- -+-+файла |
| | --+----+-----+ | | | | | | +-----+ |
| +-----+ | | +-----+ +-----+ | | |
| | | +-----+ |
+--------------------+ +----------------------------------------+

Рисунок 13.11. Открытие удаленного файла

Рассмотрим процесс, который открывает удаленный файл
"/usr/src/cmd/login.c", где "src" - точка монтирования. Выполняя синтакси-
ческий разбор имени файла (по схеме namei-iget), ядро обнаруживает, что файл
удаленный, и посылает на машину, где он находится, запрос на получение заб-
локированного индекса. Получив желаемый ответ, локальное ядро создает в па-

394

мяти копию индекса, корреспондирующую с удаленным файлом. Затем ядро произ-
водит проверку наличия необходимых прав доступа к файлу (на чтение, напри-
мер), послав на удаленную машину еще одно сообщение. Выполнение алгоритма
open продолжается в полном соответствии с планом, приведенным в главе 5, с
посылкой сообщений на удаленную машину по мере необходимости, до полного
окончания алгоритма и освобождения индекса. Взаимосвязь между структурами
данных ядра по завершении алгоритма open показана на Рисунке 13.11.
Если клиент вызывает системную функцию read, ядро клиента блокирует ло-
кальный индекс, посылает запрос на блокирование удаленного индекса, запрос
на чтение данных, копирует данные в локальную память, посылает запрос на ос-
вобождение удаленного индекса и освобождает локальный индекс. Такая схема
соответствует семантике существующего однопроцессорного ядра, но частота ис-
пользования сети (несколько обращений на каждую системную функцию) снижает
производительность всей системы. Однако, чтобы уменьшить поток сообщений в
сети, в один запрос можно объединять несколько операций. В примере с функци-
ей read клиент может послать серверу один общий запрос на "чтение", а уж
сервер при его выполнении сам принимает решение на захват и освобождение ин-
декса. Сокращения сетевого трафика можно добиться и путем использования уда-
ленных буферов (о чем мы уже говорили выше), но при этом нужно позаботиться
о том, чтобы системные функции работы с файлами, использующие эти буферы,
выполнялись надлежащим образом.
При второй форме связи с удаленной машиной (вызов удаленной системной
функции) локальное ядро обнаруживает, что системная функция имеет отношение
к удаленному файлу, и посылает указанные в ее вызове параметры на удаленную
систему, которая исполняет функцию и возвращает результаты клиенту. Машина
клиента получает результаты выполнения функции и выходит из состояния вызо-
ва. Большинство системных функций может быть выполнено с использованием
только одного сетевого запроса с получением ответа через достаточно приемле-
мое время, но в такую модель вписываются не все функции. Так, например, по
получении некоторых сигналов ядро создает для процесса файл с именем "core"
(глава 7). Создание этого файла не связано с конкретной системной функцией,
а завершает выполнение нескольких операций, таких как создание файла, про-
верка прав доступа и выполнение ряда операций записи.
В случае с системной функцией open запрос на исполнение функции, посыла-
емый на удаленную машину, включает в себя часть имени файла, оставшуюся пос-
ле исключения компонент имени пути поиска, отличающих удаленный файл, а так-
же различные флаги. В рассмотренном ранее примере с открытием файла
"/usr/src/cmd/login.c" ядро посылает на удаленную машину имя "cmd/login.c".
Сообщение также включает в себя опознавательные данные, такие как пользова-
тельский и групповой коды идентификации, необходимые для проверки прав дос-
тупа к файлам на удаленной машине. Если с удаленной машины поступает ответ,
свидетельствующий об успешном выполнении функции open, локальное ядро выби-
рает свободный индекс в памяти локальной машины и помечает его как индекс
удаленного файла, сохраняет информацию об удаленной машине и удаленном ин-
дексе и по заведенному порядку выделяет новую запись в таблице файлов. В
сравнении с реальным индексом на удаленной машине индекс, принадлежащий ло-
кальной машине, является формальным, не нарушающим конфигурацию модели, ко-
торая в целом совпадает с конфигурацией, используемой при вызове удаленной