данной операции, уже существуют — ждем их снятия */
fcntl(fd, SETLKW, &lock);
/* Запишем данные в файл - нам никто не помешает */
write(fd, record, sizeof(record));
/* Снимем блокирование */
lock.l_type = F_UNLK;
fcntl(fd, SETLKW, &lock);
В отличие от рекомендательного в UNIX существует обязательное блокирование (mandatory lock), при котором ограничение на доступ к записям файла накладывается самим ядром. Реализация обязательных блокировок может быть различной. Например, в SCO UNIX (SVR3) снятие бита x для группы и установка бита SGID для группы приводит к тому, что блокировки, установленные fcntl(2) или lockf(3C) , станут обязательными. UNIX SVR4 поддерживает установку блокирования отдельно для записи и для чтения, обеспечивая тем самым доступ для чтения многим, а для записи — только одному процессу. Эти установки также осуществляются с помощью системного вызова fcntl(2) . Следует иметь в виду, что использование обязательного блокирования таит потенциальную опасность. Например, если процесс блокирует доступ к жизненно важному системному файлу и по каким-либо причинам теряет контроль, это может привести к аварийному останову операционной системы.
Во введении отмечалось, что работа файловой подсистемы тесно связана с обменом данными с периферийными устройствами. Для обычных файлов и каталогов — это устройство, на котором размещается соответствующая файловая система, для специальных файлов устройств — это принтер, терминал, или сетевой адаптер. Не вдаваясь в подробности подсистемы ввода/вывода, рассмотрим, как во многих версиях UNIX организован обмен данными с дисковыми устройствами — традиционным местом хранения подавляющего большинства файлов [48] На самом деле файловые системы могут располагаться на удаленных компьютерах (например, в случае NFS). Хотя при работе с такими файловыми системами дисковый ввод/вывод отсутствует, тем не менее и в этом случае кэширование блоков данных значительно повышает производительность.
.
Не секрет, что операции дискового ввода/вывода являются медленными по сравнению, например, с доступом к оперативной или сверхоперативной памяти. Время чтения данных с диска и копирования тех же данных в памяти может различаться в несколько тысяч раз. Поскольку основные данные хранятся на дисковых накопителях, дисковый ввод/вывод является узким местом операционной системы. Для повышения производительности дискового ввода/вывода и, соответственно, всей системы в целом, в UNIX используется кэширование дисковых блоков в памяти.
Для этого используется выделенная область оперативной памяти, где кэшируются дисковые блоки файлов, к которым наиболее часто осуществляется доступ. Эта область памяти и связанный с ней процедурный интерфейс носят название буферного кэша , и через него проходит большинство операций файлового ввода/вывода. Схема взаимодействия различных подсистем ядра с буферным кэшем приведена на рис. 4.13.
Рис. 4.13. Роль буферного кэша
Внутренняя структура буферного кэша
Буферный кэш состоит из буферов данных, размер которых достаточен для размещения одного дискового блока. С каждым блоком данных связан заголовок буфера , представленный структурой buf
, с помощью которого ядро производит управление кэшем, включая идентификацию и поиск буферов, а также синхронизацию доступа. Заголовок также используется при обмене данными с драйвером устройства для выполнения фактической операции ввода/вывода. Когда возникает необходимость чтения или записи буфера на диск, ядро заносит параметры операции ввода/вывода в заголовок и передает его функции драйвера устройства. После завершения операции ввода/вывода заголовок содержит информацию о ее результатах.
Основные поля структуры buf
приведены в табл. 4.9.
Таблица 4.9. Поля структуры buf
Поле |
Описание |
b_flags |
Флаги. Определяют состояние буфера в каждый момент времени (например, B_BUSY — буфер занят или B_DONE — закончена операция ввода/вывода с буфером) и направление передачи данных ( B_READ , B_WRITE , B_PHYS ) |
av_forw , av_back |
Указатели двухсвязного рабочего списка буферов, ожидающих обработки драйвером |
b_bcount |
Число байтов, которое требуется передать |
b_un.b_addr |
Виртуальный адрес буфера |
b_blkno |
Номер блока начала данных на устройстве |
b_dev |
Старший и младший номера устройства |
Поле b_flags
хранит различные флаги связанного с заголовком буфера. Часть флагов используется буферным кэшем, а часть — драйвером устройства. Например, с помощью флага B_BUSY
осуществляется синхронизация доступа к буферу. Флаг B_DELWRI
отмечает буфер как модифицированный, или "грязный", требующий сохранения на диске перед повторным использованием. Флаги B_READ
, B_WRITE
, B_ASYNC
, B_DONE
и B_ERROR
используются драйвером диска. Более подробно операция ввода/вывода для драйвера будет рассмотрена в следующей главе.
Читать дальше