Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Выделение очереди из памяти ядра и обнуление ее содержимого.



Строка 1406

Инициализация списка запросов, содержащего очередь чтения и очередь записи.

Строка 1414

Связь выбранного листа с очередью и его инициализация.

Строки 1417-1424

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

Строка 1426

Эта функция устанавливает границу объединяемого сегмента и проверяет, чтобы он был не меньше минимального размера.

Строка 1428

Эта функция устанавливает функцию, используемую при изъятии запроса из оче­реди драйвером. Позволяет использовать для обработки очереди альтернативную функцию.

Строка 1429

Инициализирует верхний предел размера комбинируемых сегментов.

Строка 1431

Инициализация максимального количества сегментов, которые может обработать драйвер.

Строка 1432

Инициализация максимального количества физических сегментов за один запрос. Значения для строк 1429-1432 устанавливаются в include/linux/kerne 1.h.

Строка 1434

Возвращение инициализированной очереди.

Строки 1435-1439

Вспомогательная функция для очистки памяти в случае возникновения ошибки.

Теперь наши запросы находятся на своих местах и инициализированы.


Устройства



Перед тем как мы рассмотрим слой обобщенного устройства и обобщенный блочный драйвер, давайте коротко пройдемся по программному слою и посмотрим на манипуля­ции с вводом-выводом блочного устройства (см. рис. 5.4).

На уровне приложения приложение инициализирует файловую операцию с помо­щью f read (). При вызове f read () этот запрос передается в слой виртуальной файло­вой системы (VFS) (описываемой в гл. 41), где хранится структура файла dentry, и через структуру inode. Слой VFS пытается найти запрашиваемую страницу в буфере кеша, и, если она там отсутствует вызывается обработчик файловой системы (filesystem han­dler) для получения требуемого физического блока; inode связан с обработчиком фай­ловой системы, который связан с соответствующей файловой системой. Обработчик фай­ловой системы вызывает утилиты очереди запросов (request queue utilites), являющиеся частью слоя обобщенного блочного устройства (generic block device layer), для созда­ния корректного запроса для физических блока и устройства. Запрос помещается в очередь запросов, поддерживаемую слоем обобщенного блочного устройства.

Пример: «обобщенное» блочное устройство

Рассмотрим слой обобщенного блочного устройства. В соответствии с рис. 5.4 он нахо­дится выше слоя физического устройства и сразу под слоем файловой системы. Основная задача слоя обобщенного устройства - это поддержание очереди запросов и связанные с ней операции.

Сначала мы регистрируем наше устройство с помощью register_blkdev (maj or, dev_name, fops). Эта функция получает старший номер запроса, имя блочного устрой­ства (появляющееся в директории /dev) и указатель на структуру файловой операции. В случае удачи возвращается желаемый старший номер.

Далее мы создаем структуру gendisk.

Функция alloc__disk( in t minors) в include/linux/genhd. h получает но­мер раздела и возвращает указатель на структуру gendisk. Теперь посмотрим на струк­туру gendisk:

include/linux/genhd.h

081 struct gendisk {

82 int major; /* старший номер драйвера */

83 int first_minor;

84 int minors;

85 char disk_name[16]; /* имя старшего драйвера */

86 struct hd_struct **part; /* [индекс младшего] */

87 struct block_device_operations *fops;

88 struct request_queue *queue;

89 void *private_data;

В гл. 6 (опечатка в оригинале). Примеч. науч. ред.



Глава 5* Ввод-Вывод


090 sector_t capacity; 091

92 int flags;

93 char devfs_name[64]; /* devfs crap */

94 int number; /* еще то же самое */

95 struct device *driverfs_dev;

96 struct kobject kob j; 097

 

98 struct timer__rand_state * random;

99 int policy; 100

 

101 unsigned sync_io; /* RAID */

102 unsigned long stamp, stamp_idle;

103 int in_flight;

104 #ifdef CONFIG_SMP

105 struct disk__stats *dkstats;

106 #else

107 struct disk_stats dkstats;

108 #endif

109 };

