Атомно изменить атрибуты файла - PullRequest
4 голосов
/ 26 февраля 2020

Я хочу атомарно изменить некоторые атрибуты файла. (Справочная информация: это для реализации NFS в пользовательском пространстве, в которой вызов SETATTR устанавливает несколько атрибутов для файла).

Проблема, которую мне не удалось решить, заключается в том, чтобы выполнить обновление атомом c. То есть другой процесс, в котором stat() s или rename() s файл не должен видеть частично обновленные атрибуты.

Различные упрощенные (то есть без проверки ошибок и обработки символических ссылок) подходы с их недостатками:

  • с использованием традиционных функций:

    int setattr(char *path, attributes attrs)
    {
        lchown(path, attr.owner, attr.group);
        chmod(path, attr.mode)
        utime(path, ...)
        return 0
    }
    

    Это не атомы c (и не работает должным образом с символическими ссылками).

  • с использованием fchown() и др.

    int setattr(char *path, attributes attrs)
    {
         int fd = open(path, O_WRONLY);
         fchown(fd, attr.owner, attr.group);
         fchmod(fd, attr.mode);
         futimens(fd, ...);
         return 0;
    }
    

    Это несколько атомов c, но происходит сбой, если режим файла не позволяет открыть или файл является символической ссылкой (в этом случае символическая ссылка атрибуты должны быть изменены вместо цели). Добавление O_PATH к вызову open() также не поможет, так как fchown() и fchmod() затем не удаются.

  • с использованием fchownat() и др.

    int setattr(char *path, attributes attrs)
    {
         int fd = open(dirname(path), O_WRONLY | O_PATH);
         fchownat(fd, basename(path), attr.owner, attr.group, AT_SYMLINK_NOFOLLOW);
         fchmodat(fd, basename(path), attr.mode, 0);
         utimensat(fd, basename(path), ..., AT_SYMLINK_NOFOLLOW);
         return 0;
    }
    

    Это выглядит наиболее многообещающе, но опять-таки это не атомы c.

Я что-то упускаю или нет подхода, который делает то, что я хочу

Ответы [ 3 ]

2 голосов
/ 26 февраля 2020

То есть другой процесс, в котором stat() s или rename() s файл не должен видеть частично обновленные атрибуты.

Если файл уже существует, мало что можно сделать сделать, чтобы остановить другой процесс от доступа к нему, прежде чем изменить его. Этот корабль отплыл.


rename - это атомы c.

Стандартное решение:

  1. Создайте файл с уникальным временным именем в каталоге назначения. Он должен находиться в том же каталоге, чтобы убедиться, что он находится в файловой системе / той же точке монтирования, чтобы не требовалась копия содержимого файла (inode).
  2. Заполните файл. Если файл записан с использованием буферизованного ввода-вывода (что-либо кроме write, pwrite, writev или других системных вызовов ), его необходимо очистить или закрыть (что вызывает грипп sh , что завершается выполнением одного из перечисленных выше системных вызовов).
  3. При необходимости установите правильные разрешения и атрибуты. Права могут быть установлены при создании файла.
  4. rename файл с его окончательным именем файла. rename по существу атомарно создает новое имя файла (жесткую ссылку) на содержимое файла (inode) и удаляет старое имя файла.

Таким образом, когда файл существует, он завершается и имеет правильные разрешения и атрибуты.

1 голос
/ 26 февраля 2020

К сожалению, это невозможно без написания своего собственного системного вызова или модуля ядра для него.

Хотя само ядро ​​Linux определенно способно это осуществить, оно не предоставляет никакого API-интерфейса пользовательского пространства. для этого. Для выполнения этой задачи потребуется либо один системный вызов, который устанавливает все атрибуты одновременно, либо какой-то механизм «блокировки» для предотвращения доступа к файлам (то есть open / stat) другими процессами, даже если они имеют права на это. Поскольку Linux не предоставляет ни системного вызова, ни такого механизма «блокировки», то, чего вы хотите добиться, невозможно из пространства пользователя.

0 голосов
/ 26 февраля 2020

Вы не можете, и ни один из приведенных вами примеров не является атомом c. Всегда существует вероятность того, что какой-то другой поток получит доступ к файлу между вызовами chown и chmod или chmod и utimes.

В Linux для такого понятия существует понятие дескриптора файловой системы (в отличие от дескриптора файла). случаи как пользовательский NFS-сервер. Единственное, что я могу найти в Google на данный момент, это справочная страница из xfsprogs: handle manpage . Но я думаю, что это было обобщено в Linux в последние годы для работы с большим количеством файловых систем.

...