Answers:
首先,让我们消除一些神话。
它是原子的,因此不会发生不一致
rename
就软件环境而言,在同一文件系统(即)系统调用中移动文件是原子的。原子性意味着寻找该文件的任何进程将在其旧位置或新位置看到该文件;没有进程能够观察到该文件具有不同的链接计数,或者该文件在目标目录中存在之后在源目录中存在,或者在源文件中不存在之后目标目录中没有该文件目录。
但是,如果系统由于错误,磁盘错误或断电而崩溃,则不能保证文件系统保持一致状态,更不用说移动未完成一半了。Linux通常不会就硬件事件提供原子性保证。
首先,您将目录条目复制到新目录中,然后擦除上一个目录中的条目,因此可能会有两次引用文件的不一致,但是引用计数为1
这是指一种特定的实现技术。还有其他
碰巧Linux上的ext2(从内核3.16开始)使用了这种特殊技术。但是,这并不意味着磁盘内容按顺序[旧位置]→[两个位置]→[新位置]进行,因为这两个操作(添加新条目,删除旧条目)在硬件级别上都不是原子的:其中之一可能会被中断,从而使文件系统处于不一致状态。(希望fsck可以修复它。)此外,块层可以对写入进行重新排序,因此前一半可以在崩溃之前提交到磁盘,而后一半将不执行。
只要系统不崩溃,就不会观察到参考计数与1有所不同(请参见上文),但是该保证不会扩展到系统崩溃。
它首先擦除指针,然后再复制指针,因此不一致之处在于该文件的引用为0
再一次,这是指一种特定的实现技术。如果系统没有崩溃,则无法观察到悬挂文件,但是至少在某些配置中,这是系统崩溃的可能结果。
根据Alexander Larsson的博客文章,ext2无法保证系统崩溃时的一致性,但是ext3可以在这种data=ordered
模式下实现。(请注意,此博客文章不是关于rename
自己的,而是关于写文件和调用rename
该文件的组合。)
ext2,ext3和ext4文件系统的主要作者Theodore Ts'o 就同一问题撰写了一篇博客文章。这篇博客文章讨论了原子性(仅关于软件环境)和持久性(关于崩溃的原子性以及承诺保证,即知道已执行操作)。不幸的是,我无法单独找到关于崩溃的原子性信息。但是,ext4的耐用性保证要求rename
是原子性的。对ext4的内核文件指出,EXT4与auto_da_alloc
选项(这是在现代内核默认设置),以及为ext4,提供了耐用性担保write
后跟一个rename
,这rename
对于硬件崩溃而言是原子的。
为增加了Btrfs,一个rename
覆写现有文件被保证是原子相对于崩溃,但一个rename
不覆盖文件可导致既不文件或现有这两个文件。
总而言之,对于您的问题的答案是,不仅因为ext2崩溃而移动的文件不是原子的,而且甚至不能保证使文件保持一致的状态(尽管fsck
无法修复的故障很少见)—几乎什么都没有,这就是为什么发明了更好的文件系统的原因。Ext3,ext4和btrfs确实提供了有限的保证。
重命名操作在任何文件系统上都非常快,因此不太可能被中断,但是在经典文件系统上,它肯定可以被中断-如果它先创建目标链接,则可以在文件上留下两个链接-这是合法的,但该文件认为它只有一个,如果以后删除一个,可能会导致问题。另一方面,如果先删除源链接,则文件可能会丢失。运行fsck通常会检测并更正这两种情况,但是如果文件丢失,它将以任意名称而不是所需的位置放置在“丢失+找到”目录中-如果它具有两个链接,则链接计数将很简单进行更新,因此如果文件系统支持,文件将存在于两个位置。
如果您需要一个文件系统来应对电源故障,那么应该使用日记文件系统,例如NTFS,EXT3或XFS。默认情况下,大多数现代系统将默认使用日记文件系统,但是您应该知道,如果将FAT用于外部驱动器,则它不是日记文件系统。
日记文件系统使用“重复输入”系统-将要移动的事实写入日记文件,然后执行移动。在启动时检查文件系统时,如果文件系统被中断,它将注意到该移动尚未完成,然后重做。
日记文件系统有两种类型-元数据日记和完整日记。元数据日记功能意味着它不会跟踪日记系统中文件内容的更改(因此,如果您正在写入文件,最终可能会丢失内容),但仍会跟踪重要的文件系统信息,例如目录内容,文件属性等。
当人们谈论重命名操作是原子的时,他们意味着不能在过渡过程中通过系统上的另一个进程观察到它,也不能通过例如用中断mv
命令本身来使它完成一半^C。写入每个目录的物理过程(其存储空间可能位于磁盘上的不同位置)在硬件级别可能不是真正的原子操作。
为了完整起见,我会注意到,除了在目标目录中创建新链接并在旧目录中删除它之外,还有一些与重命名相关的偶然I / O操作-更新两个目录的mtime,可能会扩展目标目录的分配大小,..
如果文件是目录,则更改链接和父目录的链接计数。另外,我不确定文件本身的时间是否受到影响。
在超级用户上,该问题的询问方式略有不同。该mv
命令的Wikipedia页面也对此进行了很好的解释:
通常,在同一文件系统内移动文件的方式与复制文件然后删除原始文件的方式不同。在不支持重命名syscall的平台上,新链接将添加到新目录,原始链接将被删除。无法访问文件数据。
Linux具有重命名的syscall,因此会将文件重命名为原子操作,即不可互操作。因此,在您描述的情况下文件系统不会变得不一致。
rename
即使发生电源故障,系统调用也不能导致文件系统处于不一致状态。我觉得这是@ graphtheory92问题的核心。
rename
是原子的,但是btrfs却不符合Wiki(请参阅我的回答)。也可以在没有日志的情况下保证原子性(我不知道Linux上的示例,但可能会有一些)。您是否有关于ext2的可靠信息?