Параллельное программирование
Реализация пространств имен
Кэширование файлов
Сети и коммуникационные устройства
Поддержка сетей на уровне ядра
Протокол IL
Аутентификация
Права доступа к файлам
Обсуждение

К середине 80-х годов наметилась тенденция отхода от больших централизованных компьютеров, работающих в режиме разделения времени, и переориентации на сети из небольших персональных машин (как правило, из рабочих UNIX-станций). Пользователям надоели вечно перегруженные "бюрократические" машины с разделением времени, и они стремились перейти на небольшие системы, которые могли обслуживать сами, даже если это влекло за собой потерю в вычислительной мощности. Микрокомпьютеры становились быстрее, и эти потери компенсировались. Такой стиль вычислений остается популярным и сегодня. В "колыбели" UNIX, Bell Labs, разработана операционная система следующего поколения -- Plan 9.

Параллельное программирование

Поддержка параллельного программирования в Plan 9 имеет два аспекта. Во-первых, ядро обеспечивает простую модель процесса и несколько системных вызовов для синхронизации и совместного использования переменных. Во-вторых, разработан новый язык параллельного программирования, названный Alef.

В новых ОС имеется тенденция вводить два класса процессов: обычные, как в UNIX, процессы и легковесные нити. Вместо этого в Plan 9 предложен единый класс процессов, допускающий тонкий контроль за разделением ресурсов, таких как память и дескрипторы файлов.

Основные требования параллельных программ таковы: управление разделяемыми ресурсами; наличие интерфейса к планировщику; детализированная синхронизация с использованием взаимоблокировок. У команды rfork предусмотрен аргумент, битовый вектор, устанавливающий, какие из ресурсов родительского процесса должны быть использованы совместно, скопированы или созданы заново в дочернем процессе. К числу этих ресурсов относятся: пространство имен, окружение, таблица дескрипторов файлов, память и пометки (аналог механизма сигналов UNIX). Один из бит определяет, действительно ли rfork создаст новый процесс: если бит выключен, дальнейшая модификация ресурсов будет выполняться в том же процессе, который выполнил вызов. Alef поддерживает ветвление, в котором все ресурсы, включая память, совместно используются родительским и порожденным процессами, по аналогии с порождением нитей во многих системах.

Доказательством правильности модели rfork является множество способов, какими она используется. В отличие от канонического использования fork, трудно найти два обращения к rfork с одинаковым набором бит. Система с двумя типами процессов - обычными и нитями - не была бы столь гибкой.

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

Системный вызов rendezvous обеспечивает синхронизацию процессов. Alef использует его для организации коммуникационных каналов, блокировок создания очередей, множественных блокировок "чтение/запись" и механизма перевода в состояние ожидания и активизации. У rendezvous два аргумента, тег и значение. Вызов rendezvous с некоторым тегом переводит процесс в состояние ожидания, до тех пор пока другой процесс не представит соответствующий тег. Когда между тегами в паре имеется соответствие, происходит обмен их значениями между двумя процессами и оба вызова возвращают управление. Эта примитивная схема достаточна для построения полного набора средств синхронизации.

Взаимоблокировки обеспечиваются архитектурно-зависимой библиотекой, доступной пользователю. Большинство процессоров снабжены набором инструкций, которые могут использоваться для введения блокировок на "атомарном уровне". Исключением является MIPS R3000: процессоры семейства SGI Power Series имеют специальную аппаратную блокировку на шине.

Независимо от "веса", процесс Plan9 будет блокироваться. Это означает, что, когда программа хочет считать из медленного устройства без блокировки всех вычислений, она должна разветвить процесс, чтобы сделать для него чтение. Решение заключается в том, чтобы начать сопутствующий процесс, который произведет ввод/вывод и выдаст результат в основной процесс путем совместно используемой памяти или, возможно, конвейера. Это звучит тяжеловато, но на практике работает легко и эффективно; в действительности, большинство интерактивных приложений Plan 9, даже относительно обычных, написанных на С, таких как текстовый редактор sam, исполняются как многопроцессные программы.

