КаталогИндекс раздела
НазадОглавлениеВперед


4. ПРОСТРАНСТВО ИМЕН СИСТЕМЫ ВВОДА/ВЫВОДА

4.1. Введение

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

4.1.1. Префиксы и области полномочий

В системе QNX пространство составных имен разделено на области полномочий. Любой процесс, выполняющий файл-ориетированное обслуживание ввода/вывода, регистрирует у Администратора процессов свой префикс, определяя часть пространства имен, с которым он собирается работать (т.е. область своих полномочий). Эти префиксы образуют дерево префиксов, которое хранится в памяти каждого компьютера, загруженного системой QNX.

4.2. Составные имена

4.2.1. Префиксы Администратора ввода/вывода

При открытии файла, его составное имя сопоставляется с деревом префиксов для того, чтобы направить запрос open() к соответствующему администратору ресурсов ввода/вывода. Например, Администратор устройств (Dev) обычно регистрирует префикс /dev. Если процесс вызывает функцию open(), задавая /dev/xxx, то в результате совпадения начала составного имени с префиксом /dev, запрос open() будет направлен к администратору Dev (владельцу). Дерево префиксов может содержать частично перекрывающиеся области полномочий. В этом случае выбор осуществляется по принципу наибольшего совпадения. Например, предположим, что имеется три зарегистрированных префикса:

/ файловая система на диске (Fsys);
/dev система символьных устройств (Dev);
/dev/hd0 дисковый том (Fsys).

Администратор файловой системы зарегистрировал два префикса - один для смонтированной файловой системы QNX (/), а один для блок-ориентированного специального файла, который представляет целиком физический жесткий диск (/dev/hd0). Администратор устройств зарегистрировал один префикс.

Ниже в таблице приведен пример определения соответствующего администратора по принципу наибольшего совпадения.

Составные имена Совпадает Передается к
/dev/con1 /dev Dev
/dev/hd0 /dev/hd0 Fsys
/usr/dtdodge/test / Fsys

Дерево префиксов представляет собой список префиксов, разделенных двоеточиями, как показано ниже

    prefix=pid,unit:prefix=pid,unit:prefix=pid,unit

pid - это идентификатор процесса для администратора ресурсов ввода/вывода;
unit - это однознаковый номер, позволяющий выбирать один из нескольких возможных префиксов, которые имеет администратор.

В предыдущем примере, если Fsys - это процесс 3, а Dev - процесс 5, то дерево системных префиксов могло бы выглядеть так

  /dev/hd0=3, a:/dev=5, а:/=3,е

Если вам нужно Воспользуйтесь
Отобразить на экране дерево префиксов Утилитой prefix
Получить доступ к дереву префиксов из Си-программы Функцией qnx_prefix_query()

4.2.2. Сетевой корень

В системе QNX имеется понятие суперкорня или сетевого корня, использование которого позволяет задавать составные имена, минуя дерево префиксов конкретного узла. Сетевой корень задается двумя слешами, за которыми следует номер узла. Используя сетевой корень, можно легко получить доступ к файлам и устройствам, которые не входят в пространство составных имен вашего узла. Например, в типичной сети QNX следующие пути определяют:

/dev/ser1 - последовательный порт своего узла;
//10/dev/ser1 - последовательный порт узла 10;
//0/dev/ser1 - последовательный порт своего узла;
//20/usr/dtdodge/test - файл на узле 20.

Обратите внимание на то, что //0 всегда относится к своему узлу.

4.2.3. Сетевой корень по умолчанию

Если программа запускается на чужом узле, то приходится выполнять разрешение путевых имен в контексте пространства путевых имен своего узла. Например, команда

    //5 ls / 
запускающая утилиту ls на узле 5, должна обрабатывать также, как
    ls /
