Динамическая установка драйвера в ядро операционной системы требует выполнения следующих операций:
□ Размещение и динамическое связывание символов драйвера. Эта операция аналогична загрузке динамических библиотек, и выполняется специальным загрузчиком.
□ Инициализация драйвера и устройства.
□ Добавление точек входа драйвера в соответствующий коммутатор устройств.
□ Установка обработчика прерываний драйвера.
Естественно, код динамически загружаемых драйверов сложнее, и содержит, помимо стандартных точек входа, ряд функций, отвечающих за загрузку и выгрузку драйвера, а также ряд дополнительных структур. Пример дополнительных функций и структур данных, которые должны быть определены в динамически загружаемом драйвере операционной системы Solaris 2.5, приведен в табл. 5.2.
Таблица 5.2. Дополнительные функции и структуры данных для загружаемых драйверов
_init() |
Функция инициализации и установки, вызываемая при загрузке драйвера |
_fini() |
Функция, вызываемая перед выгрузкой драйвера, удаляющая его из системы |
_infо() |
Функция, возвращающая информацию о драйвере по запросу ядра |
struct modlinkage |
Структура, используемая функциями _init() , _fini() и _info() при загрузке, выгрузке и получении информации о драйвере |
struct modldrv |
Структура, экспортируемая ядру при загрузке драйвера, в частности, содержит адреса точек входа в драйвер |
Помимо этого Solaris 2.5 предоставляет ряд функций ядра для работы с динамически загружаемыми драйверами: mod_install(9F) , mod_remove(9F) и mod_info(9F) .
Драйверы блочных устройств предназначены для обслуживания периферийного оборудования, обеспечивающего обмен данными с помощью фрагментов фиксированной длины, называемыми блоками , размер которых значительно превышает один байт. В основном эти драйверы используются файловой подсистемой и подсистемой управления памятью. Например, свопинг характеризуется обменом данными с устройством вторичной памяти, размер которых обычно равен размеру страницы, что составляет 4 или 8 Кбайт. Файловая подсистема производит чтение и запись данных фрагментами, размер которых равен одному или нескольким блокам устройства. Типичными представителями блочных устройств являются жесткий и гибкий диски.
Блочные устройства можно разделить на два типа в зависимости от того, используются ли они для хранения файловой системы или нет. Соответственно различается и схема доступа к этим устройствам. В последнем случае доступ к устройству осуществляется только через специальный файл устройства, представляющий интерфейс низкого уровня. Хотя обращение к устройствам, содержащим файловые системы, может также осуществляться через интерфейс низкого уровня, доступ к таким устройствам, как правило, осуществляется процессом косвенно, через запросы к файловой системе. Например, чтение или запись обычного файла вызывает операции с драйвером блочного устройства (жесткого диска), на котором расположена файловая система, хранящая данный файл. В этом случае обмен данными происходит при активном участии буферного кэша, позволяющего минимизировать число обращений непосредственно к физическому устройству.
Вообще говоря, операции ввода/вывода для блочного устройства могут быть вызваны рядом событий:
□ Чтением или записью в обычный файл.
□ Чтением или записью непосредственно в специальный файл устройства.
□ Операциями подсистемы управления памятью: страничным замещением или свопингом.
Доступ к блочным устройствам осуществляется с помощью трех основных точек входа: xx open()
, xx close()
и xx strategy()
. При этом за фактическое выполнение ввода/вывода отвечает xx strategy()
. Единственным аргументом, передаваемым этой функции, является указатель на структуру buf
, представляющую собой заголовок буфера обмена, с которой мы уже встречались в предыдущей главе при разговоре о буферном кэше. Структура buf
содержит всю необходимую для операций ввода/вывода информацию. Основные поля структуры buf
:
b_flags |
Флаги. Определяют состояние буфера (например, B_BUSY или B_DONE ) и направление передачи данных ( B_READ , B_WRITE , B_PHYS ) |
av_back , av_forw |
Указатели двухсвязного рабочего списка буферов, ожидающих обработки драйвером |
b_bufsize |
Размер буфера |
b_un.b_addr |
Виртуальный адрес буфера |
b_blkno |
Номер блока начала данных на устройстве |
b_bcount |
Число байтов, которые требуется передать |
b_dev |
Старший и младший номера устройства |
Использование заголовка buf
при передачи блока данных показано на рис. 5.7.
Читать дальше