Введение

Компьютерный механизм

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

Процесс A считывает запись о клиенте из файла, содержащего информацию об учетной записи, включая остаток на счете клиента и номер телефона. Процесс B затем считывает ту же запись из того же файла, создавая свою собственную копию. Процесс A изменяет остаток на счете в своей копии записи о клиенте и записывает запись обратно в файл. Процесс B, который все еще имеет устаревшее значение остатка на счете в своей копии записи о клиенте, обновляет остаток на счете и записывает запись о клиенте обратно в файл. В результате процесс B перезаписал устаревшее значение остатка на счете в файл, что привело к потере изменений, внесенных процессом A. Большинство операционных систем поддерживают блокировку записей, что означает, что отдельные записи в любом файле могут быть заблокированы, тем самым увеличивая количество одновременно выполняемых процессов обновления. Блокировка файлов используется при обслуживании баз данных для последовательной организации доступа ко всему физическому файлу, лежащему в основе базы данных. Хотя это предотвращает доступ к файлу со стороны других процессов, это может быть эффективнее, чем индивидуальная блокировка множества областей в файле, поскольку снижает накладные расходы на получение и освобождение каждой блокировки. Неправильное использование блокировки файлов, как и любой другой компьютерной блокировки, может привести к снижению производительности или возникновению взаимоблокировок. Блокировка файлов также может относиться к дополнительным мерам безопасности, применяемым пользователем компьютера с помощью средств безопасности Windows, разрешений NTFS или установки стороннего программного обеспечения для блокировки файлов.

В мейнфреймах

IBM впервые применила блокировку файлов в 1963 году для использования в мэйнфреймах под управлением OS/360, где она называлась "исключительным контролем".

В системах типа Unix

Unix-подобные операционные системы (включая Linux и macOS от Apple) обычно не блокируют открытые файлы автоматически. Доступно несколько механизмов блокировки файлов в различных вариантах Unix, и многие операционные системы поддерживают более одного типа для совместимости. Наиболее распространенным механизмом является fcntl, а два других таких механизма – flock и lockf – каждый из которых может быть реализован поверх fcntl или независимо от него. Хотя некоторые типы блокировок могут быть настроены как обязательные, блокировки файлов в Unix по умолчанию являются совещательными. Это означает, что взаимодействующие процессы могут использовать блокировки для координации доступа к файлу между собой, но не взаимодействующие процессы также могут игнорировать блокировки и получать доступ к файлу любым удобным способом. Иными словами, файловые блокировки блокируют только другие процессы, пытающиеся установить блокировки, а не операции ввода-вывода. Существует два типа блокировок: разделяемые и эксклюзивные. В случае fcntl различные типы блокировок могут применяться к разным участкам (диапазонам байтов) файла или ко всему файлу целиком. Разделяемые блокировки могут удерживаться несколькими процессами одновременно, но эксклюзивная блокировка может удерживаться только одним процессом и не может существовать одновременно с разделяемой блокировкой. Чтобы получить разделяемую блокировку, процесс должен дождаться, пока ни один процесс не удерживает эксклюзивные блокировки. Чтобы получить эксклюзивную блокировку, процесс должен дождаться, пока ни один процесс не удерживает блокировки какого-либо типа. В отличие от блокировок, созданных fcntl, блокировки, созданные flock, сохраняются при вызовах fork, что делает их полезными для форкающихся серверов. Следовательно, более одного процесса может удерживать эксклюзивную блокировку на одном и том же файле, при условии, что эти процессы имеют общую историю (отношение родитель-потомок) и эксклюзивная блокировка была первоначально создана в одном процессе до ее дублирования через fork. Разделяемые блокировки иногда называют "блокировками для чтения", а эксклюзивные блокировки – "блокировками для записи". Однако, поскольку блокировки в Unix являются совещательными, это не обеспечивается. Таким образом, база данных может иметь концепцию "разделяемой записи" и "эксклюзивной записи"; например, изменение поля на месте может быть разрешено при разделяемом доступе, в то время как сборка мусора и перезапись базы данных могут потребовать эксклюзивного доступа. Файловые блокировки применяются к самому файлу, а не к имени файла. Это важно, поскольку Unix позволяет нескольким именам ссылаться на один и тот же файл. В сочетании с совещательными блокировками это обеспечивает большую гибкость при доступе к файлам из нескольких процессов. С другой стороны, подход к кооперативной блокировке может привести к проблемам, когда процесс записывает в файл, не соблюдая файловые блокировки, установленные другими процессами. По этой причине некоторые Unix-подобные операционные системы также предлагают ограниченную поддержку обязательных блокировок. В таких системах файл, у которого установлен бит setgid, но снят бит группового исполнения при открытии, будет автоматически подвергаться обязательной блокировке, если базовая файловая система ее поддерживает. Однако, удаленные разделы NFS, как правило, игнорируют этот бит. Если файл подвергается обязательной блокировке, попытки чтения из области, заблокированной эксклюзивной блокировкой, или записи в область, заблокированную разделяемой или эксклюзивной блокировкой, будут блокироваться до тех пор, пока блокировка не будет снята. Эта стратегия впервые появилась в System V и сегодня встречается в операционных системах Solaris, HP-UX и Linux. Однако она не является частью POSIX, и BSD-производные операционные системы, такие как FreeBSD, OpenBSD, NetBSD и macOS от Apple, не поддерживают ее. Linux также поддерживает обязательную блокировку через специальный параметр "mand" при монтировании файловой системы, но это используется редко. Некоторые Unix-подобные операционные системы предотвращают попытки открыть исполняемый файл работающей программы для записи; это третья форма блокировки, отличная от тех, которые предоставляются fcntl и flock.

