
- •Глава 10. Подсистема управления вводом-выводом
- •10.1 Взаимодействие драйверов с программной и аппаратной средой
- •10.1.1 Конфигурация системы
- •10.1.2 Системные функции и взаимодействие с драйверами
- •1. Просматривается таблица файлов для того, чтобы убедиться в том, что ни
- •2. Если устройство символьного типа, ядро запускает процедуру закрытия уст-
- •Ibm 370 имеется инструкция "Start I/o" (Начать ввод-вывод), которая иниции-
- •10.1.2.4 Стратегический интерфейс
- •10.1.2.5 Ioctl
- •Ioctl(fd,command,arg);
- •10.1.2.6 Другие функции, имеющие отношение к файловой системе
- •10.1.3 Программы обработки прерываний
- •5, Как пользуясь блочным интерфейсом, так и не прибегая к структурированию
- •0, Младший - 21. Файл "/dev/rdsk15" соответствует устройству посимвольного
- •10.3 Терминальные драйверы
- •Ioctl. Когда соответствующие критерии удовлетворены, программа обработки
- •Ioctl для того, чтобы перевести терминал в режим без обработки: он отключает
- •10.3.5 Назначение операторского терминала
- •10.3.6 Драйвер косвенного терминала
- •10.3.7 Вход в систему
- •10.4 Потоки
- •10.4.2 Анализ потоков
5, Как пользуясь блочным интерфейсом, так и не прибегая к структурированию
данных. Непосредственно работают с диском две важные программы - mkfs и
fsck. Программа mkfs форматирует раздел диска для файловой системы UNIX,
создавая при этом суперблок, список индексов, список свободных дисковых бло-
ков с указателями и корневой каталог новой файловой системы. Программа fsck
проверяет целостность существующей файловой системы и исправляет ошибки, как
показано в главе 5.
Рассмотрим программу, приведенную на Рисунке 10.8, в применении к файлам
"/dev/dsk15" и "/dev/rdsk15", и предположим, что команда ls выдала следующую
информацию:
ls -1 /dev/dsk15 /dev/rdsk15
br-------- 2 root root 0,21 Feb 12 15:40 /dev/dsk15
crw-rw---- 2 root root 7,21 Mar 7 09:29 /dev/rdsk15
Отсюда видно, что файл "/dev/dsk15" соответствует устройству блочного
типа, владельцем которого является пользователь под именем "root", и только
пользователь "root" может читать с него непосредственно. Его старший номер -
0, Младший - 21. Файл "/dev/rdsk15" соответствует устройству посимвольного
ввода-вывода, владельцем которого является пользователь "root", однако права
доступа к которому на запись и чтение есть как у владельца, так и у группы.
Его старший номер - 7, младший - 21. Процесс, открывающий файлы, получает
доступ к устройству через таблицу клю-
чей устройств ввода-вывода блоками и таблицу ключей устройств посимвольного
ввода-вывода, соответственно, а младший номер устройства 21 информирует
драйвер о том, к какому разделу диска производится обращение, например, дис-
ковод 2, раздел 1. Поскольку младшие номера у файлов совпадают, они ссылают-
ся на один и тот же раздел диска, если предположить, что это одно устройство
(***). Таким образом, процесс, выполняющий программу, открывает один и тот
---------------------------------------
(***) Не существует иного способа установить, что символьный и блочный драй-
веры ссылаются на одно и то же устройство, кроме просмотра таблиц сис-
темной конфигурации и текста программ драйвера.
303
же драйвер дважды (используя различные интерфейсы), позиционирует головку к
смещению с адресом 8192 и считывает данные с этого места. Результаты выпол-
нения операций чтения должны быть идентичными при условии, что работает
только одна файловая система.
+------------------------------------------------------------+
| #include "fcntl.h" |
| main() |
| { |
| char buf1[4096], buf2[4096] |
| int fd1, fd2, i; |
| |
| if (((fd1 = open("/dev/dsk5/", O_RDONLY)) == -1) || |
| ((fd2 = open("/dev/rdsk5", O_RDONLY)) == -1))|
| { |
| printf("ошибка при открытии\n"); |
| exit(); |
| } |
| |
| lseek(fd1, 8192L, 0); |
| lseek(fd2, 8192L, 0); |
| |
| if ((read(fd1, buf1, sizeof(buf1)) == -1) || |
| (read(fd2, buf2, sizeof(buf2)) == -1)) |
| { |
| printf("ошибка при чтении\n"); |
| exit(); |
| } |
| |
| for (i = 0; i < sizeof(buf1); i++) |
| if (buf1[i] != buf2[i]) |
| { |
| printf("различие в смещении %d\n", i); |
| exit(); |
| } |
| printf("данные совпадают\n"); |
| } |
+------------------------------------------------------------+
Рисунок 10.8. Чтение данных с диска с использованием блочного
интерфейса и без структурирования данных
Программы, осуществляющие чтение и запись на диск непосредственно, пред-
ставляют опасность, поскольку манипулируют с чувствительной информацией,
рискуя нарушить системную защиту. Администраторам следует защищать интерфей-
сы ввода-вывода путем установки прав доступа к файлам дисковых устройств.
Например, дисковые файлы "/dev/dsk15" и "/dev/rdsk15" должны принадлежать
пользователю с именем "root", и права доступа к ним должны быть определены
таким образом, чтобы пользователю "root" было разрешено чтение, а всем ос-
тальным пользователям и чтение, и запись должны быть запрещены.
Программы, осуществляющие чтение и запись на диск непосредственно, могут
также нарушить целостность данных в файловой системе. Алгоритмы файловой
системы, рассмотренные в главах 3, 4 и 5, координируют выполнение операций
ввода-вывода, связанных с диском, тем самым поддерживая целостность информа-
ционных структур на диске, в том числе списка свободных дисковых блоков и
указателей из индексов на информационные блоки прямой и косвенной адресации.
Процессы, обращающиеся к диску непосредственно, обходят эти алгоритмы. Пусть
даже их программы написаны с большой осторожностью, проблема целостности все
304
равно не исчезнет, если они выполняются параллельно с работой другой файло-
вой системы. По этой причине программа fsck не должна выполняться при нали-
чии активной файловой системы.
Два типа дискового интерфейса различаются между собой по использованию
буферного кеша. При работе с блочным интерфейсом ядро пользуется тем же ал-
горитмом, что и для файлов обычного типа, исключение составляет тот момент,
когда после преобразования адреса смещения логического байта в адрес смеще-
ния логического блока (см. алгоритм bmap в главе 4) оно трактует адрес сме-
щения логического блока как физический номер блока в файловой системе. За-
тем, используя буферный кеш, ядро обращается к данным, и, в конечном итоге,
к стратегическому интерфейсу драйвера. Однако, при обращении к диску через
символьный интерфейс (без структурирования данных), ядро не превращает адрес
смещения в адрес файла, а передает его немедленно драйверу, используя для
передачи рабочее пространство задачи. Процедуры чтения и записи, входящие в
состав драйвера, преобразуют смещение в байтах в смещение в блоках и копиру-
ют данные непосредственно в адресное пространство задачи, минуя буферы ядра.
Таким образом, если один процесс записывает на устройство блочного типа,
а второй процесс затем считывает с устройства символьного типа по тому же
адресу, второй процесс может не считать информацию, записанную первым про-
цессом, так как информация может еще находиться в буферном кеше, а не на
диске. Тем не менее, если второй процесс обратится к устройству блочного ти-
па, он автоматически попадет на новые данные, находящиеся в буферном кеше.
При использовании символьного интерфейса можно столкнуться со странной
ситуацией. Если процесс читает или пишет на устройство посимвольного вво-
да-вывода порциями меньшего размера, чем, к примеру, блок, результаты будут
зависеть от драйвера. Например, если производить запись на ленту по 1 байту,
каждый байт может попасть в любой из ленточных блоков.
Преимущество использования символьного интерфейса состоит в скорости,
если не возникает необходимость в кешировании данных для дальнейшей работы.
Процессы, обращающиеся к устройствам ввода -вывода блоками, передают инфор-
мацию блоками, размер каждого из которых ограничивается размером логического
блока в данной файловой системе. Например, если размер логического блока в
файловой системе 1 Кбайт, за одну операцию ввода-вывода может быть передано
не больше 1 Кбайта информации. При этом процессы, обращающиеся к диску с по-
мощью символьного интерфейса, могут передавать за одну дисковую операцию
множество дисковых блоков, в зависимости от возможностей дискового контрол-
лера. С функциональной точки зрения, процесс получает тот же самый резуль-
тат, но символьный интерфейс может работать гораздо быстрее. Если воспользо-
ваться примером, приведенным на Рисунке 10.8, можно увидеть, что когда про-
цесс считывает 4096 байт, используя блочный интерфейс для файловой системы с
размером блока 1 Кбайт, ядро производит четыре внутренние итерации, на каж-
дом шаге обращаясь к диску, прежде чем вызванная системная функция возвраща-
ет управление, но когда процесс использует символьный интерфейс, драйвер мо-
жет закончить чтение за одну дисковую операцию. Более того, использование
блочного интерфейса вызывает дополнительное копирование данных между адрес-
ным пространством задачи и буферами ядра, что отсутствует в символьном ин-
терфейсе.