О надёжности блокировки файлов

Lennart Poettering, “On the Brokenness of File Locking”, public translation into Russian from English More about this translation.

See also 165 similar translations

Translate into another language.

Participants

unixhater 1109 points
constantine 95 points
toxin65 89 points
Join Translated.by to translate! If you already have a Translated.by account, please sign in.
If you do not want to register an account, you can sign in with OpenID.
Pages: ← previous Ctrl next
1 2 3

On the Brokenness of File Locking

О надёжности блокировки файлов

History of edits (Latest: unixhater 7 years, 6 months ago) §

It's amazing how far Linux has come without providing for proper file locking that works and is usable from userspace. A little overview why file locking is still in a very sad state:

Удивительно, как далеко смог продвинуться Linux без обеспечения корректной блокировки файлов, которая работает и может быть использованна из пространства пользователя. Это небольшой обзор причин плачевного сотояния блокировки файлов:

History of edits (Latest: toxin65 7 years, 5 months ago) §

— жалкого состояния блокировки файлов Chris9111

To begin with, there's a plethora of APIs, and all of them are awful:

Начнём с того, что существует множество API и все они ужасны:

History of edits (Latest: unixhater 7 years, 5 months ago) §

POSIX File locking as available with fcntl(F_SET_LK): the POSIX locking API is the most portable one and in theory works across NFS. It can do byte-range locking. So much on the good side. On the bad side there's a lot more however: locks are bound to processes, not file descriptors. That means that this logic cannot be used in threaded environments unless combined with a process-local mutex. This is hard to get right, especially in libraries that do not know the environment they are run in, i.e. whether they are used in threaded environments or not. The worst part however is that POSIX locks are automatically released if a process calls close() on any (!) of its open file descriptors for that file. That means that when one part of a program locks a file and another by coincidence accesses it too for a short time, the first part's lock will be broken and it won't be notified about that. Modern software tends to load big frameworks (such as Gtk+ or Qt) into memory as well as arbitrary modules via mechanisms such as NSS, PAM, gvfs, GTK_MODULES, Apache modules, GStreamer modules where one module seldom can control what another module in the same process does or accesses. The effect of this is that POSIX locks are unusable in any non-trivial program where it cannot be ensured that a file that is locked is never accessed by any other part of the process at the same time. Example: a user managing daemon wants to write /etc/passwd and locks the file for that. At the same time in another thread (or from a stack frame further down) something calls getpwuid() which internally accesses /etc/passwd and causes the lock to be released, the first thread (or stack frame) not knowing that. Furthermore should two threads use the locking fcntl()s on the same file they will interfere with each other's locks and reset the locking ranges and flags of each other. On top of that locking cannot be used on any file that is publicly accessible (i.e. has the R bit set for groups/others, i.e. more access bits on than 0600), because that would otherwise effectively give arbitrary users a way to indefinitely block execution of any process (regardless of the UID it is running under) that wants to access and lock the file. This is generally not an acceptable security risk. Finally, while POSIX file locks are supposedly NFS-safe they not always really are as there are still many NFS implementations around where locking is not properly implemented, and NFS tends to be used in heterogenous networks. The biggest problem about this is that there is no way to properly detect whether file locking works on a specific NFS mount (or any mount) or not.

В POSIX блокировка файла доступна через вызов fcntl(F_SETLK). API POSIX блокировок наиболее переносим и в теории работает через NFS. Он позволяет заблокировать часть файла. С одной стороны в POSIX блокировке много хорошего. С другой стороны, тем не менее, намного больше проблем: блокировки связанны с процессами, а не с файловыми дескрипторам. Это означает, что эта логика не может быть использована в многопоточных средах, разве что в сочетании с мьютексами. Её тяжело сделать правильно, особенно в библиотеках, которые ничего не знают об окружении в котором они запущены, т.е. используются ли они в многопоточном окружении или нет. Тем не менее, хуже всего то, что POSIX-блокировки автоматически освобождаются если процесс вызывает close() на любом(!) открытом файловом дескрипторе этого файла. Это означает, что когда одна часть программы блокирует файл, а другая, случайно, обращается к нему на короткое время, то блокировка из первой части будет снята, причём она не будет уведомлена об этом. Современное програмное обеспечение как правило загружает большие фреймворки (такие как GTK+ или QT) в память, а так же модули через механизмы, такие как NSS, PAM, gvfs, GTK_MODULES, модули Apache, модули GStreamer, где один модуль редко может контролировать то, что делает и к чему обращается другой. В результате чего POSIX-блокировки непригодны для использования в любой не тривиальной программе, где нельзя гарантировать, что к заблокированному файлу никогда не будет обращений из любой другой части программы в то же время. Пример: демон управления учётными записями пользователей хочет записать /etc/passwd и блокирует файл для этого. В тоже время в другом потоке (или из стека дальше) нечто вызывает getpwuid(), который внутри обращается к /etc/passwd и приводит к освобождению блокировки. Первый поток (или стековый фрейм) не узнает об этом. Кроме того, если два потока используют fcntl() блокировки на одном и том же файле, они помешают другим блокировкам и сбросят блокировки сегментов и флаги друг друга. Вдобавок, эти блокировки не могут быть использованы на любом общедоступном файле (с правами на чтение для группы/остальных, т.е. более широкий доступ, чем 0600), потому что в противном случае это даст возможность произвольному пользователю на неопределённое время заблокировать выполнение любых процессов (независимо от UID под которыми он запущены) которые хотят получить доступ и блокируют файл. Это, как правило, неоправданный риск с точки зрения безопасности. И напоследок: в то время как POSIX-блокировки якобы NFS-безопасны, это не всегда так в действительности: существует множество реализаций NFS, которые не обрабатывают блокировки должным образом, а также NFS, как правило, используется в гетерогенных сетях. Самая большая проблема состоит в том, что не существует надёжного способа определить, работает ли блокировка файлов на конкретном смонтированном NFS (или на любом смонтированном) или нет.

History of edits (Latest: toxin65 7 years, 5 months ago) §

— Есть мнение, что broken в контексте locks корректнее переводить как "снятие". unixhater

Pages: ← previous Ctrl next
1 2 3