以原子方式更改文件的属性

Atomically change attributes of a file

我想自动更改文件的某些属性。 (背景:这是针对用户空间 NFS 实现的,其中 SETATTR 调用在文件上设置了多个属性)。

我未能解决的问题是以原子方式进行更新。也就是说,stat()s 或 rename()s 文件的不同进程不应看到部分更新的属性。

不同的简化(即没有错误检查和符号链接处理)方法及其缺点是:

我是不是遗漏了什么,或者没有一种方法可以满足我的要求?

你不能,而且你展示的示例中 none 是原子的。在 chown 和 chmod 或 chmod 和 utimes 调用之间总是有其他线程访问文件的机会。

在Linux 下有文件系统句柄的概念(与文件描述符相对),用于用户空间NFS 服务器等情况。目前我在 google 中唯一能找到的是 xfsprogs 的联机帮助页:handle manpage。但我认为这已在近年来 Linux 中得到推广,以处理更多文件系统。

不幸的是,如果不为它编写您自己的自定义系统调用或内核模块,这是不可能的。

虽然 Linux 内核本身确实有能力做到这一点,但它不会为它公开任何用户空间 API。此任务将需要一次设置所有属性的单个系统调用,或某种 "locking" 机制来防止文件被其他人访问(即 open/stat)过程,即使他们有权这样做。由于 Linux 不提供这样的系统调用,也不提供这样的 "locking" 机制,因此您无法从用户空间实现您想要实现的目标。

That is, a different process that stat()s or rename()s the file should not see partially updated attributes.

如果该文件已经存在,那么在修改它之前您几乎无法阻止另一个进程访问它。那艘船已经起航了。


rename 是原子的。

标准溶液是:

  1. 在目标目录中创建一个具有唯一临时名称的文件。必须在同一个目录才能保证在filesystem/same-mount点,这样就不需要文件内容(inode)拷贝了。
  2. 填充文件。如果文件是使用缓冲 I/O(除 writepwritewritev 或其他 系统调用 之外的任何其他内容)编写的,则需要被刷新或关闭(这会导致刷新,最终会执行上述系统调用之一)。
  3. 如有必要,设置正确的权限和属性。创建文件时可以设置权限。
  4. rename 将文件更改为最终文件名。 rename 基本上以原子方式为文件内容(inode)创建一个新文件名(硬链接)并删除旧文件名。

这样当文件存在时它是完整的并且具有正确的权限和属性。