Linux Kernel (Ядро линукса) (часть 2)


Настройка обработчика прерываний

драйвер должен зарегистрировать линию IRQ для устройства. Это можно сделать следующим образом:
request_irq(foo_irq, foo_interrupt,
SA_INTERRUPT|SA_SHIRQ, "foo", NULL);
Функция foo interrupt является обработчиком прерываний устройства. Мы обсудим некоторые ее особенности далее, в разд. "Обработчик прерываний”.

Регистрация диска

Итак, все структуры драйвера устройства готовы. Последний этап инициализации заключается в регистрации и активизации диска. Для этого достаточно одной строчки:
add_disk(foo.gd);
Функция add disko принимает адрес дескриптора gendisk и выполняет следующие действия:
1. Устанавливает флаг genhd fl up в поле gd->f lags.
2. Вызывает функцию kobj mapO, чтобы создать связь между драйвером и старшим номером устройства с его диапазоном младших номеров необходимо понимать, что в этом случае область отображения объекта kobject представлена переменной bdevmap.
3. Регистрирует объект kobject, включенный в дескриптор gendisk, в модели драйвера устройства в качестве нового устройства, обслуживаемого данным драйвером (например, /sys/block/foo).
4. Сканирует таблицу разделов диска, если таковая имеется. Для каждого найденного раздела инициализирует соответствующий дескриптор hd struct в массиве foo.gd->part. Регистрирует разделы в модели драйвера устройства (например, /sys/block/foo/fool).
5. Регистрирует объект kobject, встроенный в дескриптор очереди запросов, в модели драйвера устройства (например, /sys/block/foo/queue).
После того как функция add disko возвратит управление, драйвер заработает. Функция, выполнившая инициализацию, завершается. Процедура-стратег и обработчик прерываний позаботятся об обслуживании каждого запроса, направленного драйверу планировщиком ввода/вывода.

Процедура-стратег

Процедура-стратег представляет собой функцию (или группу функций) драйвера блочного устройства, которая взаимодействует с аппаратным блочным устройством с целью удовлетворения запросов, находящихся в диспетчерной очереди. Процедура-стратег вызывается с помощью метода request fn дескриптора очереди запросов. В примере из предыдущего раздела этим методом является функция foo strategy о. Слой планировщика ввода/вывода передает этой функции адрес q дескриптора очереди запросов.

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

Такая реализация, однако, не будет особо эффективной. Даже если предположить, что данные будут пересылаться с использованием механизма DMA, процедура-стратег должна приостановить сама себя, ожидая, пока завершится операция ввода/вывода. Это означает, что эта процедура должна выполняться в специально выделенном потоке ядра (мы ведь не хотим наказывать ни в чем неповинный пользовательский процесс, не так ли?). Более того, такой драйвер не сможет поддерживать современные контроллеры дисков, способные обрабатывать несколько операций пересылки данных одновременно.
Поэтому большинство драйверов блочных устройств придерживается следующей стратегии:
- процедура-стратег запускает пересылку данных для первого запроса в очереди и настраивает контроллер блочного устройства так, чтобы он выдал прерывание, когда пересылка завершится. После этого процедура завершает работу;
- когда контроллер диска выдаст прерывание, обработчик прерывания снова вызовет процедуру-стратега (чаще всего, напрямую, но иногда путем активизации рабочей очереди). Процедура-стратег либо запускает еще одну пересылку данных для текущего запроса, либо, если все данные для этого запроса пересланы, удаляет запрос из диспетчерной очереди и приступает к обработке следующего.
Запросы могут состоять из нескольких bio, которые, в свою очередь, могут состоять из нескольких сегментов. В принципе, драйверы блочных устройств могут использовать механизм DMA двумя способами:
- для каждого сегмента в каждом bio запроса драйвер запускает отдельную DMA-пересылку;
- драйвер запускает одну DMA-пересылку вразброс, чтобы обслужить все сегменты во всех bio этого запроса.

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

В нашем примере процедура-стратег foo strategy о выполняет следующие действия:
1. Получает текущий запрос из диспетчерной очереди, вызывая вспомогательную функцию elv next request о планировщика ввода/вывода. Если диспетчерная очередь пуста, процедура-стратег возвращает управление:
req = elv_next_request (q) ; if (!req) return;
2. Выполняет макрос bik fs request, чтобы проверить, установлен ли в запросе флаг req cmd, т. е. содержит ли запрос обычную операцию ввода/вывода:
if (!blk_fs_request(req))
goto handle_special_request;
3. Если контроллер блочного устройства поддерживает DMA-пересылку вразброс, процедура-стратег программирует контроллер на выполнение пересылки данных для всего запроса и на выдачу прерывания по окончании пересылки. Вспомогательная функция bik_rq_map_sg возвращает список для пересылки вразброс, которым можно немедленно воспользоваться.
4. В противном случае драйвер должен пересылать данные сегментами. Тогда процедура-стратег выполняет макросы rq for each bio и bio_ for each segment, которые просматривают список bio и список сегментов в каждом bio соответственно:
rq_for_each_bio(bio, rq)
bio_for_each_segment(bvec, bio, i) {
/ transfer the i-th segment bvec / local_irq_save(flags);
addr = kmap_atomic(bvec->bv_page, KM_BIO_SRC_IRQ); foo_start_dma_transfer(addr+bvec->bv_offset, bvec->bv_len); kunmap_atomic(bvec->bv_page, KM_BIO_SRC_IRQ); local_irq_restore(flags);}
Функции kmap atomico и kunmap atomic необходимы, если пересылае- мые данные могут находиться в верхней памяти. Функция foo_start_ dma transfer о программирует аппаратное устройство на запуск пересылки данных с использованием механизма DMA и на выдачу прерывания по окончании пересылки.
5. Возвращает управление.

Предыдущая страница | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | Следующая страница




Возможно, Вас также заинтересует:

ОС Knoppix - это Linux без про...

ВведениеЕсли вы цените свое время, умеете считать деньги и знаете стоимость информации, то эта книга...

Linux Kernel (Ядро линукса) (ч...

Спин-блокировкаСпин-блокировка необходима в многопроцессорной системе, потому что могут возникнуть...

Linux Kernel (Ядро линукса) (ч...

Копирование при записи В системах Unix первых поколений создание процесса было реализовано довольно...

Linux Kernel (Ядро линукса) (ч...

Буферы блоков и головы буферовУ каждого буфера есть дескриптор голова буфера, имеющий тип buffer...