The design of the unix operating system by Maurice J
Вид материала | Реферат |
13.2 Связь типа newcastle 13.3 "Прозрачные" распределенные файловые системы 13.4 Распределенная модель без передаточных процессов |
- Лекция 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.
│ выполнения │ об ошибке │ сигнала │ Поток данных │
│ системной │ │ │ │
│ функции │ │ │ │
L------------+-----------+---------+----------------------
Рисунок 13.3. Форматы сообщений
ошибке (если она имела место), номер сигнала и массив данных пе-
ременной длины, содержащий, например, информацию, прочитанную из
файла. Периферийный процесс приостанавливается до получения отве-
та, получив его, производит расшифровку и передает результаты
пользователю. Такова общая схема обработки обращений к операцион-
ной системе; теперь перейдем к более детальному рассмотрению от-
дельных функций.
Для того, чтобы объяснить, каким образом работает периферий-
ная система, рассмотрим ряд функций: getppid, open, write, fork,
exit и signal. Функция getppid довольно проста, поскольку она
связана с простыми формами запроса и ответа, которыми обменивают-
ся периферийный и центральный процессоры. Ядро на периферийном
процессоре формирует сообщение, имеющее признак, из которого сле-
дует, что запрашиваемой функцией является функция getppid, и по-
сылает запрос центральному процессору. Процесс-спутник на цент-
ральном процессоре читает сообщение с периферийного процессора,
расшифровывает тип системной функции, исполняет ее и получает
идентификатор своего родителя. Затем он формирует ответ и переда-
ет его периферийному процессу, находящемуся в состоянии ожидания
на другом конце линии связи. Когда периферийный процессор получа-
ет ответ, он передает его процессу, вызвавшему системную функцию
getppid. Если же периферийный процесс хранит данные (такие, как
идентификатор процесса-родителя) в локальной памяти, ему вообще
не придется связываться со своим спутником.
Если производится обращение к системной функции open, перифе-
рийный процесс посылает своему спутнику соответствующее сообще-
ние, которое включает имя файла и другие параметры. В случае ус-
пеха процесс-спутник выделяет индекс и точку входа в таблицу фай-
лов, отводит запись в таблице пользовательских дескрипторов файла
в своем пространстве и возвращает дескриптор файла периферийному
процессу. Все это время на другом конце линии связи периферийный
процесс ждет ответа. У него в распоряжении нет никаких структур,
которые хранили бы информацию об открываемом файле; возвращаемый
функцией open дескриптор представляет собой указатель на запись в
Центральный процессор Периферийный процессор
---------------------------------------┐ ----------------------┐
│ таблица │ │ │
│ пользо- │ │ │
│ ватель- │ │ │
│ ских │ │ │
│ дескрип- │ │ │
│ таблица таблица торов │ │ │
│ индексов файлов файла ---------┐│ │ ----------┐ │
│ ------┐ ------┐ ------┐ │Процесс-││ Процесс │ │
│ │ │ │ │ │ │ │спутник ││ │ L---------- │
│ +-----+ +-----+ +-----+ L-T-------│ │ │
│ │ -+-┐ │ │ -+- -+---- │ │ │
│ +-----+ │ +-----+ │+-----+ дескрип- │ │ │
│ │ │ L-+- -+--│ │ тор файла │ │ │
│ +-----+ +-----+ L------ │ │ │
│ │ │ │ │ │ │ │
│ +-----+ +-----+ │ │ │
│ │ │ │ │ │ │ │
│ L------ L------ │ │ │
L--------------------------------------- L----------------------
Рисунок 13.4. Вызов функции open из периферийного процесса
таблице пользовательских дескрипторов файла, принадлежащей про-
цессу-спутнику. Результаты выполнения функции показаны на Рисунке
13.4.
Если производится обращение к системной функции write, пери-
ферийный процессор формирует сообщение, состоящее из признака
функции write, дескриптора файла и объема записываемых данных.
Затем из пространства периферийного процесса он по линии связи
копирует данные процессу-спутнику. Процесс-спутник расшифровывает
полученное сообщение, читает данные из линии связи и записывает
их в соответствующий файл (в качестве указателя на индекс которо-
го и запись о котором в таблице файлов используется содержащийся
в сообщении дескриптор); все указанные действия выполняются на
центральном процессоре. По окончании работы процесс-спутник пере-
дает периферийному процессу посылку, подтверждающую прием сообще-
ния и содержащую количество байт данных, успешно переписанных в
файл. Операция read выполняется аналогично; спутник информирует
периферийный процесс о количестве реально прочитанных байт (в
случае чтения данных с терминала или из канала это количество не
всегда совпадает с количеством, указанным в запросе). Для выпол-
нения как той, так и другой функции может потребоваться многок-
ратная пересылка информационных сообщений по сети, что определя-
ется объемом пересылаемых данных и размерами сетевых пакетов.
Единственной функцией, требующей внесения изменений при рабо-
те на центральном процессоре, является системная функция fork.
Когда процесс исполняет эту функцию на ЦП, ядро выбирает для него
периферийный процессор и посылает сообщение специальному процессу
-серверу, информируя последний о том, что собирается приступить к
выгрузке текущего процесса. Предполагая, что сервер принял зап-
рос, ядро с помощью функции fork создает новый периферийный про-
цесс, выделяя запись в таблице процессов и адресное пространство.
Центральный процессор выгружает копию процесса, вызвавшего функ-
цию fork, на периферийный процессор, затирая только что выделен-
ное адресное пространство, порождает локальный спутник для связи
с новым периферийным процессом и посылает на периферию сообщение
о необходимости инициализации счетчика команд для нового процес-
са. Процесс-спутник (на ЦП) является потомком процесса, вызвавше-
го функцию fork; периферийный процесс с технической точки зрения
выступает потомком процесса-сервера, но по логике он является по-
томком процесса, вызвавшего функцию fork. Процесс-сервер не имеет
логической связи с потомком по завершении функции fork; единс-
твенная задача сервера состоит в оказании помощи при выгрузке по-
Центральный процессор Периферийный процессор
-----------------------┐ -----------------------┐
│ -------------------┐ │ │ -------------------┐ │
│ │ Процесс-родитель ││ Процесс-сервер │ │
│ L---------T--------- │ │ L------------------- │
│ │ │ │ │
│ │ │ │ │
│ │ │ │ │
│ │ │ │ │
│ ----------+--------┐ │ │ -------------------┐ │
│ │ Порожденный спут-││ Порожденный про- │ │
│ │ ник │ │ │ │ цесс │ │
│ L------------------- │ │ L------------------- │
L----------------------- L-----------------------
Рисунок 13.5. Выполнение функции fork на центральном процес-
соре
томка. Из-за сильной связи между компонентами системы (периферий-
ные процессоры не располагают автономией) периферийный процесс и
процесс-спутник имеют один и тот же код идентификации. Взаимос-
вязь между процессами показана на Рисунке 13.5: непрерывной лини-
ей показана связь типа "родитель-потомок", пунктиром - связь меж-
ду равноправными партнерами.
Когда процесс исполняет функцию fork на периферийном процес-
соре, он посылает сообщение своему спутнику на ЦП, который и ис-
полняет после этого всю вышеописанную последовательность дейс-
твий. Спутник выбирает новый периферийный процессор и делает
необходимые приготовления к выгрузке образа старого процесса: по-
сылает периферийному процессу-родителю запрос на чтение его обра-
за, в ответ на который на другом конце канала связи начинается
передача запрашиваемых данных. Спутник считывает передаваемый об-
раз и переписывает его периферийному потомку. Когда выгрузка об-
раза заканчивается, процесс-спутник исполняет функцию fork, соз-
давая своего потомка на ЦП, и передает значение счетчика команд
периферийному потомку, чтобы последний знал, с какого адреса на-
чинать выполнение. Очевидно, было бы лучше, если бы потомок про-
цесса-спутника назначался периферийному потомку в качестве
родителя, однако в нашем случае порожденные процессы получают
возможность выполняться и на других периферийных процессорах, а
не только на том, на котором они созданы. Взаимосвязь между про-
цессами по завершении функции fork показана на Рисунке 13.6. Ког-
да периферийный процесс завершает свою работу, он посылает соот-
ветствующее сообщение процессу-спутнику и тот тоже завершается.
От процесса-спутника инициатива завершения работы исходить не мо-
жет.
Центральный процессор
--------------------------------------------------------┐
│ │
│ -------------------┐ ------------------┐ │
│ │ Спутник-родитель +----------+ Спутник-потомок │ │
│ L------------------- L------------------ │
│ │
L------------------------------------------------------
---------------------------┐ ---------------------------┐
│ │ │ │
│ ------------------------┐ │ │ -----------------------┐ │
│ │ Периферийный родитель │ │ │ │ Периферийный потомок │ │
│ L------------------------ │ │ L----------------------- │
│ │ │ │
L---------------------------- L----------------------------
Периферийный процессор Периферийный процессор
Рисунок 13.6. Выполнение функции fork на периферийном процес-
соре
И в многопроцессорной, и в однопроцессорной системах процесс
должен реагировать на сигналы одинаково: процесс либо завершает
выполнение системной функции до проверки сигналов, либо, напро-
тив, получив сигнал, незамедлительно выходит из состояния приос-
танова и резко прерывает работу системной функции, если это сог-
ласуется с приоритетом, с которым он был приостановлен. Поскольку
процесс-спутник выполняет системные функции от имени периферийно-
го процесса, он должен реагировать на сигналы, согласуя свои
действия с последним. Если в однопроцессорной системе сигнал зас-
тавляет процесс завершить выполнение функции аварийно, процес-
су-спутнику в многопроцессорной системе следует вести себя тем же
образом. То же самое можно сказать и о том случае, когда сигнал
побуждает процесс к завершению своей работы с помощью функции
exit: периферийный процесс завершается и посылает соответствующее
сообщение процессу-спутнику, который, разумеется, тоже завершает-
ся.
Когда периферийный процесс вызывает системную функцию signal,
он сохраняет текущую информацию в локальных таблицах и посылает
сообщение своему спутнику, информируя его о том, следует ли ука-
занный сигнал принимать или же игнорировать. Процессу-спутнику
безразлично, выполнять ли перехват сигнала или действие по умол-
чанию. Реакция процесса на сигнал зависит от трех факторов (Рису-
нок 13.7): поступает ли сигнал во время выполнения процессом сис-
темной функции, сделано ли с помощью функции signal указание об
игнорировании сигнала, возникает ли сигнал на этом же периферий-
ном процессоре или на каком-то другом. Перейдем к рассмотрению
различных возможностей.
Допустим, что периферийный процесс приостановил свою работу
на то время, пока процесс-спутник исполняет системную функцию от
его имени. Если сигнал возникает в другом месте, процесс-спутник
-------------------------------------------------------------┐
│ алгоритм sighandle /* алгоритм обработки сигналов */ │
│ входная информация: отсутствует │
│ выходная информация: отсутствует │
│ { │
│ если (текущий процесс является чьим-то спутником или │
│ имеет прототипа) │
│ { │
│ если (сигнал игнорируется) │
│ вернуть управление; │
│ если (сигнал поступил во время выполнения системной │
│ функции) │
│ поставить сигнал перед процессом-спутником; │
│ в противном случае │
│ послать сообщение о сигнале периферийному процес-│
│ су; │
│ } │
│ в противном случае /* периферийный процесс */ │
│ { │
│ /* поступил ли сигнал во время выполнения системной │
│ * функции или нет │
│ */ │
│ послать сигнал процессу-спутнику; │
│ } │
│ } │
│ │
│ алгоритм satellite_end_of_syscall /* завершение систем- │
│ * ной функции, выз- │
│ * ванной периферийным│
│ * процессом */ │
│ входная информация: отсутствует │
│ выходная информация: отсутствует │
│ { │
│ если (во время выполнения системной функции поступило │
│ прерывание) │
│ послать периферийному процессу сообщение о прерыва- │
│ нии, сигнал; │
│ в противном случае /* выполнение системной функции не│
│ * прерывалось */ │
│ послать ответ: включить флаг, показывающий поступле- │
│ ние сигнала; │
│ } │
L-------------------------------------------------------------
Рисунок 13.7. Обработка сигналов в периферийной системе
обнаруживает его раньше, чем периферийный процесс. Возможны три
случая.
1. Если в ожидании некоторого события процесс-спутник не перехо-
дил в состояние приостанова, из которого он вышел бы по полу-
чении сигнала, он выполняет системную функцию до конца, посы-
лает результаты выполнения периферийному процессу и показыва-
ет, какой из сигналов им был получен.
2. Если процесс сделал указание об игнорировании сигнала данного
типа, спутник продолжает следовать алгоритму выполнения сис-
темной функции, не выходя из состояния приостанова по
longjmp. В ответе, посылаемом периферийному процессу, сообще-
ние о получении сигнала будет отсутствовать.
3. Если по получении сигнала процесс-спутник прерывает выполне-
ние системной функции (по longjmp), он информирует об этом
периферийный процесс и сообщает ему номер сигнала.
Периферийный процесс ищет в поступившем ответе сведения о по-
лучении сигналов и в случае обнаружения таковых производит обра-
ботку сигналов перед выходом из системной функции. Таким образом,
поведение процесса в многопроцессорной системе в точности соот-
ветствует его поведению в однопроцессорной системе: он или завер-
шает свою работу, не выходя из режима ядра, или обращается к
пользовательской функции обработки сигнала, или игнорирует сигнал
и успешно завершает выполнение системной функции.
Периферийный процесс Процесс-спутник
-------------------------------------------------------------
│ Вызывает системную функцию read
│ Посылает сообщение о вызове функции
│ процессу-спутнику
│ Приостанавливается до получения
│ ответа от процесса-спутника Получает сообщение о
│ вызове системной функ-
│ ции read
│ Читает данные с тер-
│ минала
│ Приостанавливается в
│ ожидании получения
│ порции данных
│
│
│
│ Сигнал (пользователь
│ нажал клавишу "break")
│ Выходит из состояния
│ приостанова
│ Прекращает выполнение
│ системной функции
│ Посылает ответ пери-
│ ферийному процессу:
│ выполнение функции
│ прервано
│ Выходит из состояния приостанова
│ Анализирует ответ
v Обрабатывает сигнал
Рисунок 13.8. Прерывание во время выполнения системной функ-
ции
Предположим, например, что периферийный процесс вызывает
функцию чтения с терминала, связанного с центральным процессором,
и приостанавливает свою работу на время выполнения функции про-
цессом-спутником (Рисунок 13.8). Если пользователь нажимает кла-
вишу прерывания (break), ядро ЦП посылает процессу-спутнику соот-
ветствующий сигнал. Если спутник находился в состоянии приостано-
ва в ожидании ввода с терминала порции данных, он немедленно вы-
ходит из этого состояния и прекращает выполнение функции read. В
своем ответе на запрос периферийного процесса спутник сообщает
код ошибки и номер сигнала, соответствующий прерыванию. Перифе-
рийный процесс анализирует ответ и, поскольку в сообщении гово-
рится о поступлении сигнала прерывания, отправляет сигнал самому
себе. Перед выходом из функции read периферийное ядро осуществля-
ет проверку поступления сигналов, обнаруживает сигнал прерывания,
поступивший от процесса-спутника, и обрабатывает его обычным по-
рядком. Если в результате получения сигнала прерывания периферий-
ный процесс завершает свою работу с помощью функции exit, данная
функция берет на себя заботу об уничтожении процесса-спутника.
Если периферийный процесс перехватывает сигналы о прерывании, он
вызывает пользовательскую функцию обработки сигналов и по выходе
из функции read возвращает пользователю код ошибки. С другой сто-
роны, если спутник исполняет от имени периферийного процесса сис-
темную функцию stat, он не будет прерывать ее выполнение при по-
лучении сигнала (функции stat гарантирован выход из любого приос-
танова, поскольку для нее время ожидания ресурса ограничено).
Спутник доводит выполнение функции до конца и возвращает перифе-
рийному процессу номер сигнала. Периферийный процесс посылает
сигнал самому себе и получает его на выходе из системной функции.
Если сигнал возник на периферийном процессоре во время выпол-
нения системной функции, периферийный процесс будет находиться в
неведении относительно того, вернется ли к нему вскоре управление
от процесса-спутника или же последний перейдет в состояние приос-
танова на неопределенное время. Периферийный процесс посылает
спутнику специальное сообщение, информируя его о возникновении
сигнала. Ядро на ЦП расшифровывает сообщение и посылает сигнал
спутнику, реакция которого на получение сигнала описана в преды-
дущих параграфах (аварийное завершение выполнения функции или до-
ведение его до конца). Периферийный процесс не может послать со-
общение спутнику непосредственно, поскольку спутник занят испол-
нением системной функции и не считывает данные из линии связи.
Если обратиться к примеру с функцией read, следует отметить,
что периферийный процесс не имеет представления о том, ждет ли
его спутник ввода данных с терминала или же выполняет другие
действия. Периферийный процесс посылает спутнику сообщение о сиг-
нале: если спутник находится в состоянии приостанова с приорите-
том, допускающим прерывания, он немедленно выходит из этого сос-
тояния и прекращает выполнение системной функции; в противном
случае выполнение функции доводится до успешного завершения.
Рассмотрим, наконец, случай поступления сигнала во время, не
связанное с выполнением системной функции. Если сигнал возник на
другом процессоре, спутник получает его первым и посылает сообще-
ние о сигнале периферийному процессу, независимо от того, касает-
ся ли этот сигнал периферийного процесса или нет. Периферийное
ядро расшифровывает сообщение и посылает сигнал процессу, который
реагирует на него обычным порядком. Если сигнал возник на перифе-
рийном процессоре, процесс выполняет стандартные действия, не
прибегая к услугам своего спутника.
Когда периферийный процесс посылает сигнал другим периферий-
ным процессам, он кодирует сообщение о вызове функции kill и по-
сылает его процессу-спутнику, который исполняет вызываемую функ-
цию локально. Если часть процессов, для которых предназначен
сигнал, имеет местонахождение на других периферийных процессорах,
сигнал получат (и прореагируют на его получение вышеописанным об-
разом) их спутники.
13.2 СВЯЗЬ ТИПА NEWCASTLE
В предыдущем разделе мы рассмотрели тип сильносвязанной сис-
темы, для которого характерна посылка всех возникающих на перифе-
рийном процессоре обращений к функциям подсистемы управления
файлами на удаленный (центральный) процессор. Теперь перейдем к
рассмотрению систем с менее сильной связью, которые состоят из
машин, производящих обращение к файлам, находящимся на других ма-
шинах. В сети, состоящей из персональных компьютеров и рабочих
станций, например, пользователи часто обращаются к файлам, распо-
ложенным на большой машине. В последующих двух разделах мы расс-
мотрим такие конфигурации систем, в которых все системные функции
выполняются в локальных подсистемах, но при этом имеется возмож-
ность обращения к файлам (через функции подсистемы управления
файлами), расположенным на других машинах.
Для идентифицирования удаленных файлов в этих системах ис-
пользуется один из следующих двух путей. В одних системах в сос-
тавное имя файла добавляется специальный символ: компонента име-
ни, предшествующая этому символу, идентифицирует машину, осталь-
ная часть имени - файл, находящийся на этой машине. Так, напри-
мер, составное имя
"sftig!/fs1/mjb/rje"
идентифицирует файл "/fs1/mjb/rje", находящийся на машине
"sftig". Такая схема идентифицирования файла соответствует согла-
шению, установленному программой uucp относительно передачи фай-
лов между системами типа UNIX. В другой схеме удаленные файлы
идентифицируются добавлением к имени специального префикса, нап-
ример:
/../sftig/fs1/mjb/rje
где "/../" - префикс, свидетельствующий о том, что файл удален-
ный; вторая компонента имени файла является именем удаленной ма-
шины. В данной схеме используется привычный синтаксис имен файлов
в системе UNIX, поэтому в отличие от первой схемы здесь пользова-
тельским программам нет необходимости приноравливаться к исполь-
зованию имен, имеющих необычную конструкцию (см. [Pike 85]).
Процесс-клиент Процесс-сервер
------------------------------┐ -----------------------------┐
│ Таблица │ │ Процесс- │
│ Си-библиотека открытых │ │ спутник Запрос │
│ файлов │ │ (пользо- на чтение │
│ -------┐ │ │ вательский │ │ │
│ ---------------+--- │ │ │ уровень) │ │ │
│ │ +------+ │ │ │ │ │
│ │ локальный │ │ │ │ --------------- │ │
│ │ +------+ │ │ │ │ │
│ │ -----+--- │ │ │ │ │ │
│ │ │ +------+ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ L------- │ │ │ │ │
│ │ L-----┐ │ │ │ │ │
L----+---------------+--------- L----+-----------------+------
│ │ удаленный │ │
-----+---------------+--------┐ -----+-----------------+-----┐
│ │ Сетевой │ │ │ Сетевой │
│ Ядро интерфейс │ │ Ядро интерфейс │
│ │ │ │ │ │
L--------------------+--------- L----------------------+------
│ с е т ь │
L--------------------------------------
Рисунок 13.9. Формулирование запросов к файловому серверу
(процессору)
Всю оставшуюся часть раздела мы посвятим рассмотрению модели
системы, использующей связь типа Newcastle, в которой ядро не за-
нимается распознаванием удаленных файлов; эта функция полностью
возлагается на подпрограммы из стандартной Си-библиотеки, выпол-
няющие в данном случае роль системного интерфейса. Эти подпрог-
раммы анализируют первую компоненту имени файла, в обоих описан-
ных способах идентифицирования содержащую признак удаленности
файла. В этом состоит отступление от заведенного порядка, при ко-
тором библиотечные подпрограммы не занимаются синтаксическим раз-
бором имен файлов. На Рисунке 13.9 показано, каким образом форму-
лируются запросы к файловому серверу. Если файл локальный, ядро
локальной системы обрабатывает запрос обычным способом. Рассмот-
рим обратный случай:
open("/../sftig/fs1/mjb/rje/file",O_RDONLY);
Подпрограмма open из Си-библиотеки анализирует первые две компо-
ненты составного имени файла и узнает, что файл следует искать на
удаленной машине "sftig". Чтобы иметь информацию о том, была ли
ранее у процесса связь с данной машиной, подпрограмма заводит
специальную структуру, в которой запоминает этот факт, и в случае
отрицательного ответа устанавливает связь с файловым сервером,
работающим на удаленной машине. Когда процесс формулирует свой
первый запрос на дистанционную обработку, удаленный сервер подт-
верждает запрос, в случае необходимости ведет запись в поля поль-
зовательского и группового кодов идентификации и создает процесс-
спутник, который будет выступать от имени процесса-клиента.
Чтобы выполнять запросы клиента, спутник должен иметь на уда-
ленной машине те же права доступа к файлам, что и клиент. Другими
словами, пользователь "mjb" должен иметь и к удаленным, и к ло-
кальным файлам одинаковые права доступа. К сожалению, не исключе-
на возможность того, что код идентификации клиента "mjb" может
совпасть с кодом идентификации другого клиента удаленной машины.
Таким образом, администраторам систем на работающих в сети маши-
нах следует либо следить за назначением каждому пользователю кода
идентификации, уникального для всей сети, либо в момент формули-
рования запроса на сетевое обслуживание выполнять преобразование
кодов. Если это не будет сделано, процесс-спутник будет иметь на
удаленной машине права другого клиента.
Более деликатным вопросом является получение в отношении ра-
боты с удаленными файлами прав суперпользователя. С одной сторо-
ны, клиент-суперпользователь не должен иметь те же права в отно-
шении удаленной системы, чтобы не вводить в заблуждение средства
защиты удаленной системы. С другой стороны, некоторые из прог-
рамм, если им не предоставить права суперпользователя, просто не
смогут работать. Примером такой программы является программа
mkdir (см. главу 7), создающая новый каталог. Удаленная система
не разрешила бы клиенту создавать новый каталог, поскольку на
удалении права суперпользователя не действуют. Проблема создания
удаленных каталогов служит серьезным основанием для пересмотра
системной функции mkdir в сторону расширения ее возможностей в
автоматическом установлении всех необходимых пользователю связей.
Тем не менее, получение setuid-программами (к которым относится и
программа mkdir) прав суперпользователя по отношению к удаленным
файлам все еще остается общей проблемой, требующей своего реше-
ния. Возможно, что наилучшим решением этой проблемы было бы уста-
новление для файлов дополнительных характеристик, описывающих
доступ к ним со стороны удаленных суперпользователей; к сожале-
нию, это потребовало бы внесения изменений в структуру дискового
индекса (в части добавления новых полей) и породило бы слишком
большой беспорядок в существующих системах.
Если подпрограмма open завершается успешно, локальная библио-
тека оставляет об этом соответствующую отметку в доступной для
пользователя структуре, содержащей адрес сетевого узла, идентифи-
катор процесса-спутника, дескриптор файла и другую аналогичную
информацию. Библиотечные подпрограммы read и write устанавливают,
исходя из дескриптора, является ли файл удаленным, и в случае по-
ложительного ответа посылают спутнику сообщение. Процесс-клиент
взаимодействует со своим спутником во всех случаях обращения к
системным функциям, нуждающимся в услугах удаленной машины. Если
процесс обращается к двум файлам, расположенным на одной и той же
удаленной машине, он пользуется одним спутником, но если файлы
расположены на разных машинах, используются уже два спутника: по
одному на каждой машине. Два спутника используются и в том слу-
чае, когда к файлу на удаленной машине обращаются два процесса.
Вызывая системную функцию через спутника, процесс формирует сооб-
щение, включающее в себя номер функции, имя пути поиска и другую
необходимую информацию, аналогичную той, которая входит в струк-
туру сообщения в системе с периферийными процессорами.
Механизм выполнения операций над текущим каталогом более сло-
жен. Когда процесс выбирает в качестве текущего удаленный ката-
лог, библиотечная подпрограмма посылает соответствующее сообщение
спутнику, который изменяет текущий каталог, при этом подпрограмма
запоминает, что каталог удаленный. Во всех случаях, когда имя пу-
ти поиска начинается с символа, отличного от наклонной черты (/),
подпрограмма посылает это имя на удаленную машину, где про-
цесс-спутник прокладывает маршрут, начиная с текущего каталога.
Если текущий каталог - локальный, подпрограмма просто передает
имя пути поиска ядру локальной системы. Системная функция chroot
в отношении удаленного каталога выполняется похоже, но при этом
ее выполнение для ядра локальной системы проходит незамеченным;
строго говоря, процесс может оставить эту операцию без внимания,
поскольку только библиотека фиксирует ее выполнение.
Когда процесс вызывает функцию fork, соответствующая библио-
течная подпрограмма посылает сообщения каждому спутнику. Процессы
-спутники выполняют операцию ветвления и посылают идентификаторы
своих потомков клиенту-родителю. Процесс-клиент запускает систем-
ную функцию fork, которая передает управление порождаемому потом-
ку; локальный потомок ведет диалог с удаленным потомком-спутни-
ком, адреса которого сохранила библиотечная подпрограмма. Такая
трактовка функции fork облегчает процессам-спутникам контроль над
открытыми файлами и текущими каталогами. Когда процесс, работаю-
щий с удаленными файлами, завершается (вызывая функцию exit),
подпрограмма посылает сообщения всем его удаленным спутникам,
чтобы они по получении сообщения проделали то же самое. Отдельные
моменты реализации системных функций exec и exit затрагиваются в
упражнениях.
Преимущество связи типа Newcastle состоит в том, что
обращение процесса к удаленным файлам становится "прозрачным"
(незаметным для пользователя), при этом в ядро системы никаких
изменений вносить не нужно. Однако, данной разработке присущ и
ряд недостатков. Прежде всего, при ее реализации возможно сниже-
ние производительности системы. В связи с использованием расши-
ренной Си-библиотеки размер используемой каждым процессом памяти
увеличивается, даже если процесс не обращается к удаленным фай-
лам; библиотека дублирует функции ядра и требует для себя больше
места в памяти. Увеличение размера процессов приводит к удлинению
продолжительности периода запуска и может вызвать большую конку-
ренцию за ресурсы памяти, создавая условия для более частой выг-
рузки и подкачки задач. Локальные запросы будут исполняться мед-
леннее из-за увеличения продолжительности каждого обращения к яд-
ру, замедление может грозить и обработке удаленных запросов, зат-
раты по пересылке которых по сети увеличиваются. Дополнительная
обработка удаленных запросов на пользовательском уровне увеличи-
вает количество переключений контекста, операций по выгрузке и
подкачке процессов. Наконец, для того, чтобы обращаться к удален-
ным файлам, программы должны быть перекомпилированы с использова-
нием новых библиотек; старые программы и поставленные объектные
модули без этого работать с удаленными файлами не смогут. Все эти
недостатки отсутствуют в системе, описываемой в следующем разде-
ле.
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 │
│ │ │ │ │ │ │ │
│ ----+---┐ │ │ │ │ +------T-----┐ │
│ │ │ │ │ │ │ │ │ │ │
│ troff vi │ │ │ │ lib cmd uts │
│ │ │ │ │ │ │
│ │ │ │ │ ----+---┐ │
│ │ │ │ │ │ │ │
│ │ │ │ │ login.c mail.c │
L---------------------------│-- │ L------------------------------
L----
Рисунок 13.10. Файловые системы после удаленного монтирования
Наличие сходства между монтированием локальных файловых сис-
тем и открытием доступа к удаленным файловым системам послужило
поводом для адаптации функции mount применительно к удаленным
файловым системам. В данном случае ядро получает в свое распоря-
жение таблицу монтирования расширенного формата. Выполняя функцию
mount, ядро организует сетевую связь с удаленной машиной и сохра-
няет в таблице монтирования информацию, характеризующую данную
связь.
Интересная проблема связана с именами путей, включающих "..".
Если процесс делает текущим каталог из удаленной файловой систе-
мы, последующее использование в имени символов ".." скорее вернет
процесс в локальную файловую систему, чем позволит обращаться к
файлам, расположенным выше текущего каталога. Возвращаясь вновь к
Рисунку 13.10, отметим, что когда процесс, принадлежащий машине
A, выбрав предварительно в качестве текущего каталог
"/usr/src/cmd", расположенный в удаленной файловой системе, ис-
полнит команду
cd ../../..
текущим каталогом станет корневой каталог, принадлежащий машине
A, а не машине B. Алгоритм namei, работающий в ядре удаленной
системы, получив последовательность символов "..", проверяет, яв-
ляется ли вызывающий процесс агентом процесса-клиента, и в случае
положительного ответа устанавливает, трактует ли клиент текущий
рабочий каталог в качестве корня удаленной файловой системы.
Связь с удаленной машиной принимает одну из двух форм: вызов
удаленной процедуры или вызов удаленной системной функции. В пер-
вой форме каждая процедура ядра, имеющая дело с индексами, прове-
ряет, указывает ли индекс на удаленный файл, и если это так, по-
сылает на удаленную машину запрос на выполнение указанной
операции. Данная схема естественным образом вписывается в абс-
трактную структуру поддержки файловых систем различных типов,
описанную в заключительной части главы 5. Таким образом, обраще-
ние к удаленному файлу может инициировать пересылку по сети нес-
кольких сообщений, количество которых определяется количеством
подразумеваемых операций над файлом, с соответствующим увеличени-
ем времени ответа на запрос с учетом принятого в сети времени
ожидания. Каждый набор удаленных операций включает в себя, по
крайней мере, действия по блокированию индекса, подсчету ссылок и
т.п. В целях усовершенствования модели предлагались различные оп-
тимизационные решения, связанные с объединением нескольких опера-
ций в один запрос (сообщение) и с буферизацией наиболее важных
данных (см. [Sandberg 85]).
Сервер Клиент (процесс/процессор)
---------------------┐ -----------------------------------------┐
│ таблица │ │ таблица таблица таблица │
│ индексов --------┐ │ │ индексов файлов пользо- │
│ ------┐ │Спутник││ │ ------┐ ------┐ ватель- │
│ │ │ L-T------ │ │ │ │ │ │ ских │
│ +-----+ │ │ +-----+ +-----+ дескрип- --------┐│
│ │ │ │ -------+- -+-┐ │ │ торов ---+Процесс││
│ +-----+ │ │ │ │ +-----+ │ +-----+ файла │ L--------│
│ │ │ │ │ │ │ │ │ L-+- -+┐ ------┐ │ │
│ +-----+ │ │ │ │ +-----+ +-----+│ │ │ │ │
│ │ │ │ │ │ │ │ │ │ ││ +-----+ │дескриптор │
│ +-----+ │ │ │ │ +-----+ +-----+L-+- -+--файла │
│ │ --+----+------ │ │ │ │ │ │ +-----+ │
│ L------ │ │ L------ L------ │ │ │
│ │ │ L------ │
L--------------------- L-----------------------------------------
Рисунок 13.11. Открытие удаленного файла
Рассмотрим процесс, который открывает удаленный файл
"/usr/src/cmd/login.c", где "src" - точка монтирования. Выполняя
синтаксический разбор имени файла (по схеме namei-iget), ядро об-
наруживает, что файл удаленный, и посылает на машину, где он на-
ходится, запрос на получение заблокированного индекса. Получив
желаемый ответ, локальное ядро создает в памяти копию индекса,
корреспондирующую с удаленным файлом. Затем ядро производит про-
верку наличия необходимых прав доступа к файлу (на чтение, напри-
мер), послав на удаленную машину еще одно сообщение. Выполнение
алгоритма open продолжается в полном соответствии с планом, при-
веденным в главе 5, с посылкой сообщений на удаленную машину по
мере необходимости, до полного окончания алгоритма и освобождения
индекса. Взаимосвязь между структурами данных ядра по завершении
алгоритма open показана на Рисунке 13.11.
Если клиент вызывает системную функцию read, ядро клиента
блокирует локальный индекс, посылает запрос на блокирование уда-
ленного индекса, запрос на чтение данных, копирует данные в ло-
кальную память, посылает запрос на освобождение удаленного индек-
са и освобождает локальный индекс. Такая схема соответствует
семантике существующего однопроцессорного ядра, но частота ис-
пользования сети (несколько обращений на каждую системную функ-
цию) снижает производительность всей системы. Однако, чтобы
уменьшить поток сообщений в сети, в один запрос можно объединять
несколько операций. В примере с функцией read клиент может пос-
лать серверу один общий запрос на "чтение", а уж сервер при его
выполнении сам принимает решение на захват и освобождение индек-
са. Сокращения сетевого трафика можно добиться и путем использо-
вания удаленных буферов (о чем мы уже говорили выше), но при этом
нужно позаботиться о том, чтобы системные функции работы с файла-
ми, использующие эти буферы, выполнялись надлежащим образом.
При второй форме связи с удаленной машиной (вызов удаленной
системной функции) локальное ядро обнаруживает, что системная
функция имеет отношение к удаленному файлу, и посылает указанные
в ее вызове параметры на удаленную систему, которая исполняет
функцию и возвращает результаты клиенту. Машина клиента получает
результаты выполнения функции и выходит из состояния вызова.
Большинство системных функций может быть выполнено с использова-
нием только одного сетевого запроса с получением ответа через
достаточно приемлемое время, но в такую модель вписываются не все
функции. Так, например, по получении некоторых сигналов ядро соз-
дает для процесса файл с именем "core" (глава 7). Создание этого
файла не связано с конкретной системной функцией, а завершает вы-
полнение нескольких операций, таких как создание файла, проверка
прав доступа и выполнение ряда операций записи.
В случае с системной функцией open запрос на исполнение функ-
ции, посылаемый на удаленную машину, включает в себя часть имени
файла, оставшуюся после исключения компонент имени пути поиска,
отличающих удаленный файл, а также различные флаги. В рассмотрен-
ном ранее примере с открытием файла "/usr/src/cmd/login.c" ядро
посылает на удаленную машину имя "cmd/login.c". Сообщение также
включает в себя опознавательные данные, такие как пользователь-
ский и групповой коды идентификации, необходимые для проверки
прав доступа к файлам на удаленной машине. Если с удаленной маши-
ны поступает ответ, свидетельствующий об успешном выполнении
функции open, локальное ядро выбирает свободный индекс в памяти
локальной машины и помечает его как индекс удаленного файла, сох-
раняет информацию об удаленной машине и удаленном индексе и по
заведенному порядку выделяет новую запись в таблице файлов. В
сравнении с реальным индексом на удаленной машине индекс, принад-
лежащий локальной машине, является формальным, не нарушающим кон-
фигурацию модели, которая в целом совпадает с конфигурацией,
используемой при вызове удаленной процедуры (Рисунок 13.11). Если
вызываемая процессом функция обращается к удаленному файлу по его
дескриптору, локальное ядро узнает из индекса (локального) о том,
что файл удаленный, формулирует запрос, включающий в себя вызыва-
емую функцию, и посылает его на удаленную машину. В запросе со-
держится указатель на удаленный индекс, по которому процесс-спут-
ник сможет идентифицировать сам удаленный файл.
Получив результат выполнения любой системной функции, ядро
может для его обработки прибегнуть к услугам специальной програм-
мы (по завершении которой ядро закончит работу с функцией), ибо
не всегда локальная обработка результатов, применяемая в однопро-
цессорной системе, подходит для системы с несколькими процессора-
ми. Вследствие этого возможны изменения в семантике системных ал-
горитмов, направленные на обеспечение поддержки выполнения уда-
ленных системных функций. Однако, при этом в сети циркулирует ми-
нимальный поток сообщений, обеспечивающий минимальное время
реакции системы на поступающие запросы.
13.4 РАСПРЕДЕЛЕННАЯ МОДЕЛЬ БЕЗ ПЕРЕДАТОЧНЫХ ПРОЦЕССОВ
Использование передаточных процессов (процессов-спутников) в
"прозрачной" распределенной системе облегчает слежение за удален-
ными файлами, однако при этом таблица процессов удаленной системы
перегружается процессами-спутниками, бездействующими большую