Поддержка ядром параллельного программирования в Plan 9 заключена в нескольких сотнях строк переносимого кода; куча простых примитивов позволяет отслеживать проблемы на уровне пользователя. Хотя эти C-примитивы и работают хорошо, создание и управление подчиненными процессами куда проще запрограммировать на Alef. Высокоуровневая поддержка параллельного программирования на языке уровня пользователя, а не в ядре способствует согласованности интерфейсов между всеми компонентами. Сравните такой подход с системным вызовом select в UNIX: select применим только к ограниченному набору устройств, не может быть обобщен на сетевые задачи, труден в использовании.

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

Реализация пространств имен

Пространство имен организуется при помощи трех вызовов: mount, bind и unmount. Вызов mount присоединяет дерево, обслуживаемое файловым сервером, к текущему пространству имен, расширяя его; bind копирует часть существующего пространства имен в другую точку в пространстве имен; unmount отменяет действие mount или bind.

При использовании вызовов bind или mount, в одной точке пространства имен может быть организован стек из нескольких каталогов. В терминологии Plan 9 это называется объединенным каталогом, который ведет себя подобно конкатенации составляющих его каталогов. Специальный аргумент bind и mount устанавливает положение нового каталога в объединении, допуская добавление новых элементов в начало или конец объединения, причем каждый его элемент ищется поочередно и берется первый подходящий. Объединенные каталоги являются одним из наиболее широко используемых свойств организации пространства имен Plan 9. Например, каталог /bin построен как объединение каталогов /$cputype/bin (двоичные коды), /rc/bin (командные файлы) и, возможно, других, включенных пользователем. Это устраняет необходимость в переменной окружения $PATH.

Один из вопросов, связанных с объединением каталогов, - в какой элемент объединения попадает вновь созданный файл. Проанализировав несколько вариантов, мы решили следующее. Каталогу, добавляемому к объединению, можно приписать разрешение на создание файла - как свойство пространства имен. Когда в объединении создается файл с новым именем, он попадает в первый каталог объединения, обладающий таким признаком.

Универсальный протокол 9Р объединяет компоненты Plan 9, образуя распределенную систему. Вместо изобретения уникального протокола для каждой службы, такого как rlogin, FTP, TFTP и XWindows, Plan 9 реализует службы как операции над файловыми объектами и затем использует единый, хорошо документированный протокол для обмена информацией между компьютерами.

Будучи внешне похожим на NFS, 9Р, однако, воспринимает файлы как последовательность байт, а не блоков. Кроме того, в отличие от NFS, клиенты выполняют вызовы удаленных процедур для установки указателей на объекты в удаленном файловом сервере. Эти указатели называются файловыми идентификаторами,. которые используются для идентификации объекта в удаленной файловой системе.

Протокол 9Р определяет 16 сообщений, обеспечивающих средства для аутентификации пользователей, навигации по иерархии файловой системы, копирования файлов, выполнения ввода/вывода, изменения атрибутов файлов и их создания и удаления. Процедура для получения доступа к иерархии имен, предоставляемой сервером, такова. Связь с файловым сервером устанавливается через конвейер или сетевое соединение. Начальное сообщение session выполняет двустороннюю аутентификацию между клиентом и сервером. Сообщение attach затем подсоединяет файловый идентификатор, предлагаемый системой клиента, к корневому каталогу дерева файлов сервера. Одновременно с этим проверяется идентичность пользователя. Соединение могут разделять несколько пользователей, однако каждый должен выполнять операцию подсоединения, чтобы установить свою идентичность.

Сообщение walk перемещает файловый идентификатор через один уровень иерархии файловой системы. Сообщение clone порождает копию идентификатора, которая указывает на тот же файл как на оригинал. Цель этого шага - переход к файлу в каталоге без потери указателя на сам каталог. Сообщение open блокирует идентификатор некоторого файла, проверяет разрешения на доступ и подготавливает его к вводу/выводу. Сообщения read и write выполняют операции ввода/вывода. Сообщение clunk указывает, что клиент не может больше использовать идентификатор. Сообщение remove приводит к удалению файла и перераспределению ресурсов сервера должен быть распределен заново.