Проблемы

Более одного процесса может удерживать эксклюзивный flock-замок для данного файла, если эксклюзивный замок был продублирован при последующем вызове fork. Это упрощает программирование для сетевых серверов и помогает предотвратить гонки данных, но может быть неочевидно для неподготовленного пользователя. Обязательные блокировки не оказывают влияния на системный вызов unlink. Следовательно, некоторые программы могут фактически обходить механизм обязательных блокировок. Стивенс и Раго (2005) отметили, что редактор ed действительно поступал таким образом. Работа flock-замков на сетевых файловых системах, таких как NFS, зависит от реализации. В системах BSD вызовы flock для файлового дескриптора, открытого для файла на NFS-разделе, завершаются успешно, но не оказывают никакого эффекта. В Linux до версии 2.6.12 вызовы flock для NFS-файлов действовали только локально. Начиная с ядра 2.6.12, вызовы flock для NFS-файлов реализуются с использованием POSIX-блокировок по диапазону байтов. Эти блокировки будут видны другим NFS-клиентам, поддерживающим POSIX-блокировки в стиле fcntl, но не будут видны тем, кто их не поддерживает. Повышение и понижение уровня блокировки освобождают старый замок перед применением нового. Если приложение понижает эксклюзивный замок до общего, а другое приложение заблокировано в ожидании эксклюзивного замка, последнее приложение может получить эксклюзивный замок и заблокировать первое приложение. Это означает, что понижение уровня блокировки может приводить к блокировкам, что может быть контринтуитивно. Все fcntl-блокировки, связанные с файлом для данного процесса, удаляются при закрытии любого файлового дескриптора этого файла этим процессом, даже если для этого дескриптора блокировка никогда не запрашивалась. Кроме того, fcntl-блокировки не наследуются дочерним процессом. Семантика закрытия файловых дескрипторов fcntl особенно проблематична для приложений, вызывающих библиотеки подпрограмм, которые могут получать доступ к файлам. Ни один из этих "багов" не возникает при использовании настоящих flock-замков. Сохранение статуса блокировки на открытых файловых дескрипторах, передаваемых другому процессу через Unix domain socket, зависит от реализации.

Буферизированные проблемы ввода/вывода

Один из источников сбоев блокировки возникает, когда буферизированный ввод-вывод использует буферы, выделенные в локальном рабочем пространстве пользователя, а не в пуле буферов операционной системы. Функции fread и fwrite обычно используются для буферизированного ввода-вывода, и после прочтения части файла последующая попытка прочитать ту же часть, скорее всего, извлечет данные из локального буфера. Проблема заключается в том, что другой пользователь, работающий с тем же файлом, имеет собственные локальные буферы, и для него происходит то же самое. Запись данных, полученных из буфера функцией fread, не будет производиться непосредственно из файла, и другой пользователь мог их изменить. Оба пользователя могут использовать flock для обеспечения эксклюзивного доступа, что предотвращает одновременную запись, но поскольку чтение происходит из буфера, а не из самого файла, любые изменения, внесенные пользователем №1, могут быть потеряны пользователем №2 (перезаписаны). Наилучшим решением этой проблемы является использование небуферизированного ввода-вывода (чтения и записи) в сочетании с flock, что также подразумевает использование lseek вместо fseek и ftell. Разумеется, потребуется внести корректировки в параметры функций и возвращаемые значения. В целом, буферизированный ввод-вывод небезопасен при работе с общими файлами.

В AmigaOS

В AmigaOS, блокировка файла (или каталога) может быть установлена с помощью функции Lock (в библиотеке dos.library). Блокировка может быть разделяемой (другие процессы могут читать файл/каталог, но не могут его изменять или удалять), или исключительной, так что доступ к объекту и его изменение разрешены только процессу, успешно установившему блокировку. Блокировка распространяется на весь объект целиком, а не на его часть. Блокировку необходимо снять с помощью функции UnLock: в отличие от Unix, операционная система не снимает блокировку автоматически при завершении процесса.

Программное обеспечение для разблокировки

Разблокировщик — это утилита, используемая для определения процесса, блокирующего файл, и отображающая список этих процессов, а также варианты действий с ними (завершить задачу, разблокировать и т. д.) вместе со списком опций для файла, таких как удаление или переименование. Его назначение — устранять некорректные или устаревшие блокировки файлов, которые часто возникают из-за нештатных ситуаций, например, аварийного завершения или зависания процессов, приводящих к сохранению блокировки файла даже после завершения процесса-владельца. В некоторых Unix-подобных системах для проверки состояния блокировок файлов можно использовать утилиты, такие как fstat и lockf, по процессу, по имени файла или по обоим параметрам. В системах Windows, если файл заблокирован, можно запланировать его перемещение или удаление при следующей перезагрузке. Этот подход обычно используется программами установки для замены заблокированных системных файлов.

Системы управления версиями

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