Полезное в сети

Всегда в теме

Статистика


Яндекс.Метрика


Онлайн всего: 1
Гостей: 1
Пользователей: 0

Рекомендуем



Главная » Статьи » Операционные системы » Общее

Байт-ориентированные драйверы

Драйвер байт-ориентированного устройства состоит из следующих стандартных функций:

  •  open — открывает устройство; 
  •  close — закрывает устройство;
  •  read — читает данные из устройства;
  •  write — записывает данные в устройство;
  •  ioctl — управляет вводом-выводом;
  •  poll — опрашивает устройство для выяснения, не произошло ли некоторое событие;
  •  mmap, segmap — используются при отображении файла-устройства в виртуальную память.

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

Функция управления ioctl обеспечивает интерфейс к драйверу устройства, который выходит за рамки возможностей функций read и write. С помощью функции ioctl обычно устанавливается режим работы устройства, например задаются параметры СОМ-порта, такие как разрядность символов, количество стоповых бит, режим проверки четности и т. п.

Функции, используемые для отображения специального файла в виртуальную память, рассматриваются ниже в разделе «Отображаемые в память файлы».

Если драйвер не поддерживает какую-либо из стандартных функций, то в таблицу bdevsw помещается указатель на специальную функцию nodev ядра. Например, драйвер принтера может не поддерживать функцию read. Функция nodev при вызове просто возвращает код ошибки ENODEV и на этом завершает свою работу. Для тех случаев, когда функция должна обязательно поддерживаться (примерами таких функций являются функции open и cl ose), но она не выполняет ника-• кой полезной работы, в операционной системе имеется функция nul I dev, которая похожа на функцию nodev, но в отличие от нее возвращает значение 0, которое во всех системных вызовах означает успешное завершение.

На рис. 8.5 показано взаимодействие функции записи драйвера байт-ориентированного устройства с обработчиком прерываний. Функция записи осуществляет передачу данных из пользовательского буфера процесса, выдавшего запрос на обмен, в системный буфер, организованный в виде очереди байт. Передача байт идет до тех пор, пока системный буфер не заполнится до некоторого, заранее определенного в драйвере уровня. Затем функция записи драйвера приостанавливается, выполнив системную функцию sleep, переводящую процесс, в рамках которого работает функция записи write, в состояние ожидания.

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

Отображаемые в память файлы

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

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

Механизм отображения файлов в память использует возможности системы виртуальной памяти для файлов, содержащих произвольные данные (а не только данные исполняемого модуля программы).

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

В UNIX SystemV Release 4 отображение файла в память выполняется с помощью системного вызова mmар. 

Этот вызов имеет следующие аргументы:

  •  addr — виртуальный адрес начала сегмента, если он задается нулевым, то система сама выбирает подходящий адрес и возвращает его в качестве значения функции mmap;
  •  len — размер сегмента;
  •  prot — атрибуты защиты сегмента: только чтение, только запись и т. п.;
  •  flags — флаги, определяющие режим использования сегмента: разделяемый (shared) или закрытый (private);
  •  fd — дескриптор открытого файла, данные которого отображаются;
  •  offset — смещение в файле, с которого начинаются отображаемые данные.

Для сравнения рассмотрим две функции, которые выполняют одни и те же действия с файлом ,но с помощью разных средств — функция f f i 1 е использует традиционные файловые операции, а функция fmap работает с отображенным в память файлом.

Пусть файл /data/base 1 .dat состоит из записей фиксированной длины, каждая из которых включает переменную, отражающую значение баланса предприятия (переменная balance) и признак типа баланса (переменная mode):

/* Структура записи */ 

struct record {

unsigned long balance;

unsigned short mode:

}:

/* Функция ffile использует для работы файловые операции */ 

finction ffile ()

{

int fd;

struct record r:

/* Открытие файла и "пролистывание" первых 24 записей и чтение 25-й */

 fd - openC'/data/basel.dat". 0_RDWR, 0):

 lseek (fd, 24 * sizeof(struct record). SEEKJET):

 read(fd, &r. sizeof(struct record));

 /* Модификация данных 25-й записи */

 r.balance - 1000000; г.mode - 3:

/* Возвращение указателя на начало 25-й записи, так как в результате чтения он переместился на начало 26-й*/ 

lseek (fd. 24 * sizeof (struct record). SEEKJET); 

/* Запись модифицированных данных и закрытие файла*/ 

write (fd. &r. sizeof(struct record)): close (fd): 

}

/* Функция fmap отображает файл в паиять */

 function fmap ():

{

int fd;

struct record *rp: 

/* rp является адресом записи recored */

int len = 1000 * sizeoftstruct record); 

/* len хранит длину файла.

состоящего из 1000 записей */

/* Открытие файла и отображение его в память, которая доступна для чтения и записи, причем доступна в режиме разделения другим процессам*/

 rр =nmapt(0. len. PROT_READ|PROT_WRITE. MAP_SHARED. fd. 0): 

