Добавлен: 29.10.2018
Просмотров: 47998
Скачиваний: 190
11.7. Ввод-вывод в Windows
1021
загружаются специальным кодом, который распознает их необходимость, — например,
распознаватель файловых систем обращается к тому и определяет, файловую систему
какого типа он содержит.
Интересная функциональная возможность Windows — поддержка динамических
дисков
(dynamic disks). Эти диски могут простираться на несколько разделов и даже
несколько дисков и могут переконфигурироваться на ходу, без необходимости в пере-
загрузке. То есть логические диски больше не ограничены одним разделом (или даже
одним диском), так что одна файловая система может захватывать несколько дисков.
Ввод-вывод для томов данных может фильтроваться специальным драйвером Windows,
который реализует теневые копии томов (Volume Shadow Copies). Драйвер-фильтр
создает моментальный снимок тома, который можно монтировать отдельно и который
представляет собой том данных в некий предыдущий момент времени. Он делает это,
отслеживая изменения после выполнения моментального снимка. Это очень удобно
для восстановления файлов, которые были случайно удалены, или возвращения об-
ратно в предыдущие моменты времени (чтобы увидеть состояние файла во время вы-
полнения ранее моментальных снимков).
Теневые копии важны и для выполнения точных резервных копий для серверных си-
стем. Система работает с серверными приложениями до того времени, когда наступает
удобный момент для выполнения резервного копирования. Когда все приложения
готовы, система инициализирует моментальный снимок тома, а затем сообщает при-
ложениям, что они могут продолжать свою работу. Резервная копия делается из со-
стояния тома (на момент выполнения моментального снимка). Приложения при этом
блокируются на очень короткое время (их не надо выводить в автономный режим на
все время резервного копирования).
Приложения участвуют в процессе изготовления моментального снимка, поэтому
резервная копия отражает такое состояние, которое легко восстановить в случае воз-
никновения сбоя. Если бы это было не так, то резервная копия могла бы получиться
вполне пригодной, но сохраненное резервной копией состояние больше напоминало
бы состояние системы при сбое. Восстановление системы в точке сбоя может быть
более трудным или даже невозможным, поскольку сбои происходят в произвольные
моменты времени выполнения приложения. Закон Мэрфи утверждает, что сбои про-
исходят в самое неподходящее время, то есть в тот момент, когда данные приложения
находятся в таком состоянии, восстановление из которого невозможно.
Еще один аспект Windows — это ее поддержка асинхронного ввода-вывода. Поток
может начать операцию ввода-вывода, а затем продолжить выполнение параллельно
с вводом-выводом. Эта функциональная возможность особенно важна для серверов.
Есть несколько способов, при помощи которых поток может определить завершение
ввода-вывода. Один из них — указать объект события в момент выполнения вызова
и затем дожидаться его. Другой — указать очередь, в которую система поместит собы-
тие о завершении ввода-вывода. Третий — предоставить процедуру обратного вызова,
которую система вызовет после завершения ввода-вывода. Четвертый — опросить адрес
памяти, который диспетчер ввода-вывода обновляет после завершения ввода-вывода.
Последний аспект, который мы упомянем, — это приоритетный ввод-вывод. Приоритет
ввода-вывода определяется приоритетом потока (либо его можно указать явным об-
разом). Есть пять уровней приоритета: critical (критический), high (высокий), normal
(нормальный), low (низкий) и very low (очень низкий). Критический зарезервирован
1022
Глава 11. Изучение конкретных примеров: Windows 8
для диспетчера памяти (во избежание взаимоблокировок, которые в противном случае
могли бы произойти в периоды острой нехватки памяти). Низкий и очень низкий при-
оритеты используются фоновыми процессами (службой дефрагментации дисков или
ведущими поиск шпионского программного обеспечения сканерами, а также поиском
по компьютеру — все эти процессы стараются не создавать помех для нормальной
работы системы). Большинство операций ввода-вывода получают нормальный при-
оритет, но мультимедийные приложения могут пометить свой ввод-вывод высоким
приоритетом (чтобы избежать проблем). Мультимедийные приложения могут также
использовать резервирование полосы пропускания (bandwidth reservation) — они
запрашивают гарантированную ширину полосы пропускания для обращения к кри-
тичным в смысле временных задержек файлам (вроде музыки или видео). Система
ввода-вывода сообщит приложению оптимальный размер передачи и количество
ожидающих выполнения операций ввода-вывода (которое следует поддерживать для
того, чтобы система ввода-вывода гарантированно достигла запрошенной ширины
полосы пропускания).
11.7.2. Вызовы интерфейса прикладного
программирования ввода-вывода
Интерфейсы системных вызовов, предоставляемые диспетчером ввода-вывода, не
очень отличаются от предлагаемых большинством других операционных систем. Ос-
новные операции: open, read, write, ioctl и close, но есть и другие операции: Plug-and-Play,
управления энергопотреблением, установки параметров, сброса системных буферов
и т. д На уровне Win32 эти API заключаются в оболочку интерфейсов, которые предо-
ставляют операции более высокого уровня (специфичные для конкретных устройств).
На нижнем уровне эти оболочки открывают устройства и выполняют основные опера-
ции. Даже некоторые операции метаданных (такие, как переименование файла) реа-
лизованы без специфичных системных вызовов. Они просто используют специальную
версию операции ioctl. Это станет более понятно, когда мы объясним реализацию стеков
устройств ввода-вывода и использование пакетов запросов ввода-вывода (I/O request
packets (IRP)) диспетчером ввода-вывода.
Собственные системные вызовы ввода-вывода NT (в соответствии с общей филосо-
фией Windows) имеют множество параметров и много вариантов. В табл. 11.15 пере-
числены основные интерфейсы системных вызовов диспетчера ввода-вывода.
Таблица 11.15. Собственные вызовы интерфейса прикладного программирования
NT для выполнения ввода-вывода
Системный вызов ввода-
вывода
Описание
NtCreateFile
Открыть новый или существующий файл либо устройство
NtReadFile
Читать из файла или устройства
NtWriteFile
Писать в файл или устройство
NtQueryDirectoryFile
Запросить информацию о каталоге (включая файлы)
NtQueryVolumeInformationFile
Запросить информацию о томе
NtSetVolumeInformationFile
Модифицировать информацию тома
11.7. Ввод-вывод в Windows
1023
Системный вызов ввода-
вывода
Описание
NtNotifyChangeDirectoryFile
Завершается, когда любой файл каталога или его подкатало-
гов будет модифицирован
NtQueryInformationFile
Запросить информацию о файле
NtSetInformationFile
Модифицировать информацию файла
NtLockFile
Заблокировать диапазон байтов файла
NtUnlockFile
Снять блокировку диапазона
NtFsControlFile
Различные операции с файлом
NtFlushBuffersFile
Сбросить находящиеся в памяти файловые буферы на диск
NtCancelIoFile
Отменить невыполненные операции ввода-вывода для файла
NtDeviceIoControlFile
Специальные операции с устройством
NtCreateFile используется для открытия существующих или новых файлов. Он предо-
ставляет дескрипторы безопасности для новых файлов, описание требуемых прав
доступа, дает создателю новых файлов некоторые функции управления выделением
блоков. NtReadFile и NtWriteFile принимают описатель файла, буфер и длину. Они также
принимают явное смещение файла и позволяют указать ключ для доступа к заблокиро-
ванным диапазонам байтов в файле. Большая часть параметров относится к указанию
того, какие методы следует использовать для сообщения о завершении ввода/вывода
(возможно, асинхронного), — они описаны ранее.
NtQueryDirectoryFile — это пример стандартной парадигмы исполнительного уровня,
где существуют различные API для обращения (или модификации) к информации об
определенных типах объектов. В данном случае это объекты файлов, которые ссыла-
ются на каталоги. Параметр указывает, какой тип информации запрашивается, — на-
пример, список названий файлов в каталоге либо подробная информация о каждом
файле (которая нужна для расширенного листинга каталога). Поскольку это фактиче-
ски операция ввода-вывода, то поддерживаются все стандартные способы сообщений
о завершении ввода-вывода. NtQueryVolumeInformationFile подобен операции запроса
каталога, но ожидает получения описателя файла, представляющего открытый том,
который может содержать (это необязательно) файловую систему. В отличие от ката-
логов, для томов есть параметры, которые можно модифицировать, поэтому существует
отдельный вызов NtSetVolumeInformationFile.
NtNotifyChangeDirectoryFile — это пример интересной парадигмы NT. Потоки могут
выполнять ввод-вывод, чтобы определить, происходят ли с объектами какие-либо из-
менения (в основном это каталоги файловых систем, как в данном случае, или ключи
реестра). Поскольку ввод-вывод асинхронный, то поток возвращается и продолжает
выполнение (а позже уведомляется, когда что-то модифицируется). Незавершенный
запрос ставится в очередь в файловой системе как ожидающая выполнения операция
ввода-вывода (с использованием пакета запросов IRP). Если вы хотите удалить том
с файловой системой из компьютера, то извещения становятся проблемой, поскольку
есть незавершенные операции ввода-вывода. Поэтому Windows поддерживает средства
для отмены незавершенных операций ввода-вывода (в том числе в файловых системах
есть поддержка принудительного размонтирования тома с незавершенными операци-
ями ввода-вывода).
1024
Глава 11. Изучение конкретных примеров: Windows 8
NtQueryInformationFile — это специфичная (для файлов) версия системного вызова для
каталогов. У нее есть напарник — системный вызов NtSetInformationFile. Эти интерфей-
сы обращаются и модифицируют все виды информации об именах файлов, файловых
функциональных возможностях (наподобие шифрования, сжатия и разреженности),
а также прочих атрибутах файлов (и их подробностях). И в том числе они определяют
внутренний идентификатор файла или присваивают файлу уникальное двоичное имя
(идентификатор объекта).
Эти системные вызовы являются, по существу, специфичной для файлов формой ioctl.
Для переименования или удаления файла можно использовать операцию set. Однако
обратите внимание на то, что они принимают описатели, а не имена файлов, так что
до переименования или удаления файл должен быть сначала открыт. Их можно также
использовать для переименования альтернативных потоков данных в NTFS (см. раз-
дел 11.8).
Отдельные вызовы (NtLockFile и NtUnlockFile) существуют для установки и удаления
побайтовых блокировок для файлов. NtCreateFile позволяет ограничить доступ ко всему
файлу при помощи режима совместного использования. Альтернатива ему — вызовы
блокировки, которые накладывают обязательные ограничения доступа на диапазон
байтов в файле. Операции чтения и записи должны предоставлять ключ, совпадающий
с заданным в NtLockFile (чтобы работать с блокированными диапазонами).
Аналогичные средства имеются и в UNIX, но там приложения соблюдают блокировки
диапазонов по своему усмотрению. NtFsControlFile во многом похожа на предыдущие
операции query и set, но является операцией более общего типа, нацеленной на обработ-
ку специфичных для файлов операций (которые не выполняются другими вызовами).
Например, некоторые операции специфичны для конкретной файловой системы.
И наконец, существуют разнообразные вызовы типа NtFlushBuffersFile. Подобно вызову
sync операционной системы UNIX, он заставляет записать данные файловой системы
на диск. NtCancelIoFile отменяет незавершенные запросы ввода-вывода для конкретного
файла. NtDeviceIoControlFile реализует операции ioctl для устройств. Список операций
на самом деле гораздо длиннее. Существуют системные вызовы для удаления файлов
по имени, для запроса атрибутов конкретного файла, но это просто оболочки для дру-
гих операций диспетчера ввода-вывода (которые мы уже перечислили), и их не нужно
реализовывать в виде отдельных системных вызовов. Есть также системные вызовы
для работы с портами завершения ввода-вывода (I/O completion ports) — это сред-
ство формирования очередей в Windows, которое помогает многопоточным серверам
эффективно использовать операции асинхронного ввода-вывода (за счет подготовки
потоков по требованию и уменьшения количества переключений контекста, требуемых
для обслуживания ввода-вывода специальными потоками).
11.7.3. Реализация ввода-вывода
Система ввода-вывода в Windows состоит из служб Plug-and-Play, диспетчера электро-
питания, менеджера ввода-вывода, а также модели драйвера устройств. Plug-and-Play
обнаруживает изменения в конфигурации аппаратного обеспечения, создает (или
уничтожает) стеки устройств (для каждого устройства), а также загружает и вы-
гружает драйверы устройств. Диспетчер электропитания настраивает состояние
электропитания устройств ввода-вывода, чтобы уменьшить потребление энергии
системой, когда устройства не используются. Диспетчер ввода-вывода предоставляет
11.7. Ввод-вывод в Windows
1025
поддержку манипулирования объектами ядра для ввода-вывода, а также операций
типа IoCallDrivers и IoCompleteRequest. Однако большая часть работы по поддержке
ввода-вывода в Windows реализована в самих драйверах устройств.
Драйверы устройств
Чтобы гарантировать, что драйверы устройств хорошо работают с Windows, компания
Microsoft описала модель WDM (Windows Driver Model), которой должны соответ-
ствовать драйверы устройств. Существует набор разработчика (Windows Driver Kit),
который содержит документацию и примеры, помогающие создавать драйверы, со-
ответствующие WDM. Большинство драйверов Windows начинается с копирования
подходящего образцового драйвера из WDK и его модификации создателем нового
драйвера.
Компания Microsoft также предоставляет верификатор для драйверов (driver verifier),
который проверяет многие действия драйвера, чтобы обеспечить уверенность в том,
что он соответствует требованиям WDM (по структуре и протоколам запросов ввода-
вывода, управлению памятью и т. д.). Верификатор поставляется вместе с системой,
администраторы могут запустить его командой verifier.exe, которая позволяет им ука-
зать, какие драйверы будут проверяться и насколько всесторонними (то есть дорогими)
должны быть эти проверки.
При всей этой поддержке разработки и верификации драйверов в Windows по-
прежнему очень трудно написать даже простой драйвер, поэтому компания Microsoft
создала систему оболочек под названием WDF (Windows Driver Foundation), которая
работает поверх WDM и упрощает многие стандартные требования (в основном свя-
занные с правильным взаимодействием с управлением электропитанием и операциями
Plug-and-Play).
Чтобы еще больше упростить написание драйверов, а также повысить живучесть си-
стемы, WDF включает в себя инфраструктуру UMDF (User-Mode Driver Framework)
для написания драйверов в виде выполняющихся в процессах служб. Существует
также KMDF (Kernel-Mode Driver Framework) для написания драйверов как служб,
выполняющихся в ядре, при этом многие подробности WDM реализуются автомати-
чески. Поскольку в основе лежит WDM (с ее моделью драйверов), то именно на ней
мы и сосредоточимся в этом разделе.
Устройства в Windows представлены объектами устройств. Объекты устройств ис-
пользуются для представления аппаратных средств (таких, как шины), а также как
программные абстракции (наподобие файловых систем, сетевых протоколов и рас-
ширений ядра вроде антивирусных драйверов-фильтров). Все они формируют то, что
Windows называет стеком устройств (как было показано на рис. 11.7).
Операции ввода-вывода инициируются диспетчером ввода-вывода, который вызыва-
ет интерфейс IoCallDriver исполнительного уровня с указателями на верхний объект
устройства и на IRP (который представляет запрос ввода-вывода). Эта процедура
находит объект драйвера, связанный с объектом устройства. Указанные в IRP типы
операций обычно соответствуют описанным ранее системным вызовам диспетчера
ввода-вывода, таким как CREATE, READ и CLOSE.
На рис. 11.21 показаны связи для одного уровня стека устройств. Для каждой из этих
операций драйвер должен указать точку входа. IoCallDriver берет тип операции из
IRP, использует объект устройства на текущем уровне стека устройств (для поиска