FCNTL(2) | Руководство программиста Linux | FCNTL(2) |
fcntl - работа с файловым дескриптором
#include <unistd.h> #include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
fcntl() позволяет выполнять различные команды над открытым файловым дескриптором fd. Команда определяется содержимым аргумента cmd.
fcntl() может принимать необязательный третий аргумент. Необходимость его указания зависит от значения, указанного в cmd. Тип необходимого аргумента указан в скобках после каждого имени значения cmd (в большинстве случаев требуется тип int, и мы определяем аргумент с помощью имени arg), или указывается void, если аргумент не нужен.
Некоторые операции, описанные далее, поддерживаются только начиная с определённой версии ядра Linux. Корректным методом проверки доступности операции в ядре является вызов fcntl() с желаемой операцией в cmd и сравнение кода возврата вызов с EINVAL, который указывает на неподдерживаемость значения ядром.
Следующие команды работают с флагами, связанными с файловым дескриптором. В настоящее время определён только один флаг: FD_CLOEXEC, флаг close-on-exec. Если бит FD_CLOEXEC равен 1, то файловый дескриптор будет автоматически закрыт при успешном вызове execve(2) (если execve(2) завершится с ошибкой, то файловый дескриптор останется открытым). Если бит FD_CLOEXEC равен 0, то файловый дескриптор останется открытым после execve(2).
В многонитевых программах использование fcntl() с F_SETFD для установки флага close-on-exec в то время как другая нить выполняет fork(2) плюс execve(2) приводит к состязательности, что может вызвать передачу файлового дескриптора программе, запущенной в дочернем процессе. Смотрите обсуждение флага O_CLOEXEC в open(2) и решение проблемы.
Каждое описание открытого файла имеет несколько связанных с ним флагов состояния, которые инициализируются вызовом open(2) и, возможно, изменяются затем вызовом fcntl(). Эти флаги совместно используются копиями файловых дескрипторов (сделанными с помощью dup(2), fcntl(F_DUPFD), fork(2) и т.д.), которые указывают на одно описание открытого файла.
Эти флаги состояния и их смысл описаны в open(2).
В Linux реализована обычная («попроцессная») блокировка UNIX, стандартизованная POSIX. Описание Linux-альтернативную блокировку открытых файловых описаний с лучшей семантикой смотрите далее.
Команды F_SETLK, F_SETLKW и F_GETLK используются для установки, снятия и тестирования существования блокировок записей (также известных как блокировки байтового диапазона, сегмента или области файла). Третий аргумент, lock, является указателем на структуру, которая имеет, по крайней мере, следующие поля (в произвольном порядке):
struct flock { ... short l_type; /* Тип блокировки: F_RDLCK, F_WRLCK, F_UNLCK */ short l_whence; /* Как интерпретировать l_start: SEEK_SET, SEEK_CUR, SEEK_END */ off_t l_start; /* Начальное смещение блокировки */ off_t l_len; /* Количество блокируемых байт */ pid_t l_pid; /* PID процесса, блокирующего нашу блокировку (только для F_GETLK и F_OFD_GETLK) */ ... };
Поля l_whence, l_start и l_len этой структуры задают диапазон байт, который мы хотим заблокировать. Могут блокироваться байты за концом файла, но не перед началом файла.
l_start — это начальное смещение для блокировки, которое интерпретируется как начало файла (если значение l_whence равно SEEK_SET); как текущая позиция в файле (если значение l_whence равно SEEK_CUR); как конец файла (если значение l_whence равно SEEK_END). В последних двух случаях, l_start может иметь отрицательное значение, предоставляя смещение, которого не может указать до начала файла.
В l_len задаётся количество байт, которые нужно заблокировать. Если l_len положительно, то диапазон блокировки начинается со l_start и кончается l_start+l_len-1 включительно. Если в l_len указан 0, то блокируются все байты начиная с места, указанного l_whence и l_start и до конца файла, независимо от величины файла.
POSIX.1-2001 позволяет (но не требует) реализации поддерживать отрицательное значение l_len; если l_len отрицательно, то интервал, описываемый lock, имеет размер l_start+l_len до l_start-1 включительно. Это поддерживается в Linux начиная с ядер версии 2.4.21 и 2.5.49.
Поле l_type может быть использовано для указания типа блокировки файла: чтение (F_RDLCK) или запись (F_WRLCK). Любое количество процессов могут удерживать блокировку на чтение (общая блокировка) области файла, но только один процесс может удерживать блокировку на запись (эксклюзивная блокировка). Эксклюзивная блокировка исключает все другие блокировки, как общие так и эксклюзивные. Один процесс может удерживать только один тип блокировки области файла; если происходит новая блокировка уже заблокированной области, то существующая блокировка преобразуется в новый тип блокировки. (Такие преобразования могут привести к разбиению, уменьшению или срастанию с существующей блокировкой, если диапазон байт, заданный для новой блокировки, неточно совпадает с диапазоном существующей блокировки.)
Для того, чтобы установить блокировку на чтение, fd должен быть открыт на чтение. Для того, чтобы установить блокировку на запись, fd должен быть открыт на запись. Чтобы установить оба типа блокировки, дескриптор должен быть открыт на запись и на чтение.
При размещении блокировок с помощью F_SETLKW, ядро обнаруживает взаимные блокировки (deadlocks), при которых два и более процессов создают запросы на блокировку, блокируемые блокировками, удерживаемые другими процессами. Например, предположим, что процесс А удерживает блокировку на запись файла в байт 100, а процесс Б удерживает блокировку на запись в байт 200. Если каждый процесс затем попытается заблокировать байт, который уже заблокирован другим процессом с помощью F_SETLKW, то без обнаружения взаимных блокировок оба процесса останутся заблокированными навсегда. Когда ядро обнаруживает такие взаимные блокировки оно сразу же завершает одну из блокирующих блокировок с ошибкой EDEADLK; приложение, встретившее такую ошибку, должно освободить одну из своих блокировок перед попыткой восстановить блокировки, которые ему нужны, позволив другому приложению продолжить работу. Зацикленные взаимные блокировки обнаруживаются и для более двух процессов. Однако заметим, что есть ограничения в алгоритме обнаружения взаимных блокировок; смотрите ДЕФЕКТЫ.
Также как и при снятии блокировки через явное указание F_UNLCK, блокировка автоматически снимается, когда процесс завершается.
Блокировки не наследуются потомком, созданным через fork(2), но сохраняются при вызове execve(2).
Поскольку буферизация выполняется через библиотеку stdio(3), использование блокировок с функциями в этом пакете нужно избегать; вместо этих функций используйте read(2) и write(2).
Записи о блокировках, описанных выше, связаны с процессом (в отличие от блокировках открытых файловых описаний, описанных далее). Это приводит к некоторым печальным последствиям:
Блокировки открытых файловых описаний решают обе эти проблемы.
Блокировки открытых файловых описаний являются консультативными блокировками диапазона байт, чьё действие почти идентично обычным блокировкам, описанным выше. Данный тип блокировок есть только в Linux и доступен с версии 3.15 (есть предложение в Austin Group включить данный тип блокировки в следующую версию POSIX.1). Описание открытых файловых описаний смотрите в open(2).
Принципиальное различие между двумя типами блокировок в том, что обычные блокировки связаны с процессом, а блокировки открытых файловых описаний связаны с открытым файловым описанием, для которого они получены (очень похоже на блокировки, получаемые с помощью flock(2). В следствие этого (и в отличие от обычных консультативных блокировок), блокировки открытых файловых описаний наследуются при fork(2) (и при clone(2) с CLONE_FILES), и освобождаются только автоматически при последнем закрытии открытого файлового описания, а не при любом закрытии файла.
Конфликт комбинаций блокировок (блокировка чтения и блокировка записи или две блокировки записи), при котором одна блокировка — открытое файловое описание, а другая — обычная блокировка, конфликтуют даже когда они запрашиваются одним процессом для одного и того же файлового дескриптора.
Блокировки открытых файловых описаний, полученные для одного и того же файлового описания (т. е., для одного и того же файлового дескриптора или его копии, созданной в результате fork(2), dup(2), fcntl() F_DUPFD и т. п.), всегда совместимы: если новая блокировка помещается на уже заблокированную область, то существующая блокировка преобразуется в блокировку нового типа (такие преобразования могут приводить к разделению, сокращению или объединению существующей блокировки, как описывалось ранее).
С другой стороны, блокировки открытых файловых описаний могут конфликтовать друг с другом, когда они запрашиваются через разные открытые файловые описания. То есть, нити в многонитевых программах могут использовать блокировки открытых файловых описаний для синхронизации доступа к области файла, если каждая нить выполняет отдельный вызов open(2) на файл и применяет блокировки для получаемого файлового дескриптора.
Как и у обычных блокировок, третий аргумент fcntl(), lock, является указателем на структуру flock. Но в отличие от обычных блокировок при использовании команд, описанных далее, поле l_pid этой структуры должно иметь значение 0.
Команды для работы с блокировками открытых файловых описаний аналогичны используемым для обычных блокировок:
В текущей реализации для блокировок открытых файловых описаний обнаружение взаимных блокировок не выполняется (в этом отличие от попроцессных блокировок, для которых ядро выполняет обнаружение взаимных блокировок).
Предупреждение: реализация Linux обязательного блокирования ненадёжна. Смотрите раздел ДЕФЕКТЫ далее. Из-за этих дефектов и того факта, что это свойство, вероятно, мало где будет использоваться, начиная с Linux 4.5 обязательная блокировка был сделана необязательной, и включается параметром настройки (CONFIG_MANDATORY_FILE_LOCKING). Это первый шаг последующего полного удаления данного свойства.
По умолчанию, обычные (связанные с процессом) блокировки и блокировки открытого файлового описания являются консультативными. Консультативные блокировки не обязательны к выполнению и полезны только в сотрудничающих процессах.
Оба типа блокировки могут быть также обязательными. Если процесс пытается получить несовместимый доступ (например, read(2) и write(2)) к области файла, на которую установлена несовместимая обязательная блокировка, то результат зависит от состояния флага O_NONBLOCK в описании этого открытого файла. Если флаг O_NONBLOCK не установлен, то системный вызов блокируется до удаления блокировки или преобразуется в режим, который совместим с доступом. Если флаг O_NONBLOCK установлен, то системный вызов завершается с ошибкой EAGAIN.
Чтобы использовать обязательные блокировки, обязательное блокирование должно быть включено в файловой системе, содержащей файл, и на самом файле. Обязательное блокирование включается в файловой системе с помощью параметра «-o mand» команды mount(8) или с помощью флага MS_MANDLOCK в mount(2). Обязательное блокирование включается на файле посредством отключения права исполнения группе и установкой бита set-group-ID (см. chmod(1) и chmod(2)).
Обязательная блокировка не описана в POSIX. В некоторых других системах обязательная блокировка также поддерживается, хотя процесс её создания различен.
При получении консультативной блокировки на сетевой файловой системе, например NFS, возможна её потеря. Это может случиться из-за административного действия или сетевой проблемы (т. е., потеря связи с сервером), которая длится достаточно долго для того, чтобы сервер посчитал клиента за неработающего.
Когда файловая система определяет, что блокировка потеряна, последующие запросы read(2) или write(2) могут завершиться ошибкой EIO. Эта ошибка будет повторяться до тех пор, пока блокировка не удалится или не закроется файловый дескриптор. Начиная с Linux 3.12, так работает, по крайней мере, NFSv4 (включая все предыдущие версии).
Некоторые версии UNIX при таких обстоятельствах посылают сигнал (SIGLOST). В Linux такой сигнал не определён и не существует какого-либо асинхронного уведомления о потере блокировки.
Для управления сигналами доступности ввода/вывода используются команды F_GETOWN, F_SETOWN, F_GETOWN_EX, F_SETOWN_EX, F_GETSIG и F_SETSIG:
struct f_owner_ex { int type; pid_t pid; };
Используя эти механизмы, программа может реализовать полностью асинхронный ввод-вывод почти не используя в своей работе select(2) или poll(2).
Использование O_ASYNC, является специфичным для BSD и Linux. В POSIX.1 описано только использование F_GETOWN и F_SETOWN вместе с сигналом SIGURG для сокетов (в POSIX не определён сигнал SIGIO). F_GETOWN_EX, F_SETOWN_EX, F_GETSIG, and F_SETSIG есть только в Linux. В POSIX описан асинхронный ввод-вывод и структура aio_sigevent, используемая для сходных действий; они также доступны в Linux как часть библиотеки GNU C (Glibc).
Команды F_SETLEASE и F_GETLEASE (в Linux 2.4 и выше) используются для установки новой и получения текущей аренды открытого описания файла, на который указывает файловый дескриптор fd. Аренда файла предоставляет механизм, посредством которого процесс, который удерживает аренду («арендатор»), уведомляется (отправкой сигнала), когда процесс («нарушитель аренды») пытается выполнить вызов open(2) или truncate(2) на файл, указанный в этом файловом дескрипторе.
Аренды ассоциируются с открытым файловым описанием (см. open(2)). Это значит, что дублированные файловые дескрипторы (созданные, например, fork(2) или dup(2)) указывают на одну и ту же аренду, и эта аренда может изменяться или освобождаться через любой из этих дескрипторов. Более того, аренда освобождается или через явную команду F_UNLCK на любом из этих дублированных файловых дескрипторов, или когда все эти файловые дескрипторы будут закрыты.
Аренды могут быть выданы только на обычные файлы. Непривилегированный процесс может получить аренду только на файл, чей UID (владельца) совпадает с UID на файловой системе процесса. Процесс с мандатом CAP_LEASE может получить аренду на любые файлы.
Когда процесс («нарушителя аренды») выполняет вызов open(2) или truncate(2), который конфликтует с арендой, установленной через F_SETLEASE, то системный вызов блокируется ядром и ядро уведомляет арендатора сигналом (по умолчанию SIGIO). Арендатор должен при получении этого сигнала выполнить все необходимые действия по очистке для подготовки этого файла к использованию другим процессом (например, сбросить буферы кэша) и затем удалить или снизить условия аренды. Аренда удаляется по команде F_SETLEASE с аргументом arg, установленным в F_UNLCK. Если арендатор удерживает аренду на запись в файл, и нарушитель аренды открывает файл на чтение, то достаточно того, что арендатор понизит условия аренды до аренды на чтение. Это выполняется командой F_SETLEASE с аргументом arg, установленным в F_RDLCK.
Если арендатор не освободит аренду или не снизит условия в течении определённого количества секунд, указанного в файле /proc/sys/fs/lease-break-time, то ядро принудительно удалит или снизит условия аренды для арендатора.
После того, как был начат разрыв аренды, F_GETLEASE возвращает тип назначения аренды (или F_RDLCK или F_UNLCK, в зависимости от необходимости совместимости с нарушителем аренды) до тех пор, пока держатель аренды добровольно не отдаст или не удалит аренду или ядро принудительно не сделает это после истечения таймера разрыва аренды.
После того как аренда снята держателем аренды или принудительно удалена и снижены условия, и предполагая, что нарушитель аренды не выполнял неблокирующий системный вызов, ядро позволяет продолжить работу системного вызова нарушителя аренды.
Если нарушитель аренды, заблокированный в open(2) или truncate(2), прерывается обработчиком сигнала, то системный вызов завершается неудачно с ошибкой EINTR, но другие шаги по-прежнему выполняются как описано ранее. Если нарушитель аренды завершается по сигналу будучи блокированным в open(2) или truncate(2), то другие шаги по-прежнему выполняются как описано ранее. Если нарушитель аренды указал флаг O_NONBLOCK при вызове open(2), то вызов немедленно завершается неудачей с ошибкой EWOULDBLOCK, но другие шаги по-прежнему выполняются как описано ранее.
По умолчанию, для уведомления арендатора используется сигнал SIGIO, но его можно изменить, используя команду F_SETSIG для fcntl(). Если выполняется команда F_SETSIG (даже назначая сигнал SIGIO), и при этом обработчик сигнала устанавливается с использованием SA_SIGINFO, то обработчик получит в качестве второго аргумента структуру siginfo_t, в которой поле si_fd будет содержать файловый дескриптор арендованного файла, к которому пытается получить доступ другой процесс (это полезно, если вызывающий процесс удерживает аренду на несколько файлов).
Опечатывание файла позволяет ограничить набор выполняемых над файлом операций. Любая операция с файлом, попавшая в набор опечатанных, завершается с ошибкой EPERM. Набор печатей по умолчанию зависит от типа файла, к которому он применяется и файловой системы. Описание опечатывания файла, предназначение и примеры кода смотрите в memfd_create(2).
В настоящее время опечатывание файла может применяться к файловому дескриптору, возвращаемому memfd_create(2) (если был указан MFD_ALLOW_SEALING). В других файловых системах все операции fcntl(), относящиеся к печатям, возвращают EINVAL.
Печати (seals) — свойство inode. То есть все открытые файловые дескрипторы, указывающие на один inode, имеют общий набор печатей. Кроме этого, печати нельзя удалять, можно только добавлять.
Доступны следующие печати:
Подсказки срока службы записи можно использовать для уведомления ядра об относительно ожидаемом сроке службы записи заданной иноды и открытого файлового описания (об открытых файловых описаниях читайте в open(2)). В этом контексте термин «срок службы записи» (write lifetime) означает ожидаемое время, которое будут существовать данные на носителе до их перезаписи или стирания.
В приложении можно использовать различные значения подсказок, перечисленные ниже, для разделения записей на различные классы, чтобы несколько пользователей или приложений, работающие на одном аппаратном хранилище могли объединить свои шаблоны ввода-вывода в непротиворечивую форму. Однако, для флагов не подразумевается какая-то функциональная семантика, и для различных классов ввода-вывода можно использовать подсказки срока службы записи произвольным образом, пока подсказки не противоречат друг другу.
Следующие операции могут применяться к файловому дескриптору fd:
Если открытому файловому описанию не была назначена подсказка чтения/записи, то будет использоваться значение (если есть), назначенное иноде.
Начиная с Linux 4.13, действуют следующие подсказки чтения/записи:
Все подсказки записи соотносятся друг с другом и нет отдельного абсолютного смысла им предписываемого.
При успешном выполнении возвращаемое значение зависит от используемой команды:
В случае ошибки возвращается -1 и значение errno устанавливается соответствующим образом.
SVr4, 4.3BSD, POSIX.1-2001. В POSIX.1-2001 указаны только команды F_DUPFD, F_GETFD, F_SETFD, F_GETFL, F_SETFL, F_GETLK, F_SETLK и F_SETLKW.
Значения F_GETOWN и F_SETOWN определены в POSIX.1-2001. Для получения их определений, определите _XOPEN_SOURCE со значением 500 или больше или _POSIX_C_SOURCE со значением 200809L или больше.
F_DUPFD_CLOEXEC указана в POSIX.1-2008. Для получения определения, определите _POSIX_C_SOURCE со значением 200809L или больше, или _XOPEN_SOURCE со значением 700 или больше.
Команды F_GETOWN_EX, F_SETOWN_EX, F_SETPIPE_SZ, F_GETPIPE_SZ, F_GETSIG, F_SETSIG, F_NOTIFY, F_GETLEASE и F_SETLEASE есть только в Linux. Для задействования этих определений определите макрос _GNU_SOURCE.
Значения F_OFD_SETLK, F_OFD_SETLKW и F_OFD_GETLK есть только в Linux (и для получения их определений нужно определить _GNU_SOURCE), но ведётся работа по их включению в следующую версию POSIX.1.
Значения F_ADD_SEALS и F_GET_SEALS есть только в Linux.
Ошибки, возвращаемые dup2(2), отличаются от тех, что возвращаются при F_DUPFD.
Первоначальная версия системного вызова fcntl() в Linux не умела работать с большими файловыми смещениями (в структуре flock). Позднее, в Linux 2.4 был добавлен системный вызов fcntl64(). Новый системный вызов использует другую структуру для блокировки файлов — flock64 и соответствующие команды — F_GETLK64, F_SETLK64 и F_SETLKW64. Однако, это различие может игнорироваться приложениями, которые используют glibc, так как имеющаяся в ней обёрточная функция fcntl() самостоятельно задействует более новый системный вызов, если он доступен.
Начиная с ядра 2.0, не существует разницы между типами блокировки, которые осуществляют flock(2) и fcntl().
Некоторые системы имеют дополнительные поля в структуре struct flock, например, l_sysid (признак машины, на которой удерживается блокировка). Вообще говоря, один l_pid не очень полезен, если процесс, удерживающий блокировку, может работать на другой машине; в Linux, хотя это поле и есть на некоторых архитектурах (например, MIPS32), но оно не используется.
Первоначальная версия системного вызова fcntl() в Linux не умела работать с большими файловыми смещениями (в структуре flock). Позднее, в Linux 2.4 был добавлен системный вызов fcntl64(). Новый системный вызов использует другую структуру для блокировки файлов — flock64 и соответствующие команды — F_GETLK64, F_SETLK64 и F_SETLKW64. Однако, это различие может игнорироваться приложениями, которые используют glibc, так как имеющаяся в ней обёрточная функция fcntl() самостоятельно задействует более новый системный вызов, если он доступен.
До Linux 3.12, если клиент NFSv4 теряет связь с сервером на некоторый период времени (более 90 секунд), то он может потерять и перезапросить блокировки даже не зная об этом (период времени, после которого контакт предполагается потерянным в NFSv4 называется время аренды (leasetime). У Linux в сервере NFS его можно узнать по значению в /proc/fs/nfsd/nfsv4leasetime, которое отражает период в секундах. В этом файле значение по умолчанию равно 90). Данный сценарий несёт потенциальный риск повреждения данных, так как в этот перерыв другой процесс может установить блокировку и выполнить файловый ввод-вывод.
Начиная с Linux 3.12, если клиент NFSv4 теряет контакт с сервером, то любой файловый ввод-вывод, выполняемый процессом, который «думает», что имеет блокировку, будет завершаться с ошибкой до тех пор, пока этот процесс не закроет и не переоткроет файл. Чтобы вернуть поведение, которое было до версии pre-3.12, можно параметру ядра nfs.recover_lost_locks присвоить значение 1, из-за чего клиент буде пытаться восстановить потерянные блокировки при переустановлении связи с сервером. Из-за наличия сопутствующего риска повреждения данных, значение данного параметра по умолчанию равно 0 (отключено).
Невозможно использовать F_SETFL для смены состояния флагов O_DSYNC и O_SYNC. Попытка изменить состояние этих флагов просто игнорируется.
Ограничение в соглашениях по системным вызовам Linux на некоторых архитектурах (в частности i386) приводит к тому, что если значение ID группы процесса (отрицательное), возвращаемое по команде F_GETOWN, попадает в диапазон от -1 до -4095, то оно неправильно интерпретируется glibc и считается ошибкой в системном вызове; то есть возвращаемое значение fcntl() будет равно -1, а errno будет содержать значение ID группы процесса (положительное). Команда F_GETOWN_EX (есть только в Linux) не подвержена этой проблеме. Начиная с glibc версии 2.11, glibc делает проблему для F_GETOWN невидимой, реализовав F_GETOWN с помощью F_GETOWN_EX.
В Linux 2.4 и более раннем, есть ошибка, которая может произойти когда непривилегированный процесс использует F_SETOWN для задания владельца дескриптора файла сокета как процесса (группу) отличного от вызывающего. В этом случае fcntl() может вернуть -1 с errno равным EPERM, даже когда процесс (группа) владелец такая же как и вызывающий имеет право посылать сигнал. Несмотря на возвращаемую ошибку, владелец файлового дескриптора всё равно устанавливается и сигналы будут посылаться владельцу.
Алгоритм обнаружения взаимных блокировок задействуется ядром при работе с запросами F_SETLKW и может закончиться как ненахождением (не удалось обнаружить взаимную блокировку и процессы блокируют друг друга навсегда), так и ошибочным нахождением (ошибка EDEADLK, но взаимная блокировка отсутствует). Например, ограничение ядра на вложенность зависимостей блокировки при поиске равна 10, что означает, что цепочки циклических зависимостей, превышающие этот размер, не будут обнаружены. Также ядро может ошибочно посчитать за взаимную блокировку ситуацию, когда два и более процесса, созданных с помощью clone(2) с флагом CLONE_FILES, размещают блокировки, которые похожи (для ядра) на конфликтующие.
Реализация обязательной блокировки в Linux проводит к состязательности процессов, что делает её ненадёжной: вызов write(2), пересекающийся с блокировкой, может изменить данные после установления обязательной блокировки; вызов read(2), пересекающийся с блокировкой, может обнаружить изменившиеся данные, которые были внесены уже установления блокировки на запись. Подобная состязательность существует между обязательными блокировками и mmap(2). Поэтому нецелесообразно полагаться на обязательную блокировку.
dup2(2), flock(2), open(2), socket(2), lockf(3), capabilities(7), feature_test_macros(7), lslocks(8)
Файлы locks.txt, mandatory-locking.txt и dnotify.txt из каталога Documentation/filesystems. исходного кода ядра Linux (в старых ядрах эти файлы были в каталоге Documentation/, а mandatory-locking.txt назывался mandatory.txt).
2019-03-06 | Linux |