因为rename(2)
被 调用mv
,所以可以安全地假设以下内容是原子的吗?
$ mv /home/me/someDir /tmp/toBeDeleted
$ rm -rf /tmp/toBeDeleted
答案1
这mv
命令称为rename
系统调用,保证是原子的。但是,有两个例外:
- 如果源和目标位于不同的文件系统上(这对于
/home
vs.来说相对常见)/tmp
,则rename
失败,mv
然后通过将源树复制到目标,然后删除源树来工作。这显然不是原子的。 - 有些文件系统不是
rename
原子的,例如 NFS 的某些实现。在任何“正常”本地文件系统上,rename
都是原子的。
答案2
如果目录位于作为单个文件系统安装的同一硬件分区上,那么移动某些东西实际上只是将其重命名为不同的路径。但是,如果不是,则可能需要读入并复制其中的每个文件,因此移动的任何部分都不是原子的。正如 Gilles 指出的,POSIX 规定离散文件系统就是这种情况。
strace
除此之外,使用确认进行快速检查mv
确实使用了rename()
系统调用(不要与rename
命令行实用程序混淆)。从用户空间的角度来看,这将使mv
目录成为原子的。如果出现以下情况,系统rename()
调用将抛出 EBUSY 错误:
oldpath 或 newpath 是某个进程正在使用的目录(可能作为当前工作目录,或根目录,或者因为它已打开以供读取)或正在被系统使用(例如作为挂载点),而系统认为这是一个错误。 (请注意,在这种情况下不需要返回 EBUSY — 无论如何进行重命名都没有问题 — 但如果系统无法以其他方式处理此类情况,则允许返回 EBUSY。)
从man 2 rename
。这里与“原子性”的联系是,你不能中断在目录中工作的另一个进程,另一个进程也不能中断它——如果你击败它,它最终会出现无效路径/未找到类型错误追逐。
答案3
这两个答案本质上说的是同一件事,但只关注删除的一个方面。
如果您的 shell 的工作目录位于重命名/移动的目录树中,它将继续看和使用这些文件直到它们被实际删除。因此,shell 将看到处于不同删除状态的文件,因此,重命名/移动(同时 可能是“原子”本身)是不是从文件的所有用户的角度来看,这是一种原子形式的删除。它只影响 shell 从一开始就位于目录树之外的用户。
shell 维护自己有关其所在目录的信息。这是因为在某些配置中,您可能会将当前目录更改为您无权读取确定实际路径所需的目录信息链的目录,例如,通过以下方式到受保护目录的符号链接。