Может ли POSIX / Linux unlink полностью освободить записи файлов от гонки?


POSIX, как известно, позволяет процессам переименовывать и отсоединять записи файлов, не заботясь о последствиях для других, использующих их, в то время как Windows по умолчанию вызывает ошибку, если вы даже пытаетесь коснуться временных меток каталога, в котором есть дескриптор файла, открытый где-то глубоко внутри.

Однако Windows не должна быть такой консервативной. Если вы открываете все ваши дескрипторы файлов с помощью FILE_FLAG_BACKUP_SEMANTICS и FILE_SHARE_DELETE и заботитесь о переименовании файлов в случайные имена непосредственно перед тем, как помечать их удаление, вы получаете семантику POSIX, включая отсутствие ограничений на манипулирование путями файлов, содержащими открытые дескрипторы файлов.

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

В связи с этим возникает вопрос: А как же POSIX? В POSIX отменить привязку() принимает путь, и между получением текущий путь к файлу, используя дескриптор файла /proc/самоуправления/ФД/х или F_GETPATH и вызова отключить() кто-то может изменилось, что путь, таким образом, потенциально ведущих к неправильный файл разблокируется и данные теряются.

Значительно более безопасным решением является следующее:

  1. получите один из текущих путей открытого файлового дескриптора, используя /proc / self/fd/x или F_GETPATH и т. д.
  2. откройте содержащую его директорию.
  3. выполните statat () в содержащем каталоге для имени листа открытого файлового дескриптора, проверяя, совпадают ли идентификаторы устройств и индексы.
  4. если они совпадают, выполните unlinkat (), чтобы удалить имя листа.

Это гонка безопасно от родительского каталога вверх, хотя жесткая ссылка, которую вы удаляете, может быть не той, которую ожидали. Однако это небезопасно, если внутри содержащего каталога сторонний процесс переименует ваш файл во что-то другое и переименует другой файл в ваше имя листа между проверкой эквивалентности индексов и вызовом unlinkat(). Здесь неправильный файл может быть удален, и данные потеряны.

Поэтому я задаю вопрос: Может ли POSIX, или любая конкретная реализация POSIX, такая как Linux, чтобы полностью отключить файлы бесплатно гонки? Одним из решений может быть снятие связи с записью файла по открытому файловому дескриптору, другим-снятие связи с записью файла по индексу, однако google не нашел решений ни для одного из них. Интересно, что NTFS позволяет удалять по выбору inode или GUID (да, NTFS предоставляет inode, вы можете получить их из ядра NT) в дополнение к удалению через открытый файловый дескриптор, но это не очень помогает здесь.

В случае, если это кажется, слишком эзотерический вопрос, эта проблема влияет на предлагаемый импульс.AFIO , где мне нужно определить, какие гонки системы регистрации я могу смягчить, а какие не могу в рамках ее документированных жестких гарантий поведения.

Edit: уточнил, что нет канонического текущего пути к открытому файловому дескриптору, и что в этом случае нам все равно - мы просто хотим разорвать какую-то из ссылок для файла.

1 3

1 ответ:

Ответов на этот вопрос нет, и я потратил несколько дней, копаясь в исходном коде Linux. Я считаю, что ответ "в настоящее время вы не можете разорвать связь с файлом race free", поэтому я открыл запрос функции по адресу https://bugzilla.kernel.org/show_bug.cgi?id=93441 чтобы иметь Linux extend unlinkat() с флагом расширения At_empty_path Linux. Если они примут эту идею, я отмечу этот ответ как правильный.