Протокол 9Р имеет две формы: сообщения RPC, посылаемые по конвейеру или сетевому соединению, и процедурный интерфейс внутри ядра. Поскольку драйверы устройств помещены в ядро, они адресуемы непосредственно, и для связи с ними нет необходимости посылать сообщения; вместо этого каждое действие 9Р выполняется путем прямого вызова процедуры. Такое раздвоение дает, по меньшей мере, пару преимуществ. Первое - повышенная скорость адресации локальных устройств. Второе - возможность обойтись одной реализацией RPC: системный механизм вызова удаленной процедуры объединен с мультиплексированием сообщений 9Р в единый компонент.

Для каждого идентификатора файла ядро поддерживает его локальное представление в структуре данных, называемое каналом (channel), так что все операции над файлами, выполняемые ядром, включают канал, соединенный с этим идентификатором. Простейший пример: дескрипторы файлов процесса пользователя, отображаемые в набор каналов. Таблица в ядре представляет список, имеющийся для каждого устройства, точек входа, соответствующих сообщениям 9Р. Системный вызов (например read) переводится в один или больше вызовов процедур согласно этой таблице, индексированных по типу, сохраняемому в канале: procread, eiaread и т.д. Специальное устройство монтирования ядра (mount device) позволяет перевести вызовы процедур в сообщения, то есть конвертирует локальные вызовы процедур в удаленные. В сущности, этот специальный драйвер становится локальным замещением для файлов, обслуживаемых удаленным файловым сервером. Указатель канала в локальном вызове переводится в ассоциированный файл в переданном сообщении.

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

Каждый файл в Plan 9 однозначно идентифицируется набором целых чисел: типом сервера (сохраняемого в канале и используемого как индекс в таблице вызовов функций), номером сервера или устройства, различающего сервер от других такого же типа (разрешимый локально драйвером), и идентификатором, образованный двумя 32-разрядными числами, называемыми путем (path) и версией (version). Путь является уникальным номером файла, присвоенным драйвером устройства или файловым сервером при создании файла. Номер версии обновляется при модификации файла; он может быть использован для поддержания когерентности кэша между клиентами серверами.

Тип и номер устройства аналогичны большому и малому номерам устройства в UNIX; комбинация путь-версия аналогична идентификатору i-node. Устройство и тип связывают канал с драйвером устройства, а путь-версия идентифицирует файл в пределах этого устройства.

ТАБЛИЦА 1 - СООБЩЕНИЯ 9Р
СООБЩЕНИЕ 9Р
    ОПИСАНИЕ
Nop
Нет операции; используется для отладки
Session
Установить соединение
Attach
Проверить пользователя и присоединить идентификатор к корневому каталогу
Clone
Дублировать идентификатор файла
Walk
Продвинуть идентификатор на один уровень в иерархии каталогов
Open
Проверить разрешения на доступ и разрешить чтение и запись
Create
Создать новый файл (или каталог)
Read
Считать содержимое файла, ассоциированного с идентификатором
Write
Записать содержимое файла, ассоциированного с идентификатором
Clunk
Освободить идентификатор
Remote
Удалить файл, ассоциированный с идентификатором
Stat
Считать свойства файла, ассоциированного с идентификатором
Wstat
Модифицировать свойства файла, ассоциированного с идентификатором
Flush
Сбросить выведенное сообщение 9Р
Error
(Только ответ) Возвратить сообщение об ошибке из неудачного вызова
Clwalk
Используется только специальными серверами по низкоскоростным линиям
(Clone and walk)

Кэширование файлов

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

Поле версий при модификации файла изменяется слабо, что делает возможным осуществление некоторых слабо когерентных форм кэширования. Наиболее важной из них является кэширование сегментов текста и данных исполняемых файлов на клиенте. Когда процесс выполняет вызов exec, файл открывается заново и поле версии сравнивается с версией в кэше; если они соответствуют друг другу, используется локальная копия. Такой же метод может быть использован для организации локального кэширующего файлового сервера. Этот сервер уровня пользователя является посредником в соединениях 9Р с удаленным сервером и отслеживает трафик, копируя данные на локальный диск. Когда он встречает команду чтения известных данных, он отвечает непосредственно, тогда как записи проходят немедленно (кэш со сквозной записью), чтобы центральная копия всегда была обновленной. Эта процедура прозрачна для процессов на терминале и не требует изменений для 9Р; он работает хорошо и на домашних машинах, соединенных последовательными линиями. Подобный метод может быть также использован и для организации общего клиентского кэша в неиспользуемой локальной памяти, однако в Plan 9 этого сделано не было.