Строка 82

Поле ma j or__num заполняется на основе результата regis ter_blkdev ().

Строка 83

Блочное устройство для жесткого диска может обрабатывать несколько физических устройств. Несмотря на то что это зависит от драйвера, младший номер обычно со­ответствует каждому физическому приводу. Поле f irst_minor является первым физическим устройством.

Строка 85

Имя disk__name, такое, как hda или sdb, является именем всего диска. (Разделы диска именуются hdal, hda2 и т. д. Они являются логическими дисками внутри физического диска.)

Строка 87

Поле fops в block_device_operations инициализирует структуру файловой операции. Структура файловой операции содержит указатель на вспомогательную функцию в низкоуровневом драйвере устройства. Эти функции являются драйверо-зависимыми и не обязательно реализованы во всех драйверах. Обычно реализуются файловые операции open, close, read и write. В гл. 4, «Управление памя­тью»1 обсуждается структура файловой операции.

Очевидно, имеется в виду гл. 6, «Файловые системы». Примеч. науч. ред.


Устройства



Строка 88

Поле queue указывает на список запрашиваемых операций, которые должен вы­полнить драйвер. (Мы еще обсудим инициализацию очереди запросов.)

Строка 89

Поле private_data хранит драйверозависимые данные.

Строка 90

Поле capacity устанавливается в соответствии с размером устройства (в секторах по 512 кб). Вызов set_capacity () должен получать это значение.

Строка 92

Поле flags означает атрибуты устройства. В случае дискового привода это тип но­сителя, т. е. CD, съемный привод и т. д.

Теперь мы посмотрим, с чем связана инициализация очереди запросов. Когда очередь запросов уже определена, мы вызываем blk_init_queue (request_fn_proc, spinlock__t). Эта функция получает в качестве первого параметра функцию передачи, которая будет вызываться в интересах файловой системы. Функция blk_init_ queue () выделяет очередь с помощью blk__alloc__queue () и затем инициализирует структуру очереди. Второй параметр, blk_init__queue (), - это связанная с очередью блокировка всех операций.

И наконец, для того чтобы сделать блочное устройство видимым для ядра, драйвер должен вызвать add__disk():

Drivers/block/genhd.с

193 void add_disk(struct gendisk *disk)

194 {

 

195 disk-> flags |= GENHD_FL_UP;

196 blk_register_region(MKDEV(disk-> major, disk-> f irst_minor),

197 disk-> minors, NULL, exact_match, exact_lock, disk);

198 register_disk(disk);

199 blk_register_queue(disk);

200 }

Строка 196

Устройство отображается в ядро на основе своего размера и количества разделов.

Вызов blk_register__region () имеет несколько параметров:

1. В этот параметр упакованы старший номер диска и первый младший номер.

2. Это диапазон младших номеров, следующих за первым (если этот драйвер обраба­тывает несколько младших номеров).



Глава 5 • Ввод-Вывод


3. Это загружаемый модуль, содержащий драйвер (если он есть).

4. exact__match - это функция для поиска соответствующего диска.

5. exact_lock - это функция блокировки кода, после того как exact_match най­дет нужный диск.

6. disk - это обработчик, используемый ехасt_match и exact_lock для иденти­фикации нужного диска.

Строка 198

register__disk проверяет раздел и добавляет его в файловую систему.

Строка 199

Регистрация очереди запросов для определенного региона.

Операции с устройством

Базовое обобщенное блочное устройство имеет open, close (освобождение), ioctl и, что самое главное, функцию request. По крайней мере функции open и close могут быть простыми счетчиками. Интерфейс ioctl() может использоваться для отладки и выполнения измерений при прохождении через различные слои программного обес­печения. Функция request, вызываемая, когда запрос помещается в очередь файловой системой, извлекает структуру запроса и обрабатывает его содержимое. В зависимости от того, является ли запрос запросом на чтение или на запись, устройство выполняет со­ответствующее действие.