/* Модификация 25-й записи простым присваиванием значений пеерменным */

 rp[24].balance -1000000; 

rp[24].mode = 3; 

Close(fd); 

}

В некоторых операционных системах, например в версиях UNIX, основанных на коде System V Release 4, можно отобразить в память не только обычные файлы, но и некоторые другие типы файлов, например специальные файлы. Отображение в память блок-ориентированного специального файла, то есть раздела или части раздела диска, дает простой доступ к любой области диска, рассматриваемого как последовательность байт. При отображении байт-ориентированных устройств в оперативную память отображается внутренняя память контроллера устройства, например память сетевого адаптера Ethernet.

В общем случае не все типы файлов можно отобразить в память, например в UNIX SVR4 нельзя отображать каталоги и символьные связи.

Отображение файла эффективней непосредственного использования файловых операций в нескольких отношениях.

  •  Исключаются операции копирования данных из системной памяти в пользовательскую. При выполнении файловых операций read и write данные сначала попадают в системный буфер, а затем копируются в пользовательскую память, а при отображении они сразу копируются в страницы пользовательской памяти.
  •  Программист применяет более удобный интерфейс, использующий адресные указатели.
  •  Уменьшается количество системных вызовов, так как при использовании файловых операций каждая операция обмена с файлом связана с выполнением системного вызова, а при отображении выполняется один системный вызов для всех последующих операций доступа к данным файла.
  •  Обеспечивается возможность обмена данными между процессами с помощью разделяемых сегментов памяти, соответствующих одному отображенному файлу, вместо многочисленных операций обмена данными между диском и памятью.

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

Механизм отображения файлов в память используется большинством современных операционных систем.

Дисковый кэш

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

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

Дисковый кэш обычно занимает достаточно большую часть оперативной системной памяти, чтобы максимально повысить вероятность попадания в кэш при выполнении дисковых операций. В таких специализированных операционных системах, как NetWare 3.x и 4.x дисковый кэш занимает большую часть физической памяти компьютера, что во многом и обеспечивает высокую скорость файлового сервиса, который находит значительную часть запрошенных по сети данных в кэше. Доля оперативной памяти, отводимой под дисковый кэш, зависит от специфики функций, выполняемых компьютером, — например, сервер приложений выделяет под дисковый кэш меньше памяти, чем файловый сервер, чтобы обеспечить более высокую скорость работы приложений за счет предоставления им большего объема оперативной памяти.

Отрицательным последствием использования дискового кэша является потенциальное снижение надежности системы. При крахе системы, когда по разным причинам (сбой по питанию, ошибка кода ОС и т. д.) теряется информация, находившаяся в оперативной памяти, могут пропасть и данные, которые пользователь считает надежно сохраненными на диске, но которые фактически до диска еще не дошли и хранились в кэше. Обычно для предотвращения таких потерь все содержимое дискового кэша периодически переписывается («сбрасывается») на диск. Существуют специальные системные вызовы, которые позволяют организовать принудительное выталкивание всех модифицированных блоков кэша на диск. Примером может служить системный вызов sync в ОС UNIX.

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

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

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

Традиционный дисковый кэш

Рассмотрим традиционный дисковый кэш на примере его организации в ОС UNIX, где он появился в первых же версиях.

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

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

Диспетчер дискового кэша управляет пулом буферов данных дисковых блоков с помощью дважды связанного списка заголовков buf, каждый из которых указывает на буфер данных (рис. 8.6).

При наличии кэша большая часть операций, которые выполняет функция strategy блок-ориентированного драйвера, производится с данными, размещенными в буферах дискового кэша, хотя драйверу все равно, кто инициировал данную операцию — диспетчер кэша или другой модуль ядра ОС, лишь бы она описывалась структурой buf с правильно заполненными полями. Отличие для драйвера заключается только в том, что диспетчер кэша всегда указывает в buf в качестве размера переписываемых данных размер блока диска (который чаще всего составляет 512 байт), а другие модули ОС могут указывать произвольный размер области данных. Например, менеджер виртуальной памяти запрашивает обмен страницами.

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