Сети и коммуникационные устройства

Сетевые интерфейсы являются файловыми системами, резидентно размещенными в ядре. Установка и отмена вызова достигаются посредством записи текстовых последовательностей в управляющий файл, ассоциированный с устройством; информация посылается и принимается путем чтения и записи файла данных. Структура и семантика устройств едина для сетей всех типов.

Верхний каталог /net/tcp содержит файл clone и ряд последовательно пронумерованных подкаталогов. Каждый подкаталог соответствует IP-соединению. Открытие clone резервирует неиспользованное соединение и открывает его управляющий файл. Чтение управляющего файла возвращает номер соединения в текстовой форме, так что процесс пользователя может построить полное имя вновь назначенного каталога соединения. Файлы local, remote и status являются диагностическими: например, remote содержит адрес (для ТСР - IP-адрес и номер порта) удаленного узла.

Вызов инициируется записью сообщения о соединении с конкретным сетевым адресом в качестве его аргумента; например, чтобы открыть сеанс Telnet (порт 23) с удаленной машиной с IP-адресом 135.104.9.52, последовательность должна быть такой:

    connect 135.104.9.52!23

Запись в управляющий файл блокируется до тех пор, пока поддерживается соединение; если адресат недостижим, команда записи возвращает ошибку. Как только соединение установлено, приложение telnet считывает и записывает файл data, чтобы общаться с удаленным демоном Telnet. С другой стороны, демон Telnet стартует путем записи

    announce 23

в свой управляющий файл, чтобы указать свою готовность к получению вызовов на этот порт. В Plan 9 такой демон называется слушатель (listener).

Однородная структура для сетевых устройств не может скрыть все детали адресации и коммуникации для различающихся сетей. Например, Datakit использует текстуальные иерархические адреса, отличающиеся от 32-разрядных адресов IP, так что определенный приложением управляющий файл должен все же знать, какую сеть он представляет. Вместо того, чтобы каждое приложение знало адресацию каждой сети, Plan 9 скрывает эти детали в сервере соединений (connection server), называемом cs. Cs - это файловая система, смонтированная в известном месте. Этот механизм позволяет приложению установить соединение с хостом. Приложение передает символьный адрес и имя службы, например net!kremvax!telnet, и получает в ответ имя открываемого файла и представляемый ему адрес, например /net/tcp/clone 111.123.112. 94!23. Если машины связаны несколькими сетями, cs представляет список возможных сетей и адресов, которые будут последовательно перебираться; порядок определяется эвристически. Например, первым представляется вариант с наибольшей пропускной способностью.

Для установления соединения с cs используется единая библиотечная функция, названная dial. Приложение, применяющее dial, не требует никаких изменений, даже перекомпиляции, для адаптации к новым сетям; все детали при этом скрыты интерфейсом к cs.

Благодаря однородной структуре сетей в Plan 9 для организации сетей достаточно команды import.

Поддержка сетей на уровне ядра

В ядре для построения коммуникационных каналов Plan 9 предусмотрен специальный механизм, называемый потоками (streams). Поток - это двунаправленный канал, соединяющий физическое или псевдоустройство с процессом пользователя. Процесс пользователя вводит и удаляет данные на одном конце потока; процесс ядра, действующий от имени устройства, выполняется на другом конце. Поток включает линейный список обрабатывающих модулей (processing modules). Каждый модуль обладает процедурой продвижения данных как вверх (к процессу), так и вниз (к устройству). Вызов этой процедуры модуля на любом конце потока вводит в него данные. Каждый модуль вызывает последующий для посылки данных вверх или вниз по потоку. Подобно потокам UNIX, потоки Plan 9 могут быть сконфигурированы динамически.