К очереди запросов нельзя получить прямой доступ, а только через вспомогательные функции. (Их можно найти в driver /block/elevator, с и include /linux/ blkdev.h.) Для сохранения совместимости с базовой моделью устройства мы можем включить возможность взаимодействия со следующим запросом в нашу функцию request:

drivers/block/elevator.с

186 struct request *elv_next_request (request__queue_t *q)

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

Когда драйвер завершает запрос, он сообщает об этом ядру с помощью вспомога­тельной функции end_request ():

drivers/block/ll_rw_blk.с

2599 void end_request(struct request *req, int uptodate)


Устройства



2600 {

2601 if (! end_that_request_first (req, uptodate, req-> hard_.cur_sectors)) {

2602 add_disk_randomness (req-> rq_disk);

2603 blkdev_dequeue_request(req);

2604 end_that_request_last(req);

2605 }

2606 }

Строка 2599

Передает очередь запроса, полученную из elev_next_request ().

Строка 2601

end__that_request_first () передает соответствующее количество секторов [если секторы находятся близко, просто возвращается end_request ()].

Строка 2602

Добавляет в систему пул энтропии. Пул энтропии - это способ генерации случайных номеров в системе из функции, достаточно быстрой для вызова во время обработки прерываний. Базовая идея заключается в том, чтобы собрать байты из данных раз­ных драйверов в системе и сгенерировать на их основе случайное число. Это обсуж­дается в гл. 10, «Добавление вашего кода в ядро». Еще одно объяснение находится в конце /drivers/char/random.с.

Строка 2603

Удаление структуры запроса из очереди.

Строка 2604

Сбор статистики и приготовление структуры к освобождению.

В этой точке обобщенный драйвер обслуживает запросы до их освобождения.

В соответствии с рис. 5.4 мы имеем слой обобщенного блочного устройства, соз­дающего и поддерживающего очереди запросов. Последним слоем в системе блочного ввода-вывода является аппаратный (или специальный) драйвер устройства. Аппаратный драйвер устройства использует вспомогательные функции очереди запросов из обобщен­ного слоя для обслуживания запросов из зарегистрированной очереди запросов и передает уведомление, когда запрос завершен.

Аппаратный драйвер устройства обладает знаниями о нижестоящем оборудовании относительно их регистров, ввода-вывода, таймера, прерываний и DMA (обсуждается в подразд. 5.2.9, «Прямой доступ к памяти (DMA)»). (Подробности реализации драйверов для ШЕ и SCSI лежат за пределами рассмотрения этой главы. Мы рассмотрим подробнее аппаратные драйверы устройств в гл. 10, а серия проектов поможет вам написать каркас для собственного драйвера.)



Глава 5 • Ввод-Вывод


Обзор символьных устройств

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

Как разработчики драйвера устройства мы можем сделать с устройством что угодно, но на практике мы редко будем получать случайный доступ к аудиопотоку или писать по­ток на IDE-диск. Несмотря на то что оба примера звучат заманчиво, мы должны при­держиваться двух простых правил:

• все устройства ввода-вывода в Linux основаны на файлах;

• все устройства ввода-вывода в Linux являются либо символьными, либо блочными.

Драйвер параллельного порта в конце этой главы - символьный драйвер устройства. Символьные и блочные устройства схожи между собой интерфейсом, основанным на фай­ловом вводе-выводе. Извне оба типа используют файловые операций, такие, как open, close, read и write. Внутри самое главное различие между символьными драйверами устройств и блочными драйверами устройств заключается в том, что символьные устрой­ства не обладают системой блокировки для очередей запросов операций на чтение и на за­пись (как было сказано ранее). Зачастую для не имеющих буфера символьных устройств прерывание выполняется для каждого полученного элемента (символа). Для блочных устройств, наоборот, получается целая порция (порции) данных и затем для этой порции вызывается прерывание.


Поделиться:



Популярное:

Последнее изменение этой страницы: 2016-03-25; Просмотров: 677; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.033 с.)
Главная | Случайная страница | Обратная связь