Интерфейс диспетчера кэша образуют следующие функции.

  •  Функция bwrite при сброшенных признаках B_ASYNC и B_DELWRI в buf (рассматриваются ниже) — синхронная запись. В результате выполнения данной функции немедленно инициируется физический обмен с внешним устройством. Процесс, выдавший запрос, переходит в состояние ожидания результата выполнения операции ввода-вывода, используя функцию sleep. В данном случае в процессе может быть предусмотрена собственная реакция на ошибочную ситуацию. Такой тип записи используется тогда, когда необходима гарантия правильного завершения операции ввода-вывода.
  •  Функция bwrite при установленном признаке B_ASYNC и сброшенном признаке B_DELWRI — асинхронная запись. Признак B_ASYNC задает асинхронный характер выполнения операции, при этом так же, как и в предыдущем случае, инициируется физический обмен с устройством, однако завершения операции ввода-вывода функция bwrite не дожидается и немедленно возвращает управление. В этом случае возможные ошибки ввода-вывода не могут быть переданы в процесс, выдавший запрос. Такая операция записи целесообразна при поточной обработке файлов, когда ожидание завершения операции ввода-вывода не обязательно, но есть уверенность в возможности повторения этой операции.
  •  Функция bwrite с установленными признаками B_ASYNC и B_DELWRI — отложенная запись. При этом передача данных из системного буфера не производится, а в заголовке буфера делается отметка о том, что буфер заполнен и может быть выгружен, если потребуется его освободить. Управление немедленно возвращается вызвавшей функции.
  •  Функции bread и getbl k — прочитать и получить блок. Каждая из этих функций ищет в пуле буфер, содержащий указанный блок данных (по номеру устройства и номеру блока). Если такого блока в буферном пуле нет, то в случае использования функции getbl k осуществляется поиск любого свободного буфера, а при его отсутствии возможна выгрузка на диск буфера, содержащего в заголовке признак отложенной записи. В случае использования функции bread при отсутствии заданного блока в буферном пуле сначала вызывается функция getbl k для получения свободного буфера, а затем организуется загрузка в него данных с помощью вызова блок-ориентированного драйвера.

Функция getblk используется тогда, когда содержимое зарезервированного блока не существенно, например при записи на устройство блока данных.

Упрощенный алгоритм выполнения запросов к подсистеме буферизации приведен на рис. 8.7.

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

Дисковый кэш на основе виртуальной памяти

После того как средства виртуальной памяти получили в ОС большое распространение, их стали использовать для кэширования файлов вместо специализированных традиционных механизмов автономного буферного пула. Выше были рассмотрены механизмы отображения файлов в пользовательское виртуальное пространство по явному запросу приложения (например, с помощью системного вызова пипар ОС UNIX). При кэшировании же файл отображается не в пользовательскую, а в общую системную часть виртуального адресного пространства, а в остальном использование виртуальной памяти остается таким же. Для прикладного программиста кэширование файла путем отображения в системную область памяти остается прозрачным, оно выполняется неявно по инициативе ОС при выполнении обычных системных вызовов read и write.

В операционных системах UNIX на основе кода SVR4 в виртуальном адресном пространстве системы существует специальный сегмент segkmap, в который отображаются данные всех открытых файлов. Диспетчер кэша поддерживает массив структур smap, каждая из которых хранит описание одного отображения. Одно отображение состоит из 8096 последовательных блоков одного файла. Отображаемый файл описывается в структуре smap парой vnode/offset, где vnode является указателем на виртуальный дескриптор операции с файлом (см. раздел «Файловые операции» в главе 7 «Ввод-вывод и файловая система»), a offset — смещением в файле на диске, начиная с которого отображаются данные файла. Кроме того, в структуре smap указывается виртуальный адрес внутри сегмента segkmap, на который отображаются данные файла.

При выполнении системного вызова read для чтения данных из некоторого открытого файла подсистема ввода-вывода вызывает функцию segmap_getmap диспетчера кэша, которой передается в качестве параметра пара vnode/offset (эти значения берутся из структуры file, описывающей операцию с файлом). Функция segmap_getmap ищет в массиве smap элемент, который содержит требуемую пару vnode/offset. Если такого элемента нет, то это значит, что требуемый участок файла еще не был отображен в системную память и для нового отображения создается новый элемент smap, а значение виртуального адреса, на который он указывает, возвращается в read. После этого системный вызов read пытается скопировать данные из системной памяти, начиная с указанного адреса, в пользовательский буфер. Так как страницы, содержащей требуемый виртуальный адрес, в оперативной памяти пока нет, то при обращении к памяти возникает страничное прерывание, которое обслуживается соответствующим обработчиком прерываний. В результате блок-ориентированный драйвер читает блоки отсутствующей страницы (а при упреждающей загрузке — и нескольких окружающих ее страниц) с диска и помещает их в системную память. Затем системный вызов read продолжает свою работу, фактически копируя данные в пользовательский буфер. Последующие обращения с помощью вызова read к близкой к прочитанным данным области файла (в пределах 8096 блоков) уже не вызывают нового отображения, а страничные прерывания будут загружать новые блоки файла в кэш по мере необходимости.

На основе таких же принципов работают диспетчеры кэша и в других современных ОС, поддерживающих виртуальную память, например Windows NT, OS/2.


Категория: Общее | Добавил: Admin (21.04.2012)
Просмотров: 2837 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]

Поиск

Вход

Гость
  • Вход
  • Регистрация
  • Читаемое

    Заходи не жди