Протокол IL

Протокол 9Р должен выполняться поверх надежного транспортного протокола. 9Р не имеет механизма для восстановления после ошибок передачи, и система предполагает, что каждое считывание из коммуникационного канала возвратит единственное сообщение 9Р; она не анализирует поток данных для определения границ сообщений. Конвейеры и некоторые сетевые протоколы уже имеют эти возможности, но стандартный протокол 9Р - нет. TCP не разделяет сообщения, тогда как UDP не обеспечивает надежной упорядоченной доставки.

Мы разработали новый протокол, названный IL (Internet Link), для передачи сообщений 9Р поверх IP. Это основанный на предварительном соединении протокол, обеспечивающий надежную передачу упорядоченных сообщений между машинами. Так как процесс может иметь только один ожидающий выполнения запрос 9Р, в IL нет необходимости в управлении потоком. Подобно ТСР, в IL предусмотрены адаптивные задержки: он изменяет времена квитирования и ретрансляции, согласуя их с пропускной способностью сети. Это позволяет протоколу хорошо работать в сетях как Internet, так и в локальных Ethernet. Кроме того, IL не затемняет повторную передачу, чтобы не вызвать дополнительной перегрузки сети.

В Plan 9 использование IL меньше и быстрее, чем ТСР. IL является нашим основным транспортным протоколом Internet.

Аутентификация

Аутентификация устанавливает идентичность пользователя, запрашивающего доступ к ресурсам.

С каждым пользователем Plan 9 ассоциирован ключ аутентификации DES; идентичность пользователя подтверждается его способностью кодировать и декодировать специальные сообщения, называемые вызовами. Так как знание ключа пользователя дает доступ к ресурсам этого пользователя, протоколы аутентификации Plan 9 никогда не передают сообщения, содержащие чисто текстовый ключ.

Процесс аутентификации двусторонний: в конце аутентификационного обмена каждая сторона приобретает убежденность в идентичности другой. Каждая машина начинает обмен, имея в памяти ключ DES. В случае вычислительных и файловых серверов ключ, имя пользователя и имя домена для сервера считываются из постоянной памяти. В случае терминалов ключ порождается из пароля, набираемого пользователем во время загрузки. Специальный компьютер, известный как сервер аутентификации (authentication server), поддерживает базу данных ключей для всех пользователей в своем административном домене и участвует в процедуре аутентификации.

Процедура аутентификации в чем-то подобна системе Kerberos, но в отличие от нее не завязана на синхронизацию часов. Кроме того, в отличие от Kerberos, аутентификация Plan 9 поддерживает связь типа "говорить за", которая позволяет одному пользователю получать полномочия другого; именно таким образом вычислительный сервер выполняет процессы от имени своих клиентов.

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

Аутентификация внешних соединений

Обычный протокол аутентификации Plan 9 не подходит для текстовых служб, таких как Telnet или FTP. В этих случаях пользователи Plan 9 проходят аутентификацию с помощью DES-калькулятора. (используется продукт SecureNet Key компании Digital Pathways). Аутентификатор содержит ключ, отличный от обычного ключа пользователя. Пользователь идентифицируется аутентификатором по четырехзначному значению PIN (индивидуального идентификационного номера). Правильный PIN позволяет аутентификатору обмениваться вызовом/ответом с сервером. Поскольку правильный обмен действителен только один раз и ключи никогда не посылаются по сети, эта процедура не чувствительна к отражению попыток нарушения защиты, однако совместима с протоколами типа Telnet и FTP.

Специальные пользователи

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

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

Наконец, специальный пользователь с именем none не имеет пароля и ему всегда разрешено соединение; именем none может назваться каждый. Такой пользователь имеет ограниченные права; например, ему не разрешено изучать дампы; он может читать только общедоступные файлы.

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

Аутентификация с посредником

Когда на вычислительный сервер поступает вызов от некоторого пользователя (допустим, его имя - Peter), это означает, что пользователь хочет запустить процесс со своими собственными полномочиями. Вычислительный сервер при получении вызова поступает следующим образом. Прежде всего, слушатель разветвляется. Порожденный процесс перенаправляется на пользователя none, чтобы избежать выдачи лишних привилегий. Затем выполняется аутентификация, чтобы убедиться в том, что вызывающий пользователь действительно Peter, и показать ему, что сама машина заслуживает доверия. Наконец, происходит переподсоединение ко всем необходимым файловым серверам - снова с использованием протокола аутентификации. В этом случае вычислительный сервер является клиентом файлового сервера и выполняет клиентскую часть аутентификационного обмена от имени Peter. Сервер аутентификации выдаст билеты только в том случае, если административный пользователь вычислительного сервера имеет разрешение говорить за пользователя с именем Peter.

Права доступа к файлам

Одно из преимуществ построения служб как файловых серверов заключается в том, что проблемы владения и прав разрешаются естественным образом. Как и в UNIX, с каждым файлом или каталогом связаны отдельные разрешения на чтение, запись и выполнение/поиск для владельца файла, группы и других пользователей. Трактовка группы необычна и состоит в том, что имя одного из пользователей может быть выделено как лидера группы (group leader). Если группа имеет лидера, то этот пользователь обладает специальными правами, такими как возможность изменения групповых прав файлов этой группы. Если лидер не установлен, члены группы считаются равными, как если бы каждый был лидером.

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

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

Другим необычным применением прав на файл является файловая система дампов, которая не только обслуживается тем же самым файловым сервером, что и исходные данные, но и представлена той же самой базой данных пользователя. Файлам в дампе, следовательно, дана защита, идентичная файлам в обычной файловой системе; если пользователь владеет файлом и тот защищен от чтения, та же самая картина сохранится и в файловой системе дампов. Кроме того, поскольку файловую систему дампов нельзя заменить, файл не может быть изменен; он навсегда останется защищенным от чтения.

Обсуждение

Plan 9 имеет относительно традиционное ядро; новизна системы заключается в компонентах вне ядра и в том, как они взаимодействуют. Наилучшим примером этого является протокол 9Р, который централизует наименование, доступ и аутентификацию. 9Р действительно является сердцем системы: можно сказать, что ядром Plan 9 является в первую очередь мультиплексор 9Р.

В Plan 9 основное внимание уделено файлам; предложенный механизм именования является основным фактором ее выразительности. В частности, при распределенных вычислениях принятый для наименования способ оказывает глубокое влияние на систему. Комбинация локального пространства имен и глобальных соглашений о взаимосвязи сетевых ресурсов позволяет избежать трудностей поддержания глобального однородного пространства имен, тогда как наименование всего как файлов делает понимание системы легкой даже для новичков. Рассмотрим файловую систему дампов, которая тривиальна в использовании для каждого, кто знаком с иерархической файловой системой. На более глубоком уровне, построение всех ресурсов над единым однородным интерфейсом делает интероперабельность легкой. Как только ресурс экспортирует интерфейс 9Р, он может прозрачным образом сочетаться с любой другой частью системы для построения необычных приложений; детали при этом остаются скрытыми. Это может звучать подобно объектно-ориентированному подходу, но на самом деле кое в чем от него отличается. Во-первых, 9Р определяет фиксированный набор "методов"; он не является расширяемым протоколом. Более важно то, что файлы хорошо определены и понятны и поступают предварительно скомпонованными со знакомыми методами доступа, защиты, наименования и обращения в сети. Объекты, несмотря на их общность, не поступают с этими определенными атрибутами. Редуцируя "объект" в "файл", Plan 9 без дополнительных усилий получает определенную технологию.

Тем не менее есть опасность развить идею вычислений, основанных на файлах, слишком далеко. Преобразование каждого ресурса в системе в файловую систему является в каком-то смысле метафорой, а метафоры могут приводить к конфузам. Хорошим примером ограничений является /proc, который только внешне выглядит как процесс, но не представляет его. Для исполнения процессов необходимы все еще обычные вызовы fork и exec, а не чего-то, подобное

cp /bin/date /proc/clone/mem.

