Как и в случае с OCB, вы можете расширять «стандартную» атрибутную запись вашими собственными данными — см. раздел «Дополнительно».
Запись точки монтирования iofunc_mount_t
Запись точки монтирования содержит информацию, общую для нескольких атрибутных записей.
Вот содержимое записи точки монтирования (взято из <sys/iofunc.h>):
typedef struct _iofunc_mount {
uint32_t flags;
uint32_t conf;
dev_t dev;
int32_t blocksize;
iofunc_funcs_t *funcs;
} iofunc_mount_t;
Поле flags содержит только один флаг — IOFUNC_MOUNT_32BIT. Этот флаг указывает на то, что параметр offset в OCB и параметры nbytes и inode в атрибутной записи являются 32-разрядными. Заметьте, что вы можете определять ваши собственные флаги в поле flags, используя биты, определенные константой IOFUNC_MOUNT_FLAGS_PRIVATE.
Поле conf содержит следующие флаги:
IOFUNC_PC_CHOWN_RESTRICTED
Указывает, что файловая система является «chown-ограниченной», то есть никто, кроме суперпользователя (root), не может применять к файлам операцию chown().
IOFUNC_PC_NO_TRUNC
Указывает на то, что файловая система не выполняет усечение имен.
IOFUNC_PC_SYNC_IO
Указывает на то, что файловая система поддерживает синхронные операции ввода-вывода.
IOFUNC_PC_LINK_DIR
Указывает на то, что допускается создание/уничтожение связей (linking/unilnking) для каталогов.
Поле dev содержит номер устройства и описывается ниже в параграфе «О номерах устройств, индексных дескрипторах и нашем друге rdev».
Поле blocksize описывает типовой для данного устройства размер блока в байтах. Например, для дисковых устройств типовым значением будет 512.
И наконец, поле funcs указывает на следующую структуру (взято из <sys/iofunc.h>):
typedef struct _iofunc_funcs {
unsigned nfuncs;
IOFUNC_OCB_T *(*ocb_calloc)(
resmgr_context_t *ctp, IOFUNC_ATTR_T *attr);
void (*ocb_free)(IOFUNC_OCB_T *ocb);
} iofunc_funcs_t;
Как и в таблицах функций установления соединения и ввода/вывода, поле nfuncs должен содержать текущий размер таблицы. Используйте для этого константу _IOFUNC_NFUNCS.
Указатели на функции ocb_calloc и ocb_free могут быть заполнены адресами функций, которые следует вызывать всякий раз при создании и уничтожении OCB. Зачем вам могут понадобиться эти функции — мы обсудим это чуть позже, когда будем говорить о расширении OCB.
О номерах устройств, индексных дескрипторах и нашем друге
rdevЗапись точки монтирования содержит поле с именем dev. Атрибутная запись содержит два поля: inode и rdev. Давайте рассмотрим их взаимосвязь на примере традиционной дисковой файловой системы. Файловая система монтируется на блок- ориентированном устройстве (которое представляет собой весь диск целиком). Это блок-ориентированное устройство может называться, скажем, /dev/hd0 (первый жесткий диск в системе). На этом диске может быть несколько разделов, один из которых вполне может называться /dev/hd0t77 (первый раздел файловой системы QNX на этом конкретном устройстве). И, наконец, на этом разделе может находиться произвольное число файлов, один из которых может иметь имя /hd/spud.txt.
Поле dev («device number» — «номер устройства») содержит число, уникальное для узла, на котором зарегистрирован данный администратор ресурсов. Поле rdev — значение dev для корневого устройства (root device). И, наконец, поле inode — порядковый номер файла.
Попробуем соотнести это с нашим примером дисковой системы. В приведенной ниже таблице приведен ряд чисел; взглянем на таблицу, а потом посмотрим, откуда появились эти номера и как они соотносятся.
Устройство dev inode rdev /dev/hd0 6 2 1 /dev/hd0t77 1 12 77 /hd/spud.txt 77 47343 -
Для «сырого» блок-ориентированного устройства /dev/hd0 значения dev и inode назначил администратор процессов (значения 6 и 2 в таблице, см. выше). Администратор ресурсов при старте получил для устройства уникальное значение rdev (число 1).
Для раздела /dev/hd0t77 значение dev взялось из значения rdev «сырого» блок-ориентированного устройства (та самая 1). Значение inode было выбрано администратором ресурсов как уникальное в пределах rdev. Так появилась цифра 12. Наконец, значение rdev было также выбрано администратором ресурсов — здесь разработчик администратора выбрал значение 77, потому что оно соответствует типу раздела.
И наконец, для файла /hd/spud.txt, значение dev (77) было взято из значения rdev для раздела. Значение inode было выбрано администратором ресурса (в случае файла номер выбирается так, чтобы соответствовать некоторому внутреннему представлению файла — конкретное число не имеет значения, лишь бы оно было ненулевым и уникальным в пределах rdev). Отсюда число 47343. Для файла поле rdev не имеет значения.
Не все вызовы обработчиков соответствуют клиентским сообщениям. Некоторые из них синтезируются ядром, а некоторые — библиотекой.
Я организовал этот раздел следующим образом:
• общие замечания;
• замечания о функциях установления соединения;
• алфавитный список сообщений установления соединения и ввода/вывода.
Каждой функции-обработчику передается внутренний контекстный блок (параметр ctp), который следует рассматривать как «только для чтения», за исключением поля iov. Как это уже упоминалось в параграфе «Внутренний контекстный блок resmgr_context_t», этот контекстный блок содержит несколько интересных вещей. Также, каждой функции передается указатель на сообщение (аргумент msg). Вы будете активно использовать этот указатель, поскольку он содержит параметры, которыми его для вас заполнил клиентский библиотечный вызов. Функция, которую вы пишете, должна возвращать некоторое значение (все функции описаны как возвращающие int).
Значения выбираются из следующего списка:
_RESMGR_NOREPLY
Указывает библиотеке администратора ресурсов, что она не должна выполнять MsgReplyv() — в предположении, что вы либо уже сделали это самостоятельно в вашей функции-обработчике, либо собираетесь сделать это несколько позже.
_RESMGR_NPARTS(n)
Указывает библиотеке администратора ресурсов при выполнении MsgReplyv() возвратить n-элементный вектор ввода/вывода (он располагается в ctp->iov). Ваша функция ответственна за заполнение поля iov структуры ctp и возврат _RESMGR_NPARTS с корректным числом элементов.
Память под поле iov структуры ctp выделяется динамически, и ее должно быть достаточно, чтобы вместить столько число элементов массива, сколько вы записываете в iov! Детали о настройке поля nparts_max см. выше в разделе «Управляющая структура resmgr_attr_t».
_RESMGR_DEFAULT
Это говорит библиотеке администратора ресурсов выполнить низкоуровневую функцию по умолчанию (это другое семейство функций; не путайте их с iofunc_*_default()!). Это возвращаемое значение вам вряд ли когда-нибудь пригодится. В общем случае оно заставляет библиотеку администратора ресурсов возвратить клиенту значение errno, равное ENOSYS, что означает «функция не поддерживается».
_RESMGR_ERRNO(errno)
(Устаревшее.) Данное возвращаемое значение использовалось для «инкапсуляции» значения errno в возвращаемое сообщением значение. Например, если бы клиент выдал запрос open() (по записи — прим. ред.) устройству, доступному только для чтения, корректно было бы возвратить код ошибки EROFS. Поскольку данный способ сделать это считается устаревшим, вы можете возвратить код ошибки непосредственно (например, при помощи return (EROFS); вместо громоздкого _RESMGR_ERRNO(EROFS);).