запускаемая на своем узле. В том и другом случае префикс "/" должен быть разрешен по дереву префиксов своего узла, а не узла 5. В противном случае, можно представить себе беспорядок, который мог бы возникнуть, если бы префикс "/" рассматривался "своим" как для узла 5, так и для своего узла: файлы выбирались бы одновременно из совершенно разных файловых систем. С целью выбора нужного дерева префиксов при разрешении составных имен, не начинающихся с одного слэша (/), имеется возможность связать каждый процесс со своим сетевым корнем, используемым по умолчанию. После разрешения такого составного имени, перед ним добавляется сетевой корень, используемый по умолчанию. Например, если процесс имеет по умолчанию сетевой корень //9, то составное имя
    /usr/home/luc
будет разрешено, как
    //9/usr/home/luc
что интерпретируется как: "разрешить составное имя /usr/home/luc по дереву префиксов узла 9".

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

    ls /
то команда унаследовала бы используемый по умолчанию сетевой корень //9, в результате чего получилось бы < /pre> ls //9/

Аналогично, если бы вы ввели команду

    //5 ls /
то вы бы запустили команду ls на узле 5, но она унаследовала бы сетевой корень, используемый по умолчанию (//9), поэтому в результате снова получилось бы ls //9/. И в том, и в другом случае составное имя выбиралось бы из одного и того же пространства составных имен.

Если вы хотите Используйте
Получить ваш текущий сетевой корень, используемый по умолчанию Си функцию qnx_prefix_getroot()
Установить ваш сетевой корень, используемый по умолчанию Си функцию qnx_prefix_setroot()
Запустить программу с новым сетевым корнем, используемым по умолчанию утилиту on

Передача составных имен между процессами

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

При передаче составных имен от одного процесса к другому, имеющему другой сетевой корень (например, при передаче файла системе буферизованной печати Spooler), необходимо определить сетевой корень до того, как составное имя будет передано процессу-получателю. Это можно не делать только в том случае, если вы уверены, что процесс-отправитель и процесс-получатель имеют один и тот же сетевой корень, используемый по умолчанию (либо если составное имя уже имеет лидирующие символы "//node/").

4.2.4. Альтернативные префиксы

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

    префикс = строка-замена

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

    /=//10/

В этом случае ведущий символ (/) будет заменяться префиксом //10/. Например, имя

    /usr/dtdodge/test
будет заменено на
    //10/usr/dtdodge/test.

Это новое имя будет сопоставляться с деревом префиксов узла 10, т.к. оно начинается с символов "//10". В результате запрос open() будет направлен Администратору файловой системы узла 10. Таким образом, альтернативное имя позволит обеспечить доступ к удаленной файловой системе, как к своей собственной.

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

    /dev = 5,а:/=//10/

В этом случае имена, начинающиеся с "/dev", будут адресованы своему Администратору устройств, а запросы с другими именами - к администраторам удаленной файловой системы.

Создание специальных имен устройств

Можно также использовать альтернативные префиксы для создания специальных имен устройств. Например, если Spooler печати работает на узле 20, то можно изменить имя своего принтера на альтернативное следующим образом

    /dev/printer=//20/dev/spool

Любой запрос на открытие /dev/printer будет перенаправлен по сети к реальному Spooler печати. Аналогично, если у вас нет своего накопителя на гибких магнитных дисках, то вы можете обратиться к дисководу на узле 20, используя следующий альтернативный префикс

    /dev/fd0=//20/dev/fd0

В обоих рассмотренных выше случаях альтернативную переадресацию можно не выполнять, а к удаленному ресурсу обращаться непосредственно

    //20/dev/spool        или         //20/dev/fd0

4.2.5. Относительные составные имена

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

Обратите внимание на то, что при задании текущего рабочего каталога результат будет различный, если начинать ее имя с одного слэша, либо с имени сетевого корня.

4.2.6. Текущий рабочий каталог

Если текущий рабочий каталог имеет два ведущих слэша (сетевой корень), говорят, что он определен и привязан к пространству путевых имен определенного узла. Если, наоборот, он имеет один ведущий слэш, то к нему добавляется сетевой корень, используемый по умолчанию. Например, команда

    cd //18/
иллюстрирует первую (определенную) форму и привязывает все относительные составные имена к узлу 18, независимо от того, какой сетевой корень используется по умолчанию. Соответственно, вводя cd dev, в результате получим //18/dev.

Команда cd/ служит примером второй формы, в которой результирующее составное имя, получаемое из относительного, будет зависеть от сетевого корня, используемого по умолчанию. Например, если по умолчанию используется сетевой корень //9, то вводя команду cd dev, в результате получим //9/dev.

На самом деле все это не так сложно, как может показаться. Обычно сетевые корни (//node/) не определены, и вы работаете внутри своего пространства имен (которое определяется вашим сетевым корнем, используемым по умолчанию).

Большинство пользователей, регистрируясь в системе, не меняют сетевой корень, который устанавливается системой по умолчанию, т.е. работают в пространстве имен своего узла.

О команде cd

В некоторых версиях системы UNIX команда cd (сменить каталог) изменяет заданное ей имя, если это имя содержит символические связи. В результате сетевое имя нового текущего рабочего каталога, которое можно получить по команде pwd, может отличаться от заданного в команде cd.

В QNX команда cd не изменяет путевое имя за исключением сокращений "..". Например, команда

    cd /usr/home/luc/test/../doc
установит текущий рабочий каталог /usr/home/luc/doc, даже если отдельные элементы составного имени были символическими связями.

Более подробно о символических связях и сокращениях см. раздел 5 "Администратор файловой системы".

Для того, чтобы получить полное сетевое имя, вы можете воспользоваться утилитой fullpath.

4.3. Пространство имен описателей файлов

При открытии какого-либо ресурса ввода/вывода, происходит обращение к различным пространствам имен. Функция open() возвращает целочисленное значение, которое называется дескриптором файла (FD), в дальнейшем используемое для направления запросов на ввод/вывод к соответствующему администратору. (Отметим, что функция Sendfd(), обращающаяся к ядру, вызываемая из библиотеки подпрограмм, используется для направления запроса.)

Пространство имен дескрипторов файлов, в отличие от пространства составных имен, исключительно локально для каждого процесса. Для идентификации управляющей структуры, связанной с предыдущим вызовом функции open(), администратор использует комбинацию PID (идентификатор процесса) и FD (дескриптор файла). Эта структура называется управляющим блоком открытия (open control block - OCB) и содержится в администраторе ввода/вывода.

На рис._16 показано, как администратор ввода/вывода устанавливает соответствие между отдельными парами PID, FD и OCB.

Рис. 16

4.3.1. Управляющие блоки открытия

Управляющий блок открытия (OCB) содержит текущую информацию об открываемом ресурсе. Например, файловая система сохраняет текущий указатель поиска в файле. Каждая функция open() создает новый ОСВ. Поэтому, если процесс открывает один и тот же файл дважды, то любые вызовы lseek(), использующие один FD, не будут влиять на указатель поиска для другого FD. То же самое происходит, когда разные процессы открывают один и тот же файл.

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

Процесс A открывает файл /tmp/file два раза. Процесс B открывает тот же файл один раз.
Рис. 17

Несколько дескрипторов файлов одного или более процессов могут ссылаться на один и тот же ОСВ. Это достигается двумя способами:

Когда несколько дескрипторов файлов ссылаются на один и тот же ОСВ, то любое изменение состояния ОСВ немедленно становится "видимым" всем процессам, имеющим дескрипторы файлов, связанные с данным ОСВ.

Например, если некоторый процесс использует функцию lseek() для изменения положения указателя поиска, то чтение или запись происходит с новой позиции указателя, и при этом совершенно не важно, какой дескриптор файла используется.

На рис. 18 показаны два процесса, один из которых открывает файл дважды, а затем с помощью функции dup() - третий раз. Затем процесс порождает другой процесс, который наследует все открытые файлы.

Процесс дважды открывает файл, а затем получает еще один FD с помощью функции dup(). Порожденный процесс наследует все три дескриптора.
Рис. 18

Можно запретить наследование дескрипторов файлов процессами, создаваемыми функциями spawn() или exec(), с помощью функции fcntl(), установив флаг FD_CLOEXEC.


НазадОглавлениеВперед
КаталогИндекс раздела