Рассмотрим слой обобщенного блочного устройства. В соответствии с рис. 5.4 он находится выше слоя физического устройства и сразу под слоем файловой системы. Основная задача слоя обобщенного устройства - это поддержание очереди запросов и связанные с ней операции.
Сначала мы регистрируем наше устройство с помощью register_blkdev (maj or, dev_name, fops). Эта функция получает старший номер запроса, имя блочного устройства (появляющееся в директории /dev) и указатель на структуру файловой операции. В случае удачи возвращается желаемый старший номер.
Далее мы создаем структуру gendisk.
В Linux 2.6 каждое блочное устройство имеет собственную очередь запросов, обрабатывающую запросы ввода-вывода к устройству. Процесс может обновлять очередь запросов устройства только в том случае, если заблокирует очередь запросов. Давайте рассмотрим структуру request_crueue.include/1inux/blkdev.h
270 struct reguest_queue
271 {
272 /*
273 * Объединение с головой очереди для разделения кеша
274 */
275 struct list_head queue_head;
276 struct request *last_merge;
277 elevator_t elevator; 278
279 /*
280 * очередь запрашивает свободный список для записи и для чтения
281 */
Главной проблемой предварительного планировщика ввода-вывода является интенсивное поступление операций записи. Так как он нацелен на максимизацию эффективности чтения, запрос на запись может предваряться чтением, из-за чего головка диска перейдет на новую позицию, а затем для выполнения операции записи будет возвращаться назад, в начальную позицию. Предварительный планировщик ввода-вывода пытается предупредить следующую операцию и таким образом повысить производительность ввода-вывода.
Безоперационный планировщик страдает одним недостатком: при достаточно близких запросах новый запрос никогда не будет обработан. Многие новые запросы, близкие к существующим, будут слиты или вставлены между существующими элементами, а новый запрос будет отброшен и помещен в конец очереди ожидания. Предельный планировщик пытается решить эту проблему с помощью назначения каждому запросу предельного времени и, кроме того, использует две дополнительные очереди для эффективной обработки времени, а в остальном он похож по эффективности на безоперационный алгоритм для работы с диском.
Безоперационный планировщик ввода-вывода получает запросы и сканирует очередь, определяя, можно ли объединить их с уже существующими запросами. Это возможно, если новый запрос близок к существующему. Если новый запрос необходим для блока перед тем, для которого уже есть запрос, он добавляется в начало существующего запроса. Если новый запрос существует для блока после того, для которого уже есть запрос, он добавляется в конец существующего запроса. При нормальном вводе-выводе мы читаем файл с начала до конца, и поэтому большинство запросов сливаются с уже существующими запросами.
Когда запросы на чтение и запись передаются по слоям через VFS, они проходят драйверы файловой системы и кеш страниц1 и заканчиваются входом в драйвер блокового устройства для выполнения настоящих операций ввода-вывода на устройстве, хранящем требуемые данные.Как упоминалось ранее, драйвер блочного устройства создает и инициализирует очередь запросов во время инициализации. Также во время инициализации определяется алгоритм планировки ввода-вывода, используемого для чтения и записи с обслуживаемого блочного устройства.
Драйвер устройства регистрируется во время инициализации драйверов. При этом драйвер добавляется в таблицу драйверов ядра (driver table), а номер драйвера отображается в структуру block_device_operations. Структура block_device_operations хранит функции для запуска и остановки данного блочного устройства в системе:
include/linux/fs.h
760 struct block_device_operations {
761 int (*open) (struct inode *, struct file *);
762 int (*release) (struct inode *, struct file *); 7 63 int (*ioctl) (struct inode *, struct file *,
unsigned, unsigned long);
Как говорилось ранее, операционная система Linux рассматривает все устройства в качестве файлов. Любые полученные элементы от блочного устройства могут быть связаны случайным образом. Хорошим примером блочного устройства является дисковый привод. Файловая система для диска IDE называется /dev/hda. С /dev/hda. связан старший номер 3 и младший номер 0. Сам дисковый привод обычно обладает контроллером и по своей сути является электромеханическим устройством (т. е. имеющим движущиеся части). Раздел «Общая концепция файловых систем» в гл.
Существует два типа файлов устройств: файлы блочных устройств и файлы символьных устройств. Блочные устройства передают данные порциями, а символьные устройства (как следует из названия) передают данные по символу за один раз. Третий тип устройств, сетевые устройства, является специальным случаем, наследующим свойства как блочных, так и символьных устройств.
Процессор общается с окружающими устройствами через набор электрических связей, называемых линиями (lines). Шины (busses) - это группы линий с похожими функциями. Наиболее простой тип шины идет к процессору и от него и использует адресацию устройства; для посылки, получения данных (data) от устройств и для передачи управляющей информации, такой, как устройство-зависимая инициализация и характеристики. Поэтому мы можем сказать, что основными методами общения процессора с устройствами (и наоборот) являются общение через адресную шину, шину данных и управляющую шину.