При активизации обязательного блокирования системные вызовы
read
и
write
блокируются, если они конфликтуют с уже установленными блокировками. Если процесс пытается осуществить запись в часть файла, на которой имеется блокировка чтения или записи от другого процесса, первый процесс блокируется до тех пор, пока существующая блокировка не будет снята. Подобным же образом вызовы
read
блокируются на областях, включенных в обязательные блокировки записи.
Обязательное блокирование записи приводит к большей потере производительности, чем рекомендательное блокирование, поскольку каждый вызов
read
и
write
должен быть проверен на предмет конфликтов с блокировками. Оно также не настолько переносимо, как рекомендательное блокирование POSIX, поэтому в большинстве приложений обязательное
блокирование применять не следует.
13.3.4. Аренда файла
И рекомендательное, и обязательное блокирование предназначены для предотвращения доступа процесса к файлу или его части, которая используется другим процессом. Когда блокировка установлена, процесс, которому необходим доступ к файлу, должен подождать завершения процесса, владеющего блокировкой. Эта структура подходит для большинства применений, но иногда программа использует файл до тех пор, пока он не понадобится другой программе, и желает получить при необходимости эксклюзивный доступ к файлу. Для этого Linux предлагает механизм аренды файлов (в других системах это называется периодическими блокировками (oplocks)) [93] .
93
Одним из самых частых пользователей аренды файлов является файловый сервер Samba, позволяющий клиентам кэшировать свои записи для увеличения производительности.
Взятие файла в аренду позволяет процессу получать уведомления (через сигнал) о доступе к файлу со стороны другого процесса. Существуют два типа аренды: аренда чтения и аренда записи. Аренда чтения вызывает передачу сигнала при открытии файла для записи, открытии с указанием
O_TRUNC
или вызове
truncate
. Аренда записи также посылает сигнал при открытии файла для чтения [94] 22. Аренды файлов работают только для модификаций, внесенных в файл той же системой, которая владеет арендой. Если файл локальный (не файл, доступ к которому возможен через сеть), любой подходящий доступ к файлу инициирует сигнал. Если доступ к файлу возможен через сеть, передачу сигнала вызывают только процессы на одной машине с процессо-арендатором; доступ с любой другой машины удается в случае отсутствия аренды.
94
Если тот факт, что аренда записи уведомляет процесс об открытии файла для чтения, может показаться несколько странным, посмотрите на него с точки зрения процесса, получающего аренду. Ему необходимо знать, делает ли другой процесс читать файл, только в случае, когда основной процесс сам что-либо записывает в этот файл.
Системный вызов
fcntl
используется для создания, реализации и запроса аренды файлов. Аренды можно размещать только на обычных файлах (для каналов и каталогов это невозможно), кроме того, аренды записи предоставляются только владельцу файла. Первый аргумент
fcntl
— это интересующий для слежения файловый дескриптор, а второй аргумент,
command
, определяет, какую операцию следует выполнить.
F_SETLEASE
Аренда создается или освобождается в зависимости от значения последнего параметра, передаваемого в
fcntl
;
F_RDLCK
создает аренду чтения,
F_WRLCK
— аренду записи, a
F_UNLCK
освобождает любую аренду, которая может существовать. Если запрашивается новая аренда, она заменяет любую существующую аренду. В случае ошибки возвращается отрицательное число; ноль или положительное число свидетельствуют об успехе операции [95] .
95
Ядра предшествующих версий при успешной операции возвращает ноль либо единицу, тогда как более новые ядра всегда возвращают в данном случае ноль. В другом случае проверка на положительное или отрицательное значение работает нормально.
F_GETLEASE
Возвращается тип аренды, существующей в настоящий момент для файла (
F_RDLCK
,
F_WRLCK
или
F_UNLCK
).
Когда в арендованном файле происходит одно из контролируемых
событий, ядро передает сигнал удерживающему аренду процессу. По умолчанию передается
SIGIO
, но процесс может выбрать, какой сигнал передавать этому файлу, с помощью вызова
fcntl
, в котором второй параметр установлен в
F_SETSIG
, а последний — в сигнал, который должен использоваться вместо
SIGIO
.
Использование
F_SETSIG
дает один значительный эффект. По умолчанию
siginfo_t
не передается обработчику при доставке
SIGIO
. Если используется
F_SETSIG
, даже когда сигналом, передаваемым в ядро, является
SIGIO
, a
SA_SIGINFO
был установлен при регистрации обработчика сигнала, файловый дескриптор, аренда которого инициировала событие, передается в обработчик сигналов одновременно с элементом
siginfo_t
по имени
si_fd
. Это позволяет применять отдельный сигнал к аренде множества файлов, в то время как
si_fd
сообщает сигналу, какому файлу необходимо уделить внимание [96] .
96
Если один сигнал используется для аренды множества файлов, убедитесь, что сигнал является сигналом реального времени, так что множество событий аренды ставятся в очередь. Если используется обычный сигнал, он может потеряться либо события аренды могут возникать через очень короткие промежутки времени.
Единственные два системных вызова, которые могут инициировать передачу сигнала для арендуемого файла — это
open
и
truncate
. Когда они вызываются процессом для арендуемого файла, они блокируются [97] , и процессу-владельцу передается сигнал,
open
или
truncate
завершаются после удаления аренды с файла (или его закрытия процессом-владельцем, что вызывает удаление аренды). Если процесс, удерживающий аренду, не отменяет снятие в течение времени, указанного в файле
/proc/sys/fs/lease-break-time
, ядро прерывает аренду и позволяет завершиться запускающему системному вызову.
97
До тех пор пока
O_NONBLOCK
не будет определен как флаг
open
; в этом случае возвращается
EWOULDBLOCK
.
Ниже приведен пример применения владений файлами для уведомления о намерении другого процесса получить доступ к файлу. Список файлов берется командной строки, и на каждый файл помещается аренда записи. Когда другой процесс намеревается получить доступ к файлу (даже для чтения, поскольку использовалась блокировка записи), программа освобождает блокировку файла, позволяя другому процессу продолжать работу. Она также выводит сообщение о том, какой именно файл был освобожден.