Проблема с такими примерами в том, что для них нужно, чтобы сервер работал не под их управлением. Способность придавать значение командам, подобным указанным, не подразумевает, что это значение естественно выпадет из структуры ответов на запросы 9Р, которые она генерирует. Так, например, Plan 9 не помещает сетевые имена компьютеров в пространство имен файлов. Сетевые интерфейсы обеспечивают совершенно другую модель наименования, поскольку использование команд open, read и write над такими файлами не предоставляет подходящего места для кодирования всех деталей установки вызова для произвольной сети. Это не значит, что сетевой интерфейс не может быть файловоподобным, просто он должен иметь более четко определенную структуру.

Plan 9 имеет только один "официальный" механизм RPC, интегрированный с 9Р. По сравнению с системами с более общим RPC, такой подход имеет недостатки: полный вызов RPC должен быть реализован как write, за которым следует read, то есть требует вдвое больше команд; и некоторые специфичные формы RPC могут быть громоздкими. Например, реализация /dev/bitblt, которая имеет специальный RPC-подобный уровень, встроенный над 9Р, не может совместно использовать ни один из кодов для выстраивания сообщений 9Р и требует наличия сервера для сохранения состояния после некоторых вызовов write для возврата информации последующему вызову клиента read. С другой стороны, устройству Plan 9 присущи простота и общность, и (с некоторыми предосторожностями) ему не требуются компиляторы заглушек или какая-либо поддержка на языковом уровне. Громоздкость, подобная /dev/bitblt, на практике встречается редко и никогда не является ограничением. Более того, /dev/bitblt сама является примером, когда избыточность несущественна, т.к. основная масса вызовов устройств включает write без последующей read. Наконец, возможно наиболее важной является легкость написания сервера 9Р. Код, реализующий протокол, занимает всего 500 строк и обычно адаптируется из существующего сервера, а не пишется заново.

Что бы мы сделали по-другому в следующий раз? Некоторые элементы реализации нас не удовлетворили. Использование потоков для введения сетевых интерфейсов в ядре допускает, чтобы протоколы были связаны динамически, например для привязки одного и того же драйвера TTY к соединениям с TCP, URP и IL, но в Plan 9 такая способность к перестройке конфигурации не используется. (Она эксплуатировалась, однако, в том самом варианте ОС UNIX, для которого и были изобретены потоки.) Замена потоков статичными запросами ввода/вывода упрощает код и делает его быстрее.

Хотя основное ядро Plan 9 переносимо на многие машины, файловый сервер реализуется отдельно. Это вызвано несколькими причинами: драйверами, которые должны быть написаны дважды, ошибками, которые тоже должны быть выявлены дважды, и худшей переносимостью кода файловой системы. Решение просто: для реализации файловой службы ядро файлового сервера следует поддерживать как вариант обычной операционной системы, без каких-либо процессов пользователей и специальных скомпилированных внутри процессов ядра.

Хотя Plan 9 поддерживает отдельное пространство имен для каждого процесса, она не имеет никакого механизма для передачи описания пространства имен процесса другому процессу, кроме прямого наследования.

Несмотря на эти проблемы, Plan 9 работает хорошо. Она созрела до состояния системы, которая поддерживает исследования, а не является сама предметом исследования. Дальнейшая работа над ней включает разработку интерфейсов к более быстрым сетям, кэширования файлов в ядре клиента, инкапсуляции и экспортирования пространств имен, а также способности переустанавливать состояние клиента после сбоя сервера. Сейчас внимание сосредоточено на использовании системы для построения распределенных приложений.

Одна из причин успеха Plan 9 заключается в том, что она использовалась в каждодневной работе, а не только в качестве инструмента исследований. Активное использование вынуждало разрешать проблемы по мере их возникновения и адаптировать систему к решению наших задач. Благодаря этому процессу, Plan 9 стала удобной, продуктивной программной средой, а также средством для дальнейших системных исследований.


Окончание. Начало в #6 1995

(c) 1995, AT&T.

(c) 1995, USENIX Association.

Plan 9 from Bell Labs.
Rob Pike, Dave Presotto, Sean Dorward, Bob Flandrena, Ken Thompson, Howard Trickey, Phil Winterbottom.
Computing Systems, v. 8, n. 3, pp